Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions docs/site/Controller-generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Here's an example of what the template will produce given a `Todo` model and a
`TodoRepository`:

```ts
import {Filter, Where} from '@loopback/repository';
import {Filter, Where, repository} from '@loopback/repository';
import {
post,
param,
Expand All @@ -86,13 +86,12 @@ import {
del,
requestBody
} from '@loopback/rest';
import {inject} from '@loopback/context';
import {Todo} from '../models';
import {TodoRepository} from '../repositories';

export class TodoController {
constructor(
@inject('repositories.TodoRepository')
@repository(TodoRepository)
public todoRepository: TodoRepository,
Copy link
Contributor

@virkt25 virkt25 Apr 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the type not inferred to be TodoRepository?? -- Is there a way for it to be inferred automatically now?

This applies to all instances below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a very useful feature that I've not thought about. I think this task has been scope creeped enough that I'll create a new issue to implement this feature.

) {}

Expand Down
4 changes: 2 additions & 2 deletions docs/site/Controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ import {repository} from '@loopback/repository';

export class HelloController {
constructor(
@repository(HelloRepository.name) protected repository: HelloRepository,
@repository(HelloRepository) protected repository: HelloRepository,
) {}

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

export class HelloController {
constructor(
@repository(HelloRepository.name) protected repo: HelloRepository,
@repository(HelloRepository) protected repo: HelloRepository,
) {}

// returns a list of our objects
Expand Down
3 changes: 2 additions & 1 deletion docs/site/Decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@ For usage examples, see [Define Models](Repositories.md#define-models)
### Repository Decorator

Syntax:
[`@repository(model: string | typeof Entity, dataSource?: string | juggler.DataSource)`](http://apidocs.loopback.io/@loopback%2frepository/#1503)

[@repository(modelOrRepo: string | Class<Repository<Model>> | typeof Entity, dataSource?: string | juggler.DataSource)](http://apidocs.loopback.io/@loopback%2frepository/#1503)

This decorator either injects an existing repository or creates a repository
from a model and a datasource.
Expand Down
4 changes: 2 additions & 2 deletions docs/site/Repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ DataSource for in the constructor of your controller class as follows:
```ts
export class AccountController {
constructor(
@repository(AccountRepository.name) public repository: AccountRepository,
@repository(AccountRepository) public repository: AccountRepository,
) {}
```

Expand Down Expand Up @@ -331,7 +331,7 @@ Injection:

```ts
export class AccountController {
@repository(NewRepository.name) private repository: NewRepository;
@repository(NewRepository) private repository: NewRepository;
}
```

Expand Down
6 changes: 3 additions & 3 deletions docs/site/todo-tutorial-controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {TodoRepository} from '../repositories';

export class TodoController {
constructor(
@repository(TodoRepository.name) protected todoRepo: TodoRepository,
@repository(TodoRepository) protected todoRepo: TodoRepository,
) {}
}
```
Expand Down Expand Up @@ -71,7 +71,7 @@ import {HttpErrors, post, param, requestBody} from '@loopback/rest';

export class TodoController {
constructor(
@repository(TodoRepository.name) protected todoRepo: TodoRepository,
@repository(TodoRepository) protected todoRepo: TodoRepository,
) {}

@post('/todo')
Expand Down Expand Up @@ -121,7 +121,7 @@ import {

export class TodoController {
constructor(
@repository(TodoRepository.name) protected todoRepo: TodoRepository,
@repository(TodoRepository) protected todoRepo: TodoRepository,
) {}

@post('/todo')
Expand Down
7 changes: 1 addition & 6 deletions examples/todo/src/controllers/todo.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@ import {
} from '@loopback/rest';

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

@post('/todo')
async createTodo(@requestBody() todo: Todo) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Filter, Where} from '@loopback/repository';
import {Filter, Where, repository} from '@loopback/repository';
import {
post,
param,
Expand All @@ -8,14 +8,13 @@ import {
del,
requestBody
} from '@loopback/openapi-v3';
import {inject} from '@loopback/context';
import {<%= modelName %>} from '../models';
import {<%= repositoryName %>} from '../repositories';

export class <%= name %>Controller {

constructor(
@inject('repositories.<%= repositoryName %>')
@repository(<%= repositoryName %>)
public <%= repositoryNameCamel %> : <%= repositoryName %>,
) {}

Expand Down
5 changes: 1 addition & 4 deletions packages/cli/test/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,7 @@ describe('lb4 controller', () => {
assert.fileContent(tmpDir + withInputName, /class FooBarController/);

// Repository and injection
assert.fileContent(
tmpDir + withInputName,
/\@inject\('repositories.BarRepository'\)/
);
assert.fileContent(tmpDir + withInputName, /\@repository\(BarRepository\)/);
assert.fileContent(
tmpDir + withInputName,
/barRepository \: BarRepository/
Expand Down
2 changes: 1 addition & 1 deletion packages/repository/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ import {post, requestBody, get, param} from '@loopback/openapi-v3';
export class NoteController {
constructor(
// Use constructor dependency injection to set up the repository
@repository(NoteRepository.name) public noteRepo: NoteRepository,
@repository(NoteRepository) public noteRepo: NoteRepository,
) {}

// Create a new note
Expand Down
98 changes: 77 additions & 21 deletions packages/repository/src/decorators/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@
// License text available at https://opensource.org/licenses/MIT

import * as assert from 'assert';
import {Model, Entity} from '../model';
import {Repository} from '../repository';
import {Entity} from '../model';
import {DataSource} from '../datasource';
import {
DefaultCrudRepository,
DataSourceConstructor,
} from '../legacy-juggler-bridge';
import {juggler} from '../loopback-datasource-juggler';
import {inject, Context, Injection} from '@loopback/context';
import {Class} from '../common-types';
import {Repository} from '../repository';
import {Model} from '../model';

/**
* Type definition for decorators returned by `@repository` decorator factory
*/
export type RepositoryDecorator = (
target: Object,
key?: string | symbol,
// tslint:disable-next-line:no-any
descriptorOrIndex?: TypedPropertyDescriptor<any> | number,
) => void;

/**
* Metadata for a repository
Expand Down Expand Up @@ -42,7 +54,7 @@ export class RepositoryMetadata {
/**
* Constructor for RepositoryMetadata
*
* @param model Name or class of the model. If the value is a string and
* @param modelOrRepo Name or class of the model. If the value is a string and
* `dataSource` is not present, it will treated as the name of a predefined
* repository
* @param dataSource Name or instance of the data source
Expand Down Expand Up @@ -76,41 +88,85 @@ export class RepositoryMetadata {
}

/**
* Decorator for model definitions
* @param model Name of the repo or name/class of the model
* @param dataSource Name or instance of the data source
* @returns {(target:AnyType)}
* Decorator for repository injections on properties or method arguments
*
* ```ts
* class CustomerController {
* @repository(CustomerRepository) public custRepo: CustomerRepository;
*
* For example:
* constructor(
* @repository(ProductRepository) public prodRepo: ProductRepository,
* ) {}
* // ...
* }
* ```
*
* - @repository('myCustomerRepo')
* - @repository('Customer', 'mysqlDataSource')
* - @repository(Customer, mysqlDataSource)
* - @repository('Customer', mysqlDataSource)
* - @repository(Customer, 'mysqlDataSource')
* @param repositoryName Name of the repo
*/
export function repository<T extends Model>(
export function repository(
repositoryName: string | Class<Repository<Model>>,
): RepositoryDecorator;

/**
* Decorator for DefaultCrudRepository generation and injection on properties
* or method arguments based on the given model and dataSource (or their names)
*
* ```ts
* class CustomerController {
* @repository('Customer', 'mySqlDataSource')
* public custRepo: DefaultCrudRepository<
* Customer,
* typeof Customer.prototype.id
* >;
*
* constructor(
* @repository(Product, mySqlDataSource)
* public prodRepo: DefaultCrudRepository<
* Product,
* typeof Product.prototype.id
* >,
* ) {}
* // ...
* }
* ```
*
* @param model Name/class of the model
* @param dataSource Name/instance of the dataSource
*/
export function repository(
model: string | typeof Entity,
dataSource: string | juggler.DataSource,
): RepositoryDecorator;

export function repository(
modelOrRepo: string | Class<Repository<Model>> | typeof Entity,
dataSource?: string | juggler.DataSource,
) {
const meta = new RepositoryMetadata(model, dataSource);
const stringOrModel =
typeof modelOrRepo !== 'string' && modelOrRepo.prototype.execute
? modelOrRepo.name
: (modelOrRepo as typeof Entity);
const meta = new RepositoryMetadata(stringOrModel, dataSource);
return function(
target: Object,
key?: symbol | string,
descriptor?: TypedPropertyDescriptor<Repository<T>> | number,
// tslint:disable-next-line:no-any
descriptorOrIndex?: TypedPropertyDescriptor<any> | number,
) {
if (key || typeof descriptor === 'number') {
if (key || typeof descriptorOrIndex === 'number') {
if (meta.name) {
// Make it shortcut to `@inject('repositories.MyRepo')`
// Please note key is undefined for constructor. If strictNullChecks
// is true, the compiler will complain as reflect-metadata won't
// accept undefined or null for key. Use ! to fool the compiler.
inject('repositories.' + meta.name, meta)(target, key!, descriptor);
inject('repositories.' + meta.name, meta)(
target,
key!,
descriptorOrIndex,
);
} else {
// Use repository-factory to create a repository from model + dataSource
// inject('repository-factory', meta)(target, key!, descriptor);
inject('', meta, resolve)(target, key!, descriptor);
// throw new Error('@repository(model, dataSource) is not implemented');
inject('', meta, resolve)(target, key!, descriptorOrIndex);
}
return;
}
Expand Down
Loading