diff --git a/packages/repository/package.json b/packages/repository/package.json index 1c64ea4e5e23..eb32314f2da0 100644 --- a/packages/repository/package.json +++ b/packages/repository/package.json @@ -29,6 +29,8 @@ }, "dependencies": { "@loopback/context": "^4.0.0-alpha.23", + "@types/lodash": "^4.14.91", + "lodash": "^4.17.4", "loopback-datasource-juggler": "^3.9.2" }, "files": [ diff --git a/packages/repository/src/decorators/metadata.ts b/packages/repository/src/decorators/metadata.ts new file mode 100644 index 000000000000..fefffe27b731 --- /dev/null +++ b/packages/repository/src/decorators/metadata.ts @@ -0,0 +1,41 @@ +import {InspectionOptions, MetadataInspector} from '@loopback/context'; +import {MODEL_KEY, MODEL_PROPERTIES_KEY} from '../'; +import {ModelDefinition, PropertyDefinition} from '../../index'; +import * as _ from 'lodash'; + +export class ModelMetadataHelper { + /** + * A utility function to simplify retrieving metadata from a target model and + * its properties. + * @param target The class from which to retrieve metadata. + * @param options An options object for the MetadataInspector to customize + * the output of the metadata retrieval functions. + */ + static getModelMetadata(target: Function, options?: InspectionOptions) { + const classDef = MetadataInspector.getClassMetadata( + MODEL_KEY, + target, + options, + ); + const meta = new ModelDefinition( + Object.assign( + { + name: target.name, + }, + classDef, + ), + ); + if (_.isEmpty(_.keys(meta.properties))) { + meta.properties = Object.assign( + {}, + MetadataInspector.getAllPropertyMetadata( + MODEL_PROPERTIES_KEY, + target.prototype, + options, + ), + ); + MetadataInspector.defineMetadata(MODEL_KEY, meta, target); + } + return meta; + } +} diff --git a/packages/repository/src/index.ts b/packages/repository/src/index.ts index 3207690eac54..b1069dca6a7f 100644 --- a/packages/repository/src/index.ts +++ b/packages/repository/src/index.ts @@ -7,6 +7,7 @@ export * from './common-types'; export * from './decorators/model'; export * from './decorators/repository'; export * from './decorators/relation'; +export * from './decorators/metadata'; export * from './types'; export * from './model'; export * from './query'; diff --git a/packages/repository/test/unit/decorator/metadata.ts b/packages/repository/test/unit/decorator/metadata.ts new file mode 100644 index 000000000000..4fc4d00f4dfb --- /dev/null +++ b/packages/repository/test/unit/decorator/metadata.ts @@ -0,0 +1,77 @@ +import {ModelMetadataHelper} from '../../../src'; +import {property, model, ModelDefinition, MODEL_KEY} from '../../..'; +import {expect} from '@loopback/testlab'; +import {MetadataInspector} from '@loopback/context'; + +describe('Repository', () => { + describe('getAllClassMetadata', () => { + @model() + class Colour { + @property({}) + rgb: string; + } + @model() + class Widget { + @property() id: number; + @property.array(Colour) colours: Colour[]; + } + + @model() + class Samoflange { + id: number; + name: string; + canRotate: boolean; + } + + @model() + class Phlange { + @property() id: number; + @property() canFlap: boolean; + @property.array(Colour) colours: Colour[]; + } + + it('retrieves metadata for classes with @model', () => { + const meta = ModelMetadataHelper.getModelMetadata(Samoflange); + expect(meta).to.deepEqual( + new ModelDefinition({ + name: 'Samoflange', + properties: {}, + settings: new Map(), + }), + ); + }); + + it('retrieves metadata for classes with @model and @property', () => { + const meta = ModelMetadataHelper.getModelMetadata(Widget); + expect(meta).to.deepEqual( + new ModelDefinition({ + properties: { + id: { + type: Number, + }, + colours: { + array: true, + type: Colour, + }, + }, + settings: new Map(), + name: 'Widget', + }), + ); + }); + + it('returns existing properties instead of re-assembling them', () => { + const classMeta = MetadataInspector.getClassMetadata( + MODEL_KEY, + Phlange, + ) as ModelDefinition; + classMeta.properties = { + foo: { + type: String, + }, + }; + const meta = ModelMetadataHelper.getModelMetadata(Phlange); + expect(meta.properties).to.eql(classMeta.properties); + }); + }); +});