1 | // Copyright IBM Corp. and LoopBack contributors 2018,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 |
|
6 | import {InclusionFilter} from '@loopback/filter';
|
7 | import {Options} from '../common-types';
|
8 | import {Entity} from '../model';
|
9 | import {TypeResolver} from '../type-resolver';
|
10 |
|
11 | export enum RelationType {
|
12 | belongsTo = 'belongsTo',
|
13 | hasOne = 'hasOne',
|
14 | hasMany = 'hasMany',
|
15 | embedsOne = 'embedsOne',
|
16 | embedsMany = 'embedsMany',
|
17 | referencesOne = 'referencesOne',
|
18 | referencesMany = 'referencesMany',
|
19 | }
|
20 |
|
21 | export interface RelationDefinitionBase {
|
22 | /**
|
23 | * The type of the relation, must be one of RelationType values.
|
24 | */
|
25 | type: RelationType;
|
26 |
|
27 | /**
|
28 | * True for relations targeting multiple instances (e.g. HasMany),
|
29 | * false for relations with a single target (e.g. BelongsTo, HasOne).
|
30 | * This property is needed by OpenAPI/JSON Schema generator.
|
31 | */
|
32 | targetsMany: boolean;
|
33 |
|
34 | /**
|
35 | * The relation name, typically matching the name of the accessor property
|
36 | * defined on the source model. For example "orders" or "customer".
|
37 | */
|
38 | name: string;
|
39 |
|
40 | /**
|
41 | * The source model of this relation.
|
42 | *
|
43 | * E.g. when a Customer has many Order instances, then Customer is the source.
|
44 | */
|
45 | source: typeof Entity;
|
46 |
|
47 | /**
|
48 | * The target model of this relation.
|
49 | *
|
50 | * E.g. when a Customer has many Order instances, then Order is the target.
|
51 | */
|
52 | target: TypeResolver<Entity, typeof Entity>;
|
53 | }
|
54 |
|
55 | /**
|
56 | * HasManyDefinition defines one-to-many relations and also possible defines
|
57 | * many-to-many relations with through models.
|
58 | */
|
59 | export interface HasManyDefinition extends RelationDefinitionBase {
|
60 | type: RelationType.hasMany;
|
61 | targetsMany: true;
|
62 |
|
63 | /**
|
64 | * keyTo: The foreign key used by the target model for this relation.
|
65 | * keyFrom: The source key used by the source model for this relation.
|
66 | *
|
67 | * E.g. when a Customer has many Order instances, then keyTo is "customerId".
|
68 | * Note that "customerId" is the default FK assumed by the framework, users
|
69 | * can provide a custom FK name by setting "keyTo".
|
70 | * And Customer.id is keyFrom. keyFrom defaults to the id property of a model.
|
71 | * Users can provide a custom source key name by setting "keyTo".
|
72 | *
|
73 | */
|
74 | keyTo?: string;
|
75 | keyFrom?: string;
|
76 |
|
77 | /**
|
78 | * With current architecture design, polymorphic type cannot be supported without through
|
79 | * Consider using Source-hasMany->Through->hasOne->Target(polymorphic) for one-to-many relations
|
80 | */
|
81 | // polymorphic?: boolean | {discriminator: string};
|
82 |
|
83 | /**
|
84 | * Description of the through model of the hasManyThrough relation.
|
85 | *
|
86 | * A `hasManyThrough` relation defines a many-to-many connection with another model.
|
87 | * This relation indicates that the declaring model can be matched with zero or more
|
88 | * instances of another model by proceeding through a third model.
|
89 | *
|
90 | * E.g a Category has many Products, and a Product can have many Categories.
|
91 | * CategoryProductLink can be the through model.
|
92 | * Such a through model has information of foreign keys of the source model(Category) and the target model(Product).
|
93 | *
|
94 | * Warning: The hasManyThrough interface is experimental and is subject to change.
|
95 | * If backwards-incompatible changes are made, a new major version may not be
|
96 | * released.
|
97 | */
|
98 | through?: {
|
99 | /**
|
100 | * The through model of this relation.
|
101 | *
|
102 | * E.g. when a Category has many CategoryProductLink instances and a Product has many CategoryProductLink instances,
|
103 | * then CategoryProductLink is through.
|
104 | */
|
105 | model: TypeResolver<Entity, typeof Entity>;
|
106 |
|
107 | /**
|
108 | * The foreign key of the source model defined in the through model, e.g. CategoryProductLink#categoryId
|
109 | */
|
110 | keyFrom?: string;
|
111 |
|
112 | /**
|
113 | * The foreign key of the target model defined in the through model, e.g. CategoryProductLink#productId
|
114 | */
|
115 | keyTo?: string;
|
116 |
|
117 | /**
|
118 | * The polymorphism of the target model. The discriminator is a key of *through* model.
|
119 | * If the target model is not polymorphic, then the value should be left undefined or false;
|
120 | * If the key on through model indicating the concrete class of the through instance is default
|
121 | * i.e. camelCase(classNameOf(targetModelInstance)) + "Id"
|
122 | * then the discriminator field can be undefined
|
123 | *
|
124 | * With current architecture design, polymorphic type cannot be supported without through
|
125 | * Consider using Source hasMany Through hasOne Target(polymorphic)
|
126 | * or Source hasMany Through belongsTo Target(polymorphic) for one-to-many relations
|
127 | */
|
128 | polymorphic?: boolean | {discriminator: string};
|
129 | };
|
130 | }
|
131 |
|
132 | export interface BelongsToDefinition extends RelationDefinitionBase {
|
133 | type: RelationType.belongsTo;
|
134 | targetsMany: false;
|
135 |
|
136 | /*
|
137 | * The foreign key in the source model, e.g. Order#customerId.
|
138 | */
|
139 | keyFrom?: string;
|
140 |
|
141 | /*
|
142 | * The primary key of the target model, e.g Customer#id.
|
143 | */
|
144 | keyTo?: string;
|
145 | /**
|
146 | * The polymorphism of the target model. The discriminator is a key of source model.
|
147 | * If the target model is not polymorphic, then the value should be left undefined or false;
|
148 | * If the key on source model indicating the concrete class of the target instance is default
|
149 | * i.e. camelCase(classNameOf(throughModelInstance)) + "Id"
|
150 | * Then the discriminator field can be undefined
|
151 | */
|
152 | polymorphic?: boolean | {discriminator: string};
|
153 | }
|
154 |
|
155 | export interface HasOneDefinition extends RelationDefinitionBase {
|
156 | type: RelationType.hasOne;
|
157 | targetsMany: false;
|
158 |
|
159 | /**
|
160 | * keyTo: The foreign key used by the target model for this relation.
|
161 | * keyFrom: The source key used by the source model for this relation.
|
162 | *
|
163 | * E.g. when a Customer has one Address instance, then keyTo is "customerId".
|
164 | * Note that "customerId" is the default FK assumed by the framework, users
|
165 | * can provide a custom FK name by setting "keyTo".
|
166 | * And Customer.id is keyFrom. keyFrom defaults to the id property of a model.
|
167 | * Users can provide a custom source key name by setting "keyTo".
|
168 | */
|
169 | keyTo?: string;
|
170 | keyFrom?: string;
|
171 | /**
|
172 | * The polymorphism of the target model. The discriminator is a key of source model.
|
173 | * If the target model is not polymorphic, then the value should be left undefined or false;
|
174 | * If the key on source model indicating the concrete class of the target instance is default
|
175 | * i.e. camelCase(classNameOf(throughModelInstance)) + "Id"
|
176 | * Then the discriminator field can be undefined
|
177 | */
|
178 | polymorphic?: boolean | {discriminator: string};
|
179 | }
|
180 |
|
181 | export interface ReferencesManyDefinition extends RelationDefinitionBase {
|
182 | type: RelationType.referencesMany;
|
183 | targetsMany: true;
|
184 |
|
185 | /**
|
186 | * keyTo: The foreign key used by the target model for this relation.
|
187 | * keyFrom: The source key used by the source model for this relation.
|
188 | *
|
189 | * TODO(bajtos) Add relation description.
|
190 | *
|
191 | */
|
192 | keyTo?: string;
|
193 | keyFrom?: string;
|
194 | }
|
195 |
|
196 | /**
|
197 | * A union type describing all possible Relation metadata objects.
|
198 | */
|
199 | export type RelationMetadata =
|
200 | | HasManyDefinition
|
201 | | BelongsToDefinition
|
202 | | HasOneDefinition
|
203 | | ReferencesManyDefinition
|
204 | // TODO(bajtos) add other relation types and remove RelationDefinitionBase once
|
205 | // all relation types are covered.
|
206 | | RelationDefinitionBase;
|
207 |
|
208 | // Re-export Getter so that users don't have to import from @loopback/context
|
209 | export {Getter} from '@loopback/core';
|
210 |
|
211 | /**
|
212 | * @returns An array of resolved values, the items must be ordered in the same
|
213 | * way as `sourceEntities`. The resolved value can be one of:
|
214 | * - `undefined` when no target model(s) were found
|
215 | * - `Entity` for relations targeting a single model
|
216 | * - `Entity[]` for relations targeting multiple models
|
217 | */
|
218 | export type InclusionResolver<S extends Entity, T extends Entity> = (
|
219 | /**
|
220 | * List of source models as returned by the first database query.
|
221 | */
|
222 | sourceEntities: S[],
|
223 | /**
|
224 | * Inclusion requested by the user (e.g. scope constraints to apply).
|
225 | */
|
226 | inclusion: InclusionFilter,
|
227 | /**
|
228 | * Generic options object, e.g. carrying the Transaction object.
|
229 | */
|
230 | options?: Options,
|
231 | ) => Promise<(T | undefined)[] | (T[] | undefined)[]>;
|