Skip to content

Commit

Permalink
feat(repository): allow components to contribute models for DI
Browse files Browse the repository at this point in the history
Add a new optional property `models` to `Component` interface, to allow
extension developers to declaratively contribute model classes to be
bound in the target context.

Signed-off-by: Miroslav Bajtoš <[email protected]>
  • Loading branch information
bajtos committed May 18, 2020
1 parent 9fa5550 commit 1cf38b1
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
DefaultCrudRepository,
Entity,
juggler,
Model,
ModelDefinition,
Repository,
RepositoryMixin,
Expand Down Expand Up @@ -77,6 +78,23 @@ describe('RepositoryMixin', () => {
expectNoteRepoToBeBound(myApp);
});

it('binds user defined component with models', () => {
@model()
class MyModel extends Model {}

class MyModelComponent {
models = [MyModel];
}

const myApp = new AppWithRepoMixin();
myApp.component(MyModelComponent);

const boundModels = myApp.find('models.*').map(b => b.key);
expect(boundModels).to.containEql('models.MyModel');
const modelCtor = myApp.getSync<typeof MyModel>('models.MyModel');
expect(modelCtor).to.be.equal(MyModel);
});

context('migrateSchema', () => {
let app: AppWithRepoMixin;
let migrateStub: sinon.SinonStub;
Expand Down
31 changes: 25 additions & 6 deletions packages/repository/src/mixins/repository.mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ export function RepositoryMixin<T extends MixinTarget<Application>>(
nameOrOptions?: string | BindingFromClassOptions,
) {
const binding = super.component(componentCtor, nameOrOptions);
this.mountComponentRepositories(componentCtor);
const instance = this.getComponentInstance(componentCtor);
this.mountComponentRepositories(instance);
this.mountComponentModels(instance);
return binding;
}

Expand All @@ -200,11 +202,16 @@ export function RepositoryMixin<T extends MixinTarget<Application>>(
*
* @param component - The component to mount repositories of
*/
mountComponentRepositories(component: Class<unknown>) {
const componentKey = `${CoreBindings.COMPONENTS}.${component.name}`;
const compInstance = this.getSync<{
repositories?: Class<Repository<Model>>[];
}>(componentKey);
mountComponentRepositories(
component: Class<unknown> | {repositories?: Class<Repository<Model>>[]},
) {
// accept also component class to preserve backwards compatibility
const compInstance =
typeof component === 'function'
? this.getComponentInstance<{
repositories?: Class<Repository<Model>>[];
}>(component)
: component;

if (compInstance.repositories) {
for (const repo of compInstance.repositories) {
Expand All @@ -213,6 +220,18 @@ export function RepositoryMixin<T extends MixinTarget<Application>>(
}
}

mountComponentModels(component: {models?: Class<Model>[]}) {
if (!component.models) return;
for (const m of component.models) {
this.model(m);
}
}

getComponentInstance<T extends object>(component: Class<unknown>) {
const componentKey = `${CoreBindings.COMPONENTS}.${component.name}`;
return this.getSync<T>(componentKey);
}

/**
* Update or recreate the database schema for all repositories.
*
Expand Down

0 comments on commit 1cf38b1

Please sign in to comment.