Skip to content

Commit

Permalink
feat: Use decorator factories
Browse files Browse the repository at this point in the history
  • Loading branch information
Raymond Feng authored and raymondfeng committed Dec 6, 2017
1 parent 3dbc0dc commit c29588b
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 120 deletions.
8 changes: 2 additions & 6 deletions packages/context/src/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,7 @@ export function inject(
resolve,
},
);
return paramDecorator(
target,
propertyKey!,
propertyDescriptorOrParameterIndex,
);
paramDecorator(target, propertyKey!, propertyDescriptorOrParameterIndex);
} else if (propertyKey) {
if (typeof Object.getPrototypeOf(target) === 'function') {
const prop = target.name + '.' + propertyKey.toString();
Expand All @@ -100,7 +96,7 @@ export function inject(
resolve,
},
);
return propDecorator(target, propertyKey!);
propDecorator(target, propertyKey!);
} else {
throw new Error(
'@inject can only be used on properties or method parameters.',
Expand Down
37 changes: 17 additions & 20 deletions packages/repository/src/decorators/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Reflector} from '@loopback/context';
import {
Reflector,
ClassDecoratorFactory,
PropertyDecoratorFactory,
} from '@loopback/context';
import {ModelDefinition, ModelDefinitionSyntax} from '../model';
import {PropertyDefinition} from '../index';

export const MODEL_KEY = 'loopback:model';
export const PROPERTY_KEY = 'loopback:property';
export const MODEL_PROPERTIES_KEY = 'loopback:model-properties';

type PropertyMap = {[name: string]: PropertyDefinition};
Expand All @@ -21,13 +24,17 @@ type PropertyMap = {[name: string]: PropertyDefinition};
* @returns {(target:any)}
*/
export function model(definition?: ModelDefinitionSyntax) {
return function(target: any) {
return function(target: Function) {
if (!definition) {
definition = {name: target.name};
}

// Apply model definition to the model class
Reflector.defineMetadata(MODEL_KEY, definition, target);
const decorator: ClassDecorator = ClassDecoratorFactory.getDecorator(
MODEL_KEY,
definition,
);

decorator(target);

// Build "ModelDefinition" and store it on model constructor
const modelDef = new ModelDefinition(definition);
Expand All @@ -41,7 +48,7 @@ export function model(definition?: ModelDefinitionSyntax) {
modelDef.addProperty(p, propertyMap[p]);
}

target.definition = modelDef;
(<any>target).definition = modelDef;
};
}

Expand All @@ -51,18 +58,8 @@ export function model(definition?: ModelDefinitionSyntax) {
* @returns {(target:any, key:string)}
*/
export function property(definition: PropertyDefinition) {
return function(target: any, key: string) {
// Apply model definition to the model class
Reflector.defineMetadata(PROPERTY_KEY, definition, target, key);

// Because there is no way how to iterate decorated properties at runtime,
// we need to keep an explicit map of decorated properties
let map: PropertyMap = Reflector.getMetadata(MODEL_PROPERTIES_KEY, target);
if (!map) {
map = Object.create(null);
Reflector.defineMetadata(MODEL_PROPERTIES_KEY, map, target);
}

map[key] = definition;
};
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
MODEL_PROPERTIES_KEY,
definition,
);
}
84 changes: 43 additions & 41 deletions packages/repository/src/decorators/relation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import {Class} from '../common-types';
import {Entity} from '../model';

import {Reflector} from '@loopback/context';
import {PropertyDecoratorFactory} from '@loopback/context';

// tslint:disable:no-any

Expand All @@ -20,7 +20,7 @@ export enum RelationType {
referencesMany,
}

export const RELATION_KEY = 'loopback:relation';
export const RELATIONS_KEY = 'loopback:relations';

export class RelationMetadata {
type: RelationType;
Expand All @@ -34,10 +34,11 @@ export class RelationMetadata {
* @returns {(target:any, key:string)}
*/
export function relation(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
Reflector.defineMetadata(RELATION_KEY, definition, target, key);
};
// Apply relation definition to the model class
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
definition,
);
}

/**
Expand All @@ -46,11 +47,12 @@ export function relation(definition?: Object) {
* @returns {(target:any, key:string)}
*/
export function belongsTo(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.belongsTo}, definition);
Reflector.defineMetadata(RELATION_KEY, rel, target, key);
};
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.belongsTo}, definition);
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
rel,
);
}

/**
Expand All @@ -59,11 +61,11 @@ export function belongsTo(definition?: Object) {
* @returns {(target:any, key:string)}
*/
export function hasOne(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.hasOne}, definition);
Reflector.defineMetadata(RELATION_KEY, rel, target, key);
};
const rel = Object.assign({type: RelationType.hasOne}, definition);
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
rel,
);
}

/**
Expand All @@ -72,11 +74,11 @@ export function hasOne(definition?: Object) {
* @returns {(target:any, key:string)}
*/
export function hasMany(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.hasMany}, definition);
Reflector.defineMetadata(RELATION_KEY, rel, target, key);
};
const rel = Object.assign({type: RelationType.hasMany}, definition);
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
rel,
);
}

/**
Expand All @@ -85,11 +87,11 @@ export function hasMany(definition?: Object) {
* @returns {(target:any, key:string)}
*/
export function embedsOne(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.embedsOne}, definition);
Reflector.defineMetadata(RELATION_KEY, rel, target, key);
};
const rel = Object.assign({type: RelationType.embedsOne}, definition);
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
rel,
);
}

/**
Expand All @@ -98,11 +100,11 @@ export function embedsOne(definition?: Object) {
* @returns {(target:any, key:string)}
*/
export function embedsMany(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.embedsMany}, definition);
Reflector.defineMetadata(RELATION_KEY, rel, target, key);
};
const rel = Object.assign({type: RelationType.embedsMany}, definition);
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
rel,
);
}

/**
Expand All @@ -111,11 +113,11 @@ export function embedsMany(definition?: Object) {
* @returns {(target:any, key:string)}
*/
export function referencesOne(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.referencesOne}, definition);
Reflector.defineMetadata(RELATION_KEY, rel, target, key);
};
const rel = Object.assign({type: RelationType.referencesOne}, definition);
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
rel,
);
}

/**
Expand All @@ -124,9 +126,9 @@ export function referencesOne(definition?: Object) {
* @returns {(target:any, key:string)}
*/
export function referencesMany(definition?: Object) {
return function(target: any, key: string) {
// Apply model definition to the model class
const rel = Object.assign({type: RelationType.referencesMany}, definition);
Reflector.defineMetadata(RELATION_KEY, rel, target, key);
};
const rel = Object.assign({type: RelationType.referencesMany}, definition);
return <PropertyDecorator>PropertyDecoratorFactory.getDecorator(
RELATIONS_KEY,
rel,
);
}
73 changes: 20 additions & 53 deletions packages/repository/test/unit/decorator/model-and-relation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {model, property, MODEL_KEY, PROPERTY_KEY} from '../../../';
import {model, property, MODEL_KEY, MODEL_PROPERTIES_KEY} from '../../../';
import {
relation,
hasOne,
Expand All @@ -14,7 +14,7 @@ import {
hasMany,
referencesMany,
referencesOne,
RELATION_KEY,
RELATIONS_KEY,
RelationType,
} from '../../../';

Expand Down Expand Up @@ -102,11 +102,10 @@ describe('model decorator', () => {

it('adds property metadata', () => {
const meta = Reflector.getOwnMetadata(
PROPERTY_KEY,
MODEL_PROPERTIES_KEY,
Order.prototype,
'quantity',
);
expect(meta).to.eql({
expect(meta.quantity).to.eql({
type: 'number',
mysql: {
column: 'QTY',
Expand All @@ -115,90 +114,58 @@ describe('model decorator', () => {
});

it('adds embedsOne metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Customer.prototype,
'address',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Customer.prototype);
expect(meta.address).to.eql({
type: RelationType.embedsOne,
});
});

it('adds embedsMany metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Customer.prototype,
'phones',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Customer.prototype);
expect(meta.phones).to.eql({
type: RelationType.embedsMany,
});
});

it('adds referencesMany metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Customer.prototype,
'accounts',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Customer.prototype);
expect(meta.accounts).to.eql({
type: RelationType.referencesMany,
});
});

it('adds referencesOne metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Customer.prototype,
'profile',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Customer.prototype);
expect(meta.profile).to.eql({
type: RelationType.referencesOne,
});
});

it('adds hasMany metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Customer.prototype,
'orders',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Customer.prototype);
expect(meta.orders).to.eql({
type: RelationType.hasMany,
});
});

it('adds belongsTo metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Order.prototype,
'customer',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Order.prototype);
expect(meta.customer).to.eql({
type: RelationType.belongsTo,
target: 'Customer',
});
});

it('adds hasOne metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Customer.prototype,
'lastOrder',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Customer.prototype);
expect(meta.lastOrder).to.eql({
type: RelationType.hasOne,
});
});

it('adds relation metadata', () => {
const meta = Reflector.getOwnMetadata(
RELATION_KEY,
Customer.prototype,
'recentOrders',
);
expect(meta).to.eql({
const meta = Reflector.getOwnMetadata(RELATIONS_KEY, Customer.prototype);
expect(meta.recentOrders).to.eql({
type: RelationType.hasMany,
});
});
Expand Down

0 comments on commit c29588b

Please sign in to comment.