Skip to content

Commit 2cd4d83

Browse files
KalleVsamarpanB
authored andcommitted
fix(sequelize): support "defaultScope" via Model settings
Signed-off-by: KalleV <kvirtaneva@gmail.com>
1 parent 8292615 commit 2cd4d83

8 files changed

Lines changed: 113 additions & 0 deletions

File tree

extensions/sequelize/src/__tests__/fixtures/controllers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export * from './doctor.controller';
77
export * from './patient.controller';
88
export * from './product.controller';
99
export * from './programming-languange.controller';
10+
export * from './scoped-task.controller';
1011
export * from './task.controller';
1112
export * from './test.controller.base';
1213
export * from './todo-list-todo.controller';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {repository} from '@loopback/repository';
2+
import {get, response} from '@loopback/rest';
3+
import {ScopedTaskRepository} from '../repositories';
4+
import {TestControllerBase} from './test.controller.base';
5+
6+
export class ScopedTaskController extends TestControllerBase {
7+
constructor(
8+
@repository(ScopedTaskRepository)
9+
public scopedTaskRepository: ScopedTaskRepository,
10+
) {
11+
super(scopedTaskRepository);
12+
}
13+
14+
@get('/scoped-tasks/sync-sequelize-model')
15+
@response(200)
16+
async syncSequelizeModel(): Promise<void> {
17+
await this.beforeEach();
18+
}
19+
}

extensions/sequelize/src/__tests__/fixtures/models/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export * from './doctor.model';
66
export * from './patient.model';
77
export * from './product.model';
88
export * from './programming-language.model';
9+
export * from './scoped-task.model';
910
export * from './task.model';
1011
export * from './todo-list.model';
1112
export * from './todo.model';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {Entity, model, property} from '@loopback/repository';
2+
3+
/**
4+
* Simplified Entity used for testing settings "scope" functionality
5+
*/
6+
@model({
7+
settings: {
8+
scope: {
9+
limit: 1,
10+
},
11+
},
12+
})
13+
export class ScopedTask extends Entity {
14+
@property({
15+
type: 'number',
16+
id: true,
17+
generated: true,
18+
})
19+
id?: number;
20+
21+
@property({
22+
type: 'string',
23+
required: true,
24+
})
25+
title: string;
26+
27+
constructor(data?: Partial<ScopedTask>) {
28+
super(data);
29+
}
30+
}
31+
32+
export interface ScopedTaskRelations {
33+
// describe navigational properties here
34+
}
35+
36+
export type ScopedTaskWithRelations = ScopedTask & ScopedTaskRelations;

extensions/sequelize/src/__tests__/fixtures/repositories/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export * from './doctor.repository';
66
export * from './patient.repository';
77
export * from './product.repository';
88
export * from './programming-language.repository';
9+
export * from './scoped-task.repository';
910
export * from './task.repository';
1011
export * from './todo-list.repository';
1112
export * from './todo.repository';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {inject} from '@loopback/core';
2+
import {SequelizeCrudRepository} from '../../../sequelize';
3+
import {PrimaryDataSource} from '../datasources/primary.datasource';
4+
import {ScopedTask, ScopedTaskRelations} from '../models/index';
5+
6+
/**
7+
* Simplified repository used for testing Model settings "scope" functionality
8+
*/
9+
export class ScopedTaskRepository extends SequelizeCrudRepository<
10+
ScopedTask,
11+
typeof ScopedTask.prototype.id,
12+
ScopedTaskRelations
13+
> {
14+
constructor(@inject('datasources.primary') dataSource: PrimaryDataSource) {
15+
super(ScopedTask, dataSource);
16+
}
17+
18+
protected getDefaultFnRegistry() {
19+
return {
20+
...super.getDefaultFnRegistry(),
21+
customAlias: () => Math.random(),
22+
};
23+
}
24+
}

extensions/sequelize/src/__tests__/integration/repository.integration.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
TaskRepository,
2727
UserRepository,
2828
} from '../fixtures/repositories';
29+
import {ScopedTaskRepository} from '../fixtures/repositories/scoped-task.repository';
2930

3031
type Entities =
3132
| 'users'
@@ -42,6 +43,7 @@ describe('Sequelize CRUD Repository (integration)', () => {
4243
let app: SequelizeSandboxApplication;
4344
let userRepo: UserRepository;
4445
let taskRepo: TaskRepository;
46+
let scopedTaskRepo: ScopedTaskRepository;
4547
let developerRepo: DeveloperRepository;
4648
let languagesRepo: ProgrammingLanguageRepository;
4749
let client: Client;
@@ -74,6 +76,29 @@ describe('Sequelize CRUD Repository (integration)', () => {
7476
}
7577
});
7678

79+
describe('Model settings Support', () => {
80+
beforeEach(async () => {
81+
await client.get('/scoped-tasks/sync-sequelize-model').send();
82+
});
83+
it('supports setting a default "scope" in the Model settings', async () => {
84+
await Promise.all([
85+
scopedTaskRepo.create({title: 'Task 1'}),
86+
scopedTaskRepo.create({title: 'Task 2'}),
87+
scopedTaskRepo.create({title: 'Task 3'}),
88+
]);
89+
90+
const tasksDefaultLimit = await scopedTaskRepo.find();
91+
92+
expect(tasksDefaultLimit.length).to.be.eql(1);
93+
94+
const tasksCustomLimit = await scopedTaskRepo.find({
95+
limit: 3,
96+
});
97+
98+
expect(tasksCustomLimit.length).to.be.eql(3);
99+
});
100+
});
101+
77102
describe('defaultFn Support', () => {
78103
beforeEach(async () => {
79104
await client.get('/tasks/sync-sequelize-model').send();
@@ -940,6 +965,7 @@ describe('Sequelize CRUD Repository (integration)', () => {
940965
'book.model',
941966
'category.model',
942967
'product.model',
968+
'scoped-task.model',
943969
'task.model',
944970
],
945971
repositories: [
@@ -955,6 +981,7 @@ describe('Sequelize CRUD Repository (integration)', () => {
955981
'book.repository',
956982
'category.repository',
957983
'product.repository',
984+
'scoped-task.repository',
958985
'task.repository',
959986
],
960987
controllers: [
@@ -977,6 +1004,7 @@ describe('Sequelize CRUD Repository (integration)', () => {
9771004
'product.controller',
9781005
'test.controller.base',
9791006
'task.controller',
1007+
'scoped-task.controller',
9801008
],
9811009
};
9821010

@@ -1014,6 +1042,7 @@ describe('Sequelize CRUD Repository (integration)', () => {
10141042
developerRepo = await app.getRepository(DeveloperRepository);
10151043
languagesRepo = await app.getRepository(ProgrammingLanguageRepository);
10161044
taskRepo = await app.getRepository(TaskRepository);
1045+
scopedTaskRepo = await app.getRepository(ScopedTaskRepository);
10171046
client = createRestAppClient(app as RestApplication);
10181047
}
10191048

extensions/sequelize/src/sequelize/sequelize.repository.base.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,8 @@ export class SequelizeCrudRepository<
687687
timestamps: false,
688688
tableName: this.getTableName(entityClass),
689689
freezeTableName: true,
690+
// Set up optional default scope: https://sequelize.org/docs/v6/other-topics/scopes/#definition
691+
defaultScope: entityClass.definition.settings.scope,
690692
},
691693
);
692694

0 commit comments

Comments
 (0)