diff --git a/package-lock.json b/package-lock.json index b158941..45c877d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "soft-delete-plugin-mongoose", - "version": "1.0.14", + "version": "1.0.15", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "soft-delete-plugin-mongoose", - "version": "1.0.14", + "version": "1.0.15", "license": "MIT", "devDependencies": { "@types/jest": "^29.4.0", diff --git a/package.json b/package.json index 51f6883..cbaf067 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "dist/**/*" ], "scripts": { - "clean": "del .\\dist\\*", + "clean": "rm -rf ./dist", "build": "npm run clean && tsc", "test": "jest" }, diff --git a/src/soft-delete-plugin.ts b/src/soft-delete-plugin.ts index e9cb03f..f2698ca 100644 --- a/src/soft-delete-plugin.ts +++ b/src/soft-delete-plugin.ts @@ -13,6 +13,17 @@ export const softDeletePlugin = (schema: mongoose.Schema) => { }, }); + // @ts-ignore + schema.pre('findOne', + async function (this, next: (err?: CallbackError) => void) { + if (this.getFilter().isDeleted === true) { + return next(); + } + this.setQuery({ ...this.getFilter(), isDeleted: { $ne: true } }); + next(); + }, + ); + // @ts-ignore schema.pre('find', async function (this, next: (err?: CallbackError) => void) { @@ -24,6 +35,17 @@ export const softDeletePlugin = (schema: mongoose.Schema) => { }, ); + // @ts-ignore + schema.pre('findOneAndUpdate', + async function (this, next: (err?: CallbackError) => void) { + if (this.getFilter().isDeleted === true) { + return next(); + } + this.setQuery({ ...this.getFilter(), isDeleted: { $ne: true } }); + next(); + }, + ); + // @ts-ignore schema.pre('count', async function (this, next: (err?: CallbackError) => void) { diff --git a/tests/index.test.ts b/tests/index.test.ts index 7b7725a..a8ebd9c 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,5 +1,5 @@ -import mongoose from 'mongoose'; -import { softDeletePlugin, SoftDeleteModel } from '../src/index'; +import mongoose from "mongoose"; +import { softDeletePlugin, SoftDeleteModel } from "../src/index"; interface User extends mongoose.Document { name: string; @@ -8,25 +8,29 @@ const UserSchema = new mongoose.Schema({ name: String, }); UserSchema.plugin(softDeletePlugin); -const userModel = mongoose.model>('User', UserSchema); +const userModel = mongoose.model>( + "User", + UserSchema +); -describe('soft delete plugin', () => { +describe("soft delete plugin", () => { beforeAll(async () => { - await mongoose.connect('mongodb://0.0.0.0:27017/test', { useNewUrlParser: true, useUnifiedTopology: true }); - }) + const url = "'mongodb://0.0.0.0:27017/test'"; + await mongoose.connect(url); + }); afterAll(async () => { await mongoose.disconnect(); - }) + }); afterEach(async () => { await userModel.deleteMany(); }); - test('softDelete should be successed', async () => { + test("softDelete should be successed", async () => { // create one user - const user = await new userModel({ name: 'peter' }).save(); - expect(user.name).toBe('peter'); + const user = await new userModel({ name: "peter" }).save(); + expect(user.name).toBe("peter"); // get this user before we perform soft delete const userBeforeDelete = await userModel.find({ _id: user._id }); @@ -41,10 +45,53 @@ describe('soft delete plugin', () => { expect(userAfterDelete?.length).toBe(0); }); - test('restore should be successed', async () => { + test("softDelete should be successed on findOne", async () => { // create one user - const user = await new userModel({ name: 'peter' }).save(); - expect(user.name).toBe('peter'); + const user = await new userModel({ name: "peter" }).save(); + expect(user.name).toBe("peter"); + + // get this user before we perform soft delete + const userBeforeDelete = await userModel.findOne({ _id: user._id }); + expect(userBeforeDelete?.name).toBe("peter"); + + // perform soft delete + const softDeleteResp = await userModel.softDelete({ _id: user._id }); + expect(softDeleteResp.deleted).toBe(1); + + // get this user after we performed soft delete + const userAfterDelete = await userModel.findOne({ _id: user._id }); + expect(userAfterDelete).toBe(null); + }); + + test("softDelete should be successed on findOneAndUpdate", async () => { + // create one user + const user = await new userModel({ name: "peter" }).save(); + expect(user.name).toBe("peter"); + + // get this user before we perform soft delete + const userBeforeDelete = await userModel.findOneAndUpdate( + { _id: user._id }, + { name: "mahdad" }, + { new: true } + ); + expect(userBeforeDelete?.name).toBe("mahdad"); + + // perform soft delete + const softDeleteResp = await userModel.softDelete({ _id: user._id }); + expect(softDeleteResp.deleted).toBe(1); + + // get this user after we performed soft delete + const userAfterDelete = await userModel.findOneAndUpdate( + { _id: user._id }, + { name: "mahdad" } + ); + expect(userAfterDelete).toBe(null); + }); + + test("restore should be successed", async () => { + // create one user + const user = await new userModel({ name: "peter" }).save(); + expect(user.name).toBe("peter"); // perform soft delete const softDeleteResp = await userModel.softDelete({ _id: user._id }); @@ -63,10 +110,10 @@ describe('soft delete plugin', () => { expect(userAfterRestore?.length).toBe(1); }); - test('findDeleted should be successed', async () => { + test("findDeleted should be successed", async () => { // create one user - const user = await new userModel({ name: 'peter' }).save(); - expect(user.name).toBe('peter'); + const user = await new userModel({ name: "peter" }).save(); + expect(user.name).toBe("peter"); // perform soft delete const softDeleteResp = await userModel.softDelete({ _id: user._id }); @@ -81,4 +128,3 @@ describe('soft delete plugin', () => { expect(deletedUsers.length).toBe(1); }); }); - diff --git a/tsconfig.json b/tsconfig.json index 28e3ebe..9cd85b1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -44,7 +44,7 @@ /* Module Resolution Options */ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + "baseUrl": "./src", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ @@ -67,5 +67,7 @@ /* Advanced Options */ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - } + }, + "include": ["src/**/*.ts"], + "exclude": ["tests"] }