Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .cursor/rules/mongo-lib.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
description:
globs:
alwaysApply: true
---

# Your rule content

- This Project is a private npm package. it's for all projects to interact with mongo db.
- Always use clean code and design patterns.
- Alwyas propose the codes base on the current strctour.
6 changes: 0 additions & 6 deletions CHANGELOG.md

This file was deleted.

96 changes: 96 additions & 0 deletions __tests__/unit/models/thread.model.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { IThread } from '../../../src/interfaces';
import { Thread } from '../../../src/models';

describe('Thread model', () => {
describe('thread validation', () => {
let thread: IThread;
beforeEach(() => {
thread = {
id: '123456789012345678',
type: 11,
guild_id: '987654321098765432',
parent_id: '111111111111111111',
owner_id: '222222222222222222',
name: 'Test Thread',
last_message_id: '333333333333333333',
message_count: 5,
member_count: 3,
rate_limit_per_user: 0,
thread_metadata: {
archived: false,
auto_archive_duration: 1440,
archive_timestamp: '2024-01-01T00:00:00.000Z',
locked: false,
invitable: true,
},
total_message_sent: 5,
flags: 0,
applied_tags: ['444444444444444444'],
nsfw: false,
};
});

test('should correctly validate a valid Thread data', async () => {
await expect(new Thread(thread).validate()).resolves.toBeUndefined();
});

test('should fail validation with invalid thread type', async () => {
thread.type = 5 as any;
await expect(new Thread(thread).validate()).rejects.toThrow();
});

test('should fail validation with invalid auto_archive_duration', async () => {
thread.thread_metadata.auto_archive_duration = 999;
await expect(new Thread(thread).validate()).rejects.toThrow();
});

test('should fail validation with name too long', async () => {
thread.name = 'x'.repeat(101);
await expect(new Thread(thread).validate()).rejects.toThrow();
});

test('should fail validation with negative message_count', async () => {
thread.message_count = -1;
await expect(new Thread(thread).validate()).rejects.toThrow();
});

test('should fail validation with member_count over limit', async () => {
thread.member_count = 51;
await expect(new Thread(thread).validate()).rejects.toThrow();
});

test('should fail validation with rate_limit_per_user over limit', async () => {
thread.rate_limit_per_user = 21601;
await expect(new Thread(thread).validate()).rejects.toThrow();
});

test('should handle ANNOUNCEMENT_THREAD type', async () => {
thread.type = 10;
await expect(new Thread(thread).validate()).resolves.toBeUndefined();
});

test('should handle PRIVATE_THREAD type', async () => {
thread.type = 12;
thread.thread_metadata.invitable = false;
await expect(new Thread(thread).validate()).resolves.toBeUndefined();
});

test('should handle minimal required data', async () => {
const minimalThread = {
id: '123456789012345678',
type: 11,
guild_id: '987654321098765432',
parent_id: '111111111111111111',
owner_id: '222222222222222222',
name: 'Minimal Thread',
thread_metadata: {
archived: false,
auto_archive_duration: 1440,
archive_timestamp: '2024-01-01T00:00:00.000Z',
locked: false,
},
};
await expect(new Thread(minimalThread).validate()).resolves.toBeUndefined();
});
});
});
8 changes: 2 additions & 6 deletions src/interfaces/Announcement.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Model, type Types, type ObjectId } from 'mongoose';
import { Model, ObjectId, Types } from 'mongoose';

interface IDiscordOptions {
channelIds?: string[];
Expand Down Expand Up @@ -30,10 +30,6 @@ export interface IAnnouncement {
data: Array<IAnnouncementData<IDiscordOptions>>;
}

export interface IAnnouncementMethods {
softDelete: (userId: ObjectId) => void;
}

export interface AnnouncementModel extends Model<IAnnouncement, Record<string, unknown>, IAnnouncementMethods> {
export interface AnnouncementModel extends Model<IAnnouncement> {
paginate: (filter: object, options: object) => any;
}
2 changes: 1 addition & 1 deletion src/interfaces/Channel.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface IChannelUpdateBody {
type?: number;
}
export interface IChannelMethods {
softDelete: () => void;
softDelete: () => Promise<void>;
}

export interface ChannelPayload {
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/GuildMember.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface GuildMemberPayload {
}

export interface IGuildMemberMethods {
softDelete: () => void;
softDelete: () => Promise<void>;
}

export interface GuildMemberModel extends Model<IGuildMember, Record<string, unknown>, IGuildMemberMethods> {
Expand Down
5 changes: 3 additions & 2 deletions src/interfaces/Platfrom.interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type Model, type Types } from 'mongoose';
import { type PlatformNames } from '../config/enums';
import { Model, Types } from 'mongoose';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix the filename typo.

The filename contains a typo: "Platfrom" should be "Platform". This could cause confusion and make the file harder to find.

Consider renaming the file to Platform.interface.ts to correct the typo.

🤖 Prompt for AI Agents
In src/interfaces/Platfrom.interface.ts at line 1, the filename contains a typo
"Platfrom" instead of "Platform". Rename the file from Platfrom.interface.ts to
Platform.interface.ts to correct the spelling and avoid confusion.


import { PlatformNames } from '../config/enums';

export interface IPlatform {
name: PlatformNames;
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/Role.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface IRoleUpdateBody {
}

export interface IRoleMethods {
softDelete: () => void;
softDelete: () => Promise<void>;
}

export interface RolePayload {
Expand Down
51 changes: 51 additions & 0 deletions src/interfaces/Thread.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Snowflake } from 'discord.js';
import { Model } from 'mongoose';

export interface IThreadMetadata {
archived: boolean;
auto_archive_duration: number;
archive_timestamp: string;
locked: boolean;
invitable?: boolean;
create_timestamp?: string;
}

export interface IThread {
id: Snowflake;
type: 10 | 11 | 12;
guild_id: Snowflake;
parent_id: Snowflake;
owner_id: Snowflake;
name: string;
last_message_id?: Snowflake | null;
message_count?: number;
member_count?: number;
rate_limit_per_user?: number;
thread_metadata: IThreadMetadata;
total_message_sent?: number;
flags?: number;
applied_tags?: Snowflake[];
nsfw?: boolean;
deletedAt?: Date | null;
}

export interface IThreadUpdateBody {
name?: string;
archived?: boolean;
auto_archive_duration?: number;
locked?: boolean;
invitable?: boolean;
rate_limit_per_user?: number;
flags?: number;
applied_tags?: Snowflake[];
nsfw?: boolean;
deletedAt?: Date | null;
}

export interface IThreadMethods {
softDelete: () => Promise<void>;
}

export interface ThreadModel extends Model<IThread, Record<string, unknown>, IThreadMethods> {
paginate: (filter: object, options: object) => any;
}
1 change: 1 addition & 0 deletions src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './Community.interface';
export * from './Platfrom.interface';
export * from './Announcement.interface';
export * from './Module.interface';
export * from './Thread.interface';
6 changes: 6 additions & 0 deletions src/models/Thread.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { model } from 'mongoose';

import { IThread, ThreadModel } from '../interfaces';
import { threadSchema } from './schemas';

export default model<IThread, ThreadModel>('Thread', threadSchema);
21 changes: 12 additions & 9 deletions src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import User from './User.model';
import Token from './Token.model';
import HeatMap from './HeatMap.model';
import RawInfo from './RawInfo.model';
import MemberActivity from './memberActivity.model';
import GuildMember from './GuildMember.model';
import Announcement from './Announcement.model';
import Channel from './Channel.model';
import Role from './Role.model';
import Community from './Community.model';
import Platform from './Platfrom.model';
import Announcement from './Announcement.model';
import GuildMember from './GuildMember.model';
import HeatMap from './HeatMap.model';
import MemberActivity from './memberActivity.model';
import Module from './Module.model';
import Platform from './Platfrom.model';
import RawInfo from './RawInfo.model';
import Role from './Role.model';
import Thread from './Thread.model';
import Token from './Token.model';
import User from './User.model';

export {
User,
Token,
Expand All @@ -23,4 +25,5 @@ export {
Platform,
Announcement,
Module,
Thread,
};
7 changes: 4 additions & 3 deletions src/models/schemas/Channel.schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema } from 'mongoose';
import { toJSON, paginate } from './plugins';
import { type IChannel, type ChannelModel } from '../../interfaces';

import { ChannelModel, IChannel } from '../../interfaces';
import { paginate, toJSON } from './plugins';

const channelSchema = new Schema<IChannel, ChannelModel>({
channelId: {
Expand All @@ -18,7 +19,7 @@ const channelSchema = new Schema<IChannel, ChannelModel>({
},
permissionOverwrites: [
{
id: String, // or use mongoose.Schema.Types.ObjectId if Snowflake is an ObjectId
id: String,
type: {
type: Number,
enum: [0, 1],
Expand Down
Loading