UNPKG

2.97 kBPlain TextView Raw
1// Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved.
2// Node module: @loopback/repository
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6import * as assert from 'assert';
7import {DataObject, PrototypeOf} from './common-types';
8import {model} from './decorators';
9import {Model, ModelDefinition} from './model';
10
11/**
12 * Create (define) a new model class with the given name and definition.
13 *
14 * @remarks
15 *
16 * ```ts
17 * const Product = defineModelClass(Entity, new ModelDefinition('Product'));
18 * ```
19 *
20 * To enable type safety, you should describe properties of your model:
21 *
22 * ```ts
23 * const Product = defineModelClass<
24 * typeof Entity,
25 * {id: number, name: string}
26 * >(Entity, new ModelDefinition('Product'));
27 * ```
28 *
29 * If your model allows arbitrary (free-form) properties, then add `AnyObject`
30 * to the type describing model properties.
31 *
32 * ```ts
33 * const Product = defineModelClass<
34 * typeof Entity,
35 * AnyObject & {id: number},
36 * >(Entity, new ModelDefinition('Product'));
37 * ```
38 *
39 * @param base The base model to extend, typically Model or Entity.
40 * You can also use your own base class, e.g. `User`.
41 * @param definition Definition of the model to create.
42 * @typeParam BaseCtor Constructor type of the base class,
43 * e.g `typeof Model` or `typeof Entity`
44 * @typeParam Props Interface describing model properties,
45 * e.g. `{title: string}` or `AnyObject & {id: number}`.
46 */
47export function defineModelClass<
48 BaseCtor extends typeof Model,
49 Props extends object = {},
50>(
51 base: BaseCtor /* Model or Entity */,
52 definition: ModelDefinition,
53): DynamicModelCtor<BaseCtor, Props> {
54 const modelName = definition.name;
55 const defineNamedModelClass = new Function(
56 base.name,
57 `return class ${modelName} extends ${base.name} {}`,
58 );
59 const modelClass = defineNamedModelClass(base) as DynamicModelCtor<
60 BaseCtor,
61 Props
62 >;
63 assert.equal(modelClass.name, modelName);
64
65 // Apply `@model(definition)` to the generated class
66 model(definition)(modelClass);
67 return modelClass;
68}
69
70/**
71 * A type describing a model class created via `defineModelClass`.
72 *
73 * Assuming template arguments `BaseCtor` and `Props`, this type describes
74 * a class constructor with the following properties:
75 * - a constructor function accepting `DataObject<Props>` as the only argument,
76 * this argument is optional
77 * - all static fields (properties, methods) from `BaseCtor` are inherited and
78 * available as static fields on the dynamic class
79 * - all prototype fields from `BaseCtor` prototype are inherited and available
80 * as prototype fields on the dynamic class
81 */
82export type DynamicModelCtor<
83 BaseCtor extends typeof Model,
84 Props extends object,
85> = {
86 /** Model constructor accepting partial model data. */
87 new (
88 data?: DataObject<PrototypeOf<BaseCtor> & Props>,
89 ): PrototypeOf<BaseCtor> & Props;
90} & BaseCtor;