UNPKG

19.1 kBTypeScriptView Raw
1// Copyright IBM Corp. 2018. All Rights Reserved.
2// Node module: loopback-datasource-juggler
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6import {Options} from './common';
7import {RelationDefinition} from './relation';
8import {PersistedModelClass} from './persisted-model';
9
10/**
11 * Methods defined on this interface are mixed into a model class so that they
12 * can be used to set up relations between models programmatically.
13 */
14export interface RelationMixin {
15 /**
16 * Define a "one to many" relationship by specifying the model name.
17 *
18 * Examples:
19 * ```
20 * User.hasMany(Post, {as: 'posts', foreignKey: 'authorId'});
21 * ```
22 *
23 * ```
24 * Book.hasMany(Chapter);
25 * ```
26 * Or, equivalently:
27 * ```
28 * Book.hasMany('chapters', {model: Chapter});
29 * ```
30 *
31 * Query and create related models:
32 *
33 * ```js
34 * Book.create(function(err, book) {
35 *
36 * // Create a chapter instance ready to be saved in the data source.
37 * var chapter = book.chapters.build({name: 'Chapter 1'});
38 *
39 * // Save the new chapter
40 * chapter.save();
41 *
42 * // you can also call the Chapter.create method with the `chapters` property which will build a chapter
43 * // instance and save the it in the data source.
44 * book.chapters.create({name: 'Chapter 2'}, function(err, savedChapter) {
45 * // this callback is optional
46 * });
47 *
48 * // Query chapters for the book
49 * book.chapters(function(err, chapters) {
50 * // all chapters with bookId = book.id
51 * console.log(chapters);
52 * });
53 *
54 * // Query chapters for the book with a filter
55 * book.chapters({where: {name: 'test'}, function(err, chapters) {
56 * // All chapters with bookId = book.id and name = 'test'
57 * console.log(chapters);
58 * });
59 * });
60 * ```
61 *
62 * @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
63 * @options {Object} params Configuration parameters; see below.
64 * @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
65 * @property {String} foreignKey Property name of foreign key field.
66 * @property {String} polymorphic Define a polymorphic relation name.
67 * @property {String} through Name of the through model.
68 * @property {String} keyThrough Property name of the foreign key in the through model.
69 * @property {Object|Function} scope Explicitly define additional scopes.
70 * @property {Boolean} invert Specify if the relation is inverted.
71 * @property {Object} model The model object.
72 */
73 hasMany(modelTo: PersistedModelClass, params?: Options): RelationDefinition;
74
75 /**
76 * Declare "belongsTo" relation that sets up a one-to-one connection with another model, such that each
77 * instance of the declaring model "belongs to" one instance of the other model.
78 *
79 * For example, if an application includes users and posts, and each post can be written by exactly one user.
80 * The following code specifies that `Post` has a reference called `author` to the `User` model via the `userId` property of `Post`
81 * as the foreign key.
82 * ```
83 * Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
84 * ```
85 * You can then access the author in one of the following styles.
86 * Get the User object for the post author asynchronously:
87 * ```
88 * post.author(callback);
89 * ```
90 * Get the User object for the post author synchronously:
91 * ```
92 * post.author();
93 * ```
94 * Set the author to be the given user:
95 * ```
96 * post.author(user)
97 * ```
98 * Examples:
99 *
100 * Suppose the model Post has a *belongsTo* relationship with User (the author of the post). You could declare it this way:
101 * ```js
102 * Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
103 * ```
104 *
105 * When a post is loaded, you can load the related author with:
106 * ```js
107 * post.author(function(err, user) {
108 * // the user variable is your user object
109 * });
110 * ```
111 *
112 * The related object is cached, so if later you try to get again the author, no additional request will be made.
113 * But there is an optional boolean parameter in first position that set whether or not you want to reload the cache:
114 * ```js
115 * post.author(true, function(err, user) {
116 * // The user is reloaded, even if it was already cached.
117 * });
118 * ```
119 * This optional parameter default value is false, so the related object will be loaded from cache if available.
120 *
121 * @param {Class|String} modelTo Model object (or String name of model) to which you are creating the relationship.
122 * @options {Object} params Configuration parameters; see below.
123 * @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
124 * @property {String} primaryKey Property name of primary key field.
125 * @property {String} foreignKey Name of foreign key property.
126 * @property {Object|Function} scope Explicitly define additional scopes.
127 * @property {Object} properties Properties inherited from the parent object.
128 * @property {Object} options Property level options.
129 * @property {Boolean} options.invertProperties Specify if the properties should be inverted.
130 */
131 belongsTo(modelTo: PersistedModelClass, params?: Options): RelationDefinition;
132
133 /**
134 * A hasAndBelongsToMany relation creates a direct many-to-many connection with another model, with no intervening model.
135 *
136 * For example, if your application includes users and groups, with each group having many users and each user appearing
137 * in many groups, you could declare the models this way:
138 * ```
139 * User.hasAndBelongsToMany('groups', {model: Group, foreignKey: 'groupId'});
140 * ```
141 * Then, to get the groups to which the user belongs:
142 * ```
143 * user.groups(callback);
144 * ```
145 * Create a new group and connect it with the user:
146 * ```
147 * user.groups.create(data, callback);
148 * ```
149 * Connect an existing group with the user:
150 * ```
151 * user.groups.add(group, callback);
152 * ```
153 * Remove the user from the group:
154 * ```
155 * user.groups.remove(group, callback);
156 * ```
157 *
158 * @param {String|Object} modelTo Model object (or String name of model) to which you are creating the relationship.
159 * @options {Object} params Configuration parameters; see below.
160 * @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
161 * @property {String} foreignKey Property name of foreign key field.
162 * @property {String} throughTable The table name of the through model.
163 * @property {String} through Name of the through model.
164 * @property {String} polymorphic Define a polymorphic relation name.
165 * @property {Object|Function} scope Explicitly define additional scopes.
166 * @property {Object} model The model object.
167 */
168 hasAndBelongsToMany(
169 modelTo: PersistedModelClass,
170 params?: Options,
171 ): RelationDefinition;
172 /**
173 * Define a "one to one" relationship by specifying the model name.
174 *
175 * Examples:
176 * ```
177 * Supplier.hasOne(Account, {as: 'account', foreignKey: 'supplierId'});
178 * ```
179 *
180 * If the target model doesn’t have a foreign key property, LoopBack will add a property with the same name.
181 *
182 * The type of the property will be the same as the type of the target model’s id property.
183 *
184 * Please note the foreign key property is defined on the target model (in this example, Account).
185 *
186 * If you don’t specify them, then LoopBack derives the relation name and foreign key as follows:
187 * - Relation name: Camel case of the model name, for example, for the “supplier” model the relation is “supplier”.
188 * - Foreign key: The relation name appended with Id, for example, for relation name “supplier” the default foreign key is “supplierId”.
189 *
190 * Build a new account for the supplier with the supplierId to be set to the id of the supplier.
191 * ```js
192 * var supplier = supplier.account.build(data);
193 * ```
194 *
195 * Create a new account for the supplier. If there is already an account, an error will be reported.
196 * ```js
197 * supplier.account.create(data, function(err, account) {
198 * ...
199 * });
200 * ```
201 *
202 * Find the supplier's account model.
203 * ```js
204 * supplier.account(function(err, account) {
205 * ...
206 * });
207 * ```
208 *
209 * Update the associated account.
210 * ```js
211 * supplier.account.update({balance: 100}, function(err, account) {
212 * ...
213 * });
214 * ```
215 *
216 * Remove the account for the supplier.
217 * ```js
218 * supplier.account.destroy(function(err) {
219 * ...
220 * });
221 * ```
222 *
223 * @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
224 * @options {Object} params Configuration parameters; see below.
225 * @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
226 * @property {String} primaryKey Property name of primary key field.
227 * @property {String} foreignKey Property name of foreign key field.
228 * @property {String} polymorphic Define a polymorphic relation name.
229 * @property {Object|Function} scope Explicitly define additional scopes.
230 * @property {Object} model The model object.
231 * @property {Object} properties Properties inherited from the parent object.
232 * @property {Function} methods Scoped methods for the given relation.
233 */
234 hasOne(modelTo: PersistedModelClass, params?: Options): RelationDefinition;
235
236 /**
237 * References one or more instances of the target model.
238 *
239 * For example, a Customer model references one or more instances of the Account model.
240 *
241 * Define the relation in the model definition:
242 *
243 * - Definition of Customer model:
244 * ```json
245 * {
246 "name": "Customer",
247 "base": "PersistedModel",
248 "idInjection": true,
249 "properties": {
250 "name": {
251 "type": "string"
252 },
253 "age": {
254 "type": "number"
255 }
256 },
257 "validations": [],
258 "relations": {
259 "accounts": {
260 "type": "referencesMany",
261 "model": "Account",
262 "foreignKey": "accountIds",
263 "options": {
264 "validate": true,
265 "forceId": false
266 }
267 }
268 },
269 "acls": [],
270 "methods": {}
271}
272 * ```
273 *
274 * - Definition of Account model:
275 * ```json
276 * {
277 "name": "Account",
278 "base": "PersistedModel",
279 "idInjection": true,
280 "properties": {
281 "name": {
282 "type": "string"
283 },
284 "balance": {
285 "type": "number"
286 }
287 },
288 "validations": [],
289 "relations": {},
290 "acls": [],
291 "methods": {}
292}
293 * ```
294 *
295 * On the bootscript, create a customer instance and for that customer instance reference many account instances.
296 *
297 * For example:
298 * ```javascript
299 * var Customer = app.models.Customer;
300 var accounts = [
301 {
302 name: 'Checking',
303 balance: 5000
304 },
305 {
306 name: 'Saving',
307 balance: 2000
308 }
309 ];
310 Customer.create({name: 'Mary Smith'}, function(err, customer) {
311 console.log('Customer:', customer);
312 async.each(accounts, function(account, done) {
313 customer.accounts.create(account, done);
314 }, function(err) {
315 console.log('Customer with accounts:', customer);
316 customer.accounts(console.log);
317 cb(err);
318 });
319 });
320 * ```
321 *
322 * Sample referencesMany model data:
323 * ```javascript
324 * {
325 id: 1,
326 name: 'John Smith',
327 accounts: [
328 "saving-01", "checking-01",
329 ]
330}
331 * ```
332 *
333 * Supported helper methods:
334 * - customer.accounts()
335 * - customer.accounts.create()
336 * - customer.accounts.build()
337 * - customer.accounts.findById()
338 * - customer.accounts.destroy()
339 * - customer.accounts.updateById()
340 * - customer.accounts.exists()
341 * - customer.accounts.add()
342 * - customer.accounts.remove()
343 * - customer.accounts.at()
344 *
345 * @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
346 * @options {Object} params Configuration parameters; see below.
347 * @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
348 * @property {Any} default The default value.
349 * @property {Object} options Options to specify for the relationship.
350 * @property {Boolean} options.forceId Force generation of id for embedded items. Default is false.
351 * @property {Boolean} options.validate Denote if the embedded items should be validated. Default is true.
352 * @property {Boolean} options.persistent Denote if the embedded items should be persisted. Default is false.
353 * @property {Object|Function} scope Explicitly define additional scopes.
354 * @property {String} foreignKey Property name of foreign key field.
355 * @property {Object} properties Properties inherited from the parent object.
356 * @property {Function} methods Scoped methods for the given relation.
357 */
358 referencesMany(
359 modelTo: PersistedModelClass,
360 params?: Options,
361 ): RelationDefinition;
362
363 /**
364 * Represent a model that embeds another model.
365 *
366 * For example, a Customer embeds one billingAddress from the Address model.
367 *
368 * - Define the relation in bootscript:
369 * ```js
370 * Customer.embedsOne(Address, {
371 * as: 'address', // default to the relation name - address
372 * property: 'billingAddress' // default to addressItem
373 * });
374 * ```
375 *
376 * OR, define the relation in the model definition:
377 *
378 * - Definition of Customer model:
379 * ```json
380 * {
381 "name": "Customer",
382 "base": "PersistedModel",
383 "idInjection": true,
384 "properties": {
385 "name": {
386 "type": "string"
387 },
388 "age": {
389 "type": "number"
390 }
391 },
392 "validations": [],
393 "relations": {
394 "address": {
395 "type": "embedsOne",
396 "model": "Address",
397 "property": "billingAddress",
398 "options": {
399 "validate": true,
400 "forceId": false
401 }
402 }
403 },
404 "acls": [],
405 "methods": {}
406}
407 * ```
408 *
409 * - Definition of Address model:
410 * ```json
411 * {
412 "name": "Address",
413 "base": "Model",
414 "idInjection": true,
415 "properties": {
416 "street": {
417 "type": "string"
418 },
419 "city": {
420 "type": "string"
421 },
422 "state": {
423 "type": "string"
424 },
425 "zipCode": {
426 "type": "string"
427 }
428 },
429 "validations": [],
430 "relations": {},
431 "acls": [],
432 "methods": {}
433}
434 * ```
435 *
436 * Sample embedded model data:
437 * ```javascript
438 * {
439 id: 1,
440 name: 'John Smith',
441 billingAddress: {
442 street: '123 Main St',
443 city: 'San Jose',
444 state: 'CA',
445 zipCode: '95124'
446 }
447}
448 * ```
449 *
450 * Supported helper methods:
451 * - customer.address()
452 * - customer.address.build()
453 * - customer.address.create()
454 * - customer.address.update()
455 * - customer.address.destroy()
456 * - customer.address.value()
457 *
458 * @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
459 * @options {Object} params Configuration parameters; see below.
460 * @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
461 * @property {String} property Name of the property for the embedded item.
462 * @property {Any} default The default value.
463 * @property {Object} options Options to specify for the relationship.
464 * @property {Boolean} options.forceId Force generation of id for embedded items. Default is false.
465 * @property {Boolean} options.validate Denote if the embedded items should be validated. Default is true.
466 * @property {Boolean} options.persistent Denote if the embedded items should be persisted. Default is false.
467 * @property {Object|Function} scope Explicitly define additional scopes.
468 * @property {Object} properties Properties inherited from the parent object.
469 * @property {Function} methods Scoped methods for the given relation.
470 */
471 embedsOne(modelTo: PersistedModelClass, params?: Options): RelationDefinition;
472
473 /**
474 * Represent a model that can embed many instances of another model.
475 *
476 * For example, a Customer can have multiple email addresses and each email address is a complex object that contains label and address.
477 *
478 * Define the relation code in bootscript:
479 * ```javascript
480 Customer.embedsMany(EmailAddress, {
481 as: 'emails', // default to the relation name - emailAddresses
482 property: 'emailList' // default to emailAddressItems
483 });
484 * ```
485 *
486 * OR, define the relation in the model definition:
487 *
488 * - Definition of Customer model:
489 * ```json
490 * {
491 "name": "Customer",
492 "base": "PersistedModel",
493 "idInjection": true,
494 "properties": {
495 "name": {
496 "type": "string"
497 },
498 "age": {
499 "type": "number"
500 }
501 },
502 "validations": [],
503 "relations": {
504 "emails": {
505 "type": "embedsMany",
506 "model": "EmailAddress",
507 "property": "emailList",
508 "options": {
509 "validate": true,
510 "forceId": false
511 }
512 }
513 },
514 "acls": [],
515 "methods": {}
516}
517 * ```
518 *
519 * - Definition of EmailAddress model:
520 * ```json
521 * {
522 "name": "EmailAddress",
523 "base": "Model",
524 "idInjection": true,
525 "properties": {
526 "label": {
527 "type": "string"
528 },
529 "address": {
530 "type": "string"
531 }
532 },
533 "validations": [],
534 "relations": {},
535 "acls": [],
536 "methods": {}
537}
538 * ```
539 *
540 * Sample embedded model data:
541 * ```javascript
542 * {
543 id: 1,
544 name: 'John Smith',
545 emails: [{
546 label: 'work',
547 address: 'john@xyz.com'
548 }, {
549 label: 'home',
550 address: 'john@gmail.com'
551 }]
552}
553 * ```
554 *
555 * Supported helper methods:
556 * - customer.emails()
557 * - customer.emails.create()
558 * - customer.emails.build()
559 * - customer.emails.findById()
560 * - customer.emails.destroyById()
561 * - customer.emails.updateById()
562 * - customer.emails.exists()
563 * - customer.emails.add()
564 * - customer.emails.remove()
565 * - customer.emails.at()
566 * - customer.emails.value()
567 *
568 * @param {Object|String} modelTo Model object (or String name of model) to which you are creating the relationship.
569 * @options {Object} params Configuration parameters; see below.
570 * @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
571 * @property {String} property Name of the property for the embedded item.
572 * @property {Any} default The default value.
573 * @property {Object} options Options to specify for the relationship.
574 * @property {Boolean} options.forceId Force generation of id for embedded items. Default is false.
575 * @property {Boolean} options.validate Denote if the embedded items should be validated. Default is true.
576 * @property {Boolean} options.persistent Denote if the embedded items should be persisted. Default is false.
577 * @property {String} polymorphic Define a polymorphic relation name.
578 * @property {Object|Function} scope Explicitly define additional scopes.
579 * @property {Object} properties Properties inherited from the parent object.
580 * @property {Function} methods Scoped methods for the given relation.
581 */
582 embedsMany(
583 modelTo: PersistedModelClass,
584 params?: Options,
585 ): RelationDefinition;
586}