mythix-orm 1.8.2 → 1.8.3

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.
@@ -15,15 +15,73 @@ const LiteralBase = Literals.LiteralBase;
15
15
 
16
16
  /// ConnectionBase is the base class that
17
17
  /// all connection classes should inherit from.
18
+ /// It provides common functionality to all
19
+ /// connections, and converts literals and
20
+ /// types into their native database representation.
21
+ ///
22
+ /// A "connection" in Mythix ORM is essentially
23
+ /// the "application" for the ORM. It stores all
24
+ /// models used by the connection, stores and defines
25
+ /// the query generator (if any), converts literals
26
+ /// and types, and also provides the query engine.
27
+ ///
28
+ /// Multiple connections can be used at the same time
29
+ /// in Mythix ORM. It is also planned that someday
30
+ /// Mythix ORM (or the community) will provide a
31
+ /// multiplex connection, to mix multiple connections
32
+ /// into a single connection for the entire application.
33
+ ///
34
+ /// For now you can use multiple connections at once.
35
+ /// Just know that you should read and fully understand
36
+ /// [Connection Binding](./ConnectionBinding) if you plan
37
+ /// on using more than one connection for your application.
38
+ ///
39
+ /// ConnectionBase is also an [Event Emitter](https://nodejs.org/docs/latest-v16.x/api/events.html),
40
+ /// so you can bind events to a connection instance with `.on`, and unbind
41
+ /// with `.off`. Events are connection specific, but common events that
42
+ /// can be bound to are:
43
+ ///
44
+ /// 1. `connect` - Commonly fired when a connection is successfully established
45
+ /// 2. `acquire` - Commonly fired when a connection is acquired from a connection pool
46
+ /// 3. `error` - Commonly fired when a database level error occurs
47
+ /// 4. `disconnect` - Commonly fired when a connection is disconnected
48
+ ///
49
+ /// *This is just an example of common connection driver events.
50
+ /// Please see documentation for your specific database connection for the proper events.*
51
+ ///
52
+ /// Properties:
53
+ /// static Literals: Literals
54
+ /// All default Mythix ORM literal classes,
55
+ /// provided for convenient access.
56
+ /// static dialect: string
57
+ /// The dialect of the database, i.e. `'sqlite'`, or `'postgresql'`.
58
+ /// dialect: string
59
+ /// The dialect of the database, i.e. `'sqlite'`, or `'postgresql'`.
60
+ /// static _isMythixConnection: boolean
61
+ /// Helper for type checking methods. Should always be `true`.
18
62
  ///
19
63
  /// Alias: Connection
20
64
  class ConnectionBase extends EventEmitter {
21
65
  static Literals = Literals;
22
66
 
67
+ static DefaultQueryGenerator = QueryGeneratorBase;
68
+
23
69
  static dialect = 'none';
24
70
 
25
71
  static _isMythixConnection = true;
26
72
 
73
+ /// Use this method to check if a class
74
+ /// is a Mythix ORM connection. It will return
75
+ /// `true` if the provided value is a class
76
+ /// that inherits from <see>ConnectionBase</see>, or
77
+ /// if the provided value has an attribute
78
+ /// named `_isMythixConnection` that is truthy.
79
+ ///
80
+ /// Return: boolean
81
+ ///
82
+ /// Arguments:
83
+ /// value: Function
84
+ /// Value to check.
27
85
  static isConnectionClass(value) {
28
86
  if (!value)
29
87
  return false;
@@ -37,6 +95,22 @@ class ConnectionBase extends EventEmitter {
37
95
  return false;
38
96
  }
39
97
 
98
+ /// Check to see if the provided value is
99
+ /// an *instance* of a Mythix ORM <see>ConnectionBase</see>.
100
+ /// Unlike <see>ConnectionBase.static isConnectionClass</see>, which
101
+ /// checks if a *class* is a <see>ConnectionBase</see>, this will check
102
+ /// to see if an *instance* is an instance of a
103
+ /// Mythix ORM <see>ConnectionBase</see>. It will return
104
+ /// `true` if the provided value is an `instanceof`
105
+ /// <see>ConnectionBase</see>, or if the value's `constructor`
106
+ /// property has a truthy `_isMythixConnection` property
107
+ /// (`value.constructor._isMythixConnection`)
108
+ ///
109
+ /// Return: boolean
110
+ ///
111
+ /// Arguments:
112
+ /// value: any
113
+ /// Value to check
40
114
  static isConnection(value) {
41
115
  if (!value)
42
116
  return false;
@@ -50,20 +124,72 @@ class ConnectionBase extends EventEmitter {
50
124
  return false;
51
125
  }
52
126
 
127
+ /// Fetch a literal class by its name.
128
+ ///
129
+ /// The following is a table that displays
130
+ /// the `name` argument that can be provided,
131
+ /// and the resulting Literal class that would
132
+ /// be returned for that name.
133
+ /// | `name` | Resulting literal class |
134
+ /// | --------------- | --------------------------- |
135
+ /// | `'Average'` | <see>AverageLiteral</see> |
136
+ /// | `'Base'` | <see>LiteralBase</see> |
137
+ /// | `'Count'` | <see>CountLiteral</see> |
138
+ /// | `'Distinct'` | <see>DistinctLiteral</see> |
139
+ /// | `'Field'` | <see>FieldLiteral</see> |
140
+ /// | `'FieldBase'` | <see>LiteralFieldBase</see> |
141
+ /// | `'Literal'` | <see>Literal</see> |
142
+ /// | `'Max'` | <see>MaxLiteral</see> |
143
+ /// | `'Min'` | <see>MinLiteral</see> |
144
+ /// | `'Sum'` | <see>SumLiteral</see> |
145
+ ///
146
+ /// Arguments:
147
+ /// name: string
148
+ /// The name of the literal class to return.
149
+ ///
150
+ /// Return: class <see>LiteralBase</see>
151
+ /// Return the literal class requested.
53
152
  static getLiteralClassByName(_name) {
54
153
  if (!_name)
55
154
  return;
56
155
 
57
- let name = Nife.capitalize(_name.toLowerCase());
156
+ let Klass = Literals[_name];
157
+ if (Klass)
158
+ return Klass;
58
159
 
160
+ let name = Nife.capitalize(_name.toLowerCase());
59
161
  if (name === 'Literal')
60
162
  return Literals.Literal;
163
+ if (name === 'FieldBase')
164
+ return Literals.LiteralFieldBase;
61
165
  else if (name === 'Base')
62
166
  return Literals.LiteralBase;
63
167
 
64
168
  return Literals[`${name}Literal`];
65
169
  }
66
170
 
171
+ /// Create the literal specified by name.
172
+ ///
173
+ /// Whereas <see>ConnectionBase.static getLiteralClassByName</see> will
174
+ /// simply return the literal class specified, this will create
175
+ /// the specified literal, with the provided arguments.
176
+ ///
177
+ /// Please see <see>ConnectionBase.static getLiteralClassByName</see> for
178
+ /// possible names that can be provided as the `name` argument.
179
+ ///
180
+ /// See: ConnectionBase.static getLiteralClassByName
181
+ ///
182
+ /// Arguments:
183
+ /// name: string
184
+ /// The name of the literal to create. See
185
+ /// <see>ConnectionBase.static getLiteralClassByName</see> for
186
+ /// possible values.
187
+ /// ...args: Array<any>
188
+ /// Arguments to provide to the literal constructor.
189
+ ///
190
+ /// Return: <see>LiteralBase</see>
191
+ /// Return an instance the literal requested,
192
+ /// using the arguments specified.
67
193
  static Literal(name, ...args) {
68
194
  const LiteralClass = this.getLiteralClassByName(name);
69
195
  if (!LiteralClass)
@@ -73,6 +199,26 @@ class ConnectionBase extends EventEmitter {
73
199
  return literal;
74
200
  }
75
201
 
202
+ /// Create a connection.
203
+ ///
204
+ /// The `options` argument is generally connection
205
+ /// specific. However, there are a few generic options,
206
+ /// which you will find listed in the table below:
207
+ /// | Option | Type | Default Value | Description |
208
+ /// | ------------- | ---- | ------------- | ----------- |
209
+ /// | `bindModels` | `boolean` | `true` | If `true`, then bind the provided `models` to this connection. Models are bound to a connection by setting a static `_mythixBoundConnection` property on each model class to this connection instance. |
210
+ /// | `forceConnectionBinding` | `boolean` | `false` | Normally attempting to bind a connection to a model more than once will result in an exception being thrown. However, if you set this property to `true`, then Mythix ORM will rebind the connection without complaint, even if a connection is already bound to your models. Make sure you know what you are doing if you use this option. |
211
+ /// | `models` | `Array` or `Object` of <see>Models</see> | `undefined` | Models to provide to this connection. This can be either an array of <see>Models</see>, or an Object where each value is a <see>Model</see> |
212
+ /// | `QueryEngine` | class <see>QueryEngine</see> | <see>QueryEngine</see> | The QueryEngine class to use for this connection and all this connection's models. You can provide your own class if you wish to add onto the query interface. |
213
+ /// | `queryGenerator` | <see>QueryGenerator</see> | *Connection specific* | The query generator for this connection. If a <see>QueryGenerator</see> instance is provided (the correct one for the connection you are using), then this provided query generator will be used. If one isn't provided, then the connection will create its own query generator that is specific to the connection type. |
214
+ ///
215
+ /// Arguments:
216
+ /// options: object
217
+ /// Connection specific options to supply to your connection. These
218
+ /// will commonly include things like a hostname to connect to, a
219
+ /// user name and password, and any connection specific parameters.
220
+ ///
221
+ /// Return: <see>Connection</see>
76
222
  constructor(_options) {
77
223
  super();
78
224
 
@@ -124,6 +270,36 @@ class ConnectionBase extends EventEmitter {
124
270
  this.registerModels(options.models);
125
271
  }
126
272
 
273
+ /// This method is an internal method that parses
274
+ /// the "lock mode" options passed to a call to
275
+ /// <see>Connection.transaction</see>.
276
+ ///
277
+ /// These might be different depending on the connection driver
278
+ /// you are using. Please refer to the documentation
279
+ /// for your connection driver for more details.
280
+ ///
281
+ /// Arguments:
282
+ /// options: any
283
+ /// Possibly connection specific lock options for a
284
+ /// connection's <see>Connection.transaction</see> method.
285
+ /// Generally this will either be a `true` value, a Model name
286
+ /// (for which table to lock), or a complete lock options object,
287
+ /// which generally will look something like:
288
+ /// `{ lock: boolean; modelName: string; read: boolean; write: boolean }`
289
+ /// <br>
290
+ /// <br>`lock` - If `true`, then lock the transaction
291
+ /// <br>`modelName` - The name of the table(s) to lock
292
+ /// <br>`read` - If `true`, then lock for reads
293
+ /// <br>`write` - If `true`, then lock for writes
294
+ ///
295
+ /// Return: object
296
+ /// Return the lock options for a transaction. These might change
297
+ /// based on the connection driver you are using, but will generally
298
+ /// look like `{ lock: boolean; modelName: string; read: boolean; write: boolean }`.
299
+ /// 1. `lock` - If `true`, then lock the transaction
300
+ /// 2. `modelName` - The name of the table(s) to lock
301
+ /// 3. `read` - If `true`, then lock for reads
302
+ /// 4. `write` - If `true`, then lock for writes
127
303
  getLockMode(options) {
128
304
  if (!options)
129
305
  return { lock: false, read: false, write: false };
@@ -150,6 +326,25 @@ class ConnectionBase extends EventEmitter {
150
326
  }
151
327
  }
152
328
 
329
+ /// Get the default order for selecting rows
330
+ /// from the database. This will call the
331
+ /// Model's <see name="Model.defaultOrder">Model.static defaultOrder</see> method
332
+ /// first to see if the model specifies a default order
333
+ /// for itself. If it doesn't, then the connection
334
+ /// driver itself might specify a default order for
335
+ /// each table.
336
+ ///
337
+ /// Arguments:
338
+ /// Model: class <see>Model</see>
339
+ /// The model/table to fetch the default order for.
340
+ /// options: object
341
+ /// Operation specific options (i.e. options for a "select" call)
342
+ ///
343
+ /// Return: Array<string>
344
+ /// An array of fully qualified field names for this model should
345
+ /// be returned by this method. An empty array, `null`, or `undefined`
346
+ /// are also valid return values (in which case no order will be
347
+ /// applied to the given operation).
153
348
  getDefaultOrder(Model, options) {
154
349
  let order = Model.defaultOrder(options);
155
350
  if (!order)
@@ -172,10 +367,30 @@ class ConnectionBase extends EventEmitter {
172
367
  return order.map((value) => ((value.indexOf(':') < 0) ? `${modelName}:${value}` : value));
173
368
  }
174
369
 
370
+ /// This method is called (and often provided)
371
+ /// by the underlying database driver to see
372
+ /// if a `LIMIT` clause is allowed to appear in
373
+ /// a given context/operation.
374
+ ///
375
+ /// Arguments:
376
+ /// options: object
377
+ /// Driver specific options for the context.
378
+ ///
379
+ /// Return: boolean
175
380
  isLimitSupportedInContext(options) {
176
381
  return true;
177
382
  }
178
383
 
384
+ /// This method is called (and often provided)
385
+ /// by the underlying database driver to see
386
+ /// if an `ORDER BY` clause is allowed to appear in
387
+ /// a given context/operation.
388
+ ///
389
+ /// Arguments:
390
+ /// options: object
391
+ /// Driver specific options for the context.
392
+ ///
393
+ /// Return: boolean
179
394
  isOrderSupportedInContext(_options) {
180
395
  let options = _options || {};
181
396
  if (options.isSubQuery) {
@@ -213,14 +428,52 @@ class ConnectionBase extends EventEmitter {
213
428
  return value;
214
429
  }
215
430
 
431
+ /// Get the options for this connection.
432
+ ///
433
+ /// These will be the options provided to
434
+ /// the connection during creation, plus any
435
+ /// other options the connection driver itself
436
+ /// internally sets.
437
+ ///
438
+ /// Return: object
439
+ /// The options for this connection.
216
440
  getOptions() {
217
441
  return this._options;
218
442
  }
219
443
 
444
+ /// Check to see if `start` has already been called
445
+ /// on this connection. This is used to know if a
446
+ /// connection is "active" or not.
447
+ ///
448
+ /// Return: boolean
220
449
  isStarted() {
221
450
  return true;
222
451
  }
223
452
 
453
+ /// This will take something that can
454
+ /// be turned into a query and turn it
455
+ /// into a query.
456
+ ///
457
+ /// If a <see>QueryEngine</see> instance
458
+ /// is provided, it will simply be returned.
459
+ ///
460
+ /// If a Model is provided, then `Model.where`
461
+ /// will be returned, returning a <see>QueryEngine</see>
462
+ /// for the model provided.
463
+ ///
464
+ /// In the future this may also accept other possible
465
+ /// values that could be turned into a query.
466
+ ///
467
+ /// This is often internally called by methods of the connection
468
+ /// on a given argument provided by the user, which could validly
469
+ /// be either a model or a query. <see>Connection.destroyModels</see>
470
+ /// is one example of this.
471
+ ///
472
+ /// Arguments:
473
+ /// value: any
474
+ /// The value to attempt to turn into a <see>QueryEngine</see>.
475
+ ///
476
+ /// Return: <see>QueryEngine</see> | undefined
224
477
  toQueryEngine(_queryEngine) {
225
478
  let queryEngine = _queryEngine;
226
479
  if (!queryEngine)
@@ -236,6 +489,37 @@ class ConnectionBase extends EventEmitter {
236
489
  return queryEngine;
237
490
  }
238
491
 
492
+ /// Register the provided model class.
493
+ ///
494
+ /// This will register the provided model class with this
495
+ /// connection. The model must not already be bound to
496
+ /// another connection, or you must specify the `option`
497
+ /// `{ forceConnectionBinding: true }` if it is. You
498
+ /// can specify the `option` of `{ bindModels: false }`
499
+ /// if you don't wish to bind this model to this connection.
500
+ ///
501
+ /// Any `options` provided are optional, and will override
502
+ /// the same options provided to the connection itself when
503
+ /// it was created.
504
+ ///
505
+ /// Arguments:
506
+ /// Model: class <see>Model</see>
507
+ /// The model class to register with this connection. If not bound, then it
508
+ /// will simply exist in the model pool for this connection. If bound, then
509
+ /// this connection will bind itself to the model being registered.
510
+ /// options?: object
511
+ /// Options looks like `{ forceConnectionBinding: boolean; bindModels: boolean; }`.
512
+ /// This is an optional argument. Both options will default to the same options
513
+ /// provided to the connection when it was created. If you specify either of these
514
+ /// options they simply override the connection's default.
515
+ ///
516
+ /// Return: class <see>Model</see>
517
+ /// The registered model class, **which may have changed during registration**.
518
+ /// It is not uncommon for the connection driver itself to modify the model
519
+ /// class, or to return a new model class that inherits from your model class.
520
+ /// The class that is returned should be the class that you use for this connection,
521
+ /// and will be the same class returned by a call to <see>Connection.getModel</see>,
522
+ /// or <see>Connection.getModels</see>.
239
523
  registerModel(_Model, options) {
240
524
  let Model = _Model.bindConnection(this, options);
241
525
 
@@ -244,6 +528,37 @@ class ConnectionBase extends EventEmitter {
244
528
  return Model;
245
529
  }
246
530
 
531
+ /// Register multiple models at the same time.
532
+ ///
533
+ /// This will register the provided models with this
534
+ /// connection. The models provided must not already be bound to
535
+ /// another connection, or you must specify the `option`
536
+ /// `{ forceConnectionBinding: true }` if any of them are. You
537
+ /// can specify the `option` of `{ bindModels: false }`
538
+ /// if you don't wish to bind these models to this connection.
539
+ ///
540
+ /// Any `options` provided are optional, and will override
541
+ /// the same options provided to the connection itself when
542
+ /// it was created.
543
+ ///
544
+ /// Arguments:
545
+ /// Model: Array<class <see>Model</see>> | { [key: string]: class <see>Model</see> }
546
+ /// The model classes to register with this connection. If no models are bound, then
547
+ /// they will simply exist in the model pool for this connection. If bound, then
548
+ /// this connection will bind itself to every model being registered.
549
+ /// options?: object
550
+ /// Options looks like `{ forceConnectionBinding: boolean; bindModels: boolean; }`.
551
+ /// This is an optional argument. Both options will default to the same options
552
+ /// provided to the connection when it was created. If you specify either of these
553
+ /// options they simply override the connection's default.
554
+ ///
555
+ /// Return: class <see>Model</see>
556
+ /// The registered model classes, **which may have changed during registration**.
557
+ /// It is not uncommon for the connection driver itself to modify the model
558
+ /// classes, or to return a new model classes that inherit from your model classes.
559
+ /// The classes that are returned should be the classes that you use for this connection,
560
+ /// and will be the same classes returned by a call to <see>Connection.getModel</see>,
561
+ /// or <see>Connection.getModels</see>.
247
562
  registerModels(models, options) {
248
563
  if (!models)
249
564
  return;
@@ -310,6 +625,30 @@ class ConnectionBase extends EventEmitter {
310
625
  return Utils.setContextValue(key, value);
311
626
  }
312
627
 
628
+ /// This builds a "connection context" to provide to
629
+ /// the [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html) context
630
+ /// of a <see>Connection.createContext</see> call.
631
+ ///
632
+ /// By default, this will set a `connection` property on the context,
633
+ /// which will be the value of this connection instance. It also sets
634
+ /// a `connection` property on the sub-contexts for each model. This
635
+ /// is because models might have different connections, and so need
636
+ /// a context per-model to work properly.
637
+ ///
638
+ /// "How could a model have different connections?" you ask? Well, it
639
+ /// probably won't. But being as this is an [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html)
640
+ /// context, it provides the connection to **every** model inside the context.
641
+ /// Your application might be using other models that aren't part of this connection,
642
+ /// and we wouldn't want those to get the wrong connection for those models.
643
+ ///
644
+ /// Arguments:
645
+ /// connection?: <see>Connection</see> = this
646
+ /// The connection to create the context for. This can be provided, and
647
+ /// is used in place of `this` instance, for example, in the case of transactions.
648
+ /// Transactions generally are the "same" *connection*, but not the same *instance*.
649
+ ///
650
+ /// Return: Map<any, any>
651
+ /// The new context that will be used for <see>Connection.createContext</see>.
313
652
  buildConnectionContext(_connection) {
314
653
  let connection = _connection || this;
315
654
  let models = connection._models;
@@ -329,38 +668,118 @@ class ConnectionBase extends EventEmitter {
329
668
  return newContext;
330
669
  }
331
670
 
671
+ /// Create a connection context to serve all code
672
+ /// running inside it this connection.
673
+ ///
674
+ /// This uses [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html)
675
+ /// to create a context that is passed through the entire call stack of the callback. In this
676
+ /// way, a connection can be provided to every model and every operation within the call.
677
+ ///
678
+ /// Arguments:
679
+ /// callback: async Function
680
+ /// The method to provide the context to. Every call inside this call stack
681
+ /// will be provided the connection.
682
+ /// connection?: <see>Connection</see> = this
683
+ /// The connection to provide. Generally this will just be `this` connection instance,
684
+ /// however, it can be specified, and is for example inside transactions.
685
+ /// thisArg?: any = this
686
+ /// The `this` value to provide to the given `callback`.
687
+ ///
688
+ /// Return: any
689
+ /// The return value of the given `callback`.
332
690
  async createContext(callback, _connection, thisArg) {
333
691
  let connection = _connection || this;
334
692
  let context = this.buildConnectionContext(connection);
335
693
 
336
694
  return await Utils.runInContext(context, async () => {
337
- return await callback.call(thisArg, connection);
695
+ return await callback.call(thisArg || this, connection);
338
696
  });
339
697
  }
340
698
 
699
+ /// Find a specific field across all registered models.
700
+ ///
701
+ /// This method is similar to [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find),
702
+ /// except that the arguments to this `finder` method are those provided by
703
+ /// <see name="Model.iterateFields">Model.static iterateFields</see>. If this `finder` method
704
+ /// returns a truthy value for a given field, then that is the field that will be returned.
705
+ ///
706
+ /// Note:
707
+ /// This will search for the field across all models registered to the connection.
708
+ /// To find a specific field for a known model use <see>Connection.getField</see> instead.
709
+ ///
710
+ /// Arguments:
711
+ /// finder: Function
712
+ /// A function to assist in finding the specified field. The signature for this
713
+ /// function must match that used by <see name="Model.iterateFields">Model.static iterateFields</see>.
714
+ ///
715
+ /// Return: Field | undefined
716
+ /// The field found, if any.
341
717
  findModelField(finder) {
342
718
  let modelMap = this.getModels();
343
719
  let modelNames = Object.keys(modelMap);
344
- let results = [];
345
720
 
346
721
  for (let i = 0, il = modelNames.length; i < il; i++) {
347
722
  let modelName = modelNames[i];
348
723
  let Model = modelMap[modelName];
724
+ let value = Model.iterateFields(finder, null, false, true);
349
725
 
350
- results = results.concat(Model.iterateFields(finder));
726
+ if (value)
727
+ return value;
351
728
  }
352
-
353
- return results;
354
729
  }
355
730
 
731
+ /// This is simply a convenience method that
732
+ /// calls <see>ModelUtils.parseQualifiedName</see>.
733
+ ///
734
+ /// See: ModelUtils.parseQualifiedName
735
+ ///
736
+ /// Arguments:
737
+ /// fieldName: string
738
+ /// The field name, fully qualified field name, or model name to parse.
739
+ /// See <see>ModelUtils.parseQualifiedName</see> for more information.
740
+ ///
741
+ /// Return: object
742
+ /// The result. See <see>ModelUtils.parseQualifiedName</see> for more information.
356
743
  parseQualifiedName(str) {
357
744
  return Utils.parseQualifiedName(str);
358
745
  }
359
746
 
747
+ /// Get all models known to this connection.
748
+ /// Models are returned as a raw `Object`, and
749
+ /// so can be destructured. The keys of the returned
750
+ /// object are the model's names.
751
+ ///
752
+ /// Models can be registered to a connection with the
753
+ /// <see>ConnectionBase.registerModel</see> or
754
+ /// <see>ConnectionBase.registerModels</see> methods.
755
+ ///
756
+ /// Return: object
757
+ /// An object of all models known to the connection, where
758
+ /// each key is a model name, and each property value is
759
+ /// the model's class.
360
760
  getModels() {
361
761
  return this._models;
362
762
  }
363
763
 
764
+ /// Retrieve a single model by its name.
765
+ /// The model must be registered with this
766
+ /// connection to be found.
767
+ ///
768
+ /// Models can be registered to a connection with the
769
+ /// <see>ConnectionBase.registerModel</see> or
770
+ /// <see>ConnectionBase.registerModels</see> methods.
771
+ ///
772
+ /// This method is "fully qualified aware", meaning you
773
+ /// can pass a fully qualified name, such as "User:id"
774
+ /// and it will fetch the "User" model.
775
+ ///
776
+ /// Return: class <see>Model</see>
777
+ /// The model class found by the model's name, or
778
+ /// `undefined` if no model is found.
779
+ ///
780
+ /// Arguments:
781
+ /// modelName: string
782
+ /// The model's name, or a fully qualified field name.
364
783
  getModel(modelName) {
365
784
  if (typeof modelName === 'symbol')
366
785
  return;
@@ -369,6 +788,20 @@ class ConnectionBase extends EventEmitter {
369
788
  return this._models[def.modelName];
370
789
  }
371
790
 
791
+ /// Get a field by its fully qualified name,
792
+ /// or by a fieldName + a modelName.
793
+ ///
794
+ /// Return: <see>Field</see>
795
+ /// The field found, or `undefined` if the specified field is
796
+ /// not found.
797
+ ///
798
+ /// Arguments:
799
+ /// fieldName: string
800
+ /// Fully qualified field name. If a fully qualified field name
801
+ /// isn't provided, then you *must* provide the `modelName` argument.
802
+ /// modelName?: string
803
+ /// The name of the model that the field exists on. This argument is
804
+ /// optional if the provided `fieldName` is a fully qualified name.
372
805
  getField(fieldName, modelName) {
373
806
  let def = this.parseQualifiedName(fieldName);
374
807
  if (def.modelName == null)
@@ -381,19 +814,86 @@ class ConnectionBase extends EventEmitter {
381
814
  return Model.getField(def.fieldNames[0]);
382
815
  }
383
816
 
817
+ /// Return the <see>QueryEngine</see> class used
818
+ /// for this connection, all its models, and all
819
+ /// query operations. By default this is just the
820
+ /// built-in <see>QueryEngine</see> that Mythix ORM
821
+ /// provides. You can create your own, and provide
822
+ /// it as the `QueryEngine` option to the connection
823
+ /// when you create the connection.
824
+ ///
825
+ /// Return: class <see>QueryEngine</see>
826
+ /// The QueryEngine to use for this connection, all
827
+ /// its models, and all query operations for this
828
+ /// connection.
384
829
  getQueryEngineClass() {
385
830
  let options = this.getOptions();
386
831
  return options.QueryEngine;
387
832
  }
388
833
 
834
+ /// Get the <see>QueryGenerator</see> instance
835
+ /// for this connection, if it has one.
836
+ ///
837
+ /// All connection drivers may not have a query generator.
838
+ /// The query generator is the class that takes care of
839
+ /// generating queries for the underlying database (i.e. SQL).
840
+ /// If a query generator exists on a connection, it is very
841
+ /// likely to be unique to the connection (i.e. PostgreSQL and MySQL
842
+ /// have different query generators).
843
+ ///
844
+ /// Return: <see>QueryGenerator</see> | null
845
+ /// Return the <see>QueryGenerator</see> for this connection,
846
+ /// or return `null` if none is defined for this connection.
389
847
  getQueryGenerator() {
390
848
  return this.queryGenerator;
391
849
  }
392
850
 
851
+ /// Set the <see>QueryGenerator</see> instance for this
852
+ /// connection. This is rarely used as the <see>QueryGenerator</see>
853
+ /// is often supplied as connection options when creating
854
+ /// the connection (as the `queryGenerator` option). However,
855
+ /// it can be set to a new instance at any time with this
856
+ /// method.
857
+ ///
858
+ /// Return: undefined
859
+ ///
860
+ /// Arguments:
861
+ /// queryGenerator: <see>QueryGenerator</see> | null
862
+ /// The new <see>QueryGenerator</see> instance to use
863
+ /// for generating underlying database queries. Set
864
+ /// to `null` to specify no query generator (note:
865
+ /// this might break whatever connection you are using
866
+ /// as most connections require their query generator).
393
867
  setQueryGenerator(queryGenerator) {
394
868
  this.queryGenerator = queryGenerator;
395
869
  }
396
870
 
871
+ /// The low-level DB interface for escaping a
872
+ /// value. By default this function uses the
873
+ /// [sqlstring](https://www.npmjs.com/package/sqlstring)
874
+ /// module to escape values. However, the `escape`
875
+ /// method for whatever database the connection is
876
+ /// using should be used instead of this. This is
877
+ /// a "default implementation" that is meant as a
878
+ /// fallback when a connection doesn't provide its
879
+ /// own, but each connection should provide its own
880
+ /// when it is able.
881
+ ///
882
+ /// Note:
883
+ /// This method escapes "values" that are given in
884
+ /// the underlying query language of the database.
885
+ /// To escape identifiers, use the <see>ConnectionBase._escapeID</see>
886
+ /// instead.
887
+ ///
888
+ /// Return: string
889
+ /// The value provided, escaped for the specific
890
+ /// underlying database driver.
891
+ ///
892
+ /// Arguments:
893
+ /// value: any
894
+ /// The value to escape. This could be a number, a boolean,
895
+ /// a string, or anything else that can be provided to your
896
+ /// specific database.
397
897
  _escape(value) {
398
898
  if (Nife.instanceOf(value, 'string'))
399
899
  return `'${value.replace(/'/g, '\'\'')}'`;
@@ -401,6 +901,64 @@ class ConnectionBase extends EventEmitter {
401
901
  return SqlString.escape(value);
402
902
  }
403
903
 
904
+ /// Unlike <see>ConnectionBase._escape</see> --which is
905
+ /// a low-level interface for the database-- this method
906
+ /// will escape specific values in specific ways needed
907
+ /// by Mythix ORM. Said another way, whereas <see>ConnectionBase._escape</see>
908
+ /// is a "low level database method", this is a "high level
909
+ /// Mythix ORM" method.
910
+ ///
911
+ /// If this method is provided a literal, then it will convert
912
+ /// the literal into a string, and return the resulting string.
913
+ /// This is the purpose of the `options` argument. The `options`
914
+ /// argument will be passed to the literal's `toString` method.
915
+ ///
916
+ /// For any non-literal value, it is first passed through the
917
+ /// field's `serialize` method, for example `value = field.type.serialize(value, thisConnection);`.
918
+ /// This generally won't modify the incoming value, but it might,
919
+ /// for example, with DATE, or DATETIME types, that are modified
920
+ /// to match an acceptable format for the underlying database.
921
+ ///
922
+ /// If this method is provided a boolean, then it will return
923
+ /// an upper-cased version of the boolean as a string, i.e. `true` will be returned
924
+ /// as `'TRUE'`, and `false` will be returned as `'FALSE'`.
925
+ ///
926
+ /// If this method is provided a BigInt, then it will convert the
927
+ /// bigint into a string representation of the number, i.e. 42n will
928
+ /// be returned as `'42'`.
929
+ ///
930
+ /// If this method is provided an `Array` value, then the array
931
+ /// is processed by the connection-specific `prepareArrayValuesForSQL`
932
+ /// method. By default, this method will complete the following operations
933
+ /// on the provided array:
934
+ ///
935
+ /// 1. It will flatten the provided array into a 1D array
936
+ /// 2. It will filter the array, such that it removes `undefined`, and any value that isn't a <see>LiteralBase</see>, a `null`, a `string`, a `boolean`, a `number`, or a `bigint`
937
+ /// 3. It will further filter out duplicate values from the array, such that the processed array only contains unique values
938
+ ///
939
+ /// After the array is processed with the `prepareArrayValuesForSQL` method,
940
+ /// it will then be mapped such that each value is passed through this
941
+ /// `escape` method, and then all remaining values in the array will be
942
+ /// joined with a `,` character between each element. The idea here is that
943
+ /// if you are providing an array to the underlying database, it is usually
944
+ /// for an `IN` or `NOT IN` operator, so the result will generally be used for
945
+ /// one of these. Keep in mind however that each connection driver might escape
946
+ /// values (including arrays) differently.
947
+ ///
948
+ /// All other provided values are simply handed off to <see>ConnectionBase._escape</see>.
949
+ ///
950
+ /// Return: string
951
+ /// The escaped value, as a string.
952
+ ///
953
+ /// Arguments:
954
+ /// field: <see>Field</see>
955
+ /// The field this value is coming from.
956
+ /// value: any
957
+ /// The value to escape.
958
+ /// options?: object
959
+ /// The options to provide to a Literal's `toString`
960
+ /// method. This `options` object is only ever used
961
+ /// if the provided `value` is a Literal.
404
962
  escape(field, _value, options) {
405
963
  var value = _value;
406
964
  if (LiteralBase.isLiteral(value))
@@ -425,11 +983,49 @@ class ConnectionBase extends EventEmitter {
425
983
  return this._escape(value);
426
984
  }
427
985
 
986
+ /// Low-level database method for escaping an identifier.
987
+ /// Each database driver should provide its own version of
988
+ /// this method. This is the "default" method Mythix ORM
989
+ /// provides as a "fallback" to database drivers that don't
990
+ /// supply their own.
991
+ ///
992
+ /// It works by first stripping all quotes (single `'`, double `"`, and backtick `` ` ``)
993
+ /// from the provided `value`. After this, it will split on the period (dot) character
994
+ /// `.`, and then will map each resulting part through [sqlstring](https://www.npmjs.com/package/sqlstring)
995
+ /// `escapeId` method, finally re-joining the parts with a period `.` character.
996
+ ///
997
+ /// The extra processing is to allow for already escaped identifiers to not be double-escaped.
998
+ ///
999
+ /// Return: string
1000
+ /// The provided identifier, escaped for the underlying database.
1001
+ ///
1002
+ /// Arguments:
1003
+ /// value: string
1004
+ /// The identifier to escape.
428
1005
  _escapeID(value) {
429
1006
  let parts = value.replace(/['"`]/g, '').split(/\.+/g);
430
1007
  return parts.map((part) => SqlString.escapeId(part).replace(/^`/, '"').replace(/`$/, '"')).join('.');
431
1008
  }
432
1009
 
1010
+ /// This method is very similar to <see>ConnectionBase._escapeID</see>,
1011
+ /// except that instead of being a "low level database method" that the
1012
+ /// database driver itself provides, this is the "Mythix ORM" implementation
1013
+ /// of escaping identifiers. The only difference from <see>ConnectionBase._escapeID</see>
1014
+ /// is that if the provided value is a Literal, it will be converted to a
1015
+ /// string and returned *without* being escaped. Literals are never modified,
1016
+ /// and are always provided to the underlying database exactly as they were defined.
1017
+ ///
1018
+ /// Return: string
1019
+ /// The escaped identifier, or if `value` is a Literal, the Literal
1020
+ /// converted to a string.
1021
+ ///
1022
+ /// Arguments:
1023
+ /// value: string
1024
+ /// The identifier to escape. If this is a Literal instead of a string,
1025
+ /// then the Literal will be converted to a string and returned.
1026
+ /// options?: object
1027
+ /// The options to pass to `Literal.toString`. This options object is only
1028
+ /// used if the provided `value` is a Literal instance.
433
1029
  escapeID(value, options) {
434
1030
  if (LiteralBase.isLiteral(value))
435
1031
  return value.toString(this.connection, options);
@@ -437,6 +1033,34 @@ class ConnectionBase extends EventEmitter {
437
1033
  return this._escapeID(value);
438
1034
  }
439
1035
 
1036
+ /// Convert the provided <see>AverageLiteral</see> to a string
1037
+ /// for the underlying database driver. The conversion
1038
+ /// will be database specific. The database driver connection
1039
+ /// is free to override this method.
1040
+ ///
1041
+ /// Note:
1042
+ /// This method is a proxy method for <see>QueryGenerator._averageLiteralToString</see>.
1043
+ /// If the connection has no instance of a `queryGenerator` available to it,
1044
+ /// then this method will simply return `undefined`.
1045
+ ///
1046
+ /// Note:
1047
+ /// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
1048
+ /// needed or used directly by the user, but instead are used by the underlying
1049
+ /// connection itself, to define context specific options. For example, the underlying
1050
+ /// connection might have an option to tell a literal that it is the "DEFAULT" value
1051
+ /// of a field, instead of just a raw value to inject in the generated query stream,
1052
+ /// and this might change the output of the literal when converted to a string.
1053
+ ///
1054
+ /// Return: string
1055
+ /// The provided <see>AverageLiteral</see> converted to
1056
+ /// a string for the underlying database driver.
1057
+ ///
1058
+ /// Arguments:
1059
+ /// literal: <see>AverageLiteral</see>
1060
+ /// The literal to convert to a string for the database.
1061
+ /// options?: object
1062
+ /// Optional options to pass to the <see>QueryGenerator._averageLiteralToString</see>
1063
+ /// method.
440
1064
  _averageLiteralToString(literal, options) {
441
1065
  if (!literal || !LiteralBase.isLiteral(literal))
442
1066
  return;
@@ -448,6 +1072,34 @@ class ConnectionBase extends EventEmitter {
448
1072
  return queryGenerator._averageLiteralToString(literal, options);
449
1073
  }
450
1074
 
1075
+ /// Convert the provided <see>CountLiteral</see> to a string
1076
+ /// for the underlying database driver. The conversion
1077
+ /// will be database specific. The database driver connection
1078
+ /// is free to override this method.
1079
+ ///
1080
+ /// Note:
1081
+ /// This method is a proxy method for <see>QueryGenerator._countLiteralToString</see>.
1082
+ /// If the connection has no instance of a `queryGenerator` available to it,
1083
+ /// then this method will simply return `undefined`.
1084
+ ///
1085
+ /// Note:
1086
+ /// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
1087
+ /// needed or used directly by the user, but instead are used by the underlying
1088
+ /// connection itself, to define context specific options. For example, the underlying
1089
+ /// connection might have an option to tell a literal that it is the "DEFAULT" value
1090
+ /// of a field, instead of just a raw value to inject in the generated query stream,
1091
+ /// and this might change the output of the literal when converted to a string.
1092
+ ///
1093
+ /// Return: string
1094
+ /// The provided <see>CountLiteral</see> converted to
1095
+ /// a string for the underlying database driver.
1096
+ ///
1097
+ /// Arguments:
1098
+ /// literal: <see>CountLiteral</see>
1099
+ /// The literal to convert to a string for the database.
1100
+ /// options?: object
1101
+ /// Optional options to pass to the <see>QueryGenerator._countLiteralToString</see>
1102
+ /// method.
451
1103
  _countLiteralToString(literal, options) {
452
1104
  if (!literal || !LiteralBase.isLiteral(literal))
453
1105
  return;
@@ -459,6 +1111,34 @@ class ConnectionBase extends EventEmitter {
459
1111
  return queryGenerator._countLiteralToString(literal, options);
460
1112
  }
461
1113
 
1114
+ /// Convert the provided <see>DistinctLiteral</see> to a string
1115
+ /// for the underlying database driver. The conversion
1116
+ /// will be database specific. The database driver connection
1117
+ /// is free to override this method.
1118
+ ///
1119
+ /// Note:
1120
+ /// This method is a proxy method for <see>QueryGenerator._distinctLiteralToString</see>.
1121
+ /// If the connection has no instance of a `queryGenerator` available to it,
1122
+ /// then this method will simply return `undefined`.
1123
+ ///
1124
+ /// Note:
1125
+ /// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
1126
+ /// needed or used directly by the user, but instead are used by the underlying
1127
+ /// connection itself, to define context specific options. For example, the underlying
1128
+ /// connection might have an option to tell a literal that it is the "DEFAULT" value
1129
+ /// of a field, instead of just a raw value to inject in the generated query stream,
1130
+ /// and this might change the output of the literal when converted to a string.
1131
+ ///
1132
+ /// Return: string
1133
+ /// The provided <see>DistinctLiteral</see> converted to
1134
+ /// a string for the underlying database driver.
1135
+ ///
1136
+ /// Arguments:
1137
+ /// literal: <see>DistinctLiteral</see>
1138
+ /// The literal to convert to a string for the database.
1139
+ /// options?: object
1140
+ /// Optional options to pass to the <see>QueryGenerator._distinctLiteralToString</see>
1141
+ /// method.
462
1142
  _distinctLiteralToString(literal, options) {
463
1143
  if (!literal || !LiteralBase.isLiteral(literal))
464
1144
  return;
@@ -470,6 +1150,34 @@ class ConnectionBase extends EventEmitter {
470
1150
  return queryGenerator._distinctLiteralToString(literal, options);
471
1151
  }
472
1152
 
1153
+ /// Convert the provided <see>FieldLiteral</see> to a string
1154
+ /// for the underlying database driver. The conversion
1155
+ /// will be database specific. The database driver connection
1156
+ /// is free to override this method.
1157
+ ///
1158
+ /// Note:
1159
+ /// This method is a proxy method for <see>QueryGenerator._fieldLiteralToString</see>.
1160
+ /// If the connection has no instance of a `queryGenerator` available to it,
1161
+ /// then this method will simply return `undefined`.
1162
+ ///
1163
+ /// Note:
1164
+ /// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
1165
+ /// needed or used directly by the user, but instead are used by the underlying
1166
+ /// connection itself, to define context specific options. For example, the underlying
1167
+ /// connection might have an option to tell a literal that it is the "DEFAULT" value
1168
+ /// of a field, instead of just a raw value to inject in the generated query stream,
1169
+ /// and this might change the output of the literal when converted to a string.
1170
+ ///
1171
+ /// Return: string
1172
+ /// The provided <see>FieldLiteral</see> converted to
1173
+ /// a string for the underlying database driver.
1174
+ ///
1175
+ /// Arguments:
1176
+ /// literal: <see>FieldLiteral</see>
1177
+ /// The literal to convert to a string for the database.
1178
+ /// options?: object
1179
+ /// Optional options to pass to the <see>QueryGenerator._fieldLiteralToString</see>
1180
+ /// method.
473
1181
  _fieldLiteralToString(literal, options) {
474
1182
  if (!literal || !LiteralBase.isLiteral(literal))
475
1183
  return;
@@ -481,6 +1189,34 @@ class ConnectionBase extends EventEmitter {
481
1189
  return queryGenerator._fieldLiteralToString(literal, options);
482
1190
  }
483
1191
 
1192
+ /// Convert the provided <see>MaxLiteral</see> to a string
1193
+ /// for the underlying database driver. The conversion
1194
+ /// will be database specific. The database driver connection
1195
+ /// is free to override this method.
1196
+ ///
1197
+ /// Note:
1198
+ /// This method is a proxy method for <see>QueryGenerator._maxLiteralToString</see>.
1199
+ /// If the connection has no instance of a `queryGenerator` available to it,
1200
+ /// then this method will simply return `undefined`.
1201
+ ///
1202
+ /// Note:
1203
+ /// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
1204
+ /// needed or used directly by the user, but instead are used by the underlying
1205
+ /// connection itself, to define context specific options. For example, the underlying
1206
+ /// connection might have an option to tell a literal that it is the "DEFAULT" value
1207
+ /// of a field, instead of just a raw value to inject in the generated query stream,
1208
+ /// and this might change the output of the literal when converted to a string.
1209
+ ///
1210
+ /// Return: string
1211
+ /// The provided <see>MaxLiteral</see> converted to
1212
+ /// a string for the underlying database driver.
1213
+ ///
1214
+ /// Arguments:
1215
+ /// literal: <see>MaxLiteral</see>
1216
+ /// The literal to convert to a string for the database.
1217
+ /// options?: object
1218
+ /// Optional options to pass to the <see>QueryGenerator._maxLiteralToString</see>
1219
+ /// method.
484
1220
  _maxLiteralToString(literal, options) {
485
1221
  if (!literal || !LiteralBase.isLiteral(literal))
486
1222
  return;
@@ -492,6 +1228,34 @@ class ConnectionBase extends EventEmitter {
492
1228
  return queryGenerator._maxLiteralToString(literal, options);
493
1229
  }
494
1230
 
1231
+ /// Convert the provided <see>MinLiteral</see> to a string
1232
+ /// for the underlying database driver. The conversion
1233
+ /// will be database specific. The database driver connection
1234
+ /// is free to override this method.
1235
+ ///
1236
+ /// Note:
1237
+ /// This method is a proxy method for <see>QueryGenerator._minLiteralToString</see>.
1238
+ /// If the connection has no instance of a `queryGenerator` available to it,
1239
+ /// then this method will simply return `undefined`.
1240
+ ///
1241
+ /// Note:
1242
+ /// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
1243
+ /// needed or used directly by the user, but instead are used by the underlying
1244
+ /// connection itself, to define context specific options. For example, the underlying
1245
+ /// connection might have an option to tell a literal that it is the "DEFAULT" value
1246
+ /// of a field, instead of just a raw value to inject in the generated query stream,
1247
+ /// and this might change the output of the literal when converted to a string.
1248
+ ///
1249
+ /// Return: string
1250
+ /// The provided <see>MinLiteral</see> converted to
1251
+ /// a string for the underlying database driver.
1252
+ ///
1253
+ /// Arguments:
1254
+ /// literal: <see>MinLiteral</see>
1255
+ /// The literal to convert to a string for the database.
1256
+ /// options?: object
1257
+ /// Optional options to pass to the <see>QueryGenerator._minLiteralToString</see>
1258
+ /// method.
495
1259
  _minLiteralToString(literal, options) {
496
1260
  if (!literal || !LiteralBase.isLiteral(literal))
497
1261
  return;
@@ -503,6 +1267,34 @@ class ConnectionBase extends EventEmitter {
503
1267
  return queryGenerator._minLiteralToString(literal, options);
504
1268
  }
505
1269
 
1270
+ /// Convert the provided <see>SumLiteral</see> to a string
1271
+ /// for the underlying database driver. The conversion
1272
+ /// will be database specific. The database driver connection
1273
+ /// is free to override this method.
1274
+ ///
1275
+ /// Note:
1276
+ /// This method is a proxy method for <see>QueryGenerator._sumLiteralToString</see>.
1277
+ /// If the connection has no instance of a `queryGenerator` available to it,
1278
+ /// then this method will simply return `undefined`.
1279
+ ///
1280
+ /// Note:
1281
+ /// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
1282
+ /// needed or used directly by the user, but instead are used by the underlying
1283
+ /// connection itself, to define context specific options. For example, the underlying
1284
+ /// connection might have an option to tell a literal that it is the "DEFAULT" value
1285
+ /// of a field, instead of just a raw value to inject in the generated query stream,
1286
+ /// and this might change the output of the literal when converted to a string.
1287
+ ///
1288
+ /// Return: string
1289
+ /// The provided <see>SumLiteral</see> converted to
1290
+ /// a string for the underlying database driver.
1291
+ ///
1292
+ /// Arguments:
1293
+ /// literal: <see>SumLiteral</see>
1294
+ /// The literal to convert to a string for the database.
1295
+ /// options?: object
1296
+ /// Optional options to pass to the <see>QueryGenerator._sumLiteralToString</see>
1297
+ /// method.
506
1298
  _sumLiteralToString(literal, options) {
507
1299
  if (!literal || !LiteralBase.isLiteral(literal))
508
1300
  return;
@@ -514,6 +1306,35 @@ class ConnectionBase extends EventEmitter {
514
1306
  return queryGenerator._sumLiteralToString(literal, options);
515
1307
  }
516
1308
 
1309
+ /// Convert the provided Literal to a string
1310
+ /// for the underlying database driver. The conversion
1311
+ /// will be database specific. The database driver connection
1312
+ /// is free to override this method.
1313
+ ///
1314
+ /// This method will convert a <see>AverageLiteral</see>, a
1315
+ /// <see>CountLiteral</see>, a <see>DistinctLiteral</see>,
1316
+ /// a <see>FieldLiteral</see>, a <see>MaxLiteral</see>, a
1317
+ /// <see>MinLiteral</see>, a <see>SumLiteral</see>, or a
1318
+ /// <see>Literal</see> to a string. If the provided literal
1319
+ /// is not one of these types, than an exception will be thrown.
1320
+ ///
1321
+ /// If you want to add custom literals to your application, then
1322
+ /// you will need to overload this method, and handle those custom
1323
+ /// literals manually (or simply stick to using <see>Literal</see>).
1324
+ ///
1325
+ /// Return: string
1326
+ /// The provided literal, converted to a string for the underlying
1327
+ /// database driver.
1328
+ ///
1329
+ /// Arguments:
1330
+ /// literal: <see>LiteralBase</see>
1331
+ /// The literal to convert.
1332
+ /// options?: object
1333
+ /// Optional options that can be passed to the literal conversion
1334
+ /// method. These are generally not provided by the user, but rather
1335
+ /// are often provided by the connection itself, for context-specific
1336
+ /// literal conversions. These options can and will changed based on
1337
+ /// the literal being converted, and the underlying connection.
517
1338
  literalToString(literal, options) {
518
1339
  if (Literals.AverageLiteral.isLiteralType(literal))
519
1340
  return this._averageLiteralToString(literal, options);
@@ -535,86 +1356,308 @@ class ConnectionBase extends EventEmitter {
535
1356
  throw new Error(`${this.constructor.name}::literalToString: Unsupported literal ${literal}.`);
536
1357
  }
537
1358
 
1359
+ /// Convert a "BIGINT" field type to a type
1360
+ /// acceptable by the underlying database driver.
1361
+ ///
1362
+ /// For most SQL connections this would be `BIGINT`,
1363
+ /// however, it may be different based on what database you are using.
1364
+ ///
1365
+ /// Return: string
1366
+ /// The field type needed by the underlying database driver.
1367
+ ///
1368
+ /// Arguments:
1369
+ /// type: <see>Type</see>
1370
+ /// The field type to convert to use in the underlying database.
538
1371
  // eslint-disable-next-line no-unused-vars
539
1372
  _bigintTypeToString(type) {
540
1373
  return 'BIGINT';
541
1374
  }
542
1375
 
1376
+ /// Convert a "BLOB" field type to a type
1377
+ /// acceptable by the underlying database driver.
1378
+ ///
1379
+ /// For most SQL connections this would be `BLOB`,
1380
+ /// however, it may be different based on what database you are using.
1381
+ ///
1382
+ /// Return: string
1383
+ /// The field type needed by the underlying database driver.
1384
+ ///
1385
+ /// Arguments:
1386
+ /// type: <see>Type</see>
1387
+ /// The field type to convert to use in the underlying database.
543
1388
  // eslint-disable-next-line no-unused-vars
544
1389
  _blobTypeToString(type) {
545
1390
  return 'BLOB';
546
1391
  }
547
1392
 
1393
+ /// Convert a "BOOLEAN" field type to a type
1394
+ /// acceptable by the underlying database driver.
1395
+ ///
1396
+ /// For most SQL connections this would be `BOOLEAN`,
1397
+ /// however, it may be different based on what database you are using.
1398
+ ///
1399
+ /// Return: string
1400
+ /// The field type needed by the underlying database driver.
1401
+ ///
1402
+ /// Arguments:
1403
+ /// type: <see>Type</see>
1404
+ /// The field type to convert to use in the underlying database.
548
1405
  // eslint-disable-next-line no-unused-vars
549
1406
  _booleanTypeToString(type) {
550
1407
  return 'BOOLEAN';
551
1408
  }
552
1409
 
1410
+ /// Convert a "CHAR" field type to a type
1411
+ /// acceptable by the underlying database driver.
1412
+ ///
1413
+ /// For most SQL connections this would be `CHAR`,
1414
+ /// however, it may be different based on what database you are using.
1415
+ ///
1416
+ /// Return: string
1417
+ /// The field type needed by the underlying database driver.
1418
+ ///
1419
+ /// Arguments:
1420
+ /// type: <see>Type</see>
1421
+ /// The field type to convert to use in the underlying database.
553
1422
  // eslint-disable-next-line no-unused-vars
554
1423
  _charTypeToString(type) {
555
1424
  return 'CHAR';
556
1425
  }
557
1426
 
1427
+ /// Convert a "DATE" field type to a type
1428
+ /// acceptable by the underlying database driver.
1429
+ ///
1430
+ /// For most SQL connections this would be `BIGINT`,
1431
+ /// however, it may be different based on what database you are using.
1432
+ ///
1433
+ /// Note:
1434
+ /// Mythix ORM always stores DATE and DATETIME types as a timestamp
1435
+ /// (in milliseconds from the UNIX Epoch) whenever it is able to.
1436
+ /// This is why the default type for most connection drivers is
1437
+ /// `BIGINT`. Another common type for this conversion is `TIMESTAMP`.
1438
+ ///
1439
+ /// Return: string
1440
+ /// The field type needed by the underlying database driver.
1441
+ ///
1442
+ /// Arguments:
1443
+ /// type: <see>Type</see>
1444
+ /// The field type to convert to use in the underlying database.
558
1445
  // eslint-disable-next-line no-unused-vars
559
1446
  _dateTypeToString(type) {
560
1447
  return 'TIMESTAMP';
561
1448
  }
562
1449
 
1450
+ /// Convert a "DATETIME" field type to a type
1451
+ /// acceptable by the underlying database driver.
1452
+ ///
1453
+ /// For most SQL connections this would be `BIGINT`,
1454
+ /// however, it may be different based on what database you are using.
1455
+ ///
1456
+ /// Note:
1457
+ /// Mythix ORM always stores DATE and DATETIME types as a timestamp
1458
+ /// (in milliseconds from the UNIX Epoch) whenever it is able to.
1459
+ /// This is why the default type for most connection drivers is
1460
+ /// `BIGINT`. Another common type for this conversion is `TIMESTAMP`.
1461
+ ///
1462
+ /// Return: string
1463
+ /// The field type needed by the underlying database driver.
1464
+ ///
1465
+ /// Arguments:
1466
+ /// type: <see>Type</see>
1467
+ /// The field type to convert to use in the underlying database.
563
1468
  // eslint-disable-next-line no-unused-vars
564
1469
  _datetimeTypeToString(type) {
565
1470
  return 'TIMESTAMP';
566
1471
  }
567
1472
 
1473
+ /// Convert a "NUMERIC" field type to a type
1474
+ /// acceptable by the underlying database driver.
1475
+ ///
1476
+ /// For most SQL connections this would be `NUMERIC`, `DECIMAL`,
1477
+ /// or `NUMBER`, however, it may be different based on what database
1478
+ /// you are using.
1479
+ ///
1480
+ /// Return: string
1481
+ /// The field type needed by the underlying database driver.
1482
+ ///
1483
+ /// Arguments:
1484
+ /// type: <see>Type</see>
1485
+ /// The field type to convert to use in the underlying database.
568
1486
  // eslint-disable-next-line no-unused-vars
569
1487
  _numericTypeToString(type) {
570
1488
  return `NUMERIC(${type.precision}, ${type.scale})`;
571
1489
  }
572
1490
 
1491
+ /// Convert a "REAL" field type to a type
1492
+ /// acceptable by the underlying database driver.
1493
+ ///
1494
+ /// For most SQL connections this would be `FLOAT`,
1495
+ /// however, it may be different based on what database you are using.
1496
+ ///
1497
+ /// Return: string
1498
+ /// The field type needed by the underlying database driver.
1499
+ ///
1500
+ /// Arguments:
1501
+ /// type: <see>Type</see>
1502
+ /// The field type to convert to use in the underlying database.
573
1503
  // eslint-disable-next-line no-unused-vars
574
1504
  _realTypeToString(type) {
575
1505
  return 'FLOAT';
576
1506
  }
577
1507
 
1508
+ /// Convert a "INTEGER" field type to a type
1509
+ /// acceptable by the underlying database driver.
1510
+ ///
1511
+ /// For most SQL connections this would be `INTEGER`,
1512
+ /// however, it may be different based on what database you are using.
1513
+ ///
1514
+ /// Return: string
1515
+ /// The field type needed by the underlying database driver.
1516
+ ///
1517
+ /// Arguments:
1518
+ /// type: <see>Type</see>
1519
+ /// The field type to convert to use in the underlying database.
578
1520
  // eslint-disable-next-line no-unused-vars
579
1521
  _integerTypeToString(type) {
580
1522
  return 'INTEGER';
581
1523
  }
582
1524
 
1525
+ /// Convert a "STRING" field type to a type
1526
+ /// acceptable by the underlying database driver.
1527
+ ///
1528
+ /// For most SQL connections this would be `VARCHAR`,
1529
+ /// however, it may be different based on what database you are using.
1530
+ ///
1531
+ /// Return: string
1532
+ /// The field type needed by the underlying database driver.
1533
+ ///
1534
+ /// Arguments:
1535
+ /// type: <see>Type</see>
1536
+ /// The field type to convert to use in the underlying database.
583
1537
  // eslint-disable-next-line no-unused-vars
584
1538
  _stringTypeToString(type) {
585
1539
  return `VARCHAR(${type.length})`;
586
1540
  }
587
1541
 
1542
+ /// Convert a "TEXT" field type to a type
1543
+ /// acceptable by the underlying database driver.
1544
+ ///
1545
+ /// For most SQL connections this would be `TEXT`,
1546
+ /// however, it may be different based on what database you are using.
1547
+ ///
1548
+ /// Return: string
1549
+ /// The field type needed by the underlying database driver.
1550
+ ///
1551
+ /// Arguments:
1552
+ /// type: <see>Type</see>
1553
+ /// The field type to convert to use in the underlying database.
588
1554
  // eslint-disable-next-line no-unused-vars
589
1555
  _textTypeToString(type) {
590
1556
  return 'TEXT';
591
1557
  }
592
1558
 
1559
+ /// Convert a "UUIDV1" field type to a type
1560
+ /// acceptable by the underlying database driver.
1561
+ ///
1562
+ /// For most SQL connections this would be `VARCHAR`,
1563
+ /// however, it may be different based on what database you are using.
1564
+ ///
1565
+ /// Return: string
1566
+ /// The field type needed by the underlying database driver.
1567
+ ///
1568
+ /// Arguments:
1569
+ /// type: <see>Type</see>
1570
+ /// The field type to convert to use in the underlying database.
593
1571
  // eslint-disable-next-line no-unused-vars
594
1572
  _uuidV1TypeToString(type) {
595
1573
  return `VARCHAR(${type.getTotalLength()})`;
596
1574
  }
597
1575
 
1576
+ /// Convert a "UUIDV3" field type to a type
1577
+ /// acceptable by the underlying database driver.
1578
+ ///
1579
+ /// For most SQL connections this would be `VARCHAR`,
1580
+ /// however, it may be different based on what database you are using.
1581
+ ///
1582
+ /// Return: string
1583
+ /// The field type needed by the underlying database driver.
1584
+ ///
1585
+ /// Arguments:
1586
+ /// type: <see>Type</see>
1587
+ /// The field type to convert to use in the underlying database.
598
1588
  // eslint-disable-next-line no-unused-vars
599
1589
  _uuidV3TypeToString(type) {
600
1590
  return `VARCHAR(${type.getTotalLength()})`;
601
1591
  }
602
1592
 
1593
+ /// Convert a "UUIDV4" field type to a type
1594
+ /// acceptable by the underlying database driver.
1595
+ ///
1596
+ /// For most SQL connections this would be `VARCHAR`,
1597
+ /// however, it may be different based on what database you are using.
1598
+ ///
1599
+ /// Return: string
1600
+ /// The field type needed by the underlying database driver.
1601
+ ///
1602
+ /// Arguments:
1603
+ /// type: <see>Type</see>
1604
+ /// The field type to convert to use in the underlying database.
603
1605
  // eslint-disable-next-line no-unused-vars
604
1606
  _uuidV4TypeToString(type) {
605
1607
  return `VARCHAR(${type.getTotalLength()})`;
606
1608
  }
607
1609
 
1610
+ /// Convert a "UUIDV5" field type to a type
1611
+ /// acceptable by the underlying database driver.
1612
+ ///
1613
+ /// For most SQL connections this would be `VARCHAR`,
1614
+ /// however, it may be different based on what database you are using.
1615
+ ///
1616
+ /// Return: string
1617
+ /// The field type needed by the underlying database driver.
1618
+ ///
1619
+ /// Arguments:
1620
+ /// type: <see>Type</see>
1621
+ /// The field type to convert to use in the underlying database.
608
1622
  // eslint-disable-next-line no-unused-vars
609
1623
  _uuidV5TypeToString(type) {
610
1624
  return `VARCHAR(${type.getTotalLength()})`;
611
1625
  }
612
1626
 
1627
+ /// Convert a "XID" field type to a type
1628
+ /// acceptable by the underlying database driver.
1629
+ ///
1630
+ /// For most SQL connections this would be `VARCHAR`,
1631
+ /// however, it may be different based on what database you are using.
1632
+ ///
1633
+ /// Return: string
1634
+ /// The field type needed by the underlying database driver.
1635
+ ///
1636
+ /// Arguments:
1637
+ /// type: <see>Type</see>
1638
+ /// The field type to convert to use in the underlying database.
613
1639
  // eslint-disable-next-line no-unused-vars
614
1640
  _xidTypeToString(type) {
615
1641
  return `VARCHAR(${type.getTotalLength()})`;
616
1642
  }
617
1643
 
1644
+ /// Convert any field type to the type needed for the underlying
1645
+ /// database driver. Only built-in Mythix ORM fields are supported.
1646
+ /// If a custom field type that is not supported is provided then
1647
+ /// an exception will be thrown.
1648
+ ///
1649
+ /// If you need to support a custom field type, simply subclass the
1650
+ /// connection you are using, and overload this method to handle
1651
+ /// your custom field types.
1652
+ ///
1653
+ /// Return: string
1654
+ /// The field type needed by the underlying database driver.
1655
+ ///
1656
+ /// Arguments:
1657
+ /// type: <see>Type</see>
1658
+ /// The field type to convert to use in the underlying database.
1659
+ /// options?: object
1660
+ /// Optional options to pass to the underlying conversion method.
618
1661
  typeToString(type, options) {
619
1662
  if (Types.BigIntType.isSameType(type))
620
1663
  return this._bigintTypeToString(type, options);
@@ -652,6 +1695,37 @@ class ConnectionBase extends EventEmitter {
652
1695
  throw new Error(`${this.constructor.name}::typeToString: Unsupported type ${type}.`);
653
1696
  }
654
1697
 
1698
+ /// Convert a given "time" type object to
1699
+ /// the value needed by the underlying database.
1700
+ ///
1701
+ /// By default this method will take a
1702
+ /// Luxon `DateTime` instance, or a `Date` instance,
1703
+ /// and convert it to the value needed by the
1704
+ /// underlying field in the database. This is
1705
+ /// generally a `BIGINT`, or `TIMESTAMP` value,
1706
+ /// as Mythix ORM will always try to store dates
1707
+ /// and times as millisecond timestamps
1708
+ /// (number of milliseconds since the UNIX Epoch).
1709
+ ///
1710
+ /// If a `number`, `bigint`, or a `string` type is
1711
+ /// provided, then Mythix ORM will use Luxon to try
1712
+ /// and parse the provided value. If the value is parsed
1713
+ /// correctly, it will then be converted to the proper
1714
+ /// value as needed by the underlying field in the database.
1715
+ ///
1716
+ /// Return: any
1717
+ /// Return the value needed by the underlying database field.
1718
+ /// Generally this will be a `bigint` type that is returned,
1719
+ /// but may be something different depending on the field and
1720
+ /// the database itself.
1721
+ ///
1722
+ /// Arguments:
1723
+ /// value: any
1724
+ /// The incoming date/time type to convert to the proper
1725
+ /// database value for the underlying field.
1726
+ /// type: <see>Type</see>
1727
+ /// The field type that this conversion is for. This will
1728
+ /// generally be a `DATE` or `DATETIME` type.
655
1729
  convertDateToDBTime(value, type) {
656
1730
  if (Nife.instanceOf(value, 'number'))
657
1731
  return value;
@@ -667,6 +1741,35 @@ class ConnectionBase extends EventEmitter {
667
1741
  return value;
668
1742
  }
669
1743
 
1744
+ /// This method will ensure all provided "models"
1745
+ /// are instances of the provided model class.
1746
+ ///
1747
+ /// This method is used by the `insert`, `upsert`, and `update`
1748
+ /// methods of the connection to ensure every model
1749
+ /// provided by the user is an actual model instance.
1750
+ ///
1751
+ /// For example, it is perfectly valid to create a model
1752
+ /// like `await Model.create({ ...attributes })`. As you
1753
+ /// can see, the provided "model" is actually just a raw
1754
+ /// object. Nearly any call in Mythix ORM will accept a
1755
+ /// raw object in-place of a model instance, and this
1756
+ /// method is used to ensure all provided "models" are
1757
+ /// actually model instances.
1758
+ ///
1759
+ /// Return: Array<Model>
1760
+ /// Return all provided models, converted to model instances.
1761
+ /// Any provided model that is already a model instance will
1762
+ /// not be modified, and instead will simply be returned.
1763
+ ///
1764
+ /// Arguments:
1765
+ /// Model: class <see>Model</see>
1766
+ /// The model class to use for instantiating models.
1767
+ /// models: object | <see>Model</see> | Array<Model | object>
1768
+ /// The models to convert to model instances (if needed).
1769
+ /// options: object
1770
+ /// Options for the operation. This options object is used
1771
+ /// to pass the `startIndex` and `endIndex` (or `batchSize`)
1772
+ /// as provided by the user when calling `insert`, `upsert`, or `update`.
670
1773
  ensureAllModelsAreInstances(Model, _models, options) {
671
1774
  if (!_models)
672
1775
  return [];
@@ -696,6 +1799,38 @@ class ConnectionBase extends EventEmitter {
696
1799
  return instantiatedModels;
697
1800
  }
698
1801
 
1802
+ /// This method will prepare all provided models for
1803
+ /// an `insert`, `upsert`, or `update` operation.
1804
+ ///
1805
+ /// What it does is ensure every provided model is a model
1806
+ /// instance, checks if the model is persisted, and if each
1807
+ /// model has dirty fields.
1808
+ ///
1809
+ /// Models that are persisted and not dirty will be filtered out,
1810
+ /// so that proceeding operations will "ignore" them entirely.
1811
+ ///
1812
+ /// All dirty fields across all models are combined into a unified
1813
+ /// list of dirty fields. This unified list is then used for the list
1814
+ /// of columns in an `insert`, `upsert`, or `updateAll` operation.
1815
+ ///
1816
+ /// Return: PreparedModels
1817
+ /// Return an object with the shape `{ models: Array<Model>, dirtyFields: Array<Field>, dirtyModels: Array<Model> }`
1818
+ /// which is known to Mythix ORM as "prepared models". Mythix ORM can understand
1819
+ /// "prepared models" verses simple "models" in most contexts. PreparedModels are often
1820
+ /// passed around after first receiving models from the user, so as not to "prepare" them
1821
+ /// more than once.
1822
+ ///
1823
+ /// Arguments:
1824
+ /// Model: class <see>Model</see>
1825
+ /// The model class to use for preparing the provided models. All models
1826
+ /// provided must be of this model type.
1827
+ /// models: object | <see>Model</see> | Array<Model | object>
1828
+ /// The models to prepare. Any model that is a "raw object" will
1829
+ /// be instantiated into the Model class provided.
1830
+ /// options: object
1831
+ /// Options for the operation. These include `startIndex`, `endIndex`
1832
+ /// (or `batchSize`) for batch operations, and `skipPersisted`, `isUpdateOperation`,
1833
+ /// or `isInsertOperation` for other context-specific operations.
699
1834
  prepareAllModelsForOperation(Model, _models, _options) {
700
1835
  if (!_models)
701
1836
  return {};
@@ -775,6 +1910,32 @@ class ConnectionBase extends EventEmitter {
775
1910
  return finalResult;
776
1911
  }
777
1912
 
1913
+ /// Recursively walk all provided models and split models into a map
1914
+ /// of model name and model instances.
1915
+ ///
1916
+ /// This method is used to split apart provided models by the user.
1917
+ /// For example, it is fully valid to provide "sub models" during most persisting
1918
+ /// operations, such as `new User({ primaryRole: new Role({ name: 'admin' }) })`.
1919
+ ///
1920
+ /// This method would find the sub model "Role" in the above example, and split
1921
+ /// it out to be processed separately in the persisting operation.
1922
+ ///
1923
+ /// Return: Map<string, Set<Model>>
1924
+ /// Return a map of all models found, where the model name is the key for the
1925
+ /// `Map`, and each model instance is added to the `Set` for that key.
1926
+ /// Using the above example, the return value would be: `new Map({ User: new Set([ user ]), Role: new Set([ role ]) })`.
1927
+ ///
1928
+ /// Arguments:
1929
+ /// Model: class <see>Model</see>
1930
+ /// The model class of the primary model being scanned. The primary model could
1931
+ /// also be called the "root model". In our example above the primary model is `User`.
1932
+ /// primaryModel: <see>Model</see>
1933
+ /// The model instance to scan for "sub models". In the example above this would be
1934
+ /// `User` (though `Role` itself will also be passed through this method to check if
1935
+ /// it also has any sub models).
1936
+ /// _relationMap?: Map<string, Set<Model>>
1937
+ /// This argument is provided internally while recursing, and should **not** be provided
1938
+ /// unless you know exactly what you are doing.
778
1939
  splitModelAndSubModels(Model, primaryModel, _relationMap) {
779
1940
  const addModelInstance = (modelName, self) => {
780
1941
  let relatedModels = relationMap.get(modelName);
@@ -832,6 +1993,56 @@ class ConnectionBase extends EventEmitter {
832
1993
  return relationMap;
833
1994
  }
834
1995
 
1996
+ /// Recursively prepare all models for a persisting operation
1997
+ /// while also splitting each model out into its own separate
1998
+ /// list, and finally sorting the models based on insertion order.
1999
+ ///
2000
+ /// This method will use <see>ConnectionBase.splitModelAndSubModels</see>
2001
+ /// to split provided models out into their own separate space. See this
2002
+ /// method for a better explanation of what this means.
2003
+ ///
2004
+ /// It will also assign any foreign key values across models that it is able to.
2005
+ /// For example, in the example provided in the documentation for <see>ConnectionBase.splitModelAndSubModels</see>,
2006
+ /// we had `new User({ primaryRole: new Role({ name: 'admin' }) })`, where the `Role`
2007
+ /// model is being persisted (as a child of `User`) at the same time the `User` is being
2008
+ /// persisted. If `Role` has a generated id, such as one of the `UUID` or `XID` types,
2009
+ /// then in our example here the `primaryRoleID` of the `User` could be set before `User`
2010
+ /// is persisted, saving an extra query to the database to update this foreign key after
2011
+ /// `Role` is persisted. In short, this method will also assign any foreign key values
2012
+ /// that it already has before persisting any models.
2013
+ ///
2014
+ /// Finally, after it has "prepared" the models, and split all models into their own
2015
+ /// space, it will sort the resulting `Map` such that the models are in the correct
2016
+ /// order for insertion. In the example we have been using, if `User` has a `primaryRoleID`
2017
+ /// that is a foreign key, then it might require a non-null value before the `User`
2018
+ /// model can be persisted. Because of this, it is important that the `Role` model
2019
+ /// is stored first, so that we have the value we need for this `primaryRoleID` foreign key.
2020
+ /// This is why the models are sorted in what is known as "creation order", or "insertion order".
2021
+ /// This order is defined by the foreign keys themselves. Mythix ORM will walk all foreign keys
2022
+ /// involved in the operation, and decide based on these what the "creation order" should be.
2023
+ /// If you have two models that both have foreign keys pointing to each other, then the sort
2024
+ /// order is undefined. If this is the case, the work-around is to simply manually persist
2025
+ /// your models in the correct order (i.e. save `Role` first, and then supply the foreign key
2026
+ /// to `User` yourself from the result).
2027
+ ///
2028
+ /// Return: Map<string, Set<Model>>
2029
+ /// The models processed, and put into their own named `Set`. The keys for
2030
+ /// the `Map` are the names of the models themselves.
2031
+ ///
2032
+ /// Arguments:
2033
+ /// Model: class <see>Model</see>
2034
+ /// The model class of the primary model being persisted. The primary model could
2035
+ /// also be called the "root model". In our example above the primary model is `User`.
2036
+ /// models: object | <see>Model</see> | Array<Model | object>
2037
+ /// The models to prepare. Any model that is a "raw object" will
2038
+ /// be instantiated into the Model class provided. Any "sub models" will be
2039
+ /// split into their own space in the resulting `Map`.
2040
+ /// options?: object
2041
+ /// Optional options to supply to this operation. This options object
2042
+ /// isn't used by Mythix ORM, but is provided in case any driver specific
2043
+ /// connection needs them when overloading this model. These options come
2044
+ /// from the options provided to a database operation, such as the options
2045
+ /// provided to an `insert`, `upsert`, or `update` call.
835
2046
  // eslint-disable-next-line no-unused-vars
836
2047
  prepareAllModelsAndSubModelsForOperation(Model, models, _options) {
837
2048
  let primaryModelRelationMap = new Map();
@@ -908,6 +2119,60 @@ class ConnectionBase extends EventEmitter {
908
2119
  return sortedGroupedModelMap;
909
2120
  }
910
2121
 
2122
+ /// This is a low-level "helper" method that is used by all
2123
+ /// "bulk operations", such as `insert`, `upsert`, `update`,
2124
+ /// or `destroyModels`. It prepares all provided models for operation,
2125
+ /// splits out sub-models provided, skips already persisted models,
2126
+ /// and also calls the model hooks `onBeforeSave`, `onAfterSave`, etc...
2127
+ /// This method will also always operate in batches, as defined by the
2128
+ /// `batchSize` option (default is `500` if not provided).
2129
+ ///
2130
+ /// Lastly, when it is all done running the "batch operation" on all models,
2131
+ /// it will update any foreign keys on each model, and if any model has again
2132
+ /// been marked dirty from this update it will finally persist those updated
2133
+ /// models.
2134
+ ///
2135
+ /// When it is fully complete, this method will return all "primary" models supplied
2136
+ /// to the method (i.e. if saving `User` models, then all supplied users will be returned
2137
+ /// and if any sub models were involved those won't be returned). The "primary model" is
2138
+ /// the model whose model class was specified as the `Model` argument on invocation of this
2139
+ /// method, and should match the type of the input `models`.
2140
+ ///
2141
+ /// Return: Array<Model>
2142
+ /// Return all input models, converted to model instances, and updated. How they
2143
+ /// are updated depends on the operation being performed.
2144
+ ///
2145
+ /// Arguments:
2146
+ /// Model: class <see>Model</see>
2147
+ /// The model class for the input models being provided.
2148
+ /// models: Array<Model>
2149
+ /// The models to bulk operate on. All of them must be instances of the class
2150
+ /// provided as the `Model` argument.
2151
+ /// options?: object
2152
+ /// Options to supply to the method. Refer to the following table for a list of
2153
+ /// possible options.
2154
+ /// | Option | Type | Default Value | Description |
2155
+ /// | ------ | ---- | ------------- | ----------- |
2156
+ /// | `batchSize` | `number` | `500` | The number of models for each batch |
2157
+ /// | `isInsertOperation` | `boolean` | `false` | `true` if this is an insert operation. If this is an insert operation, then dirty models will be collected post-insert, and re-saved if any are re-marked dirty after foreign key updates. |
2158
+ /// | `isDeleteOperation` | `boolean` | `false` | `true` if this is a delete operation. If this is a delete operation, then model preparation and splitting is skipped, and the models are processed directly. |
2159
+ /// beforeCallback?: (Model: typeof <see>Model</see>, batchModelInstances: Array<Model>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
2160
+ /// Callback that is called for each batch of models, before the current operation (i.e. insert) operates on them.
2161
+ /// It is generally in this callback that `onBefore*` model hooks are called.
2162
+ /// callback: (Model: typeof <see>Model</see>, preparedModels: <see name="PreparedModels">ConnectionBase.prepareAllModelsForOperation</see>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
2163
+ /// Callback to call to process each batch of models. The models are in "prepared model" format, meaning they
2164
+ /// are supplied as an object with `models`, `dirtyFields`, and `dirtyModels` properties.
2165
+ /// afterCallback?: (Model: typeof <see>Model</see>, models: Array<Model>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
2166
+ /// Callback that is called for each entire model set (not in batches). For example, if you bulk insert
2167
+ /// 1000 users, and your `batchSize` is `100`, then this will be called once, with all
2168
+ /// 1000 processed users, not 10 times with 100 users each. It is generally in this callback
2169
+ /// that `onAfter*` model hooks are called.
2170
+ /// afterOperationCallback?: (Model: typeof <see>Model</see>, dirtyModels: Set<Model>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
2171
+ /// Callback that is called after the entire operation completes successfully. This will only be called
2172
+ /// if `dirtyModels` is not empty. This method generally will re-save any models that got dirty during
2173
+ /// the operation... for example, when foreign keys have been updated on the models being processed.
2174
+ /// Models won't be added to the `dirtyModels` set if they are marked dirty in `onAfter*` model hooks,
2175
+ /// but only if the foreign key update process marked the model as dirty.
911
2176
  async bulkModelOperation(Model, _models, _options, beforeCallback, callback, afterCallback, afterOperationCallback) {
912
2177
  let models = _models;
913
2178
  if (!models)
@@ -1057,6 +2322,26 @@ class ConnectionBase extends EventEmitter {
1057
2322
  return (inputIsArray || !primaryResult) ? primaryResult : primaryResult[0];
1058
2323
  }
1059
2324
 
2325
+ /// Mark all models provided as "persisted".
2326
+ ///
2327
+ /// Every Mythix ORM model instance has a non-enumerable property `_persisted`.
2328
+ /// If this is `true`, then Mythix ORM will treat the model as persisted.
2329
+ ///
2330
+ /// This method iterates all provided models, and marks each as persisted
2331
+ /// by setting this `_persisted` property to `true`.
2332
+ /// For each model iterated, this method checks if the instance property
2333
+ /// `_mythixModelInstance` is `true`. If this is not the case, then that
2334
+ /// instance (whatever it is) will be silently skipped.
2335
+ ///
2336
+ /// Return: undefined
2337
+ /// This method modifies `models` directly, and returns nothing.
2338
+ ///
2339
+ /// Arguments:
2340
+ /// models: Array<Model> | <see name="PreparedModels">ConnectionBase.prepareAllModelsForOperation</see>
2341
+ /// Models to mark as persisted.
2342
+ /// value:
2343
+ /// If `true`, models will be marked as persisted. If `false`, models will be marked
2344
+ /// as not-persisted.
1060
2345
  setPersisted(_models, value) {
1061
2346
  let models = _models;
1062
2347
  if (models._mythixPreparedModels)
@@ -1074,14 +2359,83 @@ class ConnectionBase extends EventEmitter {
1074
2359
  }
1075
2360
  }
1076
2361
 
2362
+ /// Start this connection.
2363
+ ///
2364
+ /// The default implementation will throw an exception.
2365
+ ///
2366
+ /// Every connection is expected to overload this
2367
+ /// and provide connection specific startup code
2368
+ /// (such as connecting to the database).
2369
+ ///
2370
+ /// Return: Promise<void>
1077
2371
  async start() {
1078
2372
  throw new Error(`${this.constructor.name}::start: Child class is required to implement "start".`);
1079
2373
  }
1080
2374
 
2375
+ /// Stop (shutdown) this connection.
2376
+ ///
2377
+ /// The default implementation will throw an exception.
2378
+ ///
2379
+ /// Every connection is expected to overload this
2380
+ /// and provide connection specific shutdown code
2381
+ /// (such as disconnecting from the database).
2382
+ ///
2383
+ /// Return: Promise<void>
1081
2384
  async stop() {
1082
2385
  this.removeAllListeners();
1083
2386
  }
1084
2387
 
2388
+ /// Run model hooks by name.
2389
+ ///
2390
+ /// This method will run the hooks for a model instance.
2391
+ /// `operationHookName` will be one of `onBeforeCreate`, `onBeforeUpdate`,
2392
+ /// `onAfterCreate`, or `onAfterUpdate`.
2393
+ ///
2394
+ /// `operationHookName` will be one of `onBeforeSave`, or `onAfterSave`.
2395
+ /// The idea is that any of the `onBefore*` operations will always be
2396
+ /// followed by an `onBeforeSave`, whereas the `onAfter*` operations
2397
+ /// are all followed by an `onAfterSave`.
2398
+ ///
2399
+ /// Note:
2400
+ /// Hooks for models are run serially for a given model, but all model
2401
+ /// hooks are run in parallel across all models.
2402
+ ///
2403
+ /// Note:
2404
+ /// The `onValidate` hook is called from the `onBeforeSave` hook itself.
2405
+ /// This is so that the user can decide if model validations should be
2406
+ /// ran or not (simply by calling `this.onValidate` themselves... or not).
2407
+ /// **If you overload the `onBeforeSave` method, make certain you call
2408
+ /// `super.onBeforeSave.apply(this, arguments)` (or `this.onValidate.apply(this, arguments)`
2409
+ /// directly), because if you don't
2410
+ /// your model validations will be skipped.**
2411
+ ///
2412
+ /// Return: Promise<Array<any>>
2413
+ /// The result of all model hooks. Mythix ORM ignores the return value
2414
+ /// from model hooks, but it collects them and returns them for the user.
2415
+ ///
2416
+ /// Arguments:
2417
+ /// Model: class <see>Model</see>
2418
+ /// The model class we are running hooks for. All `models` provided should
2419
+ /// be instances of this class.
2420
+ /// models: Array<<see>Model</see>>
2421
+ /// All model instances to run hooks on. These should all be instances of the
2422
+ /// provided `Model` class.
2423
+ /// operationHookName: `'onBeforeCreate'` | `'onBeforeUpdate'` | `'onAfterCreate'` | `'onAfterUpdate'`
2424
+ /// The hook to call (if not skipped by the `skipHooks` option).
2425
+ /// saveHookName: `'onBeforeSave'` | `'onAfterSave'`
2426
+ /// The name of the save hook to call after the operation hook
2427
+ /// has completed (if not skipped by the `skipHooks` option).
2428
+ /// options: object
2429
+ /// Options for the operation being completed. For example, if this is an
2430
+ /// `insert` operation, then these "options" will be the options for the
2431
+ /// `insert` operation. One other useful option that can be supplied here
2432
+ /// is the `skipHooks: boolean | { [key: 'onBeforeCreate' | 'onBeforeUpdate' | 'onAfterCreate' | 'onAfterUpdate' | 'onBeforeSave' | 'onAfterSave' ]: boolean; }` option.
2433
+ /// If this is `true`, then all hooks will be bypassed (not called).
2434
+ /// If this is an object, then each key should be a hook name, and if it has
2435
+ /// a `true` value, then that specific hook will be bypassed (not called).
2436
+ ///
2437
+ /// This allows the caller of an operation such as `insert`, or `update` to
2438
+ /// request that specific hooks not be called.
1085
2439
  async runSaveHooks(Model, models, operationHookName, saveHookName, _options) {
1086
2440
  const throwError = (error) => {
1087
2441
  throw error;
@@ -1125,10 +2479,68 @@ class ConnectionBase extends EventEmitter {
1125
2479
  await Promise.all(promises);
1126
2480
  }
1127
2481
 
2482
+ /// Drop a table/bucket from the database.
2483
+ ///
2484
+ /// This uses the provided `Model` class to
2485
+ /// find the table/bucket name to drop, and then
2486
+ /// will drop it from the underlying database.
2487
+ ///
2488
+ /// The `options` argument is database specific,
2489
+ /// but might contain options such as `ifExists`,
2490
+ /// or `cascade`, for example.
2491
+ ///
2492
+ /// Return: any
2493
+ /// A database specific return value for the drop table
2494
+ /// operation.
2495
+ ///
2496
+ /// Arguments:
2497
+ /// Model: class <see>Model</see>
2498
+ /// The model to drop from the database. The method <see name="Model.getTableName">Model.static getTableName</see>
2499
+ /// is called on the model class to figure out what table/bucket to
2500
+ /// drop from the database.
2501
+ /// options?: object
2502
+ /// Database specific operations for dropping the table/bucket. Please
2503
+ /// refer to the documentation of the driver you are using for further
2504
+ /// information.
2505
+ // eslint-disable-next-line no-unused-vars
1128
2506
  async dropTable(Model, options) {
1129
2507
  throw new Error(`${this.constructor.name}::dropTable: This operation is not supported for this connection type.`);
1130
2508
  }
1131
2509
 
2510
+ /// Drop all specified tables/buckets from the database.
2511
+ ///
2512
+ /// This uses the provided `Models` classes to
2513
+ /// find the table/bucket names to drop, and then
2514
+ /// will drop all of them from the underlying database.
2515
+ ///
2516
+ /// The `options` argument is database specific,
2517
+ /// but might contain options such as `ifExists`,
2518
+ /// or `cascade`, for example.
2519
+ ///
2520
+ /// The model classes provided are first sorted in
2521
+ /// "creation order" using the <see>Utils.sortModelNamesByCreationOrder</see>
2522
+ /// method, and then the tables/buckets are dropped in the
2523
+ /// reverse order. This is to ensure that any foreign key
2524
+ /// constraints in play will play nicely with the operation
2525
+ /// and not throw errors.
2526
+ ///
2527
+ /// This method simply calls <see>ConnectionBase.dropTable</see> for every
2528
+ /// model provided--after sorting the models based on their
2529
+ /// foreign keys.
2530
+ ///
2531
+ /// Return: any
2532
+ /// A database specific return value for the drop tables
2533
+ /// operation.
2534
+ ///
2535
+ /// Arguments:
2536
+ /// Models: Array<class <see>Model</see>>
2537
+ /// All the models to drop from the database. The method <see name="Model.getTableName">Model.static getTableName</see>
2538
+ /// is called on each model class to figure out what table/bucket to
2539
+ /// drop from the database.
2540
+ /// options?: object
2541
+ /// Database specific operations for dropping the table/bucket. Please
2542
+ /// refer to the documentation of the driver you are using for further
2543
+ /// information.
1132
2544
  async dropTables(_Models, options) {
1133
2545
  if (!_Models)
1134
2546
  return;
@@ -1165,10 +2577,67 @@ class ConnectionBase extends EventEmitter {
1165
2577
  return results;
1166
2578
  }
1167
2579
 
2580
+ /// Create a table/bucket using the provided model class.
2581
+ ///
2582
+ /// The provided `options` are database specific,
2583
+ /// but might contain things like `ifExists`, for
2584
+ /// example.
2585
+ ///
2586
+ /// Return: any
2587
+ /// A connection specific return value for the operation.
2588
+ ///
2589
+ /// Arguments:
2590
+ /// Model: class <see>Model</see>
2591
+ /// The model class used to create the table/bucket. The <see name="Model.getTableName">Model.static getTableName</see>
2592
+ /// method will be called to get the table/bucket name to create. Then
2593
+ /// the `static fields` property on the model class is used to create the
2594
+ /// columns/fields for the table/bucket. Only "concrete" fields are created
2595
+ /// in the underlying database. Any "virtual" or "relational" fields will
2596
+ /// be skipped.
2597
+ /// options?: object
2598
+ /// Database specific operations for creating the table/bucket. Please
2599
+ /// refer to the documentation of the driver you are using for further
2600
+ /// information.
1168
2601
  async createTable(Model, options) {
1169
2602
  throw new Error(`${this.constructor.name}::createTable: This operation is not supported for this connection type.`);
1170
2603
  }
1171
2604
 
2605
+ /// Create all specified tables/buckets in the database.
2606
+ ///
2607
+ /// This uses the provided `Models` classes to
2608
+ /// create the tables/buckets specified.
2609
+ ///
2610
+ /// The `options` argument is database specific,
2611
+ /// but might contain options such as `ifNotExists`,
2612
+ /// for example.
2613
+ ///
2614
+ /// The model classes provided are first sorted in
2615
+ /// "creation order" using the <see>Utils.sortModelNamesByCreationOrder</see>
2616
+ /// method, and then the tables/buckets are created in the
2617
+ /// that order. This is to ensure that any foreign key
2618
+ /// constraints in play will play nicely with the operation
2619
+ /// and not throw errors.
2620
+ ///
2621
+ /// This method simply calls <see>ConnectionBase.createTable</see> for every
2622
+ /// model provided--after sorting the models based on their
2623
+ /// foreign keys.
2624
+ ///
2625
+ /// Return: any
2626
+ /// A database specific return value for the create tables
2627
+ /// operation.
2628
+ ///
2629
+ /// Arguments:
2630
+ /// Models: Array<class <see>Model</see>>
2631
+ /// The model classes used to create the tables/buckets. The <see name="Model.getTableName">Model.static getTableName</see>
2632
+ /// method will be called for each model to get the table/bucket name to create. Then
2633
+ /// the `static fields` property on each model class is used to create the
2634
+ /// columns/fields for the table/bucket. Only "concrete" fields are created
2635
+ /// in the underlying database. Any "virtual" or "relational" fields will
2636
+ /// be skipped.
2637
+ /// options?: object
2638
+ /// Database specific operations for dropping the table/bucket. Please
2639
+ /// refer to the documentation of the driver you are using for further
2640
+ /// information.
1172
2641
  async createTables(_Models, options) {
1173
2642
  if (!_Models)
1174
2643
  return;
@@ -1220,125 +2689,886 @@ class ConnectionBase extends EventEmitter {
1220
2689
 
1221
2690
  // Alter operations
1222
2691
 
2692
+ /// Alter a table/bucket based on the provided attributes for
2693
+ /// the model.
2694
+ ///
2695
+ /// For SQL based drivers this might run a statement like the following
2696
+ /// `ALTER TABLE "users" RENAME TO "old_users";`
2697
+ ///
2698
+ /// Please refer to the documentation of the database driver
2699
+ /// you are using for more information.
2700
+ ///
2701
+ /// Return: Promise<void>
2702
+ ///
2703
+ /// Arguments:
2704
+ /// Model: class <see>Model</see>
2705
+ /// The model to alter. This is used to alter the underlying
2706
+ /// table/bucket in the database.
2707
+ /// newAttributes: object
2708
+ /// The attributes to alter. Please refer to the documentation
2709
+ /// of the database driver you are using for more information.
1223
2710
  async alterTable(Model, newModelAttributes, options) {
1224
2711
  throw new Error(`${this.constructor.name}::renameTable: This operation is not supported for this connection type.`);
1225
2712
  }
1226
2713
 
2714
+ /// Drop the specified column/field from the database.
2715
+ ///
2716
+ /// The table/bucket to drop the field from is known
2717
+ /// by the `Model` property (model class) on the field
2718
+ /// itself.
2719
+ ///
2720
+ /// The provided `options` are specific to the database
2721
+ /// you are using.
2722
+ /// Please refer to the documentation of the database driver
2723
+ /// you are using for more information.
2724
+ ///
2725
+ /// Return: any
2726
+ /// A database specific return value for the operation completed.
2727
+ ///
2728
+ /// Arguments:
2729
+ /// Field: <see>Field</see>
2730
+ /// The column/field to drop from the database.
2731
+ /// options?: object
2732
+ /// Database specific option for the operation. Please refer to the
2733
+ /// documentation of the database driver you are using for more information.
1227
2734
  async dropColumn(Field, options) {
1228
2735
  throw new Error(`${this.constructor.name}::dropColumn: This operation is not supported for this connection type.`);
1229
2736
  }
1230
2737
 
2738
+ /// Alter the specified column/field in the database.
2739
+ ///
2740
+ /// This will take the two fields, `Field` and `NewField`,
2741
+ /// and will compare them. It will generate multiple alter
2742
+ /// table statements internally, and will alter the column/field
2743
+ /// based on the differences it detects between the two fields.
2744
+ ///
2745
+ /// If `NewField` is provided as a raw object, then it will be
2746
+ /// converted into a <see>Field</see>.
2747
+ ///
2748
+ /// This method will check for the following differences between
2749
+ /// the two fields, in this order:
2750
+ /// 1. `allowNull`
2751
+ /// 2. `type`
2752
+ /// 3. `defaultValue`
2753
+ /// 4. `primaryKey`
2754
+ /// 5. `unique`
2755
+ /// 6. `index` (will calculate index differences, and do the minimum work required)
2756
+ /// 7. `columnName`
2757
+ ///
2758
+ /// Return: Promise<void>
2759
+ ///
2760
+ /// Arguments:
2761
+ /// Field: <see>Field</see>
2762
+ /// The current column/field (as it is in the database) that we are changing.
2763
+ /// NewField: <see>Field</see> | object
2764
+ /// The new field properties to compare. Only the provided properties will be compared.
2765
+ /// For example, if you only supply a `defaultValue` property, then only that will be
2766
+ /// altered (if it differs from `Field`).
2767
+ /// options?: object
2768
+ /// Operation specific options. These will change depending on the database
2769
+ /// driver you are using. Please refer to the documentation for your specific
2770
+ /// driver for more information.
1231
2771
  async alterColumn(Field, newFieldAttributes, options) {
1232
2772
  throw new Error(`${this.constructor.name}::alterColumn: This operation is not supported for this connection type.`);
1233
2773
  }
1234
2774
 
2775
+ /// Add the column/field specified to the database.
2776
+ ///
2777
+ /// The table/bucket to add the field to is fetched from the
2778
+ /// `Model` property on the supplied field.
2779
+ ///
2780
+ /// Return: Promise<void>
2781
+ ///
2782
+ /// Arguments:
2783
+ /// Field: <see>Field</see>
2784
+ /// The new field to add to the underlying database.
2785
+ /// options?: object
2786
+ /// Operation specific options. These will change depending on the database
2787
+ /// driver you are using. Please refer to the documentation for your specific
2788
+ /// driver for more information.
1235
2789
  async addColumn(Field, options) {
1236
2790
  throw new Error(`${this.constructor.name}::addColumn: This operation is not supported for this connection type.`);
1237
2791
  }
1238
2792
 
2793
+ /// Create an index (or combo index) in the database.
2794
+ ///
2795
+ /// This will create a new index for the field(s) specified.
2796
+ /// The `indexFields` argument must be an array of field names
2797
+ /// as strings. It can contain more than one field. If it does
2798
+ /// contain more than one field, then a combo index will be created
2799
+ /// for all specified fields (if the database you are using supports
2800
+ /// combined indexes).
2801
+ ///
2802
+ /// All the provided field names must exist on the provided `Model`.
2803
+ /// If they don't, then an exception will be thrown. The field names
2804
+ /// can be fully qualified, but they don't need to be. If they are
2805
+ /// fully qualified, then they must all still be owned by the provided
2806
+ /// `Model`. You can not for example use a fully qualified field name
2807
+ /// from another model.
2808
+ ///
2809
+ /// Combo indexes are created by combining two or more fields to create
2810
+ /// the index. For example, you could create a combo index for Users
2811
+ /// like `[ 'firstName', 'lastName', 'email' ]` if it is common for your
2812
+ /// application to query on all three of these fields at once.
2813
+ ///
2814
+ /// If you just want to index a single column/field, simply provide only
2815
+ /// one field name, i.e. `[ 'firstName' ]`.
2816
+ ///
2817
+ /// Return: Promise<void>
2818
+ ///
2819
+ /// Arguments:
2820
+ /// Model: class <see>Model</see>
2821
+ /// The model that owns the specified fields.
2822
+ /// indexFields: Array<string>
2823
+ /// The field names to use to create the index. One field name
2824
+ /// is valid if you only wish to index a single field. These are
2825
+ /// used to generate the index name, along with which fields to
2826
+ /// index.
2827
+ /// options?: object
2828
+ /// Operation specific options. These will change depending on the database
2829
+ /// driver you are using. Please refer to the documentation for your specific
2830
+ /// driver for more information.
1239
2831
  async addIndex(Model, indexFields, options) {
1240
2832
  throw new Error(`${this.constructor.name}::addIndex: This operation is not supported for this connection type.`);
1241
2833
  }
1242
2834
 
2835
+ /// Drop the index from the database based on the specified fields.
2836
+ ///
2837
+ /// This is the exact inverse of <see>ConnectionBase.addIndex</see>,
2838
+ /// and it functions nearly identically, except that it will drop
2839
+ /// the specified index instead of creating it.
2840
+ ///
2841
+ /// Return: Promise<void>
2842
+ ///
2843
+ /// Arguments:
2844
+ /// Model: class <see>Model</see>
2845
+ /// The model that owns the specified fields.
2846
+ /// indexFields: Array<string>
2847
+ /// The field names to used to drop the index. These are used
2848
+ /// to generate the index name, which will then be dropped.
2849
+ /// options?: object
2850
+ /// Operation specific options. These will change depending on the database
2851
+ /// driver you are using. Please refer to the documentation for your specific
2852
+ /// driver for more information.
1243
2853
  async dropIndex(Model, indexFields, options) {
1244
2854
  throw new Error(`${this.constructor.name}::addIndex: This operation is not supported for this connection type.`);
1245
2855
  }
1246
2856
 
2857
+ /// Insert the specified models into the specified
2858
+ /// table/bucket (based on the provided `Model`).
2859
+ ///
2860
+ /// This will insert one or more models into the database.
2861
+ /// Like nearly all such Mythix ORM methods, bulk operations are supported
2862
+ /// out-of-the-box. You can provide a single model to `models`,
2863
+ /// or you can provide an array of models.
2864
+ ///
2865
+ /// The provided "models" can be either an object, an array of
2866
+ /// objects, a model instance, or an array of model instances,
2867
+ /// or a mix of both. Mythix ORM will ensure any provided raw
2868
+ /// objects are first converted into model instances using the
2869
+ /// provided `Model` before it inserts anything.
2870
+ ///
2871
+ /// You can also supply "sub models", and those will also be
2872
+ /// inserted in the correct order (and any foreign keys will
2873
+ /// also be updated for you). For example, if you have a `User`
2874
+ /// model that has a virtual `Type.Model` `primaryRole` field,
2875
+ /// then you can supply a new `Role` model upon insertion and
2876
+ /// Mythix ORM will handle this properly for you. For example:
2877
+ /// `await connection.insert(User, new User({ primaryRole: new Role({ ... }) }))`.
2878
+ /// This type of sub model save also works on through-tables.
2879
+ /// If `primaryRole` was targeting a `Role` model, but through
2880
+ /// another table(s), then Mythix ORM will also create the through-table
2881
+ /// relationships (if it is able to).
2882
+ ///
2883
+ /// This **will not work** for `Types.Models` (multi-relations).
2884
+ /// Mythix ORM doesn't know what you intend for multi-relations
2885
+ /// (overwrite the set? add to the set? what?) so it will deliberately
2886
+ /// skip multi-relational fields. "sub models on insert" only work for
2887
+ /// single-relation fields defined with `Types.Model`. For multi-relation
2888
+ /// fields you must manually work through the relation yourself. For example,
2889
+ /// if our user instead had a `Types.Models` `roles` field (plural), then you
2890
+ /// would instead need to:
2891
+ ///
2892
+ /// Example:
2893
+ /// let user = await connection.insert(User, new User({ ... }));
2894
+ /// let role = await connection.insert(Role, { ... }); // model instance is not required
2895
+ /// await user.addToRoles(role);
2896
+ ///
2897
+ ///
2898
+ /// Return: Promise<Array<Model> | Model>
2899
+ /// If you provide an array of models, then an array of models will be
2900
+ /// returned. If you provide only a single model, then a single
2901
+ /// model will be returned. If you provided "sub models" then those
2902
+ /// will be returned as "related models" on the primary model. For example,
2903
+ /// using the above `User` example, the newly created `Role` model that was
2904
+ /// stored for the `primaryRole` would be available on the returned `User`
2905
+ /// model as `user.Roles[0]`, or you could also access it via the field you
2906
+ /// set it on `user.primaryRole`.
2907
+ ///
2908
+ /// Arguments:
2909
+ /// Model: class <see>Model</see>
2910
+ /// The model class used for the operation. This defines what
2911
+ /// table/bucket to insert the specified models into.
2912
+ /// models: Array<Model | object> | object | <see>Model</see>
2913
+ /// The model(s) to insert into the database. If raw objects are provided,
2914
+ /// then the properties of each object must match the required attributes
2915
+ /// for the model class.
2916
+ /// options?: object
2917
+ /// Most of these options are database/driver specific. However, the following
2918
+ /// options are common across all database drivers:
2919
+ /// | Option | Type | Default Value | Description |
2920
+ /// | ------------- | ---- | ------------- | ----------- |
2921
+ /// | `skipHooks` | `boolean` &#124; `object` | `undefined` | Skip specific hooks. See <see>ConnectionBase.runSaveHooks</see> for more information. |
2922
+ /// | `batchSize` | `number` | `500` | The size of each batch during a multi-model insert operation. |
1247
2923
  // eslint-disable-next-line no-unused-vars
1248
2924
  async insert(Model, models, _options) {
1249
2925
  throw new Error(`${this.constructor.name}::insert: This operation is not supported for this connection type.`);
1250
2926
  }
1251
2927
 
2928
+ /// Insert or update (upsert) models into the database.
2929
+ ///
2930
+ /// This method is only supported by some databases. Database
2931
+ /// drivers that don't support `upsert` natively may attempt to emulate
2932
+ /// the operation (at the cost of speed).
2933
+ ///
2934
+ /// This method should function identically to <see>ConnectionBase.insert</see>,
2935
+ /// with the exception that it should update rows that already exist in the database
2936
+ /// instead of inserting new rows.
2937
+ ///
2938
+ /// See: ConnectionBase.insert
2939
+ ///
2940
+ /// Return: Promise<Array<Model> | Model>
2941
+ /// If you provide an array of models, then an array of models will be
2942
+ /// returned. If you provide only a single model, then a single
2943
+ /// model will be returned. If you provided "sub models" then those
2944
+ /// will be returned as "related models" on the primary model. For example,
2945
+ /// using the above `User` example, the newly created `Role` model that was
2946
+ /// stored for the `primaryRole` would be available on the returned `User`
2947
+ /// model as `user.Roles[0]`, or you could also access it via the field you
2948
+ /// set it on `user.primaryRole`.
2949
+ ///
2950
+ /// Arguments:
2951
+ /// Model: class <see>Model</see>
2952
+ /// The model class used for the operation. This defines what
2953
+ /// table/bucket to insert the specified models into.
2954
+ /// models: Array<Model | object> | object | <see>Model</see>
2955
+ /// The model(s) to insert into the database. If raw objects are provided,
2956
+ /// then the properties of each object must match the required attributes
2957
+ /// for the model class.
2958
+ /// options?: object
2959
+ /// Most of these options are database/driver specific. However, the following
2960
+ /// options are common across all database drivers:
2961
+ /// | Option | Type | Default Value | Description |
2962
+ /// | ------------- | ---- | ------------- | ----------- |
2963
+ /// | `skipHooks` | `boolean` &#124; `object` | `undefined` | Skip specific hooks. See <see>ConnectionBase.runSaveHooks</see> for more information. |
2964
+ /// | `batchSize` | `number` | `500` | The size of each batch during a multi-model upsert operation. |
1252
2965
  // eslint-disable-next-line no-unused-vars
1253
2966
  async upsert(Model, models, _options) {
1254
2967
  throw new Error(`${this.constructor.name}::upsert: This operation is not supported for this connection type.`);
1255
2968
  }
1256
2969
 
2970
+ /// Update the specified models in the database.
2971
+ ///
2972
+ /// Many databases don't have good (or even decent) support
2973
+ /// for bulk updates, so unfortunately this method is fairly
2974
+ /// slow, and will usually make a query to the database for each
2975
+ /// model updated.
2976
+ ///
2977
+ /// If you want to update many models at the same time (using the same
2978
+ /// attributes across all models), then consider using the <see>ConnectionBase.updateAll</see>
2979
+ /// method instead.
2980
+ ///
2981
+ /// Note:
2982
+ /// Models will only be updated if they are dirty. Also, only the
2983
+ /// dirty attributes for each model will be updated (some attributes
2984
+ /// are always dirty, for example `updatedAt` fields are forced to
2985
+ /// always be dirty based on the configuration of their `defaultValue`).
2986
+ ///
2987
+ /// Return: Promise<Array<Model> | Model>
2988
+ /// If you provide an array of models, then an array of models will be
2989
+ /// returned. If you provide only a single model, then a single
2990
+ /// model will be returned.
2991
+ ///
2992
+ /// Arguments:
2993
+ /// Model: class <see>Model</see>
2994
+ /// The model class used for the operation. This defines what
2995
+ /// table/bucket to update.
2996
+ /// models: Array<Model | object> | object | <see>Model</see>
2997
+ /// The model(s) to update in the database. If raw objects are provided,
2998
+ /// then the properties of each object must match the required attributes
2999
+ /// for the model class.
3000
+ /// options?: object
3001
+ /// Most of these options are database/driver specific. However, the following
3002
+ /// options are common across all database drivers:
3003
+ /// | Option | Type | Default Value | Description |
3004
+ /// | ------------- | ---- | ------------- | ----------- |
3005
+ /// | `skipHooks` | `boolean` &#124; `object` | `undefined` | Skip specific hooks. See <see>ConnectionBase.runSaveHooks</see> for more information. |
3006
+ /// | `batchSize` | `number` | `500` | The size of each batch during a multi-model update operation. |
1257
3007
  // eslint-disable-next-line no-unused-vars
1258
3008
  async update(Model, models, _options) {
1259
3009
  throw new Error(`${this.constructor.name}::update: This operation is not supported for this connection type.`);
1260
3010
  }
1261
3011
 
3012
+ /// Update multiple models at the same time (bulk update).
3013
+ ///
3014
+ /// This will update multiple models at the same time
3015
+ /// using the provided `query` to select which models to update.
3016
+ /// All matching rows will set the provided `attributes` upon them.
3017
+ ///
3018
+ /// The provided `attributes` can be a model instance, or
3019
+ /// a raw object. If a raw object is provided, then they
3020
+ /// will be converted into a model instance using the provided
3021
+ /// `Model` class. This also means that you can *only* bulk update
3022
+ /// columns/fields that exist on the model itself (i.e. you might have
3023
+ /// other columns in your table not related to this model, and
3024
+ /// those can **not** be updated using this method).
3025
+ ///
3026
+ /// Note:
3027
+ /// As always with Mythix ORM, you will **never** supply
3028
+ /// raw column names as the `attributes`. You must always
3029
+ /// provide model field names in Mythix ORM.
3030
+ ///
3031
+ /// Note:
3032
+ /// This will be an update operation across all matching rows,
3033
+ /// using the data provided. This method is really only useful
3034
+ /// when you want to update multiple rows to the **same values**.
3035
+ /// If you need to update each row to different values per-row,
3036
+ /// then use the <see>ConnectionBase.update</see> method instead.
3037
+ ///
3038
+ /// Return: Promise<any>
3039
+ /// A database specific result from the `UPDATE` statement.
3040
+ /// In the future all "database specific" results will be
3041
+ /// abstracted away. So in the future, this will likely return
3042
+ /// the number of rows updated as a `number` (**HELP WANTED**).
3043
+ ///
3044
+ /// Arguments:
3045
+ /// query: <see>QueryEngine</see>
3046
+ /// The query used to select which models/rows to update.
3047
+ /// The "root model" of the query is the table/bucket that
3048
+ /// will be updated.
3049
+ /// attributes: object | Model
3050
+ /// The attributes to set across all updated rows.
3051
+ /// options?: object
3052
+ /// Operation specific options. These will change depending on the database
3053
+ /// driver you are using. Please refer to the documentation for your specific
3054
+ /// driver for more information.
1262
3055
  // eslint-disable-next-line no-unused-vars
1263
3056
  async updateAll(_queryEngine, model, _options) {
1264
3057
  throw new Error(`${this.constructor.name}::updateAll: This operation is not supported for this connection type.`);
1265
3058
  }
1266
3059
 
3060
+ /// Destroy the provided models.
3061
+ ///
3062
+ /// This method will bulk-iterate the specified
3063
+ /// models and will destroy each one. A primary key field
3064
+ /// is required for every model, or this method will throw
3065
+ /// an exception.
3066
+ ///
3067
+ /// The `skipHooks` option (see <see>ConnectionBase.runSaveHooks</see>) won't
3068
+ /// do anything here, because Mythix ORM doesn't have any `on*Destroy` hooks.
3069
+ /// Mythix ORM doesn't have any destroy hooks for performance reasons.
3070
+ /// However, the `batchSize` option is still useful for this method.
3071
+ ///
3072
+ /// Note:
3073
+ /// **WARNING!!!**: If you supply `null` or `undefined` as the `models`
3074
+ /// argument then this method will silently return. If you also supply
3075
+ /// the option `{ truncate: true }` then the entire table will be truncated.
3076
+ /// This option is an "opt-in", to make sure you don't truncate an entire
3077
+ /// table on accident.
3078
+ ///
3079
+ /// Note:
3080
+ /// Some databases (i.e. SQLite) don't support a `TRUNCATE` statement,
3081
+ /// and so will deliberately call this method with `null` for the `models`
3082
+ /// argument for `truncate` operations. When doing so they will also
3083
+ /// deliberately supply the `{ truncate: true }` option.
3084
+ ///
3085
+ /// Return: Promise<Array<Model> | Model>
3086
+ /// If you provide an array of models, then an array of models will be
3087
+ /// returned. If you provide only a single model, then a single
3088
+ /// model will be returned.
3089
+ ///
3090
+ /// Arguments:
3091
+ /// Model: class <see>Model</see>
3092
+ /// The model class used for the operation. This defines what
3093
+ /// table/bucket to delete from.
3094
+ /// models: Array<Model | object> | object | <see>Model</see>
3095
+ /// The model(s) to delete from the database. If raw objects are provided,
3096
+ /// then they must contain a `primaryKey` for each model. If any of the
3097
+ /// models provided don't contain a `primaryKey` field, then an exception
3098
+ /// will be thrown. If you have a table/bucket that has no primary key column,
3099
+ /// then you will need to destroy rows manually yourself using a manual query
3100
+ /// with <see>ConnectionBase.query</see>, or by using the <see>ConnectionBase.destroy</see> method.
3101
+ /// options?: object
3102
+ /// Most of these options are database/driver specific. However, the following
3103
+ /// options are common across all database drivers (`skipHooks` is not supported in this context):
3104
+ /// | Option | Type | Default Value | Description |
3105
+ /// | ------------- | ---- | ------------- | ----------- |
3106
+ /// | `batchSize` | `number` | `500` | The size of each batch during a multi-model destroy operation. |
1267
3107
  // eslint-disable-next-line no-unused-vars
1268
3108
  async destroyModels(Model, _models, _options) {
1269
3109
  throw new Error(`${this.constructor.name}::destroyModels: This operation is not supported for this connection type.`);
1270
3110
  }
1271
3111
 
3112
+ /// Destroy multiple models by query, or by the
3113
+ /// provided models themselves. If models are provided,
3114
+ /// then each model must have a valid primary key field,
3115
+ /// or an exception will be thrown.
3116
+ ///
3117
+ /// If models are provided as the second argument, then
3118
+ /// it is required that the first argument be a <see>Model</see>
3119
+ /// class. In this case, this method simply calls
3120
+ /// <see>ConnectionBase.destroyModels</see> to complete the operation.
3121
+ ///
3122
+ /// If the first argument is a <see>QueryEngine</see> instance,
3123
+ /// then rows will be deleted from the database using the provided query.
3124
+ /// In this case, it is expected that the second argument
3125
+ /// will be the "options" for this operation instead of an array of models.
3126
+ ///
3127
+ /// Return: Promise<Array<Models> | Model | number>
3128
+ /// Return the models deleted (if models were provided),
3129
+ /// or the number of rows deleted (if a query was provided).
3130
+ ///
3131
+ /// Arguments:
3132
+ /// queryOrModel: class <see>Model</see> | <see>QueryEngine</see>
3133
+ /// A <see>QueryEngine</see> instance to specify which models to
3134
+ /// delete via a query, or a <see>Model</see> class if models are
3135
+ /// being provided to be deleted.
3136
+ /// modelsOrOptions: Array<Model> | Model | object
3137
+ /// If a <see>QueryEngine</see> instance is provided as the first argument
3138
+ /// then this is expected to be the "options" for the operation. If however
3139
+ /// a <see>Model</see> class is provided as the first argument, then this
3140
+ /// should be a <see>Model</see> instance, or an array of <see>Model</see> instances.
3141
+ /// options?: object | undefined
3142
+ /// Most of these options are database/driver specific.
3143
+ /// The `batchSize` option is ignored if a <see>QueryEngine</see> instance is provided as the
3144
+ /// first argument to the call. If a <see>Model</see> class is provided as the first argument to
3145
+ /// the call, then this `options` object will be at argument index `1` instead (the second argument, `modelsOrOptions`).
3146
+ /// The following options are common across all database drivers
3147
+ /// (`skipHooks` is not supported in this context):
3148
+ /// | Option | Type | Default Value | Description |
3149
+ /// | ------------- | ---- | ------------- | ----------- |
3150
+ /// | `batchSize` | `number` | `500` | The size of each batch during a multi-model destroy operation. |
1272
3151
  // eslint-disable-next-line no-unused-vars
1273
3152
  async destroy(_queryEngineOrModel, modelsOrOptions, _options) {
1274
3153
  throw new Error(`${this.constructor.name}::destroy: This operation is not supported for this connection type.`);
1275
3154
  }
1276
3155
 
3156
+ /// Select data from the underlying database.
3157
+ ///
3158
+ /// To select data from the database you will use this method,
3159
+ /// providing a `query` as a <see>QueryEngine</see> instance.
3160
+ /// The provided query will be used to generate the underlying
3161
+ /// request to the database, will collect the response, and return
3162
+ /// the results to the caller.
3163
+ ///
3164
+ /// This method is an async generator method, and is designed for
3165
+ /// "streaming" results from the database, one "row" at a time. Many
3166
+ /// methods that call this method (such as <see>QueryEngine.all</see>)
3167
+ /// collect all the results from the async generator to return an array
3168
+ /// of results to the caller. This is because it is often tedious to
3169
+ /// collect the results yourself from the async generator, and often the
3170
+ /// caller simply wants a small amount of data from the database.
3171
+ /// However, if you intend to fetch large amounts of data from your database,
3172
+ /// it is a good idea to call this method directly, and iterate the results
3173
+ /// of the async generator manually. All methods that in-turn call this
3174
+ /// method (such as <see>QueryEngine.all</see>) will generally have a
3175
+ /// `{ stream: true }` option that can be provided, causing the method to
3176
+ /// return the async generator, instead of the collected results.
3177
+ ///
3178
+ ///
3179
+ /// Return: AsyncGenerator<Model>
3180
+ ///
3181
+ /// Arguments:
3182
+ /// query: <see>QueryEngine</see>
3183
+ /// The query to run against the underlying database. This is generated
3184
+ /// from a <see>QueryEngine</see> interface. The result of this <see>QueryEngine</see>
3185
+ /// instance will then be converted to a query, or generated code to
3186
+ /// interact with the underlying database.
3187
+ /// options?: object
3188
+ /// Operation specific options. These will change depending on the database
3189
+ /// driver you are using. Please refer to the documentation for your specific
3190
+ /// driver for more information.
1277
3191
  // eslint-disable-next-line no-unused-vars, require-yield
1278
3192
  async *select(_queryEngine, _options) {
1279
3193
  throw new Error(`${this.constructor.name}::select: This operation is not supported for this connection type.`);
1280
3194
  }
1281
3195
 
3196
+ /// Aggregate data across rows.
3197
+ ///
3198
+ /// Though this method can be called directly, it is generally called from
3199
+ /// one of <see>ConnectionBase.average</see>, <see>ConnectionBase.sum</see>,
3200
+ /// <see>ConnectionBase.count</see>, <see>ConnectionBase.min</see>,
3201
+ /// or <see>ConnectionBase.max</see>, or one of the other aggregate methods
3202
+ /// provided by the connection.
3203
+ ///
3204
+ /// It takes a `query` which is used to generate a query for the underlying
3205
+ /// database, and sets the query `PROJECTION` to the aggregate `literal` provided.
3206
+ /// For example, a `sum` method call would call this method with a `SumLiteral`,
3207
+ /// which would change the `query` projection to the expanded result of the
3208
+ /// `SumLiteral`, returning the "sum" of all column values targeted by the literal field.
3209
+ /// The results will then be collected, and always returned as a `number` primitive
3210
+ /// to the caller.
3211
+ ///
3212
+ /// Return: Promise<number>
3213
+ /// The result of the aggregate operation, as a number.
3214
+ ///
3215
+ /// Arguments:
3216
+ /// query: <see>QueryEngine</see>
3217
+ /// The query used to select which rows to aggregate across.
3218
+ /// literal: <see>LiteralBase</see>
3219
+ /// A literal, used as the aggregate function. For example, if a
3220
+ /// <see>CountLiteral</see> is provided, then the count of all rows
3221
+ /// matching the provided query will be the result.
3222
+ /// options?: object
3223
+ /// Operation specific options. These will change depending on the database
3224
+ /// driver you are using. Please refer to the documentation for your specific
3225
+ /// driver for more information.
1282
3226
  // eslint-disable-next-line no-unused-vars
1283
3227
  async aggregate(_queryEngine, _literal, options) {
1284
3228
  throw new Error(`${this.constructor.name}::aggregate: This operation is not supported for this connection type.`);
1285
3229
  }
1286
3230
 
3231
+ /// Get the average for a single column, spanning all matching rows.
3232
+ ///
3233
+ /// This will return the average of all values in a column,
3234
+ /// across all matching rows, as a `number` primitive.
3235
+ ///
3236
+ /// Return: Promise<number>
3237
+ /// The average of all matching columns.
3238
+ ///
3239
+ /// Arguments:
3240
+ /// query: <see>QueryEngine</see>
3241
+ /// The query used to select which rows are used to calculate the average.
3242
+ /// field: <see>Field</see> | string
3243
+ /// A field instance, or a fully qualified field name, used as the target
3244
+ /// column in the underlying database to calculate an average across all matching values.
3245
+ /// options?: object
3246
+ /// Operation specific options. These will change depending on the database
3247
+ /// driver you are using. Please refer to the documentation for your specific
3248
+ /// driver for more information.
1287
3249
  // eslint-disable-next-line no-unused-vars
1288
3250
  async average(_queryEngine, _field, options) {
1289
3251
  throw new Error(`${this.constructor.name}::average: This operation is not supported for this connection type.`);
1290
3252
  }
1291
3253
 
3254
+ /// Get the number of rows matching the query.
3255
+ ///
3256
+ /// This will return the number of rows matching
3257
+ /// the provided query, as a `number` primitive.
3258
+ ///
3259
+ /// Note:
3260
+ /// In most databases, if the `field` argument is not
3261
+ /// specified, then the count operation will be across
3262
+ /// all table columns (`COUNT(*)`).
3263
+ ///
3264
+ /// Return: Promise<number>
3265
+ /// The count (number) of all rows matching the provided query.
3266
+ ///
3267
+ /// Arguments:
3268
+ /// query: <see>QueryEngine</see>
3269
+ /// The query used to select which rows to count.
3270
+ /// field: <see>Field</see> | string
3271
+ /// A field instance, or a fully qualified field name, used as the target
3272
+ /// column in the underlying database to count the rows. If not specified,
3273
+ /// then most database drivers will count across all columns (i.e. `COUNT(*)`).
3274
+ /// options?: object
3275
+ /// Operation specific options. These will change depending on the database
3276
+ /// driver you are using. Please refer to the documentation for your specific
3277
+ /// driver for more information.
1292
3278
  // eslint-disable-next-line no-unused-vars
1293
3279
  async count(_queryEngine, _field, options) {
1294
3280
  throw new Error(`${this.constructor.name}::count: This operation is not supported for this connection type.`);
1295
3281
  }
1296
3282
 
3283
+ /// Get the minimum value for a column, spanning all matching rows.
3284
+ ///
3285
+ /// This will return the minimum of all values in a column,
3286
+ /// across all matching rows, as a `number` primitive.
3287
+ ///
3288
+ /// Return: Promise<number>
3289
+ /// The minimum value found across all matching rows.
3290
+ ///
3291
+ /// Arguments:
3292
+ /// query: <see>QueryEngine</see>
3293
+ /// The query used to select which rows are used to calculate the minimum.
3294
+ /// field: <see>Field</see> | string
3295
+ /// A field instance, or a fully qualified field name, used as the target
3296
+ /// column in the underlying database to find the minimum across all matching values.
3297
+ /// options?: object
3298
+ /// Operation specific options. These will change depending on the database
3299
+ /// driver you are using. Please refer to the documentation for your specific
3300
+ /// driver for more information.
1297
3301
  // eslint-disable-next-line no-unused-vars
1298
3302
  async min(_queryEngine, _field, options) {
1299
3303
  throw new Error(`${this.constructor.name}::min: This operation is not supported for this connection type.`);
1300
3304
  }
1301
3305
 
3306
+ /// Get the maximum value for a column, spanning all matching rows.
3307
+ ///
3308
+ /// This will return the maximum of all values in a column,
3309
+ /// across all matching rows, as a `number` primitive.
3310
+ ///
3311
+ /// Return: Promise<number>
3312
+ /// The maximum value found across all matching rows.
3313
+ ///
3314
+ /// Arguments:
3315
+ /// query: <see>QueryEngine</see>
3316
+ /// The query used to select which rows are used to calculate the maximum.
3317
+ /// field: <see>Field</see> | string
3318
+ /// A field instance, or a fully qualified field name, used as the target
3319
+ /// column in the underlying database to find the maximum across all matching values.
3320
+ /// options?: object
3321
+ /// Operation specific options. These will change depending on the database
3322
+ /// driver you are using. Please refer to the documentation for your specific
3323
+ /// driver for more information.
1302
3324
  // eslint-disable-next-line no-unused-vars
1303
3325
  async max(_queryEngine, _field, options) {
1304
3326
  throw new Error(`${this.constructor.name}::max: This operation is not supported for this connection type.`);
1305
3327
  }
1306
3328
 
3329
+ /// Get the sum of all values for a column, spanning all matching rows.
3330
+ ///
3331
+ /// This will return the sum of all values in a column,
3332
+ /// across all matching rows, as a `number` primitive.
3333
+ ///
3334
+ /// Return: Promise<number>
3335
+ /// The sum of all values found across all matching rows.
3336
+ ///
3337
+ /// Arguments:
3338
+ /// query: <see>QueryEngine</see>
3339
+ /// The query used to select which rows are used to calculate the sum.
3340
+ /// field: <see>Field</see> | string
3341
+ /// A field instance, or a fully qualified field name, used as the target
3342
+ /// column in the underlying database to find the sum of all matching values.
3343
+ /// options?: object
3344
+ /// Operation specific options. These will change depending on the database
3345
+ /// driver you are using. Please refer to the documentation for your specific
3346
+ /// driver for more information.
1307
3347
  // eslint-disable-next-line no-unused-vars
1308
3348
  async sum(_queryEngine, _field, options) {
1309
3349
  throw new Error(`${this.constructor.name}::sum: This operation is not supported for this connection type.`);
1310
3350
  }
1311
3351
 
3352
+ /// Pluck only specific columns/fields from the
3353
+ /// underlying database, using the provided `query`.
3354
+ ///
3355
+ /// This method will return only the specified `fields`
3356
+ /// from the database--as raw values--from rows matched
3357
+ /// on by the provided query.
3358
+ ///
3359
+ /// This method is often much faster than a normal `select` operation,
3360
+ /// in that only the data requested will be transmitted from the database,
3361
+ /// and models won't be constructed and stitched together on load. Use this
3362
+ /// when you just need an "array of values" across certain columns from a table.
3363
+ ///
3364
+ /// Return: Array<any> | Array<Array<any>> | Array<object>
3365
+ /// If the provided `fields` argument is an array of fields
3366
+ /// (fully qualified field names, or <see>Field</see> instances),
3367
+ /// then the result will be an array of arrays, where each item
3368
+ /// in the top-level array is a "row", and each sub-array is the
3369
+ /// values for the columns (fields) specified. If a single field
3370
+ /// is specified, then an one dimensional array is returned, where
3371
+ /// each item is the column value for each row fetched.
3372
+ /// For example, if we call `pluck` like: `let result = await connection.pluck(User.where.firstName.EQ('Bob'), 'User:id')`
3373
+ /// then the `result` would look like `[ 'USER_id_1`, `USER_id_2`, ... ]`
3374
+ /// where each value in the array is a user id. If however we call pluck like:
3375
+ /// `let result = await connection.pluck(User.where.firstName.EQ('Bob'), [ 'User:id', 'User:firstName' ])`
3376
+ /// then the `result` would look like `[ [ 'USER_id_1', 'Bob' ], [ 'USER_id_2', 'Bob' ], ... ]`, because
3377
+ /// the provided `fields` is an array, an array of field values will be returned from each row.
3378
+ /// If the `option` `mapToObjects` is `true`, then an array of objects will be returned,
3379
+ /// where each object is a "row", and each property one of the specified fields. Note that
3380
+ /// the properties of each returned object will be the fully qualified field name of each field
3381
+ /// specified. So, for example, specifying a pluck field of `User:id` means that each returned
3382
+ /// object in the array will look like `[ { 'User:id': 'USER_id_1' }, { 'User:id': 'USER_id_2' }, ... ]`.
3383
+ ///
3384
+ /// Arguments:
3385
+ /// query: <see>QueryEngine</see>
3386
+ /// The query used to select rows from which columns will be plucked.
3387
+ /// fields: <see>Field</see> | string | Array<Field> | Array<string>
3388
+ /// Which fields to "pluck" from the matching rows. If an array is provided (even if
3389
+ /// it only contains a single field), then an array of arrays will be returned
3390
+ /// as the result. If a single field is provided (not an array), then an array
3391
+ /// of raw plucked column values will be returned instead.
3392
+ /// options?: object
3393
+ /// Operation specified options. These might change based on the database driver you
3394
+ /// are using, so please refer to your specific database driver documentation. One
3395
+ /// option that is common across all drivers is the `mapToObjects` boolean option.
3396
+ /// If `true`, then each row in the returned array will be an object instead of
3397
+ /// raw column values, where the property of each "row object" will be the fully
3398
+ /// qualified names of each field provided as the `fields` argument.
1312
3399
  // eslint-disable-next-line no-unused-vars
1313
3400
  async pluck(_queryEngine, _fields, _options) {
1314
3401
  throw new Error(`${this.constructor.name}::pluck: This operation is not supported for this connection type.`);
1315
3402
  }
1316
3403
 
3404
+ /// Check if any rows match the provided `query`.
3405
+ ///
3406
+ /// Return: boolean
3407
+ /// `true` if one or more rows match the provided query, or `false` otherwise.
3408
+ ///
3409
+ /// Arguments:
3410
+ /// query: <see>QueryEngine</see>
3411
+ /// The query used to select rows, to check if said rows exist in the database.
3412
+ /// options?: object
3413
+ /// Operation specific options. These will change depending on the database
3414
+ /// driver you are using. Please refer to the documentation for your specific
3415
+ /// driver for more information.
1317
3416
  // eslint-disable-next-line no-unused-vars
1318
3417
  async exists(queryEngine, options) {
1319
3418
  throw new Error(`${this.constructor.name}::exists: This operation is not supported for this connection type.`);
1320
3419
  }
1321
3420
 
3421
+ /// Truncate (erase/clear) the entire table/bucket defined
3422
+ /// by the provided `Model`. All rows/objects from the underlying
3423
+ /// table/bucket will be destroyed, leaving you with an empty
3424
+ /// table/bucket.
3425
+ ///
3426
+ /// Return: Promise<void>
3427
+ ///
3428
+ /// Arguments:
3429
+ /// Model: class <see>Model</see>
3430
+ /// The model class that defines the underlying table/bucket to wipe clean/erase.
3431
+ /// options?: object
3432
+ /// Operation specific options. These will change depending on the database
3433
+ /// driver you are using. Please refer to the documentation for your specific
3434
+ /// driver for more information.
1322
3435
  // eslint-disable-next-line no-unused-vars
1323
3436
  async truncate(Model, options) {
1324
3437
  throw new Error(`${this.constructor.name}::truncate: This operation is not supported for this connection type.`);
1325
3438
  }
1326
3439
 
3440
+ /// "raw" database/driver specific query interface.
3441
+ ///
3442
+ /// For SQL based databases, this would send a direct
3443
+ /// query string to the database. For other drivers, the
3444
+ /// arguments and operations that are executed might change.
3445
+ ///
3446
+ /// Use this method to directly interact with the underlying
3447
+ /// database, in its own native query language.
3448
+ ///
3449
+ /// The arguments and return value from this method is database/driver
3450
+ /// specific. Any `options` argument the database provides are also
3451
+ /// specific to the underlying database driver. However, one option
3452
+ /// is common across all drivers, and this is the `logger` option. If
3453
+ /// set, it is expected to have a `log` method in the provided `logger`
3454
+ /// object. Oftentimes, this will simply be `{ logger: console }`, but
3455
+ /// you can provided any custom `logger` instance you want, as long as it
3456
+ /// has a `log` method that can be called to log the results of the query.
3457
+ /// Most drivers also support a `{ logger }` option as a connection option
3458
+ /// when the connection is first instantiated, which will provided logging
3459
+ /// to every query that goes through the connection.
3460
+ ///
3461
+ /// Return: database specific
3462
+ /// A database/driver specific return value, based on the query provided.
1327
3463
  // eslint-disable-next-line no-unused-vars
1328
3464
  async query(sql, options) {
1329
3465
  throw new Error(`${this.constructor.name}::query: This operation is not supported for this connection type.`);
1330
3466
  }
1331
3467
 
3468
+ /// Initiate a transaction (or snapshot/sub-transaction)
3469
+ /// if the database driver supports transactions.
3470
+ ///
3471
+ /// This will initiate a transaction in the underlying database,
3472
+ /// if the database supports it. For SQL type databases this would
3473
+ /// be a `BEGIN/COMMIT/ROLLBACK` block. If this method is called
3474
+ /// when a transaction is already in-progress, then a snapshot/sub-transaction
3475
+ /// will be started instead.
3476
+ ///
3477
+ /// This method will start a transaction in the underlying database,
3478
+ /// and call the provided asynchronous callback. If the callback throws
3479
+ /// an error, then the transaction (or snapshot) will be automatically
3480
+ /// rolled-back. There is a single `connection` argument that will be
3481
+ /// provided to the callback function when called. This `connection` argument
3482
+ /// will be the transaction connection itself, which for many database drivers is simply
3483
+ /// the same connection the transaction was started from. At a lower-level,
3484
+ /// Mythix ORM will use an [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html)
3485
+ /// context to provide the transaction connection to all code executed inside
3486
+ /// the callback, so the provided `connection` argument can generally be ignored.
3487
+ /// However, if [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html) isn't
3488
+ /// supported in your environment, or the specific driver you are using requires that you use
3489
+ /// the supplied `connection` argument, then you must use the supplied `connection`
3490
+ /// for all your operations, and provide it as the `{ connection }` option to all Mythix ORM
3491
+ /// calls made inside the callback.
3492
+ ///
3493
+ /// Return: Promise<any>
3494
+ /// Return whatever return value is returned from the provided callback.
3495
+ ///
3496
+ /// Arguments:
3497
+ /// callback: (connection: <see>Connection</see>) => any
3498
+ /// The async callback to call for the transaction operation. This should return as quickly as
3499
+ /// possible to avoid deadlocks in the underlying database. Whatever value this method
3500
+ /// returns will be the return value from the `transaction` call itself. If an exception is
3501
+ /// thrown in this method, then the transaction will be automatically rolled-back. If no
3502
+ /// exception is thrown from this method, then when done executing, a `COMMIT` will be sent
3503
+ /// to the underlying database automatically for you.
3504
+ /// options?: object
3505
+ /// Optional database specific options to supply for the transaction operation. There are two
3506
+ /// options that are supported across most database drivers, and those are `connection` and `lock`.
3507
+ /// The `connection` option supplies the the connection to initiate the transaction from, which for
3508
+ /// example might be another transaction connection (initiating a sub-transaction). If no `connection`
3509
+ /// option is supplied, then the `connection` this method was called from is used instead. The second
3510
+ /// common option is `lock`, which specifies how/if to lock the table for the transaction.
3511
+ /// See <see>ConnectionBase.getLockMode</see> for your specific driver for more information on this `lock` option.
1332
3512
  // eslint-disable-next-line no-unused-vars
1333
3513
  async transaction(callback, options) {
1334
3514
  throw new Error(`${this.constructor.name}::transaction: This operation is not supported for this connection type.`);
1335
3515
  }
1336
3516
 
3517
+ /// Translate the `defaultValue` as provided by each models field's
3518
+ /// into a `DEFAULT` value for the underlying database.
3519
+ ///
3520
+ /// For example, if you were to specify a `defaultValue` for one of your
3521
+ /// models field's, such as `defaultValue: Types.INTEGER.Defaults.AUTOINCREMENT`,
3522
+ /// then this method would return a database specific `autoincrement` default for
3523
+ /// the column defined by your field. For date/time fields, this might be a database
3524
+ /// specific `NOW()` default. For non-database specific "defaults", the default value
3525
+ /// as defined by your `defaultValue` on your fields is simply returned.
3526
+ ///
3527
+ /// Return: any
3528
+ /// Your defined field's `defaultValue`, intercepted, and possibly translated to
3529
+ /// a proper value for the underlying database. It is common for many database
3530
+ /// drivers that only date/time and auto-increment default values are intercepted
3531
+ /// and translated. Most other "default values" are simply returned.
3532
+ ///
3533
+ /// Arguments:
3534
+ /// type: <see>Type</see>
3535
+ /// The field's `type` instance, as defined by the field itself.
3536
+ /// context: DefaultValueContext
3537
+ /// A `DefaultValueContext` as is normally provided to all `defaultValue` methods
3538
+ /// defined on <see name="fields">Field</see>. See the documentation for the `defaultValue`
3539
+ /// property of <see>Field</see> for more information.
1337
3540
  // eslint-disable-next-line no-unused-vars
1338
3541
  async getDefaultFieldValue(type, context) {
1339
3542
  throw new Error(`${this.constructor.name}::getDefaultFieldValue: This operation is not supported for this connection type.`);
1340
3543
  }
1341
3544
 
3545
+ /// A connection specific "helper" to force "dirty" fields
3546
+ /// for all models.
3547
+ ///
3548
+ /// This method, when present on a connection, will assist in
3549
+ /// defining which fields are "dirty" for a model. It is used,
3550
+ /// for example, by `Types.DATETIME.Defaults.NOW.UPDATED` default values.
3551
+ /// In the case presented, DATETIME fields that should always be updated
3552
+ /// are always marked dirty by this method, even though they might
3553
+ /// not actually be "dirty" client-side.
3554
+ ///
3555
+ /// If this method returns _any_ value other than `undefined`, then
3556
+ /// the field being operated upon will be marked "dirty" with the value
3557
+ /// returned, even if the field would otherwise not be marked "dirty".
3558
+ ///
3559
+ /// Return: any
3560
+ /// If _any_ value is returned that is not `undefined`, then the field
3561
+ /// will be marked "dirty" with the value returned. Return `undefined`
3562
+ /// if you do not wish to mark a specific field as "dirty". Note however
3563
+ /// that the field _might_ actually still be dirty because the user modified
3564
+ /// the field, in which case this method will not even be called for that field.
3565
+ /// In short, this method is only called for fields that are not already marked
3566
+ /// as dirty, and will force a field to be marked dirty if any value other than
3567
+ /// `undefined` is returned.
3568
+ ///
3569
+ /// Arguments:
3570
+ /// context: DefaultValueContext
3571
+ /// See <see>Field</see> for documentation on the `DefaultValueContext` interface.
1342
3572
  // eslint-disable-next-line no-unused-vars
1343
3573
  dirtyFieldHelper(context) {
1344
3574