From 8622d8e72454e238080ee7c43aafb592c59cf157 Mon Sep 17 00:00:00 2001 From: Sahil-SF <138437395+sf-sahil-jassal@users.noreply.github.com> Date: Mon, 1 Jan 2024 17:06:37 +0530 Subject: [PATCH] feat(repository): implement undo soft delete feature (#185) GH-182 ## Description Add 2 functionalities to undo the soft delete of a record 1. undoSoftDeleteById() -> This will just undo soft delete entity by specified id 2. undoSoftDeleteAll() -> This will undo soft delete entities depending on where clause or all. Fixes # (issue) ## Type of change Please delete options that are not relevant. - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested ? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [x] Test A - [x] Test B ## Checklist: - [x] Performed a self-review of my own code - [x] npm test passes on your machine --- .../repository/soft-crud.repository.unit.ts | 75 +++++++++++++++++++ src/repositories/soft-crud.repository.base.ts | 31 +++++++- 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/__tests__/unit/repository/soft-crud.repository.unit.ts b/src/__tests__/unit/repository/soft-crud.repository.unit.ts index 71d05ef..5ddd30b 100644 --- a/src/__tests__/unit/repository/soft-crud.repository.unit.ts +++ b/src/__tests__/unit/repository/soft-crud.repository.unit.ts @@ -133,6 +133,7 @@ describe('SoftCrudRepository', () => { const customers = await repo.find(); expect(customers).to.have.length(3); }); + it('should find non soft deleted entries with and operator', async () => { const customers = await repo.find({ where: { @@ -793,6 +794,80 @@ describe('SoftCrudRepository', () => { }); }); + describe('undoSoftDelete', () => { + beforeEach(setupTestData); + afterEach(clearTestData); + + it('should undo soft deleted entry by id', async () => { + await repo.undoSoftDeleteById(3); + const customer = await repo.findById(3); + const customers = await repo.find(); + expect(customer.deleted).to.false(); + expect(customers).to.have.length(4); + }); + + it('should check deletedOn flag is undefined after undo', async () => { + const softDeletedCustomer = await repo.findByIdIncludeSoftDelete(3); + expect(softDeletedCustomer.deletedOn).to.Date(); + await repo.undoSoftDeleteById(3); + const customer = await repo.findById(3); + expect(customer.deletedOn).to.undefined(); + }); + + it('should undo all soft deleted entries', async () => { + await repo.deleteAll(); + await repo.undoSoftDeleteAll(); + const customers = await repo.find(); + expect(customers).to.have.length(4); + }); + + it('should undo soft deleted entries with and operator', async () => { + await repo.undoSoftDeleteAll({ + and: [{email: 'alice@example.com'}, {id: 3}], + }); + const customers = await repo.find({ + where: { + and: [ + { + email: 'alice@example.com', + }, + { + id: 3, + }, + ], + }, + }); + expect(customers).to.have.length(1); + }); + + it('should undo soft deleted entries with or operator', async () => { + await repo.deleteAll({email: 'john@example.com'}); + await repo.undoSoftDeleteAll({ + or: [ + { + email: 'john@example.com', + }, + { + email: 'alice@example.com', + }, + ], + }); + const customers = await repo.find({ + where: { + or: [ + { + email: 'john@example.com', + }, + { + email: 'alice@example.com', + }, + ], + }, + }); + expect(customers).to.have.length(2); + }); + }); + describe('deleteAll', () => { beforeEach(setupTestData); afterEach(clearTestData); diff --git a/src/repositories/soft-crud.repository.base.ts b/src/repositories/soft-crud.repository.base.ts index c29037e..99dca60 100644 --- a/src/repositories/soft-crud.repository.base.ts +++ b/src/repositories/soft-crud.repository.base.ts @@ -4,13 +4,13 @@ import {Getter} from '@loopback/core'; import { + Condition, DataObject, DefaultCrudRepository, Entity, Filter, - juggler, Where, - Condition, + juggler, } from '@loopback/repository'; import {Count} from '@loopback/repository/src/common-types'; import {HttpErrors} from '@loopback/rest'; @@ -168,6 +168,33 @@ export abstract class SoftCrudRepository< ); } + /** + * Method to perform undo the soft delete by Id. + * @param id + * @param options + */ + async undoSoftDeleteById(id: ID, options?: Options): Promise { + await this.undoSoftDeleteAll({id} as Where, options); + } + + /** + * Method to perform undo all the soft deletes + * @param where + * @param options + */ + async undoSoftDeleteAll(where?: Where, options?: Options): Promise { + const filter = new SoftFilterBuilder({where}) + .imposeCondition({ + deleted: true, + } as Condition) + .build(); + return super.updateAll( + {deleted: false, deletedOn: undefined}, + filter.where, + options, + ); + } + /** * Method to perform hard delete of entries. Take caution. * @param entity