Skip to content

Commit c146366

Browse files
committed
feat(repository): return an object for count and updateAll
1 parent d0994af commit c146366

File tree

17 files changed

+125
-83
lines changed

17 files changed

+125
-83
lines changed

docs/site/todo-list-tutorial-controller.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,13 @@ export class TodoListController {
137137
responses: {
138138
'200': {
139139
description: 'TodoList model count',
140-
content: {'application/json': {'x-ts-type': Number}},
140+
content: {'application/json': {schema: CountSchema}},
141141
},
142142
},
143143
})
144144
async count(
145145
@param.query.object('where', getWhereSchemaFor(TodoList)) where?: Where,
146-
): Promise<number> {
146+
): Promise<Count> {
147147
return await this.todoListRepository.count(where);
148148
}
149149

@@ -165,14 +165,14 @@ export class TodoListController {
165165
responses: {
166166
'200': {
167167
description: 'TodoList PATCH success count',
168-
content: {'application/json': {'x-ts-type': Number}},
168+
content: {'application/json': {schema: CountSchema}},
169169
},
170170
},
171171
})
172172
async updateAll(
173173
@requestBody() obj: Partial<TodoList>,
174174
@param.query.object('where', getWhereSchemaFor(TodoList)) where?: Where,
175-
): Promise<number> {
175+
): Promise<Count> {
176176
return await this.todoListRepository.updateAll(obj, where);
177177
}
178178

examples/todo-list/src/controllers/todo-list-todo.controller.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
55

6-
import {Filter, repository, Where} from '@loopback/repository';
6+
import {
7+
Count,
8+
CountSchema,
9+
Filter,
10+
repository,
11+
Where,
12+
} from '@loopback/repository';
713
import {
814
del,
915
get,
@@ -59,30 +65,30 @@ export class TodoListTodoController {
5965
responses: {
6066
'200': {
6167
description: 'TodoList.Todo PATCH success count',
62-
content: {'application/json': {'x-ts-type': Number}},
68+
content: {'application/json': {schema: CountSchema}},
6369
},
6470
},
6571
})
6672
async patch(
6773
@param.path.number('id') id: number,
6874
@requestBody() todo: Partial<Todo>,
6975
@param.query.object('where', getWhereSchemaFor(Todo)) where?: Where,
70-
): Promise<number> {
76+
): Promise<Count> {
7177
return await this.todoListRepo.todos(id).patch(todo, where);
7278
}
7379

7480
@del('/todo-lists/{id}/todos', {
7581
responses: {
7682
'200': {
7783
description: 'TodoList.Todo DELETE success count',
78-
content: {'application/json': {'x-ts-type': Number}},
84+
content: {'application/json': {schema: CountSchema}},
7985
},
8086
},
8187
})
8288
async delete(
8389
@param.path.number('id') id: number,
8490
@param.query.object('where', getWhereSchemaFor(Todo)) where?: Where,
85-
): Promise<number> {
91+
): Promise<Count> {
8692
return await this.todoListRepo.todos(id).delete(where);
8793
}
8894
}

examples/todo-list/src/controllers/todo-list.controller.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
55

6-
import {Filter, repository, Where} from '@loopback/repository';
6+
import {
7+
Count,
8+
CountSchema,
9+
Filter,
10+
repository,
11+
Where,
12+
} from '@loopback/repository';
713
import {
814
del,
915
get,
@@ -39,13 +45,13 @@ export class TodoListController {
3945
responses: {
4046
'200': {
4147
description: 'TodoList model count',
42-
content: {'application/json': {'x-ts-type': Number}},
48+
content: {'application/json': {schema: CountSchema}},
4349
},
4450
},
4551
})
4652
async count(
4753
@param.query.object('where', getWhereSchemaFor(TodoList)) where?: Where,
48-
): Promise<number> {
54+
): Promise<Count> {
4955
return await this.todoListRepository.count(where);
5056
}
5157

@@ -67,14 +73,14 @@ export class TodoListController {
6773
responses: {
6874
'200': {
6975
description: 'TodoList PATCH success count',
70-
content: {'application/json': {'x-ts-type': Number}},
76+
content: {'application/json': {schema: CountSchema}},
7177
},
7278
},
7379
})
7480
async updateAll(
7581
@requestBody() obj: Partial<TodoList>,
7682
@param.query.object('where', getWhereSchemaFor(TodoList)) where?: Where,
77-
): Promise<number> {
83+
): Promise<Count> {
7884
return await this.todoListRepository.updateAll(obj, where);
7985
}
8086

examples/todo-list/test/acceptance/todo-list-todo.acceptance.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe('TodoListApplication', () => {
8484
.send(patchedIsCompleteTodo)
8585
.expect(200);
8686

87-
expect(response.body).to.eql(myTodos.length);
87+
expect(response.body.count).to.eql(myTodos.length);
8888
const updatedTodos = await todoListRepo
8989
.todos(persistedTodoList.id)
9090
.find();
@@ -111,7 +111,7 @@ describe('TodoListApplication', () => {
111111
.query({where: {isComplete: false}})
112112
.send({desc: 'work in progress'})
113113
.expect(200);
114-
expect(response.body).to.equal(1);
114+
expect(response.body.count).to.equal(1);
115115

116116
// the matched Todo was updated
117117
expect(await todoRepo.findById(wip.id)).to.have.property(
@@ -156,7 +156,7 @@ describe('TodoListApplication', () => {
156156
.query({where: {isComplete: true}})
157157
.expect(200);
158158

159-
expect(response.body).to.equal(1);
159+
expect(response.body.count).to.equal(1);
160160

161161
const allRemainingTodos = await todoRepo.find();
162162
expect(allRemainingTodos.map(t => t.title).sort()).to.deepEqual(

examples/todo-list/test/acceptance/todo-list.acceptance.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ describe('TodoListApplication', () => {
5656
.get('/todo-lists/count')
5757
.send()
5858
.expect(200);
59-
expect(response.body).to.eql(persistedTodoLists.length);
59+
expect(response.body.count).to.eql(persistedTodoLists.length);
6060
});
6161

6262
it('counts a subset of todoLists', async () => {
6363
const response = await client
6464
.get('/todo-lists/count')
6565
.query({where: {title: 'so many things to do wow'}})
6666
.expect(200);
67-
expect(response.body).to.equal(1);
67+
expect(response.body.count).to.equal(1);
6868
});
6969

7070
it('finds all todoLists', async () => {
@@ -81,7 +81,7 @@ describe('TodoListApplication', () => {
8181
.patch('/todo-lists')
8282
.send(patchedColorTodo)
8383
.expect(200);
84-
expect(response.body).to.eql(persistedTodoLists.length);
84+
expect(response.body.count).to.eql(persistedTodoLists.length);
8585
const updatedTodoLists = await todoListRepo.find();
8686
for (const todoList of updatedTodoLists) {
8787
expect(todoList.color).to.eql(patchedColorTodo.color);
@@ -98,7 +98,7 @@ describe('TodoListApplication', () => {
9898
.query({where: {color: 'red'}})
9999
.send({color: 'purple'})
100100
.expect(200);
101-
expect(response.body).to.eql(1);
101+
expect(response.body.count).to.eql(1);
102102

103103
// the matched TodoList was updated
104104
expect(await todoListRepo.findByTitle('red-list')).to.have.property(

packages/cli/generators/controller/templates/src/controllers/controller-rest-template.ts.ejs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import {Filter, repository, Where} from '@loopback/repository';
1+
import {
2+
Count,
3+
CountSchema,
4+
Filter,
5+
repository,
6+
Where,
7+
} from '@loopback/repository';
28
import {
39
post,
410
param,
@@ -34,13 +40,13 @@ export class <%= className %>Controller {
3440
responses: {
3541
'200': {
3642
description: '<%= modelName %> model count',
37-
content: {'application/json': {'x-ts-type': Number}},
43+
content: {'application/json': {schema: CountSchema}},
3844
},
3945
},
4046
})
4147
async count(
4248
@param.query.object('where', getWhereSchemaFor(<%= modelName %>)) where?: Where,
43-
): Promise<number> {
49+
): Promise<Count> {
4450
return await this.<%= repositoryNameCamel %>.count(where);
4551
}
4652

@@ -66,14 +72,14 @@ export class <%= className %>Controller {
6672
responses: {
6773
'200': {
6874
description: '<%= modelName %> PATCH success count',
69-
content: {'application/json': {'x-ts-type': Number}},
75+
content: {'application/json': {schema: CountSchema}},
7076
},
7177
},
7278
})
7379
async updateAll(
7480
@requestBody() <%= modelVariableName %>: <%= modelName %>,
7581
@param.query.object('where', getWhereSchemaFor(<%= modelName %>)) where?: Where,
76-
): Promise<number> {
82+
): Promise<Count> {
7783
return await this.<%= repositoryNameCamel %>.updateAll(<%= modelVariableName %>, where);
7884
}
7985

packages/cli/test/integration/generators/controller.integration.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ function checkRestCrudContents() {
260260
/responses: {/,
261261
/'200': {/,
262262
/description: 'ProductReview model count'/,
263-
/content: {'application\/json': {'x-ts-type': Number}},\s{1,}},\s{1,}},\s{1,}}\)/,
263+
/content: {'application\/json': {schema: CountSchema}},\s{1,}},\s{1,}},\s{1,}}\)/,
264264
/async count\(\s+\@param\.query\.object\('where', getWhereSchemaFor\(ProductReview\)\) where\?: Where(|,\s+)\)/,
265265
];
266266
getCountRegEx.forEach(regex => {
@@ -286,7 +286,7 @@ function checkRestCrudContents() {
286286
/responses: {/,
287287
/'200': {/,
288288
/description: 'ProductReview PATCH success count'/,
289-
/content: {'application\/json': {'x-ts-type': Number}},\s{1,}},\s{1,}},\s{1,}}\)/,
289+
/content: {'application\/json': {schema: CountSchema}},\s{1,}},\s{1,}},\s{1,}}\)/,
290290
/async updateAll\(\s{1,}\@requestBody\(\) productReview: ProductReview,\s{1,} @param\.query\.object\('where', getWhereSchemaFor\(ProductReview\)\) where\?: Where(|,\s+)\)/,
291291
];
292292
patchUpdateAllRegEx.forEach(regex => {

packages/repository/src/common-types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,20 @@ export type NamedParameters = AnyObject;
8282
*/
8383
// tslint:disable-next-line:no-any
8484
export type PositionalParameters = any[];
85+
86+
/**
87+
* Count of Model instances that were successful for methods like `updateAll`,
88+
* `deleteAll`, etc.
89+
*/
90+
export interface Count {
91+
count: number;
92+
}
93+
94+
/**
95+
* JSON Schema describing the Count interface. It's the response type for
96+
* REST calls to APIs which return Count
97+
*/
98+
export const CountSchema = {
99+
type: 'object',
100+
properties: {count: {type: 'number'}},
101+
};

packages/repository/src/connectors/crud.connector.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import {Connector} from './connector';
77
import {Entity, EntityData} from '../model';
88
import {Filter, Where} from '../query';
9-
import {Class, Options} from '../common-types';
9+
import {Class, Options, Count} from '../common-types';
1010

1111
/**
1212
* CRUD operations for connector implementations
@@ -118,7 +118,7 @@ export interface CrudConnector extends Connector {
118118
data: EntityData,
119119
where?: Where,
120120
options?: Options,
121-
): Promise<number>;
121+
): Promise<Count>;
122122

123123
/**
124124
* Update an entity by id
@@ -163,7 +163,7 @@ export interface CrudConnector extends Connector {
163163
modelClass: Class<Entity>,
164164
where?: Where,
165165
options?: Options,
166-
): Promise<number>;
166+
): Promise<Count>;
167167

168168
/**
169169
* Delete an entity by id
@@ -190,7 +190,7 @@ export interface CrudConnector extends Connector {
190190
modelClass: Class<Entity>,
191191
where?: Where,
192192
options?: Options,
193-
): Promise<number>;
193+
): Promise<Count>;
194194

195195
/**
196196
* Check if an entity exists for the id

packages/repository/src/repositories/legacy-juggler-bridge.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
NamedParameters,
1414
Options,
1515
PositionalParameters,
16+
Count,
1617
} from '../common-types';
1718
import {HasManyDefinition} from '../decorators/relation.decorator';
1819
import {EntityNotFoundError} from '../errors';
@@ -229,15 +230,16 @@ export class DefaultCrudRepository<T extends Entity, ID>
229230
return this.deleteById(entity.getId(), options);
230231
}
231232

232-
updateAll(
233+
async updateAll(
233234
data: DataObject<T>,
234235
where?: Where,
235236
options?: Options,
236-
): Promise<number> {
237+
): Promise<Count> {
237238
where = where || {};
238-
return ensurePromise(this.modelClass.updateAll(where, data, options)).then(
239-
result => result.count,
239+
const result = await ensurePromise(
240+
this.modelClass.updateAll(where, data, options),
240241
);
242+
return {count: result.count};
241243
}
242244

243245
async updateById(
@@ -248,8 +250,8 @@ export class DefaultCrudRepository<T extends Entity, ID>
248250
const idProp = this.modelClass.definition.idName();
249251
const where = {} as Where;
250252
where[idProp] = id;
251-
const count = await this.updateAll(data, where, options);
252-
if (count === 0) {
253+
const result = await this.updateAll(data, where, options);
254+
if (result.count === 0) {
253255
throw new EntityNotFoundError(this.entityClass, id);
254256
}
255257
}
@@ -269,10 +271,11 @@ export class DefaultCrudRepository<T extends Entity, ID>
269271
}
270272
}
271273

272-
deleteAll(where?: Where, options?: Options): Promise<number> {
273-
return ensurePromise(this.modelClass.deleteAll(where, options)).then(
274-
result => result.count,
274+
async deleteAll(where?: Where, options?: Options): Promise<Count> {
275+
const result = await ensurePromise(
276+
this.modelClass.deleteAll(where, options),
275277
);
278+
return {count: result.count};
276279
}
277280

278281
async deleteById(id: ID, options?: Options): Promise<void> {
@@ -282,8 +285,9 @@ export class DefaultCrudRepository<T extends Entity, ID>
282285
}
283286
}
284287

285-
count(where?: Where, options?: Options): Promise<number> {
286-
return ensurePromise(this.modelClass.count(where, options));
288+
async count(where?: Where, options?: Options): Promise<Count> {
289+
const result = await ensurePromise(this.modelClass.count(where, options));
290+
return {count: result};
287291
}
288292

289293
exists(id: ID, options?: Options): Promise<boolean> {

0 commit comments

Comments
 (0)