Skip to content

Commit

Permalink
Implement @repository(model, dataSource) injection
Browse files Browse the repository at this point in the history
  • Loading branch information
Raymond Feng committed Jun 23, 2017
1 parent 510e2dc commit b0102f1
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 27 deletions.
Expand Up @@ -17,9 +17,5 @@ import {repository} from '../../src/decorators/repository';

// Style 1
// Create a repository that binds Customer to mongodbDataSource
@repository(Customer, 'mongodbDataSource')
export // Style 2
// Reference a pre-configured repository by name. This is close to LoopBack
// 3.x model-config.json
// @repository('myCustomerRepository')
class CustomerController {}
@repository('Customer', 'mongodbDataSource')
export class CustomerController {}
Expand Up @@ -13,7 +13,7 @@ import {repository} from '../../src/decorators/repository';
export class CustomerController {
constructor(
// Use constructor dependency injection
@repository(Customer, 'mongodbDataSource')
@repository('Customer', 'mongodbDataSource')
private repository: EntityCrudRepository<Customer, string>,
) {}
}
Expand Up @@ -13,6 +13,6 @@ import {Customer} from '../models/customer';
// @controller
export class CustomerController {
// Use property dependency injection
@repository(Customer, 'mongodbDataSource')
@repository('Customer', 'mongodbDataSource')
private repository: EntityCrudRepository<Customer, string>;
}
33 changes: 25 additions & 8 deletions packages/repository/src/decorators/repository.ts
Expand Up @@ -7,7 +7,8 @@ import {Class} from '../common-types';
import {Model} from '../model';
import {Repository} from '../repository';
import {DataSource} from '../datasource';
import {inject} from '@loopback/context';
import {juggler, DefaultCrudRepository} from '../legacy-juggler-bridge';
import {inject, Context, Injection} from '@loopback/context';

/**
* Metadata for a repository
Expand All @@ -24,15 +25,15 @@ export class RepositoryMetadata {
/**
* Class of the model
*/
modelClass?: Class<Model>;
modelClass?: typeof juggler.PersistedModel | typeof Model;
/**
* Name of the data source
*/
dataSourceName?: string;
/**
* Instance of the data source
*/
dataSource?: DataSource;
dataSource?: juggler.DataSource | DataSource;

/**
* Constructor for RepositoryMetadata
Expand All @@ -51,8 +52,8 @@ export class RepositoryMetadata {
* - new RepositoryMetadata(modelClass, dataSourceName);
*/
constructor(
modelOrRepo: string | Class<Model>,
dataSource?: string | DataSource,
modelOrRepo: string | typeof juggler.PersistedModel | typeof Model,
dataSource?: string | juggler.DataSource | DataSource,
) {
this.name = typeof modelOrRepo === 'string' && dataSource === undefined
? modelOrRepo
Expand Down Expand Up @@ -85,8 +86,8 @@ export class RepositoryMetadata {
* - @repository(Customer, 'mysqlDataSource')
*/
export function repository<T extends Model>(
model: string | Class<T>,
dataSource?: string | DataSource,
model: string | typeof juggler.PersistedModel,
dataSource?: string | juggler.DataSource,
) {
const meta = new RepositoryMetadata(model, dataSource);
return function(
Expand All @@ -104,11 +105,27 @@ export function repository<T extends Model>(
} else {
// Use repository-factory to create a repository from model + dataSource
// inject('repository-factory', meta)(target, key!, descriptor);
throw new Error('@repository(model, dataSource) is not implemented');
inject('', meta, resolve)(target, key!, descriptor);
// throw new Error('@repository(model, dataSource) is not implemented');
}
return;
}
// Mixin repostory into the class
throw new Error('Class level @repository is not implemented');
};
}

async function resolve(ctx: Context, injection: Injection) {
const meta = injection.metadata as RepositoryMetadata;
let modelClass = meta.modelClass;
if (meta.modelName) {
modelClass = await ctx.get('models.' + meta.modelName);
}
let dataSource = meta.dataSource;
if (meta.dataSourceName) {
dataSource = await ctx.get('datasources.' + meta.dataSourceName);
}
return new DefaultCrudRepository(
modelClass as typeof juggler.PersistedModel,
dataSource! as juggler.DataSource);
}
26 changes: 15 additions & 11 deletions packages/repository/test/unit/decorator/repository.ts
Expand Up @@ -27,21 +27,24 @@ class MyController {
describe('repository decorator', () => {
let ctx: Context;
let repo: Repository<juggler.PersistedModel>;
/* tslint:disable-next-line:variable-name */
let Note: typeof juggler.PersistedModel;

before(function() {
const ds: juggler.DataSource = new DataSourceConstructor({
name: 'db',
connector: 'memory',
});

/* tslint:disable-next-line:variable-name */
const Note = ds.createModel<typeof juggler.PersistedModel>(
Note = ds.createModel<typeof juggler.PersistedModel>(
'note',
{title: 'string', content: 'string'},
{},
);
repo = new DefaultCrudRepository(Note, ds);
ctx = new Context();
ctx.bind('models.Note').to(Note);
ctx.bind('datasources.memory').to(ds);
ctx.bind('repositories.noteRepo').to(repo);
ctx.bind('controllers.MyController').toClass(MyController);
});
Expand Down Expand Up @@ -69,14 +72,15 @@ describe('repository decorator', () => {
}).to.throw(/not implemented/);
});

it('throws not implemented for @repository(model, dataSource)', () => {
expect(() => {
class Controller2 {
constructor(
@repository('customer', 'mysql')
public noteRepo: Repository<juggler.PersistedModel>,
) {}
}
}).to.throw(/not implemented/);
it('supports @repository(model, dataSource)', async () => {
class Controller2 {
constructor(@repository('Note', 'memory')
public noteRepo: Repository<juggler.PersistedModel>) {}
}
ctx.bind('controllers.Controller2').toClass(Controller2);
const myController: MyController = await ctx.get(
'controllers.Controller2',
);
expect(myController.noteRepo).to.be.not.null();
});
});

0 comments on commit b0102f1

Please sign in to comment.