|
4 | 4 | // License text available at https://opensource.org/licenses/MIT |
5 | 5 |
|
6 | 6 | import * as assert from 'assert'; |
7 | | -import {Model, Entity} from '../model'; |
8 | | -import {Repository} from '../repository'; |
| 7 | +import {Entity} from '../model'; |
9 | 8 | import {DataSource} from '../datasource'; |
10 | 9 | import { |
11 | 10 | DefaultCrudRepository, |
12 | 11 | DataSourceConstructor, |
13 | 12 | } from '../legacy-juggler-bridge'; |
14 | 13 | import {juggler} from '../loopback-datasource-juggler'; |
15 | 14 | 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; |
16 | 28 |
|
17 | 29 | /** |
18 | 30 | * Metadata for a repository |
@@ -42,7 +54,7 @@ export class RepositoryMetadata { |
42 | 54 | /** |
43 | 55 | * Constructor for RepositoryMetadata |
44 | 56 | * |
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 |
46 | 58 | * `dataSource` is not present, it will treated as the name of a predefined |
47 | 59 | * repository |
48 | 60 | * @param dataSource Name or instance of the data source |
@@ -76,41 +88,85 @@ export class RepositoryMetadata { |
76 | 88 | } |
77 | 89 |
|
78 | 90 | /** |
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; |
83 | 96 | * |
84 | | - * For example: |
| 97 | + * constructor( |
| 98 | + * @repository(ProductRepository) public prodRepo: ProductRepository, |
| 99 | + * ) {} |
| 100 | + * // ... |
| 101 | + * } |
| 102 | + * ``` |
85 | 103 | * |
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 |
91 | 105 | */ |
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( |
93 | 137 | model: string | typeof Entity, |
| 138 | + dataSource: string | juggler.DataSource, |
| 139 | +): RepositoryDecorator; |
| 140 | + |
| 141 | +export function repository( |
| 142 | + modelOrRepo: string | Class<Repository<Model>> | typeof Entity, |
94 | 143 | dataSource?: string | juggler.DataSource, |
95 | 144 | ) { |
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); |
97 | 150 | return function( |
98 | 151 | target: Object, |
99 | 152 | key?: symbol | string, |
100 | | - descriptor?: TypedPropertyDescriptor<Repository<T>> | number, |
| 153 | + // tslint:disable-next-line:no-any |
| 154 | + descriptorOrIndex?: TypedPropertyDescriptor<any> | number, |
101 | 155 | ) { |
102 | | - if (key || typeof descriptor === 'number') { |
| 156 | + if (key || typeof descriptorOrIndex === 'number') { |
103 | 157 | if (meta.name) { |
104 | 158 | // Make it shortcut to `@inject('repositories.MyRepo')` |
105 | 159 | // Please note key is undefined for constructor. If strictNullChecks |
106 | 160 | // is true, the compiler will complain as reflect-metadata won't |
107 | 161 | // 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 | + ); |
109 | 167 | } else { |
110 | 168 | // 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); |
114 | 170 | } |
115 | 171 | return; |
116 | 172 | } |
|
0 commit comments