Skip to content

Commit

Permalink
Merge pull request #118 from TogetherCrew/116-cascade-delete-operations
Browse files Browse the repository at this point in the history
116 cascade delete operations
  • Loading branch information
cyri113 authored Oct 7, 2023
2 parents 434e276 + 8f11440 commit f275557
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 24 deletions.
33 changes: 32 additions & 1 deletion __tests__/unit/models/community.mode.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Community } from '../../../src/models';
import { Community, User, Platform } from '../../../src/models';
import { ICommunity } from '../../../src/interfaces';
import { Types } from 'mongoose';
// import setupTestDB from '../../utils/setupTestDB';

// setupTestDB();

describe('Community model', () => {
describe('Community validation', () => {
Expand All @@ -9,11 +12,39 @@ describe('Community model', () => {
community = {
name: 'community1',
users: [new Types.ObjectId()],
avatarURL: 'avatarURL',
platforms: [new Types.ObjectId(), new Types.ObjectId()],
};
});

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

// describe('Cascade deletes', () => {

// test('should clean up when community is deleted', async () => {
// const user = new User({ discordId: 'discordId' });
// await user.save();

// const community = new Community({ users: [user._id], name: 'community' });
// await community.save();
// user.communities?.push(community._id)

// const platform = new Platform({ name: 'platform', community: community._id });
// await platform.save();

// community.platforms?.push(platform._id);
// await community.save();

// await community.remove();

// const userDoc = await User.findById(user._id);
// expect(userDoc?.communities).not.toContain(community._id);

// const platformDoc = await Platform.findById(platform._id);
// expect(platformDoc).toBe(null);
// });
// });
});
});
43 changes: 37 additions & 6 deletions __tests__/unit/models/platform.model.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
import { Platfrom } from '../../../src/models';
import { Platform, Community } from '../../../src/models';
import { IPlatform } from '../../../src/interfaces';
import { Types } from 'mongoose';
// import setupTestDB from '../../utils/setupTestDB';

describe('Platfrom model', () => {
// setupTestDB();

describe('Platform model', () => {
describe('Platform validation', () => {
let platfrom: IPlatform;
let platform: IPlatform;
beforeEach(() => {
platfrom = {
platform = {
name: 'Discord',
community: new Types.ObjectId(),
metadata: {
guildId: 'guildId',
selectedChannels: ['c1', 'c2'],
},
disconnectedAt: null,
};
});

test('should correctly validate a valid platfrom', async () => {
await expect(new Platfrom(platfrom).validate()).resolves.toBeUndefined();
test('should correctly validate a valid platform', async () => {
await expect(new Platform(platform).validate()).resolves.toBeUndefined();
});

// describe('Cascade deletes', () => {

// test('should clean up when community is deleted', async () => {
// const community = new Community({ users: [new Types.ObjectId()], name: 'community' });
// await community.save();

// const platform = new Platform({ name: 'platform', community: community._id });
// await platform.save();

// community.platforms?.push(platform._id);
// await community.save();

// await platform.remove();

// const communityDoc = await Community.findById(community._id);

// expect(communityDoc?.platforms).not.toContain(platform._id);

// const platformDoc = await Platform.findById(platform._id);
// expect(platformDoc).toBe(null);
// });
// });
});
});
26 changes: 25 additions & 1 deletion __tests__/unit/models/user.model.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { User } from '../../../src/models';
import { User, Community } from '../../../src/models';
import { IUser } from '../../../src/interfaces';
import { Types } from 'mongoose';
// import setupTestDB from '../../utils/setupTestDB';

// setupTestDB();

describe('User model', () => {
describe('User validation', () => {
let user: IUser;

beforeEach(() => {
user = {
discordId: '1234',
email: 'email@yahoo.com',
communities: [new Types.ObjectId(), new Types.ObjectId()],
};
});

Expand All @@ -19,4 +26,21 @@ describe('User model', () => {
await expect(new User(user).validate()).rejects.toThrow();
});
});

// describe('Cascade deletes', () => {

// test('should remove user reference from community when user is deleted', async () => {
// const user = new User({ discordId: 'discordId' });
// await user.save();

// const community = new Community({ users: [user._id], name: 'community' });
// await community.save();

// await user.remove();

// const communityDoc = await Community.findById(community._id);
// expect(communityDoc?.users).not.toContain(user._id);

// });
// });
});
21 changes: 21 additions & 0 deletions __tests__/utils/setupTestDB.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// import mongoose from 'mongoose';
// import config from '../../src/config';

// const setupTestDB = () => {
// beforeAll(async () => {
// mongoose.set('strictQuery', false);
// await mongoose.connect(config.mongoose.serverURL);
// });

// beforeEach(async () => {
// await Promise.all(
// Object.values(mongoose.connection.collections).map(async (collection) => collection.deleteMany({})),
// );
// });

// afterAll(async () => {
// await mongoose.disconnect();
// });
// };

// export default setupTestDB;
11 changes: 9 additions & 2 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
// eslint-disable-next-line no-undef
module.exports = {
preset: 'ts-jest',
testPathIgnorePatterns: ['/__tests__/fixtures', '/__tests__/utils'],
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
'^.+\\.(js|jsx)$': 'babel-jest',
},
collectCoverage: true,
testEnvironment: 'node',
coverageReporters: ['json', 'lcov', 'text', 'clover', 'html'],
collectCoverageFrom: ['src/**/*.ts*'],
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@togethercrew.dev/db",
"version": "3.0.00",
"version": "3.0.10",
"description": "All interactions with DB",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand All @@ -9,7 +9,7 @@
"start": "node ./dist/index.js",
"dev": "nodemon ./src/index.ts",
"test": "jest --detectOpenHandles",
"format": "prettier --write \"src/**/*.ts\" \"__tests__/unit/models/**/*.ts\" ",
"format": "prettier --write \"src/**/*.ts\" \"__tests__/**/*.ts\" \"*.ts\" ",
"prepublishOnly": "npm test",
"version": "npm run format && git add -A src",
"postversion": "git push && git push --tags"
Expand Down
26 changes: 26 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import Joi from 'joi';

const envVarsSchema = Joi.object()
.keys({
DB_HOST: Joi.string().required().description('Mongo DB url'),
DB_PORT: Joi.string().required().description('Mongo DB port'),
DB_USER: Joi.string().required().description('Mongo DB username'),
DB_PASSWORD: Joi.string().required().description('Mongo DB password'),
DB_NAME: Joi.string().required().description('Mongo DB name'),
})
.unknown();

const { value: envVars, error } = envVarsSchema.prefs({ errors: { label: 'key' } }).validate(process.env);

if (error != null) {
throw new Error(`Config validation error: ${error.message}`);
}

export default {
mongoose: {
serverURL: `mongodb://${envVars.DB_USER}:${envVars.DB_PASSWORD}@${envVars.DB_HOST}:${envVars.DB_PORT}/${envVars.DB_NAME}`,
botURL: `mongodb://${envVars.DB_USER}:${envVars.DB_PASSWORD}@${envVars.DB_HOST}:${envVars.DB_PORT}`,
dbURL: `mongodb://${envVars.DB_USER}:${envVars.DB_PASSWORD}@${envVars.DB_HOST}:${envVars.DB_PORT}`,
},
};
8 changes: 4 additions & 4 deletions src/interfaces/Community.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { type Model, type Types } from 'mongoose';
export interface ICommunity {
name: string;
avatarURL?: string;
users: [Types.ObjectId];
platforms?: [Types.ObjectId];
users: Types.ObjectId[];
platforms?: Types.ObjectId[];
}

export interface ICommunityUpdateBody {
name?: string;
avatarURL?: string;
users?: [Types.ObjectId];
platforms?: [Types.ObjectId];
users?: Types.ObjectId[];
platforms?: Types.ObjectId[];
}

export interface CommunityModel extends Model<ICommunity> {
Expand Down
4 changes: 2 additions & 2 deletions src/interfaces/User.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { type Model, type Types } from 'mongoose';
export interface IUser {
discordId: Snowflake;
email?: string;
communities?: [Types.ObjectId];
communities?: Types.ObjectId[];
}

export interface IUserUpdateBody {
email?: string;
communities?: [Types.ObjectId];
communities?: Types.ObjectId[];
}

export interface UserModel extends Model<IUser> {
Expand Down
4 changes: 2 additions & 2 deletions src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import GuildMember from './GuildMember.model';
import Channel from './Channel.model';
import Role from './Role.model';
import Community from './Community.model';
import Platfrom from './Platfrom.model';
export { User, Token, HeatMap, RawInfo, MemberActivity, GuildMember, Channel, Role, Community, Platfrom };
import Platform from './Platfrom.model';
export { User, Token, HeatMap, RawInfo, MemberActivity, GuildMember, Channel, Role, Community, Platform };
17 changes: 15 additions & 2 deletions src/models/schemas/Community.schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema } from 'mongoose';
import { Schema, type Document } from 'mongoose';
import { toJSON, paginate } from './plugins';
import { type ICommunity, type CommunityModel } from '../../interfaces';
import { User, Platform } from '../index';

const communitySchema = new Schema<ICommunity, CommunityModel>(
{
Expand All @@ -16,7 +17,13 @@ const communitySchema = new Schema<ICommunity, CommunityModel>(
{
type: Schema.Types.ObjectId,
ref: 'User',
required: true, // A community must have at least one user
required: true,
},
],
platforms: [
{
type: Schema.Types.ObjectId,
ref: 'Platform',
},
],
},
Expand All @@ -28,4 +35,10 @@ const communitySchema = new Schema<ICommunity, CommunityModel>(
communitySchema.plugin(toJSON);
communitySchema.plugin(paginate);

communitySchema.pre('remove', async function (this: Document) {
const communityId = this._id;

await User.updateMany({ communities: communityId }, { $pull: { communities: communityId } });
await Platform.deleteMany({ community: communityId });
});
export default communitySchema;
8 changes: 7 additions & 1 deletion src/models/schemas/Platform.schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema } from 'mongoose';
import { Schema, type Document } from 'mongoose';
import { toJSON, paginate } from './plugins';
import { type IPlatform, type PlatformModel } from '../../interfaces';
import { Community } from '../index';

const platformSchema = new Schema<IPlatform, PlatformModel>(
{
Expand Down Expand Up @@ -29,4 +30,9 @@ const platformSchema = new Schema<IPlatform, PlatformModel>(
platformSchema.plugin(toJSON);
platformSchema.plugin(paginate);

platformSchema.pre('remove', async function (this: Document) {
const platformId = this._id;
await Community.updateOne({ platforms: platformId }, { $pull: { platforms: platformId } });
});

export default platformSchema;
8 changes: 7 additions & 1 deletion src/models/schemas/User.schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema } from 'mongoose';
import { Schema, type Document } from 'mongoose';
import validator from 'validator';
import { toJSON, paginate } from './plugins';
import { Community } from '../index';
import { type IUser, type UserModel } from '../../interfaces';

const userSchema = new Schema<IUser, UserModel>(
Expand Down Expand Up @@ -29,6 +30,11 @@ const userSchema = new Schema<IUser, UserModel>(
{ timestamps: true },
);

userSchema.pre('remove', async function (this: Document) {
const userId = this._id;
await Community.updateMany({ users: userId }, { $pull: { users: userId } });
});

// Plugins
userSchema.plugin(toJSON);
userSchema.plugin(paginate);
Expand Down

0 comments on commit f275557

Please sign in to comment.