mythix-orm 1.4.7 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/Associations.md +2 -2
- package/docs/Certifications.md +22 -0
- package/docs/Home.md +25 -22
- package/lib/connection/connection-base.js +92 -3
- package/lib/connection/query-generator-base.js +5 -3
- package/lib/field.js +217 -0
- package/lib/model.js +1517 -37
- package/lib/query-engine/query-engine.js +24 -6
- package/lib/types/concrete/bigint-type.js +117 -0
- package/lib/types/concrete/date-type.js +4 -3
- package/lib/types/concrete/datetime-type.js +4 -3
- package/lib/types/concrete/index.js +9 -3
- package/lib/types/concrete/{float-type.js → numeric-type.js} +12 -9
- package/lib/types/concrete/real-type.js +47 -0
- package/lib/types/concrete/serialized-type.js +134 -0
- package/lib/types/index.js +12 -4
- package/lib/types/type.js +29 -0
- package/lib/utils/model-utils.js +39 -19
- package/package.json +1 -1
package/lib/model.js
CHANGED
|
@@ -110,6 +110,24 @@ function bindStaticWhereToModelClass(ModelClass) {
|
|
|
110
110
|
/// from this class. This class provides
|
|
111
111
|
/// support for all model operations in
|
|
112
112
|
/// Mythix ORM.
|
|
113
|
+
///
|
|
114
|
+
/// Note:
|
|
115
|
+
/// Many model methods have both static and instance
|
|
116
|
+
/// methods of the same name that do the same thing.
|
|
117
|
+
/// This is because it is common to access Model
|
|
118
|
+
/// methods directly on the model class as well as an
|
|
119
|
+
/// instance. For example, <see>Model.static getModelName</see> is both
|
|
120
|
+
/// a static method, and an instance method. Nearly all
|
|
121
|
+
/// the methods listed here have both a `static` and
|
|
122
|
+
/// and instance version. We are only listing the `static`
|
|
123
|
+
/// versions because the instance versions generally will
|
|
124
|
+
/// just be proxies to these `static` methods.
|
|
125
|
+
/// Note:
|
|
126
|
+
/// An underscore prefix on a method in Mythix ORM
|
|
127
|
+
/// implies that this method should not be overloaded
|
|
128
|
+
/// unless you know exactly what you are doing.
|
|
129
|
+
/// It also implies that there is another method
|
|
130
|
+
/// that can and should be overloaded instead.
|
|
113
131
|
class Model {
|
|
114
132
|
/// This property assists with type checking
|
|
115
133
|
///
|
|
@@ -142,13 +160,14 @@ class Model {
|
|
|
142
160
|
|
|
143
161
|
/// Check to see if the provided value is
|
|
144
162
|
/// an *instance* of a Mythix ORM <see>Model</see>.
|
|
145
|
-
/// Unlike <see>Model.isModelClass</see>, which
|
|
163
|
+
/// Unlike <see>Model.static isModelClass</see>, which
|
|
146
164
|
/// checks if a *class* is a <see>Model</see>, this will check
|
|
147
165
|
/// to see if an *instance* is an instance of a
|
|
148
166
|
/// Mythix ORM <see>Model</see>. It will return
|
|
149
167
|
/// `true` if the provided value is an `instanceof`
|
|
150
|
-
/// <see>Model</see>, or if the
|
|
151
|
-
/// property has a truthy `_isMythixModel` property
|
|
168
|
+
/// <see>Model</see>, or if the value's `constructor`
|
|
169
|
+
/// property has a truthy `_isMythixModel` property
|
|
170
|
+
/// (`value.constructor._isMythixModel`)
|
|
152
171
|
///
|
|
153
172
|
/// Return: boolean
|
|
154
173
|
/// Arguments:
|
|
@@ -217,16 +236,30 @@ class Model {
|
|
|
217
236
|
/// Otherwise, if not provided, or a falsy value,
|
|
218
237
|
/// then attempt to fallback to the bound connection,
|
|
219
238
|
/// if any is available.
|
|
220
|
-
/// Note:
|
|
221
|
-
/// An underscore prefix on a method in Mythix ORM
|
|
222
|
-
/// implies that this method should not be overloaded
|
|
223
|
-
/// unless you know exactly what you are doing.
|
|
224
|
-
/// It also implies that there is another method
|
|
225
|
-
/// that can and should be overloaded instead.
|
|
226
239
|
static _getConnection(_connection) {
|
|
227
240
|
return _connection || this._mythixBoundConnection;
|
|
228
241
|
}
|
|
229
242
|
|
|
243
|
+
/// See <see>Model.static _getConnection</see>
|
|
244
|
+
///
|
|
245
|
+
/// Return: <see>Connection</see>
|
|
246
|
+
/// Arguments:
|
|
247
|
+
/// connection?: <see>Connection</see>
|
|
248
|
+
/// An optional connection that can be provided.
|
|
249
|
+
/// If provided, it will simply be returned.
|
|
250
|
+
/// Otherwise, if not provided, or a falsy value,
|
|
251
|
+
/// then attempt to fallback to `modelInstance._connection`,
|
|
252
|
+
/// if that also fails to find a connection, the finally
|
|
253
|
+
/// the method will call <see>Model.static _getConnection</see>
|
|
254
|
+
/// to get the bound connection, if any is available.
|
|
255
|
+
/// Note:
|
|
256
|
+
/// Pay attention that unlike <see>Model.static _getConnection</see>
|
|
257
|
+
/// this checks the model's instance for `._connection` property. If that is
|
|
258
|
+
/// a valid connection, then it will be returned before the bound
|
|
259
|
+
/// connection. This is helpful when you have chosen not to bind
|
|
260
|
+
/// a connection to your models. This will allow you to provide a
|
|
261
|
+
/// connection directly when you create the model, which can make
|
|
262
|
+
/// interacting with the model less tiresome. i.e. `new Model(null, { connection })`.
|
|
230
263
|
_getConnection(connection) {
|
|
231
264
|
if (connection)
|
|
232
265
|
return connection;
|
|
@@ -237,6 +270,26 @@ class Model {
|
|
|
237
270
|
return this.constructor._getConnection();
|
|
238
271
|
}
|
|
239
272
|
|
|
273
|
+
/// Get the underlying connection bound to
|
|
274
|
+
/// the model's class. Connection binding is
|
|
275
|
+
/// optional, so this method can also be provided
|
|
276
|
+
/// a connection. If a connection is provided, then
|
|
277
|
+
/// it will simply be returned. Because Mythix ORM
|
|
278
|
+
/// has no globals, this is a design pattern to
|
|
279
|
+
/// supply a connection if you have one available,
|
|
280
|
+
/// or fallback to a "bound" connection (if one can
|
|
281
|
+
/// be found). This method should be overloaded if
|
|
282
|
+
/// you wish to provide your own model specific
|
|
283
|
+
/// connection.
|
|
284
|
+
///
|
|
285
|
+
/// Return: <see>Connection</see>
|
|
286
|
+
/// Arguments:
|
|
287
|
+
/// connection?: <see>Connection</see>
|
|
288
|
+
/// An optional connection that can be provided.
|
|
289
|
+
/// If provided, it will simply be returned.
|
|
290
|
+
/// Otherwise, if not provided, or a falsy value,
|
|
291
|
+
/// then attempt to fallback to the bound connection,
|
|
292
|
+
/// if any is available.
|
|
240
293
|
static getConnection(_connection) {
|
|
241
294
|
let connection = this._getConnection(_connection);
|
|
242
295
|
if (!connection)
|
|
@@ -256,6 +309,21 @@ class Model {
|
|
|
256
309
|
return connection;
|
|
257
310
|
}
|
|
258
311
|
|
|
312
|
+
/// A <see>Connection</see> instance will call
|
|
313
|
+
/// this method on a <see>Model</see> class to
|
|
314
|
+
/// bind the model to the connection. Overload
|
|
315
|
+
/// this to change the behavior of binding connections
|
|
316
|
+
/// to models. This method should return a model
|
|
317
|
+
/// class. The default behavior is to return
|
|
318
|
+
/// `this` class. However, you might return a
|
|
319
|
+
/// different class for example if you generated
|
|
320
|
+
/// a new class that inherited from `this` class.
|
|
321
|
+
///
|
|
322
|
+
/// Return: class extends <see>Model</see>
|
|
323
|
+
/// Arguments:
|
|
324
|
+
/// connection?: <see>Connection</see>
|
|
325
|
+
/// The connection instance to bind to
|
|
326
|
+
/// this model class.
|
|
259
327
|
static bindConnection(connection) {
|
|
260
328
|
let ModelClass = this;
|
|
261
329
|
|
|
@@ -303,6 +371,22 @@ class Model {
|
|
|
303
371
|
return ModelClass;
|
|
304
372
|
}
|
|
305
373
|
|
|
374
|
+
/// This method is called every time a `Model.where`
|
|
375
|
+
/// or `Model.$` property is accessed. It should return
|
|
376
|
+
/// a class that inherits from (or is) `QueryEngine`. By default,
|
|
377
|
+
/// it will call `this.getConnection().getQueryEngineClass()`
|
|
378
|
+
/// to get the query class defined in the connection
|
|
379
|
+
/// options. Though this can be overloaded per-model
|
|
380
|
+
/// (creating a different type of `QueryEngine` per-model),
|
|
381
|
+
/// the `QueryEngine` class to instantiate to use for queries will
|
|
382
|
+
/// generally be supplied by the connection.
|
|
383
|
+
///
|
|
384
|
+
/// Return: class <see>QueryEngine</see>
|
|
385
|
+
/// Arguments:
|
|
386
|
+
/// connection?: <see>Connection</see>
|
|
387
|
+
/// An optional connection to pass through.
|
|
388
|
+
/// This is needed if your models are not
|
|
389
|
+
/// bound to a connection.
|
|
306
390
|
static getQueryEngineClass(connection) {
|
|
307
391
|
return this.getConnection(connection).getQueryEngineClass();
|
|
308
392
|
}
|
|
@@ -311,6 +395,21 @@ class Model {
|
|
|
311
395
|
return this.constructor.getQueryEngineClass(connection);
|
|
312
396
|
}
|
|
313
397
|
|
|
398
|
+
/// This method is called any time a `query.unscoped()`
|
|
399
|
+
/// call is made. It will return the query's "root class"
|
|
400
|
+
/// `where` with no <see>Model.static defaultScope</see>
|
|
401
|
+
/// scope applied. Calling "unscoped()" will reset the query,
|
|
402
|
+
/// so make sure you always call it first: `Model.where.unscoped()...`
|
|
403
|
+
///
|
|
404
|
+
/// Return: <see>QueryEngine</see>
|
|
405
|
+
/// Arguments:
|
|
406
|
+
/// connection?: <see>Connection</see>
|
|
407
|
+
/// An optional connection to pass through.
|
|
408
|
+
/// This is needed if your models are not
|
|
409
|
+
/// bound to a connection.
|
|
410
|
+
/// options?: object
|
|
411
|
+
/// Any extra options to pass to the <see>QueryEngine</see>
|
|
412
|
+
/// constructor.
|
|
314
413
|
static getUnscopedQueryEngine(connection, options) {
|
|
315
414
|
let QueryEngineClass = this.getQueryEngineClass(connection);
|
|
316
415
|
let queryEngine = new QueryEngineClass(
|
|
@@ -331,10 +430,60 @@ class Model {
|
|
|
331
430
|
return this.constructor.getUnscopedQueryEngine(connection, options);
|
|
332
431
|
}
|
|
333
432
|
|
|
433
|
+
/// One can apply a "default scope" to any model simply
|
|
434
|
+
/// by providing this static method on the model. By
|
|
435
|
+
/// default it will simply return the <see name="derp">QueryEngine</see>
|
|
436
|
+
/// instance (a query) that it was provided.
|
|
437
|
+
///
|
|
438
|
+
/// The way this works is simple. The caller provides the
|
|
439
|
+
/// query as the first and only argument. The user, by
|
|
440
|
+
/// overloading this method can then easily modify this
|
|
441
|
+
/// provided query, changing the "default scope" whenever
|
|
442
|
+
/// the model is used for queries. For example, let's say
|
|
443
|
+
/// you have a User model, and by default, you only want
|
|
444
|
+
/// to query against Users that have their `active` column
|
|
445
|
+
/// set to `true`. In order to do this, you could easily
|
|
446
|
+
/// provide a `static defaultScope` method on your model
|
|
447
|
+
/// class that would modify the base query. See the following example:
|
|
448
|
+
///
|
|
449
|
+
/// Example:
|
|
450
|
+
/// class User extends Model {
|
|
451
|
+
/// static defaultScope(baseQuery) {
|
|
452
|
+
/// // `baseQuery` is equal to `User.where`
|
|
453
|
+
/// // without a default scope.
|
|
454
|
+
/// return baseQuery.active.EQ(true);
|
|
455
|
+
/// }
|
|
456
|
+
/// }
|
|
457
|
+
/// Return: <see>QueryEngine</see>
|
|
458
|
+
/// Arguments:
|
|
459
|
+
/// query: <see>QueryEngine</see>
|
|
460
|
+
/// The query that you should add onto.
|
|
461
|
+
static defaultScope(query) {
|
|
462
|
+
return query;
|
|
463
|
+
}
|
|
464
|
+
|
|
334
465
|
defaultScope(queryEngine) {
|
|
335
466
|
return this.constructor.defaultScope(queryEngine);
|
|
336
467
|
}
|
|
337
468
|
|
|
469
|
+
/// This method is called any time a `Model.where` or
|
|
470
|
+
/// `Model.$` property is accessed. It returns a query,
|
|
471
|
+
/// based off this model class (as the root model).
|
|
472
|
+
/// It will first call <see>Model.static getUnscopedQueryEngine</see>
|
|
473
|
+
/// to get the root query for the model, and then it will
|
|
474
|
+
/// call <see>Model.static defaultScope</see> to apply any
|
|
475
|
+
/// default scope to the root query. Finally, it will return
|
|
476
|
+
/// the query to the user to start interacting with.
|
|
477
|
+
///
|
|
478
|
+
/// Return: <see>QueryEngine</see>
|
|
479
|
+
/// Arguments:
|
|
480
|
+
/// connection?: <see>Connection</see>
|
|
481
|
+
/// An optional connection to pass through.
|
|
482
|
+
/// This is needed if your models are not
|
|
483
|
+
/// bound to a connection.
|
|
484
|
+
/// options?: object
|
|
485
|
+
/// Any extra options to pass to the <see>QueryEngine</see>
|
|
486
|
+
/// constructor.
|
|
338
487
|
static getQueryEngine(connection, options) {
|
|
339
488
|
let queryEngine = this.getUnscopedQueryEngine(connection, options);
|
|
340
489
|
let defaultScope = this.defaultScope(queryEngine, options);
|
|
@@ -346,7 +495,17 @@ class Model {
|
|
|
346
495
|
return this.constructor.getQueryEngine(connection, options);
|
|
347
496
|
}
|
|
348
497
|
|
|
349
|
-
|
|
498
|
+
/// Return the foreign key relationships for the model.
|
|
499
|
+
///
|
|
500
|
+
/// Return: Map<string, array<object>>
|
|
501
|
+
/// The format is `Map[modelName] = [ { targetFieldName, sourceFieldName }, ... ]`
|
|
502
|
+
/// Arguments:
|
|
503
|
+
/// connection?: <see>Connection</see>
|
|
504
|
+
/// An optional connection to pass through.
|
|
505
|
+
/// This is needed if your models are not
|
|
506
|
+
/// bound to a connection.
|
|
507
|
+
static getForeignKeyFieldsMap(_connection) {
|
|
508
|
+
let connection = this.getConnection(_connection);
|
|
350
509
|
let foreignKeyFieldsMap = connection._getFromModelCache(this, 'foreignKeyFieldsMap');
|
|
351
510
|
if (foreignKeyFieldsMap)
|
|
352
511
|
return foreignKeyFieldsMap;
|
|
@@ -379,8 +538,20 @@ class Model {
|
|
|
379
538
|
return this.constructor.getForeignKeyFieldsMap(connection);
|
|
380
539
|
}
|
|
381
540
|
|
|
382
|
-
|
|
383
|
-
|
|
541
|
+
/// Return all the foreign key target models. This will be
|
|
542
|
+
/// all models targeted by all foreign keys defined by
|
|
543
|
+
/// foreign key fields on this model.
|
|
544
|
+
///
|
|
545
|
+
/// Return: Map<string, Model>
|
|
546
|
+
/// The format is `Map[modelName] = Model`
|
|
547
|
+
/// Arguments:
|
|
548
|
+
/// connection?: <see>Connection</see>
|
|
549
|
+
/// An optional connection to pass through.
|
|
550
|
+
/// This is needed if your models are not
|
|
551
|
+
/// bound to a connection.
|
|
552
|
+
static getForeignKeysTargetModels(_connection) {
|
|
553
|
+
let connection = this.getConnection(_connection);
|
|
554
|
+
let foreignKeyTargetModels = connection._getFromModelCache(this, 'foreignKeyTargetModels');
|
|
384
555
|
if (foreignKeyTargetModels)
|
|
385
556
|
return foreignKeyTargetModels;
|
|
386
557
|
|
|
@@ -405,8 +576,21 @@ class Model {
|
|
|
405
576
|
return this.constructor.getForeignKeysTargetModels(connection);
|
|
406
577
|
}
|
|
407
578
|
|
|
408
|
-
|
|
409
|
-
|
|
579
|
+
/// Return all the foreign key target model names. This will be
|
|
580
|
+
/// all models targeted by all foreign keys defined by
|
|
581
|
+
/// foreign key fields on this model. This will only
|
|
582
|
+
/// return the models name's.
|
|
583
|
+
///
|
|
584
|
+
/// Return: Array<string>
|
|
585
|
+
/// The format is `Array[] = modelName`
|
|
586
|
+
/// Arguments:
|
|
587
|
+
/// connection?: <see>Connection</see>
|
|
588
|
+
/// An optional connection to pass through.
|
|
589
|
+
/// This is needed if your models are not
|
|
590
|
+
/// bound to a connection.
|
|
591
|
+
static getForeignKeysTargetModelNames(_connection) {
|
|
592
|
+
let connection = this.getConnection(_connection);
|
|
593
|
+
let foreignKeyTargetModelNames = connection._getFromModelCache(this, 'foreignKeyTargetModelNames');
|
|
410
594
|
if (foreignKeyTargetModelNames)
|
|
411
595
|
return foreignKeyTargetModelNames;
|
|
412
596
|
|
|
@@ -422,9 +606,24 @@ class Model {
|
|
|
422
606
|
return this.constructor.getForeignKeysTargetModelNames(connection);
|
|
423
607
|
}
|
|
424
608
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
609
|
+
/// Return all the foreign key target field names.
|
|
610
|
+
/// This will return the target field names of all
|
|
611
|
+
/// foreign key fields specified on the model.
|
|
612
|
+
///
|
|
613
|
+
/// Return: Array<string>
|
|
614
|
+
/// The format is `Array[] = modelName`
|
|
615
|
+
/// Arguments:
|
|
616
|
+
/// connection?: <see>Connection</see>
|
|
617
|
+
/// An optional connection to pass through.
|
|
618
|
+
/// This is needed if your models are not
|
|
619
|
+
/// bound to a connection.
|
|
620
|
+
/// modelName: string
|
|
621
|
+
/// The model name for which you wish to fetch
|
|
622
|
+
/// foreign key fields from.
|
|
623
|
+
static getForeignKeysTargetFieldNames(_connection, modelName) {
|
|
624
|
+
let connection = this.getConnection(_connection);
|
|
625
|
+
let cacheKey = `${modelName}:foreignKeyFieldNames`;
|
|
626
|
+
let foreignKeyFieldNames = connection._getFromModelCache(this, cacheKey);
|
|
428
627
|
if (foreignKeyFieldNames)
|
|
429
628
|
return foreignKeyFieldNames;
|
|
430
629
|
|
|
@@ -440,7 +639,28 @@ class Model {
|
|
|
440
639
|
return this.constructor.getForeignKeysTargetFieldNames(connection, modelName);
|
|
441
640
|
}
|
|
442
641
|
|
|
443
|
-
|
|
642
|
+
/// Get a specific foreign key field's relationship
|
|
643
|
+
/// information. This will be what is stored in the
|
|
644
|
+
/// relationship field map for the specified target
|
|
645
|
+
/// field.
|
|
646
|
+
/// See <see>Model.static getForeignKeyFieldsMap</see> for more information.
|
|
647
|
+
///
|
|
648
|
+
/// Return: object<{ targetFieldName, sourceFieldName }>
|
|
649
|
+
/// This will be the relationship info for this foreign key field
|
|
650
|
+
/// which will be an object of the shape `{ targetFieldName, sourceFieldName }`.
|
|
651
|
+
/// Arguments:
|
|
652
|
+
/// connection?: <see>Connection</see>
|
|
653
|
+
/// An optional connection to pass through.
|
|
654
|
+
/// This is needed if your models are not
|
|
655
|
+
/// bound to a connection.
|
|
656
|
+
/// modelName: string
|
|
657
|
+
/// The model name for which you wish to fetch
|
|
658
|
+
/// foreign key fields from.
|
|
659
|
+
/// fieldName: string
|
|
660
|
+
/// The field name for which you wish to fetch
|
|
661
|
+
/// foreign key relational information about.
|
|
662
|
+
static getForeignKeysTargetField(_connection, modelName, fieldName) {
|
|
663
|
+
let connection = this.getConnection(_connection);
|
|
444
664
|
let cacheKey = `${modelName}:${fieldName}:foreignKeyTargetField`;
|
|
445
665
|
let foreignKeyFieldNames = connection._getFromModelCache(this, cacheKey);
|
|
446
666
|
if (foreignKeyFieldNames)
|
|
@@ -451,7 +671,7 @@ class Model {
|
|
|
451
671
|
if (!fields)
|
|
452
672
|
return;
|
|
453
673
|
|
|
454
|
-
let fieldInfo = fields.find((
|
|
674
|
+
let fieldInfo = fields.find((fieldInfo) => (fieldInfo.targetFieldName === fieldName));
|
|
455
675
|
|
|
456
676
|
connection._setToModelCache(this, cacheKey, fieldInfo);
|
|
457
677
|
|
|
@@ -462,7 +682,22 @@ class Model {
|
|
|
462
682
|
return this.constructor.getForeignKeysTargetField(connection, modelName, fieldName);
|
|
463
683
|
}
|
|
464
684
|
|
|
465
|
-
|
|
685
|
+
/// Check if the specified model is a model
|
|
686
|
+
/// pointed to by a foreign key field.
|
|
687
|
+
///
|
|
688
|
+
/// Return: boolean
|
|
689
|
+
/// `true` if the specified `modelName` model is pointed
|
|
690
|
+
/// to by one of the foreign key fields, `false` otherwise.
|
|
691
|
+
/// Arguments:
|
|
692
|
+
/// connection?: <see>Connection</see>
|
|
693
|
+
/// An optional connection to pass through.
|
|
694
|
+
/// This is needed if your models are not
|
|
695
|
+
/// bound to a connection.
|
|
696
|
+
/// modelName: string
|
|
697
|
+
/// The model name for which you wish to fetch
|
|
698
|
+
/// foreign key fields from.
|
|
699
|
+
static isForeignKeyTargetModel(_connection, modelName) {
|
|
700
|
+
let connection = this.getConnection(_connection);
|
|
466
701
|
let foreignKeyFieldsMap = this.getForeignKeyFieldsMap(connection);
|
|
467
702
|
return foreignKeyFieldsMap.has(modelName);
|
|
468
703
|
}
|
|
@@ -471,6 +706,17 @@ class Model {
|
|
|
471
706
|
return this.constructor.isForeignKeyTargetModel(connection, modelName);
|
|
472
707
|
}
|
|
473
708
|
|
|
709
|
+
/// Get the table name for this model. By default
|
|
710
|
+
/// Mythix ORM will take the model's name, and convert
|
|
711
|
+
/// it to snake_case.
|
|
712
|
+
///
|
|
713
|
+
/// Return: string
|
|
714
|
+
/// The name of the table for this model.
|
|
715
|
+
/// Arguments:
|
|
716
|
+
/// connection?: <see>Connection</see>
|
|
717
|
+
/// An optional connection to pass through.
|
|
718
|
+
/// This is needed if your models are not
|
|
719
|
+
/// bound to a connection.
|
|
474
720
|
static getTableName(connection) {
|
|
475
721
|
if (!connection) {
|
|
476
722
|
let tableName = Nife.camelCaseToSnakeCase(this.getPluralModelName());
|
|
@@ -493,6 +739,13 @@ class Model {
|
|
|
493
739
|
return this.constructor.getTableName(connection);
|
|
494
740
|
}
|
|
495
741
|
|
|
742
|
+
/// Get the model name for this model. By default
|
|
743
|
+
/// this will be the name of the class itself, i.e.
|
|
744
|
+
/// `this.name`. Overload this method to provide your
|
|
745
|
+
/// own model name (singular name).
|
|
746
|
+
///
|
|
747
|
+
/// Return: string
|
|
748
|
+
/// The name the model.
|
|
496
749
|
static getModelName() {
|
|
497
750
|
return this.name;
|
|
498
751
|
}
|
|
@@ -501,6 +754,21 @@ class Model {
|
|
|
501
754
|
return this.constructor.getModelName();
|
|
502
755
|
}
|
|
503
756
|
|
|
757
|
+
/// Get the singular model name for this model. By default
|
|
758
|
+
/// this will be the name of the class itself, i.e.
|
|
759
|
+
/// `this.name`. You should probably overload <see>Model.static getModelName</see>
|
|
760
|
+
/// to provide your own model name, instead of overloading this method.
|
|
761
|
+
///
|
|
762
|
+
/// Note:
|
|
763
|
+
/// This will return the "singular" name of the model
|
|
764
|
+
/// which is the same as <see>Model.static getModelName</see>.
|
|
765
|
+
/// Note:
|
|
766
|
+
/// This method simply calls <see>Model.static getModelName</see>
|
|
767
|
+
/// to get the singular model name.
|
|
768
|
+
/// Return: string
|
|
769
|
+
/// The name the model in singular form.
|
|
770
|
+
/// See: Model.static getPluralModelName
|
|
771
|
+
/// See: Model.static getModelName
|
|
504
772
|
static getSingularName() {
|
|
505
773
|
return this.getModelName();
|
|
506
774
|
}
|
|
@@ -509,6 +777,17 @@ class Model {
|
|
|
509
777
|
return this.constructor.getSingularName();
|
|
510
778
|
}
|
|
511
779
|
|
|
780
|
+
/// Get the plural model name for this model. By default
|
|
781
|
+
/// this will be the singular name of the model, converted
|
|
782
|
+
/// to plural using the [Inflection](https://github.com/dreamerslab/node.inflection)
|
|
783
|
+
/// library. Overload this method to provide your own plural
|
|
784
|
+
/// name for the model.
|
|
785
|
+
///
|
|
786
|
+
/// Note:
|
|
787
|
+
/// This will return the "plural" name of the model.
|
|
788
|
+
/// Return: string
|
|
789
|
+
/// The name the model in plural form.
|
|
790
|
+
/// See: Model.static getSingularName
|
|
512
791
|
static getPluralModelName() {
|
|
513
792
|
return Inflection.pluralize(this.getSingularName());
|
|
514
793
|
}
|
|
@@ -517,6 +796,9 @@ class Model {
|
|
|
517
796
|
return this.constructor.getPluralModelName();
|
|
518
797
|
}
|
|
519
798
|
|
|
799
|
+
/// Get the Model class for this model.
|
|
800
|
+
///
|
|
801
|
+
/// Return: class <see>Model</see>
|
|
520
802
|
static getModel() {
|
|
521
803
|
return this;
|
|
522
804
|
}
|
|
@@ -525,6 +807,36 @@ class Model {
|
|
|
525
807
|
return this.constructor.getModel();
|
|
526
808
|
}
|
|
527
809
|
|
|
810
|
+
/// Get the fields for this model. You can optionally
|
|
811
|
+
/// specify the `fieldNames` argument, which will cause
|
|
812
|
+
/// the method to return only the fields specified by name.
|
|
813
|
+
/// If the `fieldNames` argument is provided, then the
|
|
814
|
+
/// return value will always be an array of fields. If
|
|
815
|
+
/// the `fieldNames` argument is not provided, then
|
|
816
|
+
/// the return value could be either an Array of fields,
|
|
817
|
+
/// or an object of fields, keyed by field name (depending
|
|
818
|
+
/// on how you defined your model fields).
|
|
819
|
+
///
|
|
820
|
+
/// Note:
|
|
821
|
+
/// The first time this method is called the model's fields
|
|
822
|
+
/// will be built, and possibly modified. All fields will be
|
|
823
|
+
/// turned into <see>Field</see> instances, and each field
|
|
824
|
+
/// will be properly constructed to include required attributes,
|
|
825
|
+
/// such as their parent `Model`, their `fieldName`, and their
|
|
826
|
+
/// `columnName`. A model's fields are always initialized when
|
|
827
|
+
/// the model is first bound to a connection, or when this method
|
|
828
|
+
/// is first called.
|
|
829
|
+
/// Note:
|
|
830
|
+
/// In Mythix ORM you **never** specify a field via its `columnName`.
|
|
831
|
+
/// You always use a field's defined `fieldName` to match against
|
|
832
|
+
/// a field. Using a `columnName` simply won't work, unless `columnName`
|
|
833
|
+
/// and `fieldName` just happen to have the same value.
|
|
834
|
+
/// Return: Array<<see>Field</see>> | Object<string, <see>Field</see>>
|
|
835
|
+
/// Arguments:
|
|
836
|
+
/// fieldNames?: Array<string>
|
|
837
|
+
/// An array of field names to fetch. If not
|
|
838
|
+
/// provided then all model fields will be returned,
|
|
839
|
+
/// including virtual fields.
|
|
528
840
|
static getFields(fieldNames) {
|
|
529
841
|
let fields = this.initializeFields(this.fields);
|
|
530
842
|
if (fields !== this.fields) {
|
|
@@ -564,6 +876,21 @@ class Model {
|
|
|
564
876
|
return this.constructor.getFields(fieldNames);
|
|
565
877
|
}
|
|
566
878
|
|
|
879
|
+
/// This method is identical to <see>Model.static getFields</see>
|
|
880
|
+
/// except that it will always return an Array of fields, and the
|
|
881
|
+
/// fields will always be sorted by their `fieldName`.
|
|
882
|
+
///
|
|
883
|
+
/// Note:
|
|
884
|
+
/// In Mythix ORM you **never** specify a field via its `columnName`.
|
|
885
|
+
/// You always use a field's defined `fieldName` to match against
|
|
886
|
+
/// a field. Using a `columnName` simply won't work, unless `columnName`
|
|
887
|
+
/// and `fieldName` just happen to have the same value.
|
|
888
|
+
/// Return: Array<<see>Field</see>>
|
|
889
|
+
/// Arguments:
|
|
890
|
+
/// fieldNames?: Array<string>
|
|
891
|
+
/// An array of field names to fetch. If not
|
|
892
|
+
/// provided then all model fields will be returned,
|
|
893
|
+
/// including virtual fields.
|
|
567
894
|
static getSortedFields(fieldNames) {
|
|
568
895
|
if (Object.prototype.hasOwnProperty.call(this, '_sortedFields') && this._sortedFields)
|
|
569
896
|
return this._sortedFields;
|
|
@@ -600,6 +927,36 @@ class Model {
|
|
|
600
927
|
return this.constructor.getSortedFields(fieldNames);
|
|
601
928
|
}
|
|
602
929
|
|
|
930
|
+
/// Merge specified fields into this model's fields.
|
|
931
|
+
/// The `mergeFields` argument is optional. If not
|
|
932
|
+
/// provided, then this method will simply clone
|
|
933
|
+
/// the model's fields. If specified, then the fields
|
|
934
|
+
/// provided will be merged into the existing fields.
|
|
935
|
+
/// Merging takes place based on each field's `fieldName`
|
|
936
|
+
/// attribute. The `mergeFields` argument can be an
|
|
937
|
+
/// `Array`, an `object`, a `Map`, or a `Set`. Fields
|
|
938
|
+
/// are matched based on `fieldName`, but when a match
|
|
939
|
+
/// is found, it is completely overridden by what is
|
|
940
|
+
/// found in the `mergeFields` argument. In short, the
|
|
941
|
+
/// list of fields itself is merged, but the fields themselves
|
|
942
|
+
/// are not merged (a shallow merge). All input objects that
|
|
943
|
+
/// have keys (Object<string, <see>Field</see>> | Map<string, <see>Field</see>>)
|
|
944
|
+
/// must specify the `fieldName` of the field as the key.
|
|
945
|
+
/// If the input is an Array type (Array<<see>Field</see>> | Set<<see>Field</see>>)
|
|
946
|
+
/// then each field **must** contain a `fieldName` attribute, or
|
|
947
|
+
/// an exception will be thrown.
|
|
948
|
+
///
|
|
949
|
+
/// Note:
|
|
950
|
+
/// Anywhere you see <see>Field</see> as an input in this documentation,
|
|
951
|
+
/// you can also simply provide a raw object with the same shape, and
|
|
952
|
+
/// it will be automatically converted to a <see>Field</see> instance
|
|
953
|
+
/// for you.
|
|
954
|
+
/// Return: Array<<see>Field</see>> | object<string, <see>Field</see>>
|
|
955
|
+
/// Arguments:
|
|
956
|
+
/// mergeFields?: Array<<see>Field</see>> | Set<<see>Field</see>> | Object<string, <see>Field</see>> | Map<string, <see>Field</see>>
|
|
957
|
+
/// A list of fields to merge into the current
|
|
958
|
+
/// model fields. The field list,
|
|
959
|
+
/// as well as all fields will be cloned.
|
|
603
960
|
static mergeFields(mergeFields) {
|
|
604
961
|
const cloneField = ({ value: field, key: _fieldName, index, type }) => {
|
|
605
962
|
if (!field)
|
|
@@ -652,6 +1009,29 @@ class Model {
|
|
|
652
1009
|
return (Nife.instanceOf(fields, 'array', 'set')) ? Array.from(clonedFields.values()) : mapToObject(clonedFields);
|
|
653
1010
|
}
|
|
654
1011
|
|
|
1012
|
+
/// Initialize all fields for the model. This will be called anytime
|
|
1013
|
+
/// a <see>Model.static getFields</see> call is made. However, it
|
|
1014
|
+
/// caches its results, so it will immediately return if the model's
|
|
1015
|
+
/// fields have already been initialized.
|
|
1016
|
+
///
|
|
1017
|
+
/// This method does a number of things in the process of "initializing"
|
|
1018
|
+
/// model fields. It first ensures that every field is an instance of
|
|
1019
|
+
/// <see>Field</see>. Second, it ensures that the <see>Type</see> of the
|
|
1020
|
+
/// field is initialized (properly instantiated). Third, it ensures that
|
|
1021
|
+
/// all required attributes of each field is present. Required attributes
|
|
1022
|
+
/// are `Model` (the parent model), `fieldName` (the name of this field),
|
|
1023
|
+
/// and `columnName` (the column name for the DB). `columnName`, if not
|
|
1024
|
+
/// provided, will simply become `fieldName`.
|
|
1025
|
+
///
|
|
1026
|
+
/// Note:
|
|
1027
|
+
/// The cache for built fields is stored directly on the input `fields`
|
|
1028
|
+
/// argument, under a non-enumerable `_mythixFieldsInitialized` cache key.
|
|
1029
|
+
/// Return: Array<<see>Field</see>> | object<string, <see>Field</see>>
|
|
1030
|
+
/// Arguments:
|
|
1031
|
+
/// fields: Array<<see>Field</see>> | Set<<see>Field</see>> | Object<string, <see>Field</see>> | Map<string, <see>Field</see>>
|
|
1032
|
+
/// A list of fields to work off of. When this method is
|
|
1033
|
+
/// called by <see>Model.static getFields</see>, then
|
|
1034
|
+
/// this argument will be `static Model.fields`.
|
|
655
1035
|
static initializeFields(fields) {
|
|
656
1036
|
if (!fields)
|
|
657
1037
|
return fields;
|
|
@@ -725,6 +1105,47 @@ class Model {
|
|
|
725
1105
|
return finalizedFields;
|
|
726
1106
|
}
|
|
727
1107
|
|
|
1108
|
+
/// Iterate all model fields. This is a convenience method to
|
|
1109
|
+
/// iterate `static Model.fields`, and is needed as the fields
|
|
1110
|
+
/// of a model can be an `Array`, an `object`, a `Map`, or a `Set`.
|
|
1111
|
+
/// This method works a lot like `Array.prototype.map`. Any return
|
|
1112
|
+
/// value from the provided `callback` will be pushed into an array
|
|
1113
|
+
/// just like `Array.prototype.map`. The `callback` provided, when called,
|
|
1114
|
+
/// will be provided a `context` object, as the single argument to
|
|
1115
|
+
/// the callback.
|
|
1116
|
+
///
|
|
1117
|
+
/// At any time you can call the `stop` method provided via the context.
|
|
1118
|
+
/// When called, `iterateFields` will stop iterating, and immediately
|
|
1119
|
+
/// return an array of results returned by all calls to `callback`.
|
|
1120
|
+
///
|
|
1121
|
+
/// The provided `context` object has the following shape:
|
|
1122
|
+
///
|
|
1123
|
+
/// Interface:
|
|
1124
|
+
/// interface IterationContext {
|
|
1125
|
+
/// field: Field; // The Field instance itself.
|
|
1126
|
+
/// fieldName: string; // The name of the field.
|
|
1127
|
+
/// fields: // All the model's fields.
|
|
1128
|
+
/// Array<Field> |
|
|
1129
|
+
/// Set<Field> |
|
|
1130
|
+
/// Object<string, Field> |
|
|
1131
|
+
// Map<string, Field>;
|
|
1132
|
+
/// index: string | number; // The current index into the list of fields.
|
|
1133
|
+
/// stop: Function; // A method that when called will halt iteration.
|
|
1134
|
+
/// isStopped: Function; // Call this method to see if iteration is about to be halted.
|
|
1135
|
+
/// }
|
|
1136
|
+
///
|
|
1137
|
+
/// Return: Array<any>
|
|
1138
|
+
/// Arguments:
|
|
1139
|
+
/// callback: Function(context: IterationContext)
|
|
1140
|
+
/// A callback method that will be called for
|
|
1141
|
+
/// every field on the model.
|
|
1142
|
+
/// fields?: Array<<see>Field</see>> | Set<<see>Field</see>> | Object<string, <see>Field</see>> | Map<string, <see>Field</see>> = null
|
|
1143
|
+
/// An optional list of fields to use *instead* of `static Model.fields`. This is
|
|
1144
|
+
/// handy if, for example, you want to iterate a sub-set of the model's fields,
|
|
1145
|
+
/// such as the "dirty" fields reported by the model.
|
|
1146
|
+
/// sorted?: boolean = false
|
|
1147
|
+
/// If `true`, then sort the model fields before iterating. If `false`,
|
|
1148
|
+
/// simply iterate the model's fields in their defined order.
|
|
728
1149
|
static iterateFields(callback, _fields, sorted) {
|
|
729
1150
|
if (typeof callback !== 'function')
|
|
730
1151
|
return [];
|
|
@@ -745,6 +1166,18 @@ class Model {
|
|
|
745
1166
|
return this.constructor.iterateFields(callback, _fields, sorted);
|
|
746
1167
|
}
|
|
747
1168
|
|
|
1169
|
+
/// Check if any of the model's fields have a "remote value"
|
|
1170
|
+
/// as a `defaultValue`. A `defaultValue` method can itself
|
|
1171
|
+
/// report that it is "remote", meaning it is a value provided
|
|
1172
|
+
/// by the database itself. This method simply iterates all the
|
|
1173
|
+
/// model's fields, and calls `field.type.isRemote()` on each field.
|
|
1174
|
+
/// If `field.type.isRemote()` returns `true` for any field, then
|
|
1175
|
+
/// this method will return `true`, otherwise it will return `false`.
|
|
1176
|
+
/// Use this method to know if the model contains any fields whose
|
|
1177
|
+
/// value is obtained directly from the database itself (i.e. primary key
|
|
1178
|
+
/// date fields, etc...).
|
|
1179
|
+
///
|
|
1180
|
+
/// Return: boolean
|
|
748
1181
|
static hasRemoteFieldValues() {
|
|
749
1182
|
let hasRemote = false;
|
|
750
1183
|
|
|
@@ -762,6 +1195,12 @@ class Model {
|
|
|
762
1195
|
return this.constructor.hasRemoteFieldValues();
|
|
763
1196
|
}
|
|
764
1197
|
|
|
1198
|
+
/// Get the primary key field of the model, if any is defined.
|
|
1199
|
+
/// If no primary key field is defined, then this will return
|
|
1200
|
+
/// `undefined`. A primary key is specified per-model by using
|
|
1201
|
+
/// `primaryKey: true` on one (and only one) of the model's fields.
|
|
1202
|
+
///
|
|
1203
|
+
/// Return: <see>Field</see>
|
|
765
1204
|
static getPrimaryKeyField() {
|
|
766
1205
|
let fields = this.getFields();
|
|
767
1206
|
if (!fields)
|
|
@@ -774,6 +1213,13 @@ class Model {
|
|
|
774
1213
|
return this.constructor.getPrimaryKeyField();
|
|
775
1214
|
}
|
|
776
1215
|
|
|
1216
|
+
/// Get the *name* of the primary key field of the model,
|
|
1217
|
+
/// if any is defined.
|
|
1218
|
+
/// If no primary key field is defined, then this will return
|
|
1219
|
+
/// `undefined`. A primary key is specified per-model by using
|
|
1220
|
+
/// `primaryKey: true` on one (and only one) of the model's fields.
|
|
1221
|
+
///
|
|
1222
|
+
/// Return: string
|
|
777
1223
|
static getPrimaryKeyFieldName() {
|
|
778
1224
|
let primaryKeyField = this.getPrimaryKeyField();
|
|
779
1225
|
if (!primaryKeyField)
|
|
@@ -786,6 +1232,17 @@ class Model {
|
|
|
786
1232
|
return this.constructor.getPrimaryKeyFieldName();
|
|
787
1233
|
}
|
|
788
1234
|
|
|
1235
|
+
/// Check to see if the primary key field (if any is defined)
|
|
1236
|
+
/// has a "remote" default value. For example, an autoincrementing
|
|
1237
|
+
/// primary key field would return `true` from this method, because
|
|
1238
|
+
/// an autoincrementing field value is retrieved directly from the
|
|
1239
|
+
/// database. This could return `false`, if for example, you were
|
|
1240
|
+
/// using UUIDs, or XIDs for your primary key.
|
|
1241
|
+
///
|
|
1242
|
+
/// Return: boolean
|
|
1243
|
+
/// `true` if the primary key field of the model has a "remote"
|
|
1244
|
+
/// `defaultValue`, `false` otherwise. Remoteness is checked
|
|
1245
|
+
/// via `this.getPrimaryKeyField().type.isRemote()`.
|
|
789
1246
|
static primaryKeyHasRemoteValue() {
|
|
790
1247
|
let primaryKeyField = this.getPrimaryKeyField();
|
|
791
1248
|
if (!primaryKeyField)
|
|
@@ -798,6 +1255,20 @@ class Model {
|
|
|
798
1255
|
return this.constructor.primaryKeyHasRemoteValue();
|
|
799
1256
|
}
|
|
800
1257
|
|
|
1258
|
+
/// Get a specific model field by field name. This method
|
|
1259
|
+
/// will return `undefined` if the specified field can not
|
|
1260
|
+
/// be found on the model. This will find both concrete and
|
|
1261
|
+
/// virtual fields that are defined on the model.
|
|
1262
|
+
///
|
|
1263
|
+
/// Note:
|
|
1264
|
+
/// In Mythix ORM you **never** specify a field via its `columnName`.
|
|
1265
|
+
/// You always use a field's defined `fieldName` to match against
|
|
1266
|
+
/// a field. Using a `columnName` simply won't work, unless `columnName`
|
|
1267
|
+
/// and `fieldName` just happen to have the same value.
|
|
1268
|
+
/// Return: <see>Field</see>
|
|
1269
|
+
/// Arguments:
|
|
1270
|
+
/// fieldName: string
|
|
1271
|
+
/// The specified field name to find. This **is not** the `columnName` of the field.
|
|
801
1272
|
static getField(findFieldName) {
|
|
802
1273
|
let fields = this.getFields();
|
|
803
1274
|
if (!fields || !findFieldName)
|
|
@@ -819,6 +1290,19 @@ class Model {
|
|
|
819
1290
|
return this.constructor.getField(findFieldName);
|
|
820
1291
|
}
|
|
821
1292
|
|
|
1293
|
+
/// Check if the model has the specified field by name.
|
|
1294
|
+
/// If the specified field is found on the model, then
|
|
1295
|
+
/// return `true`, otherwise `false` will be returned.
|
|
1296
|
+
///
|
|
1297
|
+
/// Note:
|
|
1298
|
+
/// In Mythix ORM you **never** specify a field via its `columnName`.
|
|
1299
|
+
/// You always use a field's defined `fieldName` to match against
|
|
1300
|
+
/// a field. Using a `columnName` simply won't work, unless `columnName`
|
|
1301
|
+
/// and `fieldName` just happen to have the same value.
|
|
1302
|
+
/// Return: boolean
|
|
1303
|
+
/// Arguments:
|
|
1304
|
+
/// fieldName: string
|
|
1305
|
+
/// The specified field name to find. This **is not** the `columnName` of the field.
|
|
822
1306
|
static hasField(fieldName) {
|
|
823
1307
|
return !!this.getField(fieldName);
|
|
824
1308
|
}
|
|
@@ -827,6 +1311,13 @@ class Model {
|
|
|
827
1311
|
return this.constructor.hasField(fieldName);
|
|
828
1312
|
}
|
|
829
1313
|
|
|
1314
|
+
/// Count the number of concrete fields on the model.
|
|
1315
|
+
/// "concrete" fields are non-virtual fields that are
|
|
1316
|
+
/// backed by the database. A `FOREIGN_KEY` field **is**
|
|
1317
|
+
/// a concrete field, so `FOREIGN_KEY` fields will be counted.
|
|
1318
|
+
///
|
|
1319
|
+
/// Return: number
|
|
1320
|
+
/// The number of concrete fields the model has
|
|
830
1321
|
static getConcreteFieldCount() {
|
|
831
1322
|
let count = 0;
|
|
832
1323
|
|
|
@@ -844,13 +1335,51 @@ class Model {
|
|
|
844
1335
|
return this.constructor.getConcreteFieldCount();
|
|
845
1336
|
}
|
|
846
1337
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
1338
|
+
/// Specify the default SELECT "ORDER" for the model.
|
|
1339
|
+
/// This method will be called if no "ORDER" was specified
|
|
1340
|
+
/// for any given query. This method should return an
|
|
1341
|
+
/// Array of fully qualified field names. The `options`
|
|
1342
|
+
/// argument is the current options for the specific
|
|
1343
|
+
/// query being operated on.
|
|
1344
|
+
///
|
|
1345
|
+
/// Note:
|
|
1346
|
+
/// Internally, Mythix ORM will call `this.connection.getDefaultOrder(options)`,
|
|
1347
|
+
/// which--if not overloaded--will simply call this method from the
|
|
1348
|
+
/// model itself.
|
|
1349
|
+
/// Note:
|
|
1350
|
+
/// A "fully qualified field name" in Mythix ORM means
|
|
1351
|
+
/// a full field definition, including the model name.
|
|
1352
|
+
/// An example of a fully qualified field name might be
|
|
1353
|
+
/// `"User:id"`. The model name is separated from the field
|
|
1354
|
+
/// name by a colon `:`. A short hand, *not fully qualified
|
|
1355
|
+
/// field name* example would be simply `"id"`. Since this
|
|
1356
|
+
/// contains no model prefix, this is "short hand", and is
|
|
1357
|
+
/// **not** a fully qualified field name.
|
|
1358
|
+
/// Return: Array<string> | null
|
|
1359
|
+
/// An array of fully qualified field names to specify the ORDER.
|
|
1360
|
+
/// Prefix a field name with `+` to specify ASCending order, i.e.
|
|
1361
|
+
/// `[ "+User:id" ]`. Prefix the field name with `-` to specify
|
|
1362
|
+
/// DESCending order, i.e. `[ "-User:id" ]`.
|
|
1363
|
+
static getDefaultOrder(options) {
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
/// This method is called anytime a `Model.where` or `Model.$`
|
|
1367
|
+
/// attribute is accessed. It will provide the instantiated
|
|
1368
|
+
/// <see>QueryEngine</see> with the connection specified (if any).
|
|
1369
|
+
/// A connection can be specified for example by doing `Model.where(connection)`
|
|
1370
|
+
/// or `Model.$(connection)`. This is generally only useful if you
|
|
1371
|
+
/// have chosen not to bind your models to a connection.
|
|
1372
|
+
///
|
|
1373
|
+
/// Return: <see>QueryEngine</see>
|
|
1374
|
+
/// A <see>QueryEngine</see> instance (a query) for
|
|
1375
|
+
/// this model.
|
|
1376
|
+
/// Arguments:
|
|
1377
|
+
/// options?: `object { connection: Connection }`
|
|
1378
|
+
/// An object, which if supplied, should contain a
|
|
1379
|
+
/// `connection` key, specifying the connection.
|
|
1380
|
+
/// If no connection is provided, then this will
|
|
1381
|
+
/// fallback to `this.getConnection()` to try and
|
|
1382
|
+
/// find the connection itself.
|
|
854
1383
|
static getWhereWithConnection(options) {
|
|
855
1384
|
if (options && options.connection)
|
|
856
1385
|
return this.where(options.connection);
|
|
@@ -862,6 +1391,25 @@ class Model {
|
|
|
862
1391
|
return this.constructor.getWhereWithConnection(options);
|
|
863
1392
|
}
|
|
864
1393
|
|
|
1394
|
+
/// Create (insert) new models into the database.
|
|
1395
|
+
/// The `models` argument can be a single model instance,
|
|
1396
|
+
/// a single object containing model attributes,
|
|
1397
|
+
/// an array of model instances, or an array of
|
|
1398
|
+
/// objects containing model attributes. This is
|
|
1399
|
+
/// a "bulk" create method, though it can be used
|
|
1400
|
+
/// to create a single model.
|
|
1401
|
+
///
|
|
1402
|
+
/// Return: <see>Model</see>
|
|
1403
|
+
/// Return the model instance(s) created.
|
|
1404
|
+
/// Arguments:
|
|
1405
|
+
/// models: Array<<see>Model</see>> | <see>Model</see> | Array<object> | object
|
|
1406
|
+
/// Specify the model(s) to create.
|
|
1407
|
+
/// options?: object
|
|
1408
|
+
/// An "options" object to pass off to the underlying <see>Connection</see> methods.
|
|
1409
|
+
/// If a `connection` key is specified in this object, then that will be used
|
|
1410
|
+
/// as the connection for the operation. This can be important if for example
|
|
1411
|
+
/// you are calling this from a `transaction`, in which case you most certainly
|
|
1412
|
+
/// would want to provide the `connection` for the transaction.
|
|
865
1413
|
static async create(models, options) {
|
|
866
1414
|
let connection = this.getConnection() || (options && options.connection);
|
|
867
1415
|
if (!connection)
|
|
@@ -874,14 +1422,70 @@ class Model {
|
|
|
874
1422
|
return (Array.isArray(result)) ? result[0] : result;
|
|
875
1423
|
}
|
|
876
1424
|
|
|
1425
|
+
/// Count the rows in the database for this model.
|
|
1426
|
+
///
|
|
1427
|
+
/// Return: number
|
|
1428
|
+
/// Return the number of models stored in the database for this model type.
|
|
1429
|
+
/// Arguments:
|
|
1430
|
+
/// options?: object
|
|
1431
|
+
/// An "options" object to pass off to the underlying <see>Connection</see> methods.
|
|
1432
|
+
/// If a `connection` key is specified in this object, then that will be used
|
|
1433
|
+
/// as the connection for the operation. This can be important if for example
|
|
1434
|
+
/// you are calling this from a `transaction`, in which case you most certainly
|
|
1435
|
+
/// would want to provide the `connection` for the transaction.
|
|
877
1436
|
static count(options) {
|
|
878
1437
|
return this.getWhereWithConnection(options).count(null, options);
|
|
879
1438
|
}
|
|
880
1439
|
|
|
1440
|
+
/// Fetch all models from the database for this model type.
|
|
1441
|
+
///
|
|
1442
|
+
/// Note:
|
|
1443
|
+
/// This will fetch ALL rows for the model. If this is not what you want,
|
|
1444
|
+
/// then construct a query first, and call `all` from the query itself, i.e.
|
|
1445
|
+
/// `User.where.firstName.EQ('Bob').all(options)`.
|
|
1446
|
+
/// Return: Array<<see>Model</see>>
|
|
1447
|
+
/// Return all models of this type from the database.
|
|
1448
|
+
/// Arguments:
|
|
1449
|
+
/// options?: object
|
|
1450
|
+
/// An "options" object to pass off to the underlying <see>Connection</see> methods.
|
|
1451
|
+
/// If a `connection` key is specified in this object, then that will be used
|
|
1452
|
+
/// as the connection for the operation. This can be important if for example
|
|
1453
|
+
/// you are calling this from a `transaction`, in which case you most certainly
|
|
1454
|
+
/// would want to provide the `connection` for the transaction.
|
|
1455
|
+
/// If a `stream: true` option is provided, then an async generator will be
|
|
1456
|
+
/// returned, allowing you to "stream" the rows from the database in batches.
|
|
1457
|
+
/// The default `batchSize` is `500`, but can be overridden by setting the `batchSize`
|
|
1458
|
+
/// option to some valid positive number, or `Infinity` to pull everything at once.
|
|
1459
|
+
/// If the `stream` option is not specified, or is `false`, then all rows will be
|
|
1460
|
+
/// fetched from the database in batches, collected into an array, and returned
|
|
1461
|
+
/// only once all rows have been fetched. This is the default behavior.
|
|
881
1462
|
static all(options) {
|
|
882
1463
|
return this.getWhereWithConnection(options).all(options);
|
|
883
1464
|
}
|
|
884
1465
|
|
|
1466
|
+
/// Get the first (limit) rows from the database for this model type.
|
|
1467
|
+
///
|
|
1468
|
+
/// Note:
|
|
1469
|
+
/// This will fetch the first rows for the model, in database order.
|
|
1470
|
+
/// If you wish to filter, and specify the order, then construct a
|
|
1471
|
+
/// query first, and call the `first` method from the query itself, i.e.
|
|
1472
|
+
/// `User.where.firstName.EQ('Bob').ORDER('+User:firstName').first(options)`
|
|
1473
|
+
/// Return: <see>Model</see> | Array<<see>Model</see>>
|
|
1474
|
+
/// Return `limit` models of this type from the database. If
|
|
1475
|
+
/// `limit` is `null`, `undefined`, or `1`, then a single model
|
|
1476
|
+
/// instance will be returned (or `undefined` if nothing is found).
|
|
1477
|
+
/// If the `limit` argument is more than `1`, then an array
|
|
1478
|
+
/// of model instances will be returned, or an empty array if
|
|
1479
|
+
/// nothing is found.
|
|
1480
|
+
/// Arguments:
|
|
1481
|
+
/// limit?: number = 1
|
|
1482
|
+
/// The number of model instances to fetch from the database.
|
|
1483
|
+
/// options?: object
|
|
1484
|
+
/// An "options" object to pass off to the underlying <see>Connection</see> methods.
|
|
1485
|
+
/// If a `connection` key is specified in this object, then that will be used
|
|
1486
|
+
/// as the connection for the operation. This can be important if for example
|
|
1487
|
+
/// you are calling this from a `transaction`, in which case you most certainly
|
|
1488
|
+
/// would want to provide the `connection` for the transaction.
|
|
885
1489
|
static first(limit, options) {
|
|
886
1490
|
if (limit != null && !Nife.instanceOf(limit, 'number'))
|
|
887
1491
|
throw new Error(`${this.getModelName()}::first: "limit" must be null, or a number. If you want to supply a query, use "${this.getModelName()}.where.{query}.first(limit)" instead.`);
|
|
@@ -889,6 +1493,33 @@ class Model {
|
|
|
889
1493
|
return this.getWhereWithConnection(options).first(limit, options);
|
|
890
1494
|
}
|
|
891
1495
|
|
|
1496
|
+
/// Get the last (limit) rows from the database for this model type.
|
|
1497
|
+
///
|
|
1498
|
+
/// Note:
|
|
1499
|
+
/// This will fetch the last rows for the model, in database order.
|
|
1500
|
+
/// If you wish to filter, and specify the order, then construct a
|
|
1501
|
+
/// query first, and call the `last` method from the query itself, i.e.
|
|
1502
|
+
/// `User.where.firstName.EQ('Bob').ORDER('+User:firstName').last(options)`
|
|
1503
|
+
/// Note:
|
|
1504
|
+
/// This works by telling the underlying query generator to invert
|
|
1505
|
+
/// the specified ORDER of the query, and then it selects the first
|
|
1506
|
+
/// `limit` rows from the result.
|
|
1507
|
+
/// Return: <see>Model</see> | Array<<see>Model</see>>
|
|
1508
|
+
/// Return `limit` models of this type from the database. If
|
|
1509
|
+
/// `limit` is `null`, `undefined`, or `1`, then a single model
|
|
1510
|
+
/// instance will be returned (or `undefined` if nothing is found).
|
|
1511
|
+
/// If the `limit` argument is more than `1`, then an array
|
|
1512
|
+
/// of model instances will be returned, or an empty array if
|
|
1513
|
+
/// nothing is found.
|
|
1514
|
+
/// Arguments:
|
|
1515
|
+
/// limit?: number = 1
|
|
1516
|
+
/// The number of model instances to fetch from the database.
|
|
1517
|
+
/// options?: object
|
|
1518
|
+
/// An "options" object to pass off to the underlying <see>Connection</see> methods.
|
|
1519
|
+
/// If a `connection` key is specified in this object, then that will be used
|
|
1520
|
+
/// as the connection for the operation. This can be important if for example
|
|
1521
|
+
/// you are calling this from a `transaction`, in which case you most certainly
|
|
1522
|
+
/// would want to provide the `connection` for the transaction.
|
|
892
1523
|
static last(limit, options) {
|
|
893
1524
|
if (limit != null && !Nife.instanceOf(limit, 'number'))
|
|
894
1525
|
throw new Error(`${this.getModelName()}::last: "limit" must be null, or a number. If you want to supply a query, use "${this.getModelName()}.where.{query}.last(limit)" instead.`);
|
|
@@ -896,10 +1527,72 @@ class Model {
|
|
|
896
1527
|
return this.getWhereWithConnection(options).last(limit, options);
|
|
897
1528
|
}
|
|
898
1529
|
|
|
1530
|
+
/// Pluck specific fields (columns) from the database for this model type.
|
|
1531
|
+
///
|
|
1532
|
+
/// Note:
|
|
1533
|
+
/// This will pluck across ALL rows for the model, in database order.
|
|
1534
|
+
/// If you wish to filter and limit, and specify the order, then construct a
|
|
1535
|
+
/// query first, and call the `pluck` method from the query itself, i.e.
|
|
1536
|
+
/// `User.where.firstName.EQ('Bob').LIMIT(50).ORDER('+User:firstName').pluck([ 'User:firstName' ], options)`
|
|
1537
|
+
/// Note:
|
|
1538
|
+
/// In Mythix ORM you **never** specify a field via its `columnName`.
|
|
1539
|
+
/// You always use a field's defined `fieldName` to match against
|
|
1540
|
+
/// a field. Using a `columnName` simply won't work, unless `columnName`
|
|
1541
|
+
/// and `fieldName` just happen to have the same value.
|
|
1542
|
+
/// Return: Array<any> | Array<Array<any>>
|
|
1543
|
+
/// If only a single field is specified, then a flat array
|
|
1544
|
+
/// of values will be returned across all rows. If more than
|
|
1545
|
+
/// one field is specified, then an array of arrays (rows) will
|
|
1546
|
+
/// be returned for the fields specified.
|
|
1547
|
+
/// Arguments:
|
|
1548
|
+
/// fields?: Array<string>
|
|
1549
|
+
/// An array of fully qualified field names to pluck from the underlying
|
|
1550
|
+
/// database table for this model. **Do not use column names here**... these
|
|
1551
|
+
/// must be fully qualified field names.
|
|
1552
|
+
/// options?: object
|
|
1553
|
+
/// An "options" object to pass off to the underlying <see>Connection</see> methods.
|
|
1554
|
+
/// If a `connection` key is specified in this object, then that will be used
|
|
1555
|
+
/// as the connection for the operation. This can be important if for example
|
|
1556
|
+
/// you are calling this from a `transaction`, in which case you most certainly
|
|
1557
|
+
/// would want to provide the `connection` for the transaction.
|
|
899
1558
|
static pluck(fields, options) {
|
|
900
1559
|
return this.getWhereWithConnection(options).pluck(fields);
|
|
901
1560
|
}
|
|
902
1561
|
|
|
1562
|
+
/// Construct a new <see>Model</see> instance.
|
|
1563
|
+
///
|
|
1564
|
+
/// Return: <see>Model</see>
|
|
1565
|
+
/// Arguments:
|
|
1566
|
+
/// data?: object
|
|
1567
|
+
/// Attributes to provide to the new model instance.
|
|
1568
|
+
/// The key names should be a `fieldName`, not a `columnName`.
|
|
1569
|
+
/// Any model attribute missing from `data`, or whose value is
|
|
1570
|
+
/// `undefined`, will be given a default value from the `defaultValue`,
|
|
1571
|
+
/// field property for the field. If the `defaultValue` for the
|
|
1572
|
+
/// field is marked as a "remote" value (a value provided by the database)
|
|
1573
|
+
/// or if `defaultValue` is *not* marked with the flag
|
|
1574
|
+
/// `FLAG_ON_INITIALIZE`, then the field will remain with
|
|
1575
|
+
/// a value of `undefined`, at least until the model is stored
|
|
1576
|
+
/// to the database. The default for all methods provided to the
|
|
1577
|
+
/// `defaultValue` key of the field is to have the `FLAG_ON_INITIALIZE`
|
|
1578
|
+
/// flag, so the value will be created on model instantiation.
|
|
1579
|
+
/// Some default value methods however, such as `AUTOINCREMENT`,
|
|
1580
|
+
/// do not have the `FLAG_ON_INITIALIZE` set, because the defaultValue
|
|
1581
|
+
/// is provided by the database.
|
|
1582
|
+
/// `null` is a valid value, and if provided for
|
|
1583
|
+
/// an attribute, then the `defaultValue` will not be used.
|
|
1584
|
+
/// Any attribute value provided will go through
|
|
1585
|
+
/// `field.type.castValue` from the field `type` property
|
|
1586
|
+
/// (this includes `null` values). Any attributes provided
|
|
1587
|
+
/// will immediately be marked as "dirty" as soon as the model
|
|
1588
|
+
/// is instantiated.
|
|
1589
|
+
/// options?: object
|
|
1590
|
+
/// Options for the model. The only property Mythix ORM
|
|
1591
|
+
/// will use is the `connection` key. If provided, it will set
|
|
1592
|
+
/// this as the `_connection` property on the instance. Otherwise,
|
|
1593
|
+
/// these options are intended to be used by you, the developer,
|
|
1594
|
+
/// to do with as you please on your models. They can be fetched
|
|
1595
|
+
/// from any model instance simply by calling <see>Model.getOptions</see>.
|
|
903
1596
|
constructor(data, _options) {
|
|
904
1597
|
let options = _options || {};
|
|
905
1598
|
|
|
@@ -913,6 +1606,12 @@ class Model {
|
|
|
913
1606
|
};
|
|
914
1607
|
|
|
915
1608
|
Object.defineProperties(this, {
|
|
1609
|
+
'_options': {
|
|
1610
|
+
writable: true,
|
|
1611
|
+
enumberable: false,
|
|
1612
|
+
configurable: true,
|
|
1613
|
+
value: options,
|
|
1614
|
+
},
|
|
916
1615
|
'_mythixModelInstance': {
|
|
917
1616
|
writable: false,
|
|
918
1617
|
enumberable: false,
|
|
@@ -937,6 +1636,12 @@ class Model {
|
|
|
937
1636
|
configurable: true,
|
|
938
1637
|
value: {},
|
|
939
1638
|
},
|
|
1639
|
+
'_typeData': {
|
|
1640
|
+
writable: true,
|
|
1641
|
+
enumberable: false,
|
|
1642
|
+
configurable: true,
|
|
1643
|
+
value: {},
|
|
1644
|
+
},
|
|
940
1645
|
'dirtyID': {
|
|
941
1646
|
writable: true,
|
|
942
1647
|
enumberable: false,
|
|
@@ -976,11 +1681,55 @@ class Model {
|
|
|
976
1681
|
this._constructor(data);
|
|
977
1682
|
}
|
|
978
1683
|
|
|
1684
|
+
/// Get the options provided to the model, if any.
|
|
1685
|
+
/// This will always return an object, even if no
|
|
1686
|
+
/// options were provided, in which case the object
|
|
1687
|
+
/// will simply be an empty object.
|
|
1688
|
+
///
|
|
1689
|
+
/// Return: object
|
|
1690
|
+
/// Options object provided by the user to the model
|
|
1691
|
+
/// when the model was constructed.
|
|
1692
|
+
getOptions() {
|
|
1693
|
+
return this._options;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
/// This is the final call the `constructor` makes
|
|
1697
|
+
/// before it finalizes instantiating the model.
|
|
1698
|
+
/// It calls <see>Model._constructFields</see> to
|
|
1699
|
+
/// construct the model's fields, and then it calls
|
|
1700
|
+
/// <see>Model._initializeModelData</see> to initialize
|
|
1701
|
+
/// the field values for the model.
|
|
1702
|
+
///
|
|
1703
|
+
/// Return: `undefined`
|
|
1704
|
+
/// Arguments:
|
|
1705
|
+
/// data?: object
|
|
1706
|
+
/// Attributes provided to the model through
|
|
1707
|
+
/// the `constructor` call.
|
|
979
1708
|
_constructor(data) {
|
|
980
1709
|
this._constructFields();
|
|
981
1710
|
this._initializeModelData(data);
|
|
982
1711
|
}
|
|
983
1712
|
|
|
1713
|
+
/// Construct the model's fields on the model instance.
|
|
1714
|
+
/// This method will iterate the `static Model.fields`
|
|
1715
|
+
/// fields for the model. For each field (except virtual
|
|
1716
|
+
/// fields), it will call `field.type.exposeToModel()`.
|
|
1717
|
+
/// If this method returns `true`, then the field will
|
|
1718
|
+
/// be added as a getter/setter to the model instance,
|
|
1719
|
+
/// with the name defined as the field's `fieldName`.
|
|
1720
|
+
/// For example, if a `User` model had a field named
|
|
1721
|
+
/// `fieldName: 'firstName'`, then the `firstName`
|
|
1722
|
+
/// property will be added to the model instance, as a
|
|
1723
|
+
/// getter/setter property on the instance. The getter/
|
|
1724
|
+
/// setter provide the functionality of sending data in
|
|
1725
|
+
/// and out of `get` and `set` methods on the field itself,
|
|
1726
|
+
/// and through each `field.type.castValue` method on set.
|
|
1727
|
+
/// The setter will also mark a field as dirty if it is set
|
|
1728
|
+
/// to a value that is different from the current value of
|
|
1729
|
+
/// the field. The <see>Model.getDataValue</see> and
|
|
1730
|
+
/// <see>Model.setDataValue</see> instance methods will bypass
|
|
1731
|
+
/// the getter/setter of each field, allowing direct access
|
|
1732
|
+
/// to the underlying attribute value.
|
|
984
1733
|
_constructFields() {
|
|
985
1734
|
this.iterateFields(({ field, fieldName }) => {
|
|
986
1735
|
field.type.initialize(this._getConnection(), this);
|
|
@@ -989,6 +1738,8 @@ class Model {
|
|
|
989
1738
|
});
|
|
990
1739
|
}
|
|
991
1740
|
|
|
1741
|
+
/// This method simply creates the getters/setters
|
|
1742
|
+
/// for fields as described by <see>Model._constructFields</see>.
|
|
992
1743
|
_constructField(fieldName, field) {
|
|
993
1744
|
Object.defineProperties(this, {
|
|
994
1745
|
[fieldName]: {
|
|
@@ -1004,6 +1755,38 @@ class Model {
|
|
|
1004
1755
|
});
|
|
1005
1756
|
}
|
|
1006
1757
|
|
|
1758
|
+
/// Initialize the field value for each field/attribute.
|
|
1759
|
+
/// If no `data` argument is passed to the constructor,
|
|
1760
|
+
/// then each field will be initialized to its default
|
|
1761
|
+
/// value, as defined by the `defaultValue` property on
|
|
1762
|
+
/// each field. A `null` value is a valid value, and
|
|
1763
|
+
/// though it will still be piped through each field's
|
|
1764
|
+
/// `field.type.castValue` method, it will discount the
|
|
1765
|
+
/// need to call `defaultValue` on the field.
|
|
1766
|
+
/// This method calls <see>Model._initializeFieldData</see>
|
|
1767
|
+
/// to actually set the value of each field. Field values
|
|
1768
|
+
/// are set from the provided `data` object to the `constructor`
|
|
1769
|
+
/// first, for all fields, before any `defaultValue` calls
|
|
1770
|
+
/// for any fields are attempted.
|
|
1771
|
+
///
|
|
1772
|
+
/// Note:
|
|
1773
|
+
/// All fields have already been constructed before this
|
|
1774
|
+
/// method is called via <see>Model._constructFields</see>.
|
|
1775
|
+
/// Note:
|
|
1776
|
+
/// Virtual fields are not constructed against the model instance,
|
|
1777
|
+
/// however, field types *can* modify the instance, and some do.
|
|
1778
|
+
/// For example, the `Types.Model` and `Types.Models` virtual field
|
|
1779
|
+
/// types inject relational methods on the model.
|
|
1780
|
+
/// Note:
|
|
1781
|
+
/// Only concrete fields are considered "attributes" of the model,
|
|
1782
|
+
/// and can have an initial value provided via the `data` argument
|
|
1783
|
+
/// to the constructor, or via a `defaultValue` property on the field.
|
|
1784
|
+
/// Arguments:
|
|
1785
|
+
/// data?: object
|
|
1786
|
+
/// Attributes values for fields. Can be nothing, in which case
|
|
1787
|
+
/// the `defaultValue` property for each field will be used instead.
|
|
1788
|
+
/// `null` is a valid value, and if an attribute has a `null` value,
|
|
1789
|
+
/// it will not be given a default value from `defaultValue`.
|
|
1007
1790
|
_initializeModelData(_data) {
|
|
1008
1791
|
let dirtyFieldData = this._dirtyFieldData;
|
|
1009
1792
|
let data = _data || {};
|
|
@@ -1031,6 +1814,22 @@ class Model {
|
|
|
1031
1814
|
});
|
|
1032
1815
|
}
|
|
1033
1816
|
|
|
1817
|
+
/// This casts a field value to its type,
|
|
1818
|
+
/// by calling the field's `field.type.castValue`
|
|
1819
|
+
/// method for the type.
|
|
1820
|
+
///
|
|
1821
|
+
/// Return: any
|
|
1822
|
+
/// The value provided, cast to the type of the field.
|
|
1823
|
+
/// Arguments:
|
|
1824
|
+
/// field: <see>Field</see>
|
|
1825
|
+
/// The field to use to cast the value. The `type` property
|
|
1826
|
+
/// on the field will be accessed, and the `type` properties
|
|
1827
|
+
/// `castValue` method will be called on the provided `value`
|
|
1828
|
+
/// argument.
|
|
1829
|
+
/// value: any
|
|
1830
|
+
/// The value to cast to the field's type. `null` is a valid
|
|
1831
|
+
/// value, and all `castValue` methods on types should properly
|
|
1832
|
+
/// handle it.
|
|
1034
1833
|
_castFieldValue(field, value) {
|
|
1035
1834
|
let type = field.type;
|
|
1036
1835
|
if (!type)
|
|
@@ -1040,10 +1839,33 @@ class Model {
|
|
|
1040
1839
|
connection: this.getConnection(),
|
|
1041
1840
|
Model: this.getModel(),
|
|
1042
1841
|
self: this,
|
|
1842
|
+
field,
|
|
1043
1843
|
value,
|
|
1044
1844
|
});
|
|
1045
1845
|
}
|
|
1046
1846
|
|
|
1847
|
+
/// Set each field's initial value. Each field's value
|
|
1848
|
+
/// will first be fetched from the `data` argument
|
|
1849
|
+
/// given to the `constructor`--if any was given. After
|
|
1850
|
+
/// all field attributes have been set this way, then
|
|
1851
|
+
/// this method is called, being provided that value (if
|
|
1852
|
+
/// any) via the `fieldValue` argument. If `fieldValue`
|
|
1853
|
+
/// is `undefined`, then call the `defaultValue` property
|
|
1854
|
+
/// of the field to get the field's initial value.
|
|
1855
|
+
///
|
|
1856
|
+
/// Arguments:
|
|
1857
|
+
/// fieldName: string
|
|
1858
|
+
/// The name of the field we are initializing.
|
|
1859
|
+
/// field: <see>Field</see>
|
|
1860
|
+
/// The field definition itself for the field
|
|
1861
|
+
/// we are initializing.
|
|
1862
|
+
/// fieldValue: any
|
|
1863
|
+
/// The field value as provided by the `data`
|
|
1864
|
+
/// argument to the model `constructor`, if
|
|
1865
|
+
/// any was provided.
|
|
1866
|
+
/// data: object
|
|
1867
|
+
/// The `data` argument, as provided to the
|
|
1868
|
+
/// `constructor` of the model.
|
|
1047
1869
|
_initializeFieldData(fieldName, field, fieldValue, data) {
|
|
1048
1870
|
let dirtyFieldData = this._dirtyFieldData;
|
|
1049
1871
|
let fieldData = this._fieldData;
|
|
@@ -1075,6 +1897,7 @@ class Model {
|
|
|
1075
1897
|
if (shouldRunDefaultValueOnInitialize()) {
|
|
1076
1898
|
defaultValue = defaultValue({
|
|
1077
1899
|
model: this,
|
|
1900
|
+
self: this,
|
|
1078
1901
|
connection: this.getConnection(),
|
|
1079
1902
|
_initial: true,
|
|
1080
1903
|
field,
|
|
@@ -1087,12 +1910,104 @@ class Model {
|
|
|
1087
1910
|
}
|
|
1088
1911
|
}
|
|
1089
1912
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1913
|
+
let initialValue;
|
|
1914
|
+
|
|
1915
|
+
if (defaultValue === undefined || !data) {
|
|
1916
|
+
initialValue = defaultValue;
|
|
1917
|
+
|
|
1918
|
+
if (defaultValue != null)
|
|
1919
|
+
initialValue = this._castFieldValue(field, defaultValue);
|
|
1920
|
+
|
|
1921
|
+
fieldData[fieldName] = initialValue;
|
|
1922
|
+
} else {
|
|
1923
|
+
initialValue = this._castFieldValue(field, defaultValue);
|
|
1924
|
+
dirtyFieldData[fieldName] = initialValue;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
field.type.onSetFieldValue({
|
|
1928
|
+
self: this,
|
|
1929
|
+
value: initialValue,
|
|
1930
|
+
field,
|
|
1931
|
+
fieldName,
|
|
1932
|
+
});
|
|
1094
1933
|
}
|
|
1095
1934
|
|
|
1935
|
+
/// Get the dirty fields of the model instance.
|
|
1936
|
+
/// The model instance property `Model.changes`
|
|
1937
|
+
/// calls this method to get the list of dirty
|
|
1938
|
+
/// fields for the model instance. Unlike
|
|
1939
|
+
/// `Model.changes`, which is a getter, you can
|
|
1940
|
+
/// pass `options` to this method, which can change
|
|
1941
|
+
/// its behavior.
|
|
1942
|
+
///
|
|
1943
|
+
/// If this method is provided a <see>Connection</see> via the
|
|
1944
|
+
/// `connection` options value, then it will assume it is being
|
|
1945
|
+
/// used in a connection method to fetch the dirty fields for
|
|
1946
|
+
/// a database operation (update, or insert). If it has a
|
|
1947
|
+
/// <see>Connection</see> then it will behave a little differently.
|
|
1948
|
+
///
|
|
1949
|
+
/// The first difference is that if a model field is not marked
|
|
1950
|
+
/// as dirty, then it will be passed through <see>connection.dirtyFieldHelper</see>.
|
|
1951
|
+
/// If this method returns any value other than `undefined`, then
|
|
1952
|
+
/// that value will be used as the "dirty" value for the field, and
|
|
1953
|
+
/// the field will be marked as dirty. This can be used when you
|
|
1954
|
+
/// want the connection itself to control the dirty state of a field.
|
|
1955
|
+
/// This is what is done with SQLite BigInt AUTOINCREMENT emulation.
|
|
1956
|
+
/// Any time an autoincrementing BigInt is being stored to a SQLite
|
|
1957
|
+
/// database with the `emulateBigIntAutoIncrement` option enabled,
|
|
1958
|
+
/// an internal counter for this field is incremented, and the field
|
|
1959
|
+
/// is automatically updated as "dirty" (on insert only, if the field
|
|
1960
|
+
/// has and `undefined` value).
|
|
1961
|
+
///
|
|
1962
|
+
/// The next difference when using a `connection` in this method is
|
|
1963
|
+
/// that it will check if this is an "update" or an "insert" operation
|
|
1964
|
+
/// by checking the `update` and `insert` "option" keys respectively.
|
|
1965
|
+
/// If one of these is `true`, then it will invoke `defaultValue` property
|
|
1966
|
+
/// on the field, if said `defaultValue` has the `onUpdate`, or `onInsert`
|
|
1967
|
+
/// flags set to `true`. This can be used for example on `created_at`,
|
|
1968
|
+
/// and `updated_at` fields, which will only be marked dirty and given
|
|
1969
|
+
/// a value on an `insert` or `update` operation through the connection.
|
|
1970
|
+
///
|
|
1971
|
+
/// Without a `connection` provided to this method, it will simply
|
|
1972
|
+
/// return the "change list" of all dirty fields on the model. The
|
|
1973
|
+
/// "change list" is an object, where each key is the name of the field,
|
|
1974
|
+
/// and each value is another object, with `previous` and `current` keys
|
|
1975
|
+
/// describe the change that took place to the field. For example:
|
|
1976
|
+
/// ```javascript
|
|
1977
|
+
/// DirtyFieldChangeList = {
|
|
1978
|
+
/// firstName: {
|
|
1979
|
+
/// previous: undefined,
|
|
1980
|
+
/// current: 'Bob',
|
|
1981
|
+
/// },
|
|
1982
|
+
/// }
|
|
1983
|
+
/// ```
|
|
1984
|
+
///
|
|
1985
|
+
/// If no fields on the model are dirty, then an empty object
|
|
1986
|
+
/// will be returned. A field is considered "dirty" if its value
|
|
1987
|
+
/// is different from what it was when the model was first instantiated,
|
|
1988
|
+
/// or since the last time the <see>Model.clearDirty</see> method was
|
|
1989
|
+
/// called.
|
|
1990
|
+
///
|
|
1991
|
+
/// The `options` argument has the
|
|
1992
|
+
/// following shape:
|
|
1993
|
+
///
|
|
1994
|
+
/// Interface:
|
|
1995
|
+
/// interface DirtyFieldOptions {
|
|
1996
|
+
/// connection: Connection; // The connection for this operation.
|
|
1997
|
+
/// update: boolean; // If `true`, then this is an update operation.
|
|
1998
|
+
/// insert: boolean; // If `true`, then this is an insert operation.
|
|
1999
|
+
/// // ... any options you wish to pass to `connection.dirtyFieldHelper`
|
|
2000
|
+
/// }
|
|
2001
|
+
///
|
|
2002
|
+
/// Note:
|
|
2003
|
+
/// If this is an "update" or "insert" operation, as defined by
|
|
2004
|
+
/// the `update` or `insert` "options", then the default value
|
|
2005
|
+
/// for the field will be fetched via the <see>QueryGenerator.getFieldDefaultValue</see>
|
|
2006
|
+
/// method through the provided `connection`.
|
|
2007
|
+
/// Return: DirtyFieldChangeList
|
|
2008
|
+
/// Arguments:
|
|
2009
|
+
/// options?: DirtyFieldOptions
|
|
2010
|
+
/// Options to provide to the method.
|
|
1096
2011
|
_getDirtyFields(_options) {
|
|
1097
2012
|
let options = _options || {};
|
|
1098
2013
|
let fieldData = this._fieldData;
|
|
@@ -1110,6 +2025,30 @@ class Model {
|
|
|
1110
2025
|
return;
|
|
1111
2026
|
}
|
|
1112
2027
|
|
|
2028
|
+
// Does the type itself report that we are dirty?
|
|
2029
|
+
let value = field.type.isDirty({
|
|
2030
|
+
self: this,
|
|
2031
|
+
value: this.getDataValue(fieldName),
|
|
2032
|
+
field,
|
|
2033
|
+
fieldName,
|
|
2034
|
+
connection,
|
|
2035
|
+
});
|
|
2036
|
+
|
|
2037
|
+
if (value !== undefined) {
|
|
2038
|
+
// Cache this result so subsequent calls
|
|
2039
|
+
// to dirty fields doesn't get a new value
|
|
2040
|
+
dirtyFieldData[fieldName] = value;
|
|
2041
|
+
|
|
2042
|
+
dirtyFields[fieldName] = {
|
|
2043
|
+
previous: fieldData[fieldName],
|
|
2044
|
+
current: value,
|
|
2045
|
+
};
|
|
2046
|
+
|
|
2047
|
+
return;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
// Does the connection dirtyFieldHelper report that we are
|
|
2051
|
+
// dirty?
|
|
1113
2052
|
if (connection && typeof connection.dirtyFieldHelper === 'function') {
|
|
1114
2053
|
let value = connection.dirtyFieldHelper({ options, fieldData, dirtyFieldData, dirtyFields, field, fieldName });
|
|
1115
2054
|
if (value !== undefined) {
|
|
@@ -1157,12 +2096,36 @@ class Model {
|
|
|
1157
2096
|
return dirtyFields;
|
|
1158
2097
|
}
|
|
1159
2098
|
|
|
2099
|
+
/// Get a field's value. Calling this is no different
|
|
2100
|
+
/// from accessing the field directly on the model instance
|
|
2101
|
+
/// itself. For example, `userInstance.firstName` is identical
|
|
2102
|
+
/// to calling `userInstance._getFieldValue('firstName', User.fields.firstName)`.
|
|
2103
|
+
///
|
|
2104
|
+
/// This will call the `get` method defined on the field, if any is defined.
|
|
2105
|
+
/// If a `get` method is defined, then whatever value it returns will be
|
|
2106
|
+
/// the result of this method. If no `get` method is defined on the field,
|
|
2107
|
+
/// then `this.getDataValue(fieldName)` is called instead, and will provide
|
|
2108
|
+
/// the resulting return value for this method.
|
|
2109
|
+
///
|
|
2110
|
+
/// Note:
|
|
2111
|
+
/// Never call this method (or the model attribute by name), while
|
|
2112
|
+
/// inside a field's `get` method. If you do, you will enter an
|
|
2113
|
+
/// infinite recursive loop. Instead, call the provided `get`
|
|
2114
|
+
/// method (as provided by the context), or call <see>Model.getDataValue</see>.
|
|
2115
|
+
/// Return: any
|
|
2116
|
+
/// Arguments:
|
|
2117
|
+
/// fieldName: string
|
|
2118
|
+
/// The name of the field whose value we wish to get.
|
|
2119
|
+
/// field: <see>Field</see>
|
|
2120
|
+
/// The field definition itself for the value we wish to get.
|
|
2121
|
+
/// See: Field
|
|
1160
2122
|
_getFieldValue(fieldName, field) {
|
|
1161
2123
|
let value = this.getDataValue(fieldName);
|
|
1162
2124
|
|
|
1163
2125
|
if (typeof field.get === 'function') {
|
|
1164
2126
|
return field.get.call(this, {
|
|
1165
2127
|
model: this,
|
|
2128
|
+
self: this,
|
|
1166
2129
|
set: this.setDataValue.bind(this, fieldName),
|
|
1167
2130
|
get: this.getDataValue.bind(this, fieldName),
|
|
1168
2131
|
value,
|
|
@@ -1174,10 +2137,37 @@ class Model {
|
|
|
1174
2137
|
return value;
|
|
1175
2138
|
}
|
|
1176
2139
|
|
|
2140
|
+
/// Set a field's value. Calling this is no different
|
|
2141
|
+
/// from setting the field directly on the model instance
|
|
2142
|
+
/// itself. For example, `userInstance.firstName = 'Bob'` is identical
|
|
2143
|
+
/// to calling `userInstance._setFieldValue('firstName', User.fields.firstName, 'Bob')`.
|
|
2144
|
+
///
|
|
2145
|
+
/// This will call the `set` method defined on the field, if any is defined.
|
|
2146
|
+
/// If a `set` method is defined, then it is entirely up to the `set` method
|
|
2147
|
+
/// to call `this.setDataValue` to set the field's value.
|
|
2148
|
+
/// If no `set` method is defined on the field, then `this.setDataValue(fieldName, value)`
|
|
2149
|
+
/// is called instead, and will set the value on the field.
|
|
2150
|
+
///
|
|
2151
|
+
/// Note:
|
|
2152
|
+
/// This method will mark the field as dirty if the value provided
|
|
2153
|
+
/// differs from the current value the field has.
|
|
2154
|
+
/// Note:
|
|
2155
|
+
/// Never call this method (or set the model attribute by name), while
|
|
2156
|
+
/// inside a field's `set` method. If you do, you will enter an
|
|
2157
|
+
/// infinite recursive loop. Instead, call the provided `set`
|
|
2158
|
+
/// method (as provided by the context), or call <see>Model.setDataValue</see>.
|
|
2159
|
+
/// Return: undefined
|
|
2160
|
+
/// Arguments:
|
|
2161
|
+
/// fieldName: string
|
|
2162
|
+
/// The name of the field whose value we wish to get.
|
|
2163
|
+
/// field: <see>Field</see>
|
|
2164
|
+
/// The field definition itself for the value we wish to get.
|
|
2165
|
+
/// See: Field
|
|
1177
2166
|
_setFieldValue(fieldName, field, value) {
|
|
1178
2167
|
if (typeof field.set === 'function') {
|
|
1179
2168
|
field.set.call(this, {
|
|
1180
2169
|
model: this,
|
|
2170
|
+
self: this,
|
|
1181
2171
|
set: this.setDataValue.bind(this, fieldName),
|
|
1182
2172
|
get: this.getDataValue.bind(this, fieldName),
|
|
1183
2173
|
value,
|
|
@@ -1191,21 +2181,84 @@ class Model {
|
|
|
1191
2181
|
this.setDataValue(fieldName, value);
|
|
1192
2182
|
}
|
|
1193
2183
|
|
|
2184
|
+
/// Check if the model is persisted or not.
|
|
2185
|
+
/// This has nothing to do with the model's "dirty" state.
|
|
2186
|
+
/// if the model is dirty, then this will still report
|
|
2187
|
+
/// `true` if the model was initially loaded from the database.
|
|
2188
|
+
///
|
|
2189
|
+
/// Return: boolean
|
|
2190
|
+
/// `true` if the model was loaded from the database,
|
|
2191
|
+
/// `false` otherwise.
|
|
1194
2192
|
isPersisted() {
|
|
1195
2193
|
return this._persisted;
|
|
1196
2194
|
}
|
|
1197
2195
|
|
|
2196
|
+
/// Update the `this.dirtyID` cache key of the model.
|
|
2197
|
+
/// This is called any time a field is marked as "dirty" on the model.
|
|
2198
|
+
/// The `dirtyID` property of a model is an instance of
|
|
2199
|
+
/// a <see>CacheKey</see> that is intended to be used for
|
|
2200
|
+
/// caching systems. The <see>CacheKey</see> instance can
|
|
2201
|
+
/// be used for a key into a WeakMap, which can cache things.
|
|
2202
|
+
/// Because this is updated to a new instance of a <see>CacheKey</see>
|
|
2203
|
+
/// any time *any* field on the model is marked as dirty,
|
|
2204
|
+
/// any cache for this model will be invalidated as soon
|
|
2205
|
+
/// as any field on the model is dirty.
|
|
1198
2206
|
updateDirtyID() {
|
|
1199
2207
|
this.dirtyID = new CacheKey(this.dirtyID);
|
|
1200
2208
|
}
|
|
1201
2209
|
|
|
2210
|
+
/// Check if the model is dirty or not.
|
|
2211
|
+
/// If a `fieldName` is provided as an argument,
|
|
2212
|
+
/// it will only check if the specified field
|
|
2213
|
+
/// is dirty or not. If not provided, then the
|
|
2214
|
+
/// entire model will be considered "dirty" if
|
|
2215
|
+
/// one or more fields are marked as "dirty".
|
|
2216
|
+
///
|
|
2217
|
+
/// Return: boolean
|
|
2218
|
+
/// Arguments:
|
|
2219
|
+
/// fieldName?: string
|
|
2220
|
+
/// If provided, check if this one field is dirty. If not
|
|
2221
|
+
/// provided, then check if any field on the model is dirty.
|
|
1202
2222
|
isDirty(fieldName) {
|
|
1203
|
-
if (!fieldName)
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
2223
|
+
if (!fieldName) {
|
|
2224
|
+
// Do this check first, because
|
|
2225
|
+
// it takes way less computation
|
|
2226
|
+
let isDirty = (Object.keys(this._dirtyFieldData).length > 0);
|
|
2227
|
+
if (isDirty)
|
|
2228
|
+
return true;
|
|
2229
|
+
|
|
2230
|
+
let changes = this.changes;
|
|
2231
|
+
return (Object.keys(changes).length > 0);
|
|
2232
|
+
} else {
|
|
2233
|
+
// Do this check first, because
|
|
2234
|
+
// it takes way less computation
|
|
2235
|
+
let hasDirtyField = Object.prototype.hasOwnProperty.call(this._dirtyFieldData, fieldName);
|
|
2236
|
+
if (hasDirtyField)
|
|
2237
|
+
return true;
|
|
2238
|
+
|
|
2239
|
+
let changes = this.changes;
|
|
2240
|
+
return Object.prototype.hasOwnProperty.call(changes, fieldName);
|
|
2241
|
+
}
|
|
1207
2242
|
}
|
|
1208
2243
|
|
|
2244
|
+
/// Clear the dirty state of the model, or of a single field.
|
|
2245
|
+
/// If a `fieldName` argument is provided, then only the specified
|
|
2246
|
+
/// field's "dirty" status will be cleared. If no `fieldName`
|
|
2247
|
+
/// argument is provided, then all field's on the model will have
|
|
2248
|
+
/// their "dirty" status cleared, and the model will no longer be
|
|
2249
|
+
/// "dirty".
|
|
2250
|
+
///
|
|
2251
|
+
/// The "dirty" status of a field is cleared by 1) setting the real
|
|
2252
|
+
/// underlying field value (this._fieldData) to the dirty field value,
|
|
2253
|
+
/// and 2) removing the entry in `this._dirtyFieldData` on the model for
|
|
2254
|
+
/// the field.
|
|
2255
|
+
///
|
|
2256
|
+
/// Return: boolean
|
|
2257
|
+
/// Arguments:
|
|
2258
|
+
/// fieldName?: string
|
|
2259
|
+
/// If specified, clear only this field's "dirty" status.
|
|
2260
|
+
/// If not specified, clear all fields on the model, making
|
|
2261
|
+
/// the entire model no longer dirty.
|
|
1209
2262
|
clearDirty(fieldName) {
|
|
1210
2263
|
if (fieldName && Object.prototype.hasOwnProperty.call(this._dirtyFieldData, fieldName)) {
|
|
1211
2264
|
this._fieldData[fieldName] = this._dirtyFieldData[fieldName];
|
|
@@ -1218,6 +2271,22 @@ class Model {
|
|
|
1218
2271
|
this.updateDirtyID();
|
|
1219
2272
|
}
|
|
1220
2273
|
|
|
2274
|
+
/// Get the dirty field descriptors themselves
|
|
2275
|
+
/// for all fields that are dirty.
|
|
2276
|
+
///
|
|
2277
|
+
/// Whereas <see>Model._getDirtyFields</see> returns
|
|
2278
|
+
/// a "change list" of dirty fields, this method
|
|
2279
|
+
/// will return the field descriptors themselves.
|
|
2280
|
+
/// An array of <see>Field</see> will be returned
|
|
2281
|
+
/// for each dirty field, or an empty array if no
|
|
2282
|
+
/// fields are dirty.
|
|
2283
|
+
///
|
|
2284
|
+
/// Return: Array<<see>Field</see>>
|
|
2285
|
+
/// The dirty fields of the model.
|
|
2286
|
+
/// Arguments:
|
|
2287
|
+
/// options?: object
|
|
2288
|
+
/// If provided, this will be the "options" supplied to
|
|
2289
|
+
/// <see>Model._getDirtyFields</see>.
|
|
1221
2290
|
getDirtyFields(options) {
|
|
1222
2291
|
let modelChanges = this._getDirtyFields(options);
|
|
1223
2292
|
let dirtyFieldNames = Object.keys(modelChanges);
|
|
@@ -1225,6 +2294,24 @@ class Model {
|
|
|
1225
2294
|
return this.getFields(dirtyFieldNames);
|
|
1226
2295
|
}
|
|
1227
2296
|
|
|
2297
|
+
/// Get the current value of any field on the model.
|
|
2298
|
+
/// The "current" value will be the dirty value if
|
|
2299
|
+
/// the field is dirty, or it will be the clean
|
|
2300
|
+
/// value of the field if the field isn't dirty.
|
|
2301
|
+
///
|
|
2302
|
+
/// This method is a "raw" get of the field's value
|
|
2303
|
+
/// in that it won't call `get` on the field descriptor,
|
|
2304
|
+
/// if any is defined. Instead it will first attempt to
|
|
2305
|
+
/// fetch the current value of the field from `this._dirtyFieldData`,
|
|
2306
|
+
/// if there is an entry for the field in the `this._dirtyFieldData`
|
|
2307
|
+
/// property of the model instance. If there is no "dirty" entry for
|
|
2308
|
+
/// the field, then its "clean value" (or raw value) will be fetched
|
|
2309
|
+
/// from the underlying `this._fieldData` storage area for field values.
|
|
2310
|
+
///
|
|
2311
|
+
/// Return: any
|
|
2312
|
+
/// Arguments:
|
|
2313
|
+
/// fieldName: string
|
|
2314
|
+
/// The name of the field whose value you wish to fetch.
|
|
1228
2315
|
getDataValue(fieldName) {
|
|
1229
2316
|
let fieldData = this._fieldData;
|
|
1230
2317
|
let dirtyFieldData = this._dirtyFieldData;
|
|
@@ -1238,6 +2325,32 @@ class Model {
|
|
|
1238
2325
|
return value;
|
|
1239
2326
|
}
|
|
1240
2327
|
|
|
2328
|
+
/// Set the current value of any field on the model.
|
|
2329
|
+
/// The "current" value will be the dirty value if
|
|
2330
|
+
/// the field is dirty, or it will be the clean
|
|
2331
|
+
/// value of the field if the field isn't dirty.
|
|
2332
|
+
///
|
|
2333
|
+
/// This method is a "raw" set of the field's value
|
|
2334
|
+
/// in that it won't call `set` on the field descriptor,
|
|
2335
|
+
/// if any is defined. Instead, it will mark the field as
|
|
2336
|
+
/// dirty by setting the value provided as an entry for
|
|
2337
|
+
/// the field in the `this._dirtyFieldData` property of
|
|
2338
|
+
/// the model instance. If the value set is equal to the
|
|
2339
|
+
/// "clean value" of the field, as found in `this._fieldData`,
|
|
2340
|
+
/// then the dirty entry for the field will be cleared (deleted)
|
|
2341
|
+
/// instead.
|
|
2342
|
+
///
|
|
2343
|
+
/// Note:
|
|
2344
|
+
/// This method will always call <see>Model.updateDirtyID</see>,
|
|
2345
|
+
/// invalidating all down-stream cache for this model instance.
|
|
2346
|
+
/// Return: undefined
|
|
2347
|
+
/// Arguments:
|
|
2348
|
+
/// fieldName: string
|
|
2349
|
+
/// The name of the field whose value you wish to set.
|
|
2350
|
+
/// value: any
|
|
2351
|
+
/// Value to set the field to. The will be sent through
|
|
2352
|
+
/// `field.type.castValue` to cast the incoming value
|
|
2353
|
+
/// to the field's type.
|
|
1241
2354
|
setDataValue(fieldName, value) {
|
|
1242
2355
|
let fieldData = this._fieldData;
|
|
1243
2356
|
let dirtyFieldData = this._dirtyFieldData;
|
|
@@ -1248,6 +2361,13 @@ class Model {
|
|
|
1248
2361
|
|
|
1249
2362
|
let newValue = this._castFieldValue(field, value);
|
|
1250
2363
|
|
|
2364
|
+
field.type.onSetFieldValue({
|
|
2365
|
+
self: this,
|
|
2366
|
+
value: newValue,
|
|
2367
|
+
field,
|
|
2368
|
+
fieldName,
|
|
2369
|
+
});
|
|
2370
|
+
|
|
1251
2371
|
// If the values are exactly the same,
|
|
1252
2372
|
// then we are no longer dirty, and
|
|
1253
2373
|
// can just return
|
|
@@ -1264,6 +2384,27 @@ class Model {
|
|
|
1264
2384
|
this.updateDirtyID();
|
|
1265
2385
|
}
|
|
1266
2386
|
|
|
2387
|
+
/// Get all the models current raw attributes.
|
|
2388
|
+
/// This will return an object, where each key
|
|
2389
|
+
/// is the `fieldName` of each non-virtual (concrete)
|
|
2390
|
+
/// field on the model, and each value is the "current"
|
|
2391
|
+
/// value of the field on the model. The "current"
|
|
2392
|
+
/// value for each field could either be a dirty field
|
|
2393
|
+
/// value, or a clean (or raw) field value.
|
|
2394
|
+
///
|
|
2395
|
+
/// This method is nearly identical to <see>Model.toJSON</see>
|
|
2396
|
+
/// except that <see>Model.toJSON</see> always adds the primary
|
|
2397
|
+
/// key to the result first, which only matters for JavaScript
|
|
2398
|
+
/// engines that honor the insertion order of keys in native
|
|
2399
|
+
/// Objects, which is never guaranteed. <see>Model.toJSON</see>
|
|
2400
|
+
/// also differs from this method by calling `field.type.serialize`
|
|
2401
|
+
/// for every attribute on the model.
|
|
2402
|
+
///
|
|
2403
|
+
/// Note:
|
|
2404
|
+
/// Field's with `undefined` values will not be included in the
|
|
2405
|
+
/// resulting object.
|
|
2406
|
+
/// Return: object
|
|
2407
|
+
/// All models attributes (field values).
|
|
1267
2408
|
getAttributes() {
|
|
1268
2409
|
let result = {};
|
|
1269
2410
|
|
|
@@ -1281,6 +2422,34 @@ class Model {
|
|
|
1281
2422
|
return result;
|
|
1282
2423
|
}
|
|
1283
2424
|
|
|
2425
|
+
/// Set attributes on the model via the provided object.
|
|
2426
|
+
/// The provided object should contain keys that are
|
|
2427
|
+
/// field names for each field you wish to set. The
|
|
2428
|
+
/// value of each key will be what is set onto the field.
|
|
2429
|
+
/// This method ignores virtual fields, so if any virtual
|
|
2430
|
+
/// field names are supplied, then will be silently skipped.
|
|
2431
|
+
/// This method is identical to calling `modelInstance[fieldName] = value`
|
|
2432
|
+
/// on every key in the object provided.
|
|
2433
|
+
///
|
|
2434
|
+
/// Note:
|
|
2435
|
+
/// Any `undefined` value in the provided object will be
|
|
2436
|
+
/// ignored, and no update will occur for the field.
|
|
2437
|
+
/// Note:
|
|
2438
|
+
/// If a raw object instead of a model instance is provided,
|
|
2439
|
+
/// then `hasOwnProperty` is called for each field name,
|
|
2440
|
+
/// and if the provided object doesn't contain its "own"
|
|
2441
|
+
/// property matching the field name, the field will be
|
|
2442
|
+
/// silently skipped, and not set.
|
|
2443
|
+
/// Return: undefined
|
|
2444
|
+
/// Arguments:
|
|
2445
|
+
/// attributes: object | Model
|
|
2446
|
+
/// The attributes to set on the model. The keys
|
|
2447
|
+
/// of the model should be field names.
|
|
2448
|
+
/// noPrimaryKey: boolean
|
|
2449
|
+
/// If `true`, then the primary key of the model
|
|
2450
|
+
/// (if any is defined) will be skipped, and won't
|
|
2451
|
+
/// be set, even if the provided `attributes` argument
|
|
2452
|
+
/// contains a value for the primary key.
|
|
1284
2453
|
setAttributes(attributes, noPrimaryKey) {
|
|
1285
2454
|
let isObject = Nife.instanceOf(attributes, 'object');
|
|
1286
2455
|
|
|
@@ -1302,6 +2471,22 @@ class Model {
|
|
|
1302
2471
|
});
|
|
1303
2472
|
}
|
|
1304
2473
|
|
|
2474
|
+
/// Checks if the primary key's value is valid.
|
|
2475
|
+
/// Validity checks are handled by the field's `type`.
|
|
2476
|
+
/// When this method is called, the primary key
|
|
2477
|
+
/// field for the model is fetched, and if found,
|
|
2478
|
+
/// the `field.type.isValidValue` method will be called
|
|
2479
|
+
/// and provided with the current value of the
|
|
2480
|
+
/// primary key field.
|
|
2481
|
+
///
|
|
2482
|
+
/// <see>Type.isValidValue</see>
|
|
2483
|
+
/// is commonly implemented to be a strict check
|
|
2484
|
+
/// against the type. `null` will generally
|
|
2485
|
+
/// return `false` for an `isValidValue` call, however
|
|
2486
|
+
/// implementation details are entirely left up to
|
|
2487
|
+
/// the `isValidValue` method defined on the type.
|
|
2488
|
+
///
|
|
2489
|
+
/// Return: boolean
|
|
1305
2490
|
hasValidPrimaryKey() {
|
|
1306
2491
|
let pkField = this.getPrimaryKeyField();
|
|
1307
2492
|
if (!pkField)
|
|
@@ -1319,6 +2504,51 @@ class Model {
|
|
|
1319
2504
|
});
|
|
1320
2505
|
}
|
|
1321
2506
|
|
|
2507
|
+
/// Validate all concrete fields on the model.
|
|
2508
|
+
/// This method is called before any "insert"
|
|
2509
|
+
/// or "update" operation happens for the model.
|
|
2510
|
+
/// It will iterate all the fields of the model,
|
|
2511
|
+
/// and call the `validate` method defined on
|
|
2512
|
+
/// each field descriptor (<see>Field</see>),
|
|
2513
|
+
/// if any is defined.
|
|
2514
|
+
/// Each `validate` method is asynchronous, so
|
|
2515
|
+
/// all promises will be collected from all `validate`
|
|
2516
|
+
/// method calls, and will be awaited upon via
|
|
2517
|
+
/// `await Promise.all(validatePromises);`.
|
|
2518
|
+
///
|
|
2519
|
+
/// Model validation will fail if any `validate`
|
|
2520
|
+
/// method throws an exception.
|
|
2521
|
+
///
|
|
2522
|
+
/// `onValidate` is called directly from <see>Model.onBeforeSave</see>,
|
|
2523
|
+
/// so make certain you call `super.onBeforeSave(...args)` if you
|
|
2524
|
+
/// overload `onBeforeSave`. If you don't, your validation hooks
|
|
2525
|
+
/// won't be called. This design was deliberate, so the developer
|
|
2526
|
+
/// could choose to bypass model validation on purpose simply
|
|
2527
|
+
/// by not calling `super.onBeforeSave(...args)` should they choose not to.
|
|
2528
|
+
///
|
|
2529
|
+
/// Feel free to overload `onValidate` to provide your own implementation.
|
|
2530
|
+
///
|
|
2531
|
+
/// Note:
|
|
2532
|
+
/// `validate` properties on fields **must** always be methods.
|
|
2533
|
+
/// Unlike other ORMs, we don't allow a pattern, a RegExp, or
|
|
2534
|
+
/// anything else. You must provide the implementation of each
|
|
2535
|
+
/// `validate` method directly yourself (which could for example
|
|
2536
|
+
/// use a RegExp to check the field's value).
|
|
2537
|
+
/// Return: Array<any>
|
|
2538
|
+
/// Results of each `validate` call from each field. Will generally
|
|
2539
|
+
/// be `undefined` for each call. The validation for a field will
|
|
2540
|
+
/// only fail if an exception is thrown. `false` or `null` as a
|
|
2541
|
+
/// return value from a `validate` call is meaningless
|
|
2542
|
+
/// (unless you yourself wish to do something with it).
|
|
2543
|
+
/// Arguments:
|
|
2544
|
+
/// context: object
|
|
2545
|
+
/// A context object that is provided to all model hooks.
|
|
2546
|
+
/// The shape of this object is `{ connection, Model, options }`.
|
|
2547
|
+
/// It will contain the current `connection` for the operation
|
|
2548
|
+
/// (which might be a transaction connection), the `Model` for
|
|
2549
|
+
/// the operation, which is the "root model" of the operation,
|
|
2550
|
+
/// not necessarily "this" model (the model whose hook is being
|
|
2551
|
+
/// called), and the "options" defined for the current operation.
|
|
1322
2552
|
async onValidate(context) {
|
|
1323
2553
|
let promises = [];
|
|
1324
2554
|
|
|
@@ -1344,31 +2574,214 @@ class Model {
|
|
|
1344
2574
|
await Promise.all(promises);
|
|
1345
2575
|
}
|
|
1346
2576
|
|
|
2577
|
+
/// Before insert model hook.
|
|
2578
|
+
///
|
|
2579
|
+
/// This method will be called on each model instance
|
|
2580
|
+
/// before it is inserted into the database. This method
|
|
2581
|
+
/// is called before dirty fields are calculated for
|
|
2582
|
+
/// the insert operation, so you can set field values
|
|
2583
|
+
/// here before insert, and they will be captured and
|
|
2584
|
+
/// inserted into the database.
|
|
2585
|
+
///
|
|
2586
|
+
/// Arguments:
|
|
2587
|
+
/// context: object
|
|
2588
|
+
/// A context object that is provided to all model hooks.
|
|
2589
|
+
/// The shape of this object is `{ connection, Model, options }`.
|
|
2590
|
+
/// It will contain the current `connection` for the operation
|
|
2591
|
+
/// (which might be a transaction connection), the `Model` for
|
|
2592
|
+
/// the operation, which is the "root model" of the operation,
|
|
2593
|
+
/// not necessarily "this" model (the model whose hook is being
|
|
2594
|
+
/// called), and the "options" defined for the current operation.
|
|
1347
2595
|
// eslint-disable-next-line no-unused-vars
|
|
1348
2596
|
async onBeforeCreate(context) {
|
|
1349
2597
|
}
|
|
1350
2598
|
|
|
2599
|
+
/// Before update model hook.
|
|
2600
|
+
///
|
|
2601
|
+
/// This method will be called on each model instance
|
|
2602
|
+
/// before it is updated in the database. This method
|
|
2603
|
+
/// is called before dirty fields are calculated for
|
|
2604
|
+
/// the update operation, so you can set field values
|
|
2605
|
+
/// here before update, and they will be captured and
|
|
2606
|
+
/// updated in the database.
|
|
2607
|
+
///
|
|
2608
|
+
/// Arguments:
|
|
2609
|
+
/// context: object
|
|
2610
|
+
/// A context object that is provided to all model hooks.
|
|
2611
|
+
/// The shape of this object is `{ connection, Model, options }`.
|
|
2612
|
+
/// It will contain the current `connection` for the operation
|
|
2613
|
+
/// (which might be a transaction connection), the `Model` for
|
|
2614
|
+
/// the operation, which is the "root model" of the operation,
|
|
2615
|
+
/// not necessarily "this" model (the model whose hook is being
|
|
2616
|
+
/// called), and the "options" defined for the current operation.
|
|
1351
2617
|
// eslint-disable-next-line no-unused-vars
|
|
1352
2618
|
async onBeforeUpdate(context) {
|
|
1353
2619
|
}
|
|
1354
2620
|
|
|
2621
|
+
/// Before save model hook.
|
|
2622
|
+
///
|
|
2623
|
+
/// This method will be called on each model instance
|
|
2624
|
+
/// before it is inserted or updated in the database.
|
|
2625
|
+
/// This method is called before dirty fields are calculated
|
|
2626
|
+
/// for the insert or update operation, so you can set field
|
|
2627
|
+
/// values here before update, and they will be captured and
|
|
2628
|
+
/// updated in the database.
|
|
2629
|
+
///
|
|
2630
|
+
/// Note:
|
|
2631
|
+
/// This is the final hook call before the insert or update
|
|
2632
|
+
/// operation sends your data off to the database.
|
|
2633
|
+
///
|
|
2634
|
+
/// Arguments:
|
|
2635
|
+
/// context: object
|
|
2636
|
+
/// A context object that is provided to all model hooks.
|
|
2637
|
+
/// The shape of this object is `{ connection, Model, options }`.
|
|
2638
|
+
/// It will contain the current `connection` for the operation
|
|
2639
|
+
/// (which might be a transaction connection), the `Model` for
|
|
2640
|
+
/// the operation, which is the "root model" of the operation,
|
|
2641
|
+
/// not necessarily "this" model (the model whose hook is being
|
|
2642
|
+
/// called), and the "options" defined for the current operation.
|
|
1355
2643
|
// eslint-disable-next-line no-unused-vars
|
|
1356
2644
|
async onBeforeSave(context) {
|
|
1357
2645
|
await this.onValidate(context);
|
|
1358
2646
|
}
|
|
1359
2647
|
|
|
2648
|
+
/// After insert model hook.
|
|
2649
|
+
///
|
|
2650
|
+
/// This method will be called on each model instance
|
|
2651
|
+
/// after it has been inserted into the database.
|
|
2652
|
+
/// This method is called **after** each model instance
|
|
2653
|
+
/// has been fully stored, marked as persisted, and marked
|
|
2654
|
+
/// as not dirty. If you set any model fields in this method,
|
|
2655
|
+
/// then the model will be marked as dirty, and will be
|
|
2656
|
+
/// re-saved at the end of the insert operation.
|
|
2657
|
+
///
|
|
2658
|
+
/// Note:
|
|
2659
|
+
/// **Use care when updating model attributes in this method**.
|
|
2660
|
+
/// At the end of each insert operation, the models just stored
|
|
2661
|
+
/// are scanned to see if any of them are dirty. If they are dirty
|
|
2662
|
+
/// they will be re-stored to the database using an update operation.
|
|
2663
|
+
/// This can happen for example if foreign keys are in use. We might
|
|
2664
|
+
/// not be able to update a foreign key field value until after the insert
|
|
2665
|
+
/// operation is completed. When a foreign key value is updated
|
|
2666
|
+
/// post-insert, then the model might again become dirty, and be
|
|
2667
|
+
/// updated post-insert. Because of this, you should be careful
|
|
2668
|
+
/// about making your model dirty in any "after" hooks, as you
|
|
2669
|
+
/// might unintentionally incur the cost of a post-insert update.
|
|
2670
|
+
///
|
|
2671
|
+
/// Arguments:
|
|
2672
|
+
/// context: object
|
|
2673
|
+
/// A context object that is provided to all model hooks.
|
|
2674
|
+
/// The shape of this object is `{ connection, Model, options }`.
|
|
2675
|
+
/// It will contain the current `connection` for the operation
|
|
2676
|
+
/// (which might be a transaction connection), the `Model` for
|
|
2677
|
+
/// the operation, which is the "root model" of the operation,
|
|
2678
|
+
/// not necessarily "this" model (the model whose hook is being
|
|
2679
|
+
/// called), and the "options" defined for the current operation.
|
|
1360
2680
|
// eslint-disable-next-line no-unused-vars
|
|
1361
2681
|
async onAfterCreate(context) {
|
|
1362
2682
|
}
|
|
1363
2683
|
|
|
2684
|
+
/// After update model hook.
|
|
2685
|
+
///
|
|
2686
|
+
/// This method will be called on each model instance
|
|
2687
|
+
/// after it has been update in the database.
|
|
2688
|
+
/// This method is called **after** each model instance
|
|
2689
|
+
/// has been fully stored, marked as persisted, and marked
|
|
2690
|
+
/// as not dirty. Unlike an insert operation, update operations
|
|
2691
|
+
/// do not have a post-operation dirty model scan and re-update.
|
|
2692
|
+
/// You can safely update model attributes in this method without
|
|
2693
|
+
/// the worry of incurring the cost of an extra store operation.
|
|
2694
|
+
/// However, if you do set model attributes in this method, then
|
|
2695
|
+
/// the model will be marked dirty when the update operation is complete.
|
|
2696
|
+
///
|
|
2697
|
+
/// Arguments:
|
|
2698
|
+
/// context: object
|
|
2699
|
+
/// A context object that is provided to all model hooks.
|
|
2700
|
+
/// The shape of this object is `{ connection, Model, options }`.
|
|
2701
|
+
/// It will contain the current `connection` for the operation
|
|
2702
|
+
/// (which might be a transaction connection), the `Model` for
|
|
2703
|
+
/// the operation, which is the "root model" of the operation,
|
|
2704
|
+
/// not necessarily "this" model (the model whose hook is being
|
|
2705
|
+
/// called), and the "options" defined for the current operation.
|
|
1364
2706
|
// eslint-disable-next-line no-unused-vars
|
|
1365
2707
|
async onAfterUpdate(context) {
|
|
1366
2708
|
}
|
|
1367
2709
|
|
|
2710
|
+
/// After insert or update model hook.
|
|
2711
|
+
///
|
|
2712
|
+
/// This method will be called on each model instance
|
|
2713
|
+
/// after it has been inserted or updated in the database.
|
|
2714
|
+
/// This method is called **after** each model instance
|
|
2715
|
+
/// has been fully stored, marked as persisted, and marked
|
|
2716
|
+
/// as not dirty. If this is an insert operation, and
|
|
2717
|
+
/// if you set any model fields in this method,
|
|
2718
|
+
/// then the model will be marked as dirty, and will be
|
|
2719
|
+
/// re-saved at the end of the insert operation.
|
|
2720
|
+
///
|
|
2721
|
+
/// Note:
|
|
2722
|
+
/// **Use care when updating model attributes in this method**.
|
|
2723
|
+
/// At the end of each insert operation, the models just stored
|
|
2724
|
+
/// are scanned to see if any of them are dirty. If they are dirty
|
|
2725
|
+
/// they will be re-stored to the database using an update operation.
|
|
2726
|
+
/// This can happen for example if foreign keys are in use. We might
|
|
2727
|
+
/// not be able to update a foreign key field value until after the insert
|
|
2728
|
+
/// operation is completed. When a foreign key value is updated
|
|
2729
|
+
/// post-insert, then the model might again become dirty, and be
|
|
2730
|
+
/// updated post-insert. Because of this, you should be careful
|
|
2731
|
+
/// about making your model dirty in any "after" hooks, as you
|
|
2732
|
+
/// might unintentionally incur the cost of a post-insert update.
|
|
2733
|
+
///
|
|
2734
|
+
/// Arguments:
|
|
2735
|
+
/// context: object
|
|
2736
|
+
/// A context object that is provided to all model hooks.
|
|
2737
|
+
/// The shape of this object is `{ connection, Model, options }`.
|
|
2738
|
+
/// It will contain the current `connection` for the operation
|
|
2739
|
+
/// (which might be a transaction connection), the `Model` for
|
|
2740
|
+
/// the operation, which is the "root model" of the operation,
|
|
2741
|
+
/// not necessarily "this" model (the model whose hook is being
|
|
2742
|
+
/// called), and the "options" defined for the current operation.
|
|
1368
2743
|
// eslint-disable-next-line no-unused-vars
|
|
1369
2744
|
async onAfterSave(context) {
|
|
1370
2745
|
}
|
|
1371
2746
|
|
|
2747
|
+
/// Persist the model to the database.
|
|
2748
|
+
///
|
|
2749
|
+
/// This method will either initiate an insert
|
|
2750
|
+
/// operation against the model (if `this.isPersisted()`
|
|
2751
|
+
/// returns `false`), or initiate an update operation (
|
|
2752
|
+
/// if `this.isPersisted()` returns `true`).
|
|
2753
|
+
///
|
|
2754
|
+
/// This method will do nothing, and immediately return
|
|
2755
|
+
/// `false` if the model is not dirty. If you provide
|
|
2756
|
+
/// the option `force: true` as a property in the `options`
|
|
2757
|
+
/// argument, then all fields will forcefully be marked as
|
|
2758
|
+
/// dirty, using the current field's value as the "dirty"
|
|
2759
|
+
/// value for each field, and then the model will be either
|
|
2760
|
+
/// inserted or updated, based on the result from `isPersisted`.
|
|
2761
|
+
/// Using `force: true` will essentially send and insert or
|
|
2762
|
+
/// update operation through the connection that will update
|
|
2763
|
+
/// ALL columns for the model row in the database, regardless
|
|
2764
|
+
/// of if they were actually dirty or not.
|
|
2765
|
+
///
|
|
2766
|
+
/// At the end of this method--assuming the operation was successful--
|
|
2767
|
+
/// `this.clearDirty()` will be called on the model instance to clear its
|
|
2768
|
+
/// dirty state, and then the model will be marked as persisted.
|
|
2769
|
+
/// Finally, `true` will be returned, letting the caller
|
|
2770
|
+
/// know the operation completed successfully.
|
|
2771
|
+
///
|
|
2772
|
+
/// Return: boolean
|
|
2773
|
+
/// `true` if the model was persisted through the database,
|
|
2774
|
+
/// or `false` otherwise. `false` doesn't mean there was an
|
|
2775
|
+
/// error. Errors will be thrown. `false` simply means that
|
|
2776
|
+
/// the model had no dirty fields, so it was never sent to
|
|
2777
|
+
/// the database.
|
|
2778
|
+
/// Arguments:
|
|
2779
|
+
/// options?: object
|
|
2780
|
+
/// Options to pass to the underlying connection
|
|
2781
|
+
/// <see>Connection.insert</see> or <see>Connection.update</see>
|
|
2782
|
+
/// call. If a `connection` property is present on this
|
|
2783
|
+
/// options object, then it will be used as the connection
|
|
2784
|
+
/// for this operation.
|
|
1372
2785
|
async save(_options) {
|
|
1373
2786
|
let options = _options || {};
|
|
1374
2787
|
|
|
@@ -1398,6 +2811,34 @@ class Model {
|
|
|
1398
2811
|
return this;
|
|
1399
2812
|
}
|
|
1400
2813
|
|
|
2814
|
+
/// Reload the model in-place.
|
|
2815
|
+
///
|
|
2816
|
+
/// This method will create a query selecting this model
|
|
2817
|
+
/// from the database by its primary key. It will then
|
|
2818
|
+
/// take the columns from the select operation, and will
|
|
2819
|
+
/// apply the values to the model's fields in-place.
|
|
2820
|
+
///
|
|
2821
|
+
/// If a row is returned from the database, then the model's
|
|
2822
|
+
/// fields will be updated, `this.clearDirty()` will be
|
|
2823
|
+
/// called to clear the dirty status of the model, and
|
|
2824
|
+
/// finally the model will be marked as persisted.
|
|
2825
|
+
///
|
|
2826
|
+
/// If no row is returned from the database, then this method
|
|
2827
|
+
/// will immediately return, and the model won't be updated.
|
|
2828
|
+
///
|
|
2829
|
+
/// If the model has no primary key field defined, then an
|
|
2830
|
+
/// exception will be thrown.
|
|
2831
|
+
///
|
|
2832
|
+
/// Note:
|
|
2833
|
+
/// A primary key is required on the model for this method
|
|
2834
|
+
/// to work. If you don't have a primary key defined, then
|
|
2835
|
+
/// you will need to create your own "reload" operation.
|
|
2836
|
+
/// Return: undefined
|
|
2837
|
+
/// Arguments:
|
|
2838
|
+
/// options?: object
|
|
2839
|
+
/// Options to pass to the underlying <see>QueryEngine.first</see>
|
|
2840
|
+
/// call. If a `connection` property is present on this options object,
|
|
2841
|
+
/// then it will be used as the connection for this operation.
|
|
1401
2842
|
async reload(options) {
|
|
1402
2843
|
let pkFieldName = this.getPrimaryKeyFieldName();
|
|
1403
2844
|
if (!pkFieldName)
|
|
@@ -1423,6 +2864,29 @@ class Model {
|
|
|
1423
2864
|
this.clearDirty();
|
|
1424
2865
|
}
|
|
1425
2866
|
|
|
2867
|
+
/// Destroy this model instance.
|
|
2868
|
+
///
|
|
2869
|
+
/// Calling this method will destroy this model from the database.
|
|
2870
|
+
/// If the model is not persisted, then nothing will happen, and
|
|
2871
|
+
/// `0` will be returned. If the model is persisted, the result
|
|
2872
|
+
/// of <see>Connection.destroy</see> is returned, which is the number
|
|
2873
|
+
/// of rows modified in the database, which in this case should always
|
|
2874
|
+
/// be `1`.
|
|
2875
|
+
///
|
|
2876
|
+
/// If the model has no primary key field defined, then an
|
|
2877
|
+
/// exception will be thrown.
|
|
2878
|
+
///
|
|
2879
|
+
/// Note:
|
|
2880
|
+
/// A primary key is required on the model for this method
|
|
2881
|
+
/// to work. If you don't have a primary key defined, then
|
|
2882
|
+
/// you will need to create your own "destroy" operation.
|
|
2883
|
+
/// Return: number
|
|
2884
|
+
/// The number of rows modified in the database.
|
|
2885
|
+
/// Arguments:
|
|
2886
|
+
/// options?: object
|
|
2887
|
+
/// Options to pass to the underlying <see>QueryEngine.destroy</see>
|
|
2888
|
+
/// call. If a `connection` property is present on this options object,
|
|
2889
|
+
/// then it will be used as the connection for this operation.
|
|
1426
2890
|
async destroy(options) {
|
|
1427
2891
|
if (!this.isPersisted())
|
|
1428
2892
|
return 0;
|
|
@@ -1434,10 +2898,26 @@ class Model {
|
|
|
1434
2898
|
return await this.getModel().getWhereWithConnection(options)[primaryKeyFieldName].EQ(this.id).destroy(options);
|
|
1435
2899
|
}
|
|
1436
2900
|
|
|
2901
|
+
/// Get a string representation of this model.
|
|
2902
|
+
///
|
|
2903
|
+
/// Return: string
|
|
2904
|
+
/// The model's name and attributes as a string.
|
|
1437
2905
|
toString() {
|
|
1438
2906
|
return `${this.getModelName()} ${JSON.stringify(this.toJSON(), undefined, 2)}`;
|
|
1439
2907
|
}
|
|
1440
2908
|
|
|
2909
|
+
/// Return a raw Object of the model's attributes,
|
|
2910
|
+
/// ready to be passed through `JSON.stringify`. This
|
|
2911
|
+
/// method is nearly identical to <see>Model.getAttributes</see>
|
|
2912
|
+
/// except that it always inserts the primary key of the model
|
|
2913
|
+
/// (if the model has one) first. The other difference
|
|
2914
|
+
/// between this method and <see>Model.getAttributes</see>
|
|
2915
|
+
/// is that this method will call `field.type.serialize` on
|
|
2916
|
+
/// each field value.
|
|
2917
|
+
///
|
|
2918
|
+
/// Return: object
|
|
2919
|
+
/// All model attributes, ready to be serialized.
|
|
2920
|
+
/// See: Type.serialize
|
|
1441
2921
|
toJSON() {
|
|
1442
2922
|
let result = {};
|
|
1443
2923
|
let pkField = this.getPrimaryKeyField();
|
|
@@ -1469,8 +2949,8 @@ class Model {
|
|
|
1469
2949
|
}
|
|
1470
2950
|
|
|
1471
2951
|
// eslint-disable-next-line no-unused-vars
|
|
1472
|
-
[Symbol.for('nodejs.util.inspect.custom')](
|
|
1473
|
-
return
|
|
2952
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
2953
|
+
return this.toJSON();
|
|
1474
2954
|
}
|
|
1475
2955
|
}
|
|
1476
2956
|
|