Skip to content

Commit 3db07eb

Browse files
committed
feat(repository): have @repository take in constructor as arg
1 parent 59b9e9f commit 3db07eb

File tree

11 files changed

+157
-87
lines changed

11 files changed

+157
-87
lines changed

docs/site/Controller-generator.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Here's an example of what the template will produce given a `Todo` model and a
7676
`TodoRepository`:
7777

7878
```ts
79-
import {Filter, Where} from '@loopback/repository';
79+
import {Filter, Where, repository} from '@loopback/repository';
8080
import {
8181
post,
8282
param,
@@ -86,13 +86,12 @@ import {
8686
del,
8787
requestBody
8888
} from '@loopback/rest';
89-
import {inject} from '@loopback/context';
9089
import {Todo} from '../models';
9190
import {TodoRepository} from '../repositories';
9291

9392
export class TodoController {
9493
constructor(
95-
@inject('repositories.TodoRepository')
94+
@repository(TodoRepository)
9695
public todoRepository: TodoRepository,
9796
) {}
9897

docs/site/Controllers.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ import {repository} from '@loopback/repository';
195195

196196
export class HelloController {
197197
constructor(
198-
@repository(HelloRepository.name) protected repository: HelloRepository,
198+
@repository(HelloRepository) protected repository: HelloRepository,
199199
) {}
200200

201201
// returns a list of our objects
@@ -273,7 +273,7 @@ import {repository} from '@loopback/repository';
273273

274274
export class HelloController {
275275
constructor(
276-
@repository(HelloRepository.name) protected repo: HelloRepository,
276+
@repository(HelloRepository) protected repo: HelloRepository,
277277
) {}
278278

279279
// returns a list of our objects

docs/site/Decorators.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,8 @@ For usage examples, see [Define Models](Repositories.md#define-models)
575575
### Repository Decorator
576576

577577
Syntax:
578-
[`@repository(model: string | typeof Entity, dataSource?: string | juggler.DataSource)`](http://apidocs.loopback.io/@loopback%2frepository/#1503)
578+
579+
[@repository(modelOrRepo: string | Class<Repository<Model>> | typeof Entity, dataSource?: string | juggler.DataSource)](http://apidocs.loopback.io/@loopback%2frepository/#1503)
579580

580581
This decorator either injects an existing repository or creates a repository
581582
from a model and a datasource.

docs/site/Repositories.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ DataSource for in the constructor of your controller class as follows:
155155
```ts
156156
export class AccountController {
157157
constructor(
158-
@repository(AccountRepository.name) public repository: AccountRepository,
158+
@repository(AccountRepository) public repository: AccountRepository,
159159
) {}
160160
```
161161
@@ -331,7 +331,7 @@ Injection:
331331
332332
```ts
333333
export class AccountController {
334-
@repository(NewRepository.name) private repository: NewRepository;
334+
@repository(NewRepository) private repository: NewRepository;
335335
}
336336
```
337337

docs/site/todo-tutorial-controller.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import {TodoRepository} from '../repositories';
4141

4242
export class TodoController {
4343
constructor(
44-
@repository(TodoRepository.name) protected todoRepo: TodoRepository,
44+
@repository(TodoRepository) protected todoRepo: TodoRepository,
4545
) {}
4646
}
4747
```
@@ -71,7 +71,7 @@ import {HttpErrors, post, param, requestBody} from '@loopback/rest';
7171

7272
export class TodoController {
7373
constructor(
74-
@repository(TodoRepository.name) protected todoRepo: TodoRepository,
74+
@repository(TodoRepository) protected todoRepo: TodoRepository,
7575
) {}
7676

7777
@post('/todo')
@@ -121,7 +121,7 @@ import {
121121

122122
export class TodoController {
123123
constructor(
124-
@repository(TodoRepository.name) protected todoRepo: TodoRepository,
124+
@repository(TodoRepository) protected todoRepo: TodoRepository,
125125
) {}
126126

127127
@post('/todo')

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,7 @@ import {
1818
} from '@loopback/rest';
1919

2020
export class TodoController {
21-
// TODO(bajtos) Fix documentation (and argument names?) of @repository()
22-
// to allow the usage below.
23-
// See https://github.com/strongloop/loopback-next/issues/744
24-
constructor(
25-
@repository(TodoRepository.name) protected todoRepo: TodoRepository,
26-
) {}
21+
constructor(@repository(TodoRepository) protected todoRepo: TodoRepository) {}
2722

2823
@post('/todo')
2924
async createTodo(@requestBody() todo: Todo) {

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Filter, Where} from '@loopback/repository';
1+
import {Filter, Where, repository} from '@loopback/repository';
22
import {
33
post,
44
param,
@@ -8,14 +8,13 @@ import {
88
del,
99
requestBody
1010
} from '@loopback/openapi-v3';
11-
import {inject} from '@loopback/context';
1211
import {<%= modelName %>} from '../models';
1312
import {<%= repositoryName %>} from '../repositories';
1413

1514
export class <%= name %>Controller {
1615

1716
constructor(
18-
@inject('repositories.<%= repositoryName %>')
17+
@repository(<%= repositoryName %>)
1918
public <%= repositoryNameCamel %> : <%= repositoryName %>,
2019
) {}
2120

packages/cli/test/controller.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,7 @@ describe('lb4 controller', () => {
281281
assert.fileContent(tmpDir + withInputName, /class FooBarController/);
282282

283283
// Repository and injection
284-
assert.fileContent(
285-
tmpDir + withInputName,
286-
/\@inject\('repositories.BarRepository'\)/
287-
);
284+
assert.fileContent(tmpDir + withInputName, /\@repository\(BarRepository\)/);
288285
assert.fileContent(
289286
tmpDir + withInputName,
290287
/barRepository \: BarRepository/

packages/repository/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ import {post, requestBody, get, param} from '@loopback/openapi-v3';
9393
export class NoteController {
9494
constructor(
9595
// Use constructor dependency injection to set up the repository
96-
@repository(NoteRepository.name) public noteRepo: NoteRepository,
96+
@repository(NoteRepository) public noteRepo: NoteRepository,
9797
) {}
9898

9999
// Create a new note

packages/repository/src/decorators/repository.ts

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,27 @@
44
// License text available at https://opensource.org/licenses/MIT
55

66
import * as assert from 'assert';
7-
import {Model, Entity} from '../model';
8-
import {Repository} from '../repository';
7+
import {Entity} from '../model';
98
import {DataSource} from '../datasource';
109
import {
1110
DefaultCrudRepository,
1211
DataSourceConstructor,
1312
} from '../legacy-juggler-bridge';
1413
import {juggler} from '../loopback-datasource-juggler';
1514
import {inject, Context, Injection} from '@loopback/context';
15+
import {Class} from '../common-types';
16+
import {Repository} from '../repository';
17+
import {Model} from '../model';
18+
19+
/**
20+
* Type definition for decorators returned by `@repository` decorator factory
21+
*/
22+
export type RepositoryDecorator = (
23+
target: Object,
24+
key?: string | symbol,
25+
// tslint:disable-next-line:no-any
26+
descriptorOrIndex?: TypedPropertyDescriptor<any> | number,
27+
) => void;
1628

1729
/**
1830
* Metadata for a repository
@@ -42,7 +54,7 @@ export class RepositoryMetadata {
4254
/**
4355
* Constructor for RepositoryMetadata
4456
*
45-
* @param model Name or class of the model. If the value is a string and
57+
* @param modelOrRepo Name or class of the model. If the value is a string and
4658
* `dataSource` is not present, it will treated as the name of a predefined
4759
* repository
4860
* @param dataSource Name or instance of the data source
@@ -76,41 +88,85 @@ export class RepositoryMetadata {
7688
}
7789

7890
/**
79-
* Decorator for model definitions
80-
* @param model Name of the repo or name/class of the model
81-
* @param dataSource Name or instance of the data source
82-
* @returns {(target:AnyType)}
91+
* Decorator for repository injections on properties or method arguments
92+
*
93+
* ```ts
94+
* class CustomerController {
95+
* @repository(CustomerRepository) public custRepo: CustomerRepository;
8396
*
84-
* For example:
97+
* constructor(
98+
* @repository(ProductRepository) public prodRepo: ProductRepository,
99+
* ) {}
100+
* // ...
101+
* }
102+
* ```
85103
*
86-
* - @repository('myCustomerRepo')
87-
* - @repository('Customer', 'mysqlDataSource')
88-
* - @repository(Customer, mysqlDataSource)
89-
* - @repository('Customer', mysqlDataSource)
90-
* - @repository(Customer, 'mysqlDataSource')
104+
* @param repositoryName Name of the repo
91105
*/
92-
export function repository<T extends Model>(
106+
export function repository(
107+
repositoryName: string | Class<Repository<Model>>,
108+
): RepositoryDecorator;
109+
110+
/**
111+
* Decorator for DefaultCrudRepository generation and injection on properties
112+
* or method arguments based on the given model and dataSource (or their names)
113+
*
114+
* ```ts
115+
* class CustomerController {
116+
* @repository('Customer', 'mySqlDataSource')
117+
* public custRepo: DefaultCrudRepository<
118+
* Customer,
119+
* typeof Customer.prototype.id
120+
* >;
121+
*
122+
* constructor(
123+
* @repository(Product, mySqlDataSource)
124+
* public prodRepo: DefaultCrudRepository<
125+
* Product,
126+
* typeof Product.prototype.id
127+
* >,
128+
* ) {}
129+
* // ...
130+
* }
131+
* ```
132+
*
133+
* @param model Name/class of the model
134+
* @param dataSource Name/instance of the dataSource
135+
*/
136+
export function repository(
93137
model: string | typeof Entity,
138+
dataSource: string | juggler.DataSource,
139+
): RepositoryDecorator;
140+
141+
export function repository(
142+
modelOrRepo: string | Class<Repository<Model>> | typeof Entity,
94143
dataSource?: string | juggler.DataSource,
95144
) {
96-
const meta = new RepositoryMetadata(model, dataSource);
145+
const stringOrModel =
146+
typeof modelOrRepo !== 'string' && modelOrRepo.prototype.execute
147+
? modelOrRepo.name
148+
: (modelOrRepo as typeof Entity);
149+
const meta = new RepositoryMetadata(stringOrModel, dataSource);
97150
return function(
98151
target: Object,
99152
key?: symbol | string,
100-
descriptor?: TypedPropertyDescriptor<Repository<T>> | number,
153+
// tslint:disable-next-line:no-any
154+
descriptorOrIndex?: TypedPropertyDescriptor<any> | number,
101155
) {
102-
if (key || typeof descriptor === 'number') {
156+
if (key || typeof descriptorOrIndex === 'number') {
103157
if (meta.name) {
104158
// Make it shortcut to `@inject('repositories.MyRepo')`
105159
// Please note key is undefined for constructor. If strictNullChecks
106160
// is true, the compiler will complain as reflect-metadata won't
107161
// accept undefined or null for key. Use ! to fool the compiler.
108-
inject('repositories.' + meta.name, meta)(target, key!, descriptor);
162+
inject('repositories.' + meta.name, meta)(
163+
target,
164+
key!,
165+
descriptorOrIndex,
166+
);
109167
} else {
110168
// Use repository-factory to create a repository from model + dataSource
111-
// inject('repository-factory', meta)(target, key!, descriptor);
112-
inject('', meta, resolve)(target, key!, descriptor);
113-
// throw new Error('@repository(model, dataSource) is not implemented');
169+
inject('', meta, resolve)(target, key!, descriptorOrIndex);
114170
}
115171
return;
116172
}

0 commit comments

Comments
 (0)