Skip to content

Commit c4b80c4

Browse files
authored
refactor(chore): remove duplicate code and deprecate DefaultTransactionSoftCrudRepository (#131)
* fix(chore): add #122 changes in mixin and transaction repository add development note to ensure future modifications universal add changes made in PR #122 in soft-crud mixin and transaction-soft-crud repository GH-129 * refactor(chore): add common service and decorator for filter modification created soft crud service file containing common code among artifacts created softFilter and excludeSoftDeleted decorator for the common tasks GH-128 * refactor(repository): deprecate `DefaultTransactionSoftCrudRepository` in favor of SoftCrudRepositoryMixin for improving maintainability GH-132 * refactor(repository): replace modify functions with custom soft filter builder removed soft-crud service and used custom soft filter builder class providing methods like imposeCondition, fields etc. GH-0 * refactor(chore): resolve sonar code smells ignore transactional respotory file in sonar as this is deprecated and kept duplicacy of the code just for few months of support add avoid rule for arrowParens in prettier GH-0
1 parent 72b213d commit c4b80c4

16 files changed

+582
-872
lines changed

.prettierrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
"bracketSpacing": false,
33
"singleQuote": true,
44
"printWidth": 80,
5-
"trailingComma": "all"
5+
"trailingComma": "all",
6+
"arrowParens": "avoid"
67
}

.sonarcloud.properties

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Path to sources
22
sonar.sources=src
3-
sonar.exclusions=src/__tests__/**
3+
4+
# ignoring transaction repository as the duplication of the code is
5+
# a compulsion in it, It's currently deprecated and will be completely removed in future releases.
6+
sonar.exclusions=src/__tests__/**,src/repositories/default-transaction-soft-crud.repository.base.ts
47
#sonar.inclusions=
58

69
# Path to tests

README.md

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,43 @@ npm install loopback4-soft-delete
2222

2323
For a quick starter guide, you can refer to our [loopback 4 starter](https://github.com/sourcefuse/loopback4-starter) application which utilizes this package for soft-deletes in a multi-tenant application.
2424

25-
## Transaction support
25+
## Usage
2626

27-
With version 3.0.0, transaction repository support has been added. In place of SoftCrudRepository, extend your repository with DefaultTransactionSoftCrudRepository. For further usage guidelines, refer below.
27+
The package exports following classes and mixins:
2828

29-
## Usage
29+
1. [SoftDeleteEntity](#softdeleteentity) - To add required soft delete props in the model.
30+
2. [SoftCrudRepository](#softcrudrepository) - Class providing soft crud capabilitiies (to be used in place of `DefaultCrudRepository`).
31+
3. [SoftCrudRepositoryMixin](#softcrudrepositorymixin) - Mixin accepting any respository that extends the DefaultCrudRepository to add soft delete functionality to. Can be used as a wrapper for `DefaultCrudRepository`, `DefaultTransactionalRepository` etc.
32+
4. [SoftDeleteEntityMixin](#softdeleteentitymixin)
33+
5. [DefaultTransactionSoftCrudRepository](#defaulttransactionsoftcrudrepository-deprecated) (Deprecated) - Class providing soft crud capabilitiies. To be used in place of `DefaultTransactionalRepository`.
34+
35+
Following are more details on the usage of above artifcats:
36+
37+
### SoftDeleteEntity
38+
39+
An abstract base class for all models which require soft delete feature.
40+
This class is a wrapper over Entity class from [@loopback/repository](https://github.com/strongloop/loopback-next/tree/master/packages/repository) adding three attributes to the model class for handling soft-delete, namely, deleted, deletedOn, deletedBy.
41+
The column names needed to be there in DB within that table are - 'deleted', 'deleted_on', 'deleted_by'.
42+
If you are using auto-migration of loopback 4, then, you may not need to do anything specific to add this column.
43+
If not, then please add these columns to the DB table.
44+
45+
### SoftCrudRepository
46+
47+
An abstract base class for all repositories which require soft delete feature.
48+
This class is going to be the one which handles soft delete operations and ensures soft deleted entries are not returned in responses, However if there is a need to query soft deleted entries as well, there is an options to achieve that and you can use findAll() in place of find() , findOneIncludeSoftDelete() in place of findOne() and findByIdIncludeSoftDelete() in place of findById(), these will give you the responses including soft deleted entries.
49+
This class is a wrapper over DefaultCrudRepository class from [@loopback/repository](https://github.com/strongloop/loopback-next/tree/master/packages/repository).
50+
51+
### DefaultTransactionSoftCrudRepository (Deprecated)
3052

31-
Right now, this extension exports three abstract classes which are actually helping with soft delete operations.
53+
> Note: `DefaultTransactionSoftCrudRepository` is deprecated in favour of [SoftCrudRepositoryMixin](#softcrudrepositorymixin) and will be removed in future releases.
3254
33-
- **SoftDeleteEntity** -
34-
An abstract base class for all models which require soft delete feature.
35-
This class is a wrapper over Entity class from [@loopback/repository](https://github.com/strongloop/loopback-next/tree/master/packages/repository) adding three attributes to the model class for handling soft-delete, namely, deleted, deletedOn, deletedBy.
36-
The column names needed to be there in DB within that table are - 'deleted', 'deleted_on', 'deleted_by'.
37-
If you are using auto-migration of loopback 4, then, you may not need to do anything specific to add this column.
38-
If not, then please add these columns to the DB table.
39-
- **SoftCrudRepository** -
40-
An abstract base class for all repositories which require soft delete feature.
41-
This class is going to be the one which handles soft delete operations and ensures soft deleted entries are not returned in responses, However if there is a need to query soft deleted entries as well,there is an options to achieve that and you can use findAll() in place of find() , findOneIncludeSoftDelete() in place of findOne() and findByIdIncludeSoftDelete() in place of findById(), these will give you the responses including soft deleted entries.
42-
This class is a wrapper over DefaultCrudRepository class from [@loopback/repository](https://github.com/strongloop/loopback-next/tree/master/packages/repository).
43-
- **DefaultTransactionSoftCrudRepository** -
44-
An abstract base class for all repositories which require soft delete feature with transaction support.
45-
This class is going to be the one which handles soft delete operations and ensures soft deleted entries are not returned in responses, However if there is a need to query soft deleted entries as well,there is an options to achieve that and you can use findAll() in place of find() , findOneIncludeSoftDelete() in place of findOne() and findByIdIncludeSoftDelete() in place of findById(), these will give you the responses including soft deleted entries.
46-
This class is a wrapper over DefaultTransactionalRepository class from [@loopback/repository](https://github.com/strongloop/loopback-next/tree/master/packages/repository).
55+
An abstract base class similar to [SoftCrudRepository](#softcrudrepository) but with transaction support.
4756

48-
In order to use this extension in your LB4 application, please follow below steps.
57+
This class is a wrapper over `DefaultTransactionalRepository` class from [@loopback/repository](https://github.com/strongloop/loopback-next/tree/master/packages/repository).
4958

50-
1. Extend models with SoftDeleteEntity class replacing Entity. For example,
59+
In order to use this extension in your application, please follow below steps.
60+
61+
1. Extend models with SoftDeleteEntity class replacing Entity. Like below:
5162

5263
```ts
5364
import {model, property} from '@loopback/repository';
@@ -67,7 +78,7 @@ export class User extends SoftDeleteEntity {
6778
}
6879
```
6980

70-
2. Extend repositories with SoftCrudRepository class replacing DefaultCrudRepository. For example,
81+
2. Extend repositories with SoftCrudRepository class replacing DefaultCrudRepository. Like below:
7182

7283
```ts
7384
import {Getter, inject} from '@loopback/core';
@@ -92,7 +103,7 @@ export class UserRepository extends SoftCrudRepository<
92103
}
93104
```
94105

95-
3. For transaction support, extend repositories with DefaultTransactionSoftCrudRepository class replacing DefaultTransactionalRepository. For example,
106+
3. For transaction support, use the `SoftCrudRepositoryMixin` and wrap it around `DefaultTransactionalRepository`. Like below:
96107

97108
```ts
98109
import {Getter, inject} from '@loopback/core';
@@ -102,11 +113,11 @@ import {AuthenticationBindings, IAuthUser} from 'loopback4-authentication';
102113
import {PgdbDataSource} from '../datasources';
103114
import {User, UserRelations} from '../models';
104115

105-
export class UserRepository extends DefaultTransactionSoftCrudRepository<
116+
export class UserRepository extends SoftCrudRepositoryMixin<
106117
User,
107118
typeof User.prototype.id,
108119
UserRelations
109-
> {
120+
>(DefaultTransactionalRepository) {
110121
constructor(
111122
@inject('datasources.pgdb') dataSource: PgdbDataSource,
112123
@inject.getter(AuthenticationBindings.CURRENT_USER, {optional: true})
@@ -117,20 +128,17 @@ export class UserRepository extends DefaultTransactionSoftCrudRepository<
117128
}
118129
```
119130

131+
## Mixins Usage
132+
120133
The package also provides the following mixins which can be used for soft delete functionality:
121134

122-
- **SoftDeleteEntityMixin**: This mixin adds the soft delete properties to your model. The properties added are represented by the IBaseEntity interface:
135+
### SoftDeleteEntityMixin
123136

124-
```ts
125-
interface IBaseEntity {
126-
deleted?: boolean;
127-
deletedOn?: Date;
128-
deletedBy?: string;
129-
}
130-
```
137+
This mixin adds the soft delete properties to your model. The properties added are represented by the [IBaseEntity](#ibaseentity) interface:
131138

132-
There is also an option to provide config for the @property decorator for all these properties.
133-
Usage of SoftDeleteEntityMixin is as follows:
139+
There is also an option to provide config for the `@property` decorator for all these properties.
140+
141+
Usage of `SoftDeleteEntityMixin` is as follows:
134142

135143
```ts
136144
class Item extends Entity {
@@ -154,12 +162,29 @@ class Item extends Entity {
154162

155163
@model()
156164
export class ItemSoftDelete extends SoftDeleteEntityMixin(Item, {
157-
deletedBy: {name: 'deleted_by_userid'},
165+
deletedBy: {
166+
name: 'deleted_by_userid',
167+
},
158168
}) {}
159169
```
160170

161-
- **SoftCrudRepositoryMixin**: You can make use of this mixin to get the soft delete functionality for DefaultCrudRepository or any respository that extends the DefaultCrudRepository. You need to extend your repository with this mixin and provide DefaultCrudRepository (or any repository that extends DefaultCrudRepository) as input. This means that this same mixin can also be used to provide soft delete functionality for DefaultTransactionSoftCrudRepository ( as DefaultTransactionSoftCrudRepository extends DefaultCrudRepository).You will have to inject the getter for IAuthUser in the contructor of your repository.
162-
Example:
171+
#### IBaseEntity
172+
173+
The soft deleted properties added by [SoftDeleteEntityMixin](#softdeleteentitymixin) are represented by `IBaseEntity` interface.
174+
175+
```ts
176+
interface IBaseEntity {
177+
deleted?: boolean;
178+
deletedOn?: Date;
179+
deletedBy?: string;
180+
}
181+
```
182+
183+
### SoftCrudRepositoryMixin
184+
185+
You can make use of this mixin to get the soft delete functionality for `DefaultCrudRepository` or any respository that extends the `DefaultCrudRepository`. You need to extend your repository with this mixin and provide DefaultCrudRepository (or any repository that extends DefaultCrudRepository) as input. This means that this same mixin can also be used to provide soft delete functionality for DefaultTransactionSoftCrudRepository (as DefaultTransactionSoftCrudRepository extends DefaultCrudRepository). You will have to inject the getter for IAuthUser in the contructor of your repository.
186+
187+
#### Example:
163188

164189
```ts
165190
import {Constructor, Getter, inject} from '@loopback/core';

package-lock.json

Lines changed: 15 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"@semantic-release/git": "^10.0.1",
6565
"@semantic-release/npm": "^9.0.1",
6666
"@semantic-release/release-notes-generator": "^10.0.3",
67+
"@types/lodash": "^4.14.191",
6768
"@types/node": "^14.18.36",
6869
"@typescript-eslint/eslint-plugin": "^5.51.0",
6970
"@typescript-eslint/parser": "^5.51.0",

src/__tests__/unit/mixin/soft-crud.mixin.unit.ts

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// Copyright IBM Corp. 2019. All Rights Reserved.
2-
// Node module: @loopback/repository
3-
// This file is licensed under the MIT License.
4-
// License text available at https://opensource.org/licenses/MIT
1+
// DEVELOPMENT NOTE:
2+
// Please ensure that any modifications made to this file are also applied to the following locations:
3+
// 1) src/__tests_/unit/repository/default-transaction-soft-crud.repository.base.ts
4+
// 2) src/__tests_/unit/repository/soft-crud.repository.unit.ts
55

66
import {expect} from '@loopback/testlab';
77

@@ -368,6 +368,60 @@ describe('SoftCrudRepositoryMixin', () => {
368368
expect(e.message).to.be.equal('EntityNotFound');
369369
}
370370
});
371+
it('should not return soft deleted entry by id, without using deleted in fields filter', async () => {
372+
try {
373+
await repo.findById(3, {
374+
fields: {
375+
id: true,
376+
email: true,
377+
},
378+
});
379+
fail();
380+
} catch (e) {
381+
expect(e.message).to.be.equal('EntityNotFound');
382+
}
383+
});
384+
it('should not return soft deleted entry by id, without using deleted in fields filter(fields fileter is passed as array)', async () => {
385+
try {
386+
await repo.findById(3, {
387+
fields: ['id', 'email'],
388+
});
389+
fail();
390+
} catch (e) {
391+
expect(e.message).to.be.equal('EntityNotFound');
392+
}
393+
});
394+
it('should return requested fields only when not using deleted in fields filter', async () => {
395+
const customer = await repo.findById(4, {
396+
fields: {
397+
id: true,
398+
email: true,
399+
},
400+
});
401+
expect(customer).to.not.have.property('deleted');
402+
});
403+
it('should return requested fields matched with fields filter', async () => {
404+
const customer = await repo.findById(4, {
405+
fields: {
406+
id: true,
407+
email: true,
408+
deleted: true,
409+
},
410+
});
411+
expect(customer).to.have.property('deleted');
412+
});
413+
it('should return requested fields only when not using deleted in fields filter array', async () => {
414+
const customer = await repo.findById(4, {
415+
fields: ['id', 'email'],
416+
});
417+
expect(customer).to.not.have.property('deleted');
418+
});
419+
it('should return requested fields matched with fields filter array', async () => {
420+
const customer = await repo.findById(4, {
421+
fields: ['id', 'email', 'deleted'],
422+
});
423+
expect(customer).to.have.property('deleted');
424+
});
371425
});
372426

373427
describe('findByIdIncludeSoftDelete', () => {
@@ -697,7 +751,7 @@ describe('SoftCrudRepositoryMixin', () => {
697751
expect(customers).to.have.length(0);
698752
const afterDeleteAll = await repo.findAll();
699753
expect(afterDeleteAll).to.have.length(4);
700-
afterDeleteAll.forEach((rec) => {
754+
afterDeleteAll.forEach(rec => {
701755
expect(rec).to.have.property('deletedBy').equal(userData.id);
702756
});
703757
});
@@ -708,7 +762,7 @@ describe('SoftCrudRepositoryMixin', () => {
708762
expect(customers).to.have.length(0);
709763
const afterDeleteAll = await repoWithCustomDeletedByKey.findAll();
710764
expect(afterDeleteAll).to.have.length(4);
711-
afterDeleteAll.forEach((rec) => {
765+
afterDeleteAll.forEach(rec => {
712766
expect(rec).to.have.property('deletedBy').equal(userData2.username);
713767
});
714768
});

0 commit comments

Comments
 (0)