mythix-orm 1.8.2 → 1.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/connection/connection-base.d.ts +1 -0
- package/lib/connection/connection-base.js +2303 -6
- package/lib/connection/query-generator-base.js +14 -11
- package/lib/model.d.ts +17 -0
- package/lib/model.js +22 -3
- package/lib/query-engine/field-scope.js +2 -2
- package/lib/query-engine/model-scope.js +15 -15
- package/lib/query-engine/query-engine-base.js +111 -38
- package/lib/query-engine/query-engine.d.ts +29 -24
- package/lib/query-engine/query-engine.js +33 -22
- package/lib/types/concrete/date-type.js +2 -2
- package/lib/types/concrete/datetime-type.js +2 -2
- package/lib/types/concrete/foreign-key-type.js +2 -2
- package/lib/types/type.js +1 -1
- package/lib/types/virtual/model-type.js +151 -0
- package/lib/types/virtual/models-type.js +148 -1
- package/lib/types/virtual/relational-type-base.js +2 -12
- package/lib/utils/model-utils.js +47 -2
- package/lib/utils/query-utils.js +2 -2
- package/package.json +1 -1
|
@@ -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
|
|
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,104 @@ class ConnectionBase extends EventEmitter {
|
|
|
236
489
|
return queryEngine;
|
|
237
490
|
}
|
|
238
491
|
|
|
492
|
+
async finalizeQuery(crudOperation, queryEngine, options) {
|
|
493
|
+
if (!QueryEngine.isQuery(queryEngine))
|
|
494
|
+
return queryEngine;
|
|
495
|
+
|
|
496
|
+
const finalizeQueryForModel = async (query, parent, contextKey, depth) => {
|
|
497
|
+
let operations = query.getOperationStack();
|
|
498
|
+
|
|
499
|
+
// Has query already been finalized?
|
|
500
|
+
let lastOperation = operations[operations.length - 1];
|
|
501
|
+
if (lastOperation && Object.prototype.hasOwnProperty.call(lastOperation, '_queryFinalized') && lastOperation._queryFinalized)
|
|
502
|
+
return query;
|
|
503
|
+
|
|
504
|
+
let newQuery = query.clone();
|
|
505
|
+
let alreadyVisitedModels = new Set();
|
|
506
|
+
|
|
507
|
+
for (let i = 0, il = operations.length; i < il; i++) {
|
|
508
|
+
let operation = operations[i];
|
|
509
|
+
if (!Object.prototype.hasOwnProperty.call(operation, 'modelName'))
|
|
510
|
+
continue;
|
|
511
|
+
|
|
512
|
+
let modelName = operation.modelName;
|
|
513
|
+
if (alreadyVisitedModels.has(modelName))
|
|
514
|
+
continue;
|
|
515
|
+
|
|
516
|
+
alreadyVisitedModels.add(modelName);
|
|
517
|
+
|
|
518
|
+
let Model = operation.Model;
|
|
519
|
+
if (typeof Model.finalizeQuery !== 'function')
|
|
520
|
+
continue;
|
|
521
|
+
|
|
522
|
+
newQuery = await Model.finalizeQuery({
|
|
523
|
+
type: crudOperation,
|
|
524
|
+
query: newQuery,
|
|
525
|
+
queryDepth: depth,
|
|
526
|
+
operationIndex: i,
|
|
527
|
+
connection: this,
|
|
528
|
+
Model,
|
|
529
|
+
modelName,
|
|
530
|
+
operation,
|
|
531
|
+
operations,
|
|
532
|
+
parent,
|
|
533
|
+
contextKey,
|
|
534
|
+
options,
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
if (parent && contextKey)
|
|
538
|
+
parent[contextKey] = newQuery;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Mark as finalized
|
|
542
|
+
newQuery.getOperationContext()._queryFinalized = true;
|
|
543
|
+
|
|
544
|
+
return newQuery;
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
let promises = [];
|
|
548
|
+
|
|
549
|
+
queryEngine.walk((query, parent, contextKey, depth) => {
|
|
550
|
+
promises.push(finalizeQueryForModel(query, parent, contextKey, depth));
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
if (promises.length > 0)
|
|
554
|
+
await Promise.all(promises);
|
|
555
|
+
|
|
556
|
+
return await finalizeQueryForModel(queryEngine, null, null, 0);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/// Register the provided model class.
|
|
560
|
+
///
|
|
561
|
+
/// This will register the provided model class with this
|
|
562
|
+
/// connection. The model must not already be bound to
|
|
563
|
+
/// another connection, or you must specify the `option`
|
|
564
|
+
/// `{ forceConnectionBinding: true }` if it is. You
|
|
565
|
+
/// can specify the `option` of `{ bindModels: false }`
|
|
566
|
+
/// if you don't wish to bind this model to this connection.
|
|
567
|
+
///
|
|
568
|
+
/// Any `options` provided are optional, and will override
|
|
569
|
+
/// the same options provided to the connection itself when
|
|
570
|
+
/// it was created.
|
|
571
|
+
///
|
|
572
|
+
/// Arguments:
|
|
573
|
+
/// Model: class <see>Model</see>
|
|
574
|
+
/// The model class to register with this connection. If not bound, then it
|
|
575
|
+
/// will simply exist in the model pool for this connection. If bound, then
|
|
576
|
+
/// this connection will bind itself to the model being registered.
|
|
577
|
+
/// options?: object
|
|
578
|
+
/// Options looks like `{ forceConnectionBinding: boolean; bindModels: boolean; }`.
|
|
579
|
+
/// This is an optional argument. Both options will default to the same options
|
|
580
|
+
/// provided to the connection when it was created. If you specify either of these
|
|
581
|
+
/// options they simply override the connection's default.
|
|
582
|
+
///
|
|
583
|
+
/// Return: class <see>Model</see>
|
|
584
|
+
/// The registered model class, **which may have changed during registration**.
|
|
585
|
+
/// It is not uncommon for the connection driver itself to modify the model
|
|
586
|
+
/// class, or to return a new model class that inherits from your model class.
|
|
587
|
+
/// The class that is returned should be the class that you use for this connection,
|
|
588
|
+
/// and will be the same class returned by a call to <see>Connection.getModel</see>,
|
|
589
|
+
/// or <see>Connection.getModels</see>.
|
|
239
590
|
registerModel(_Model, options) {
|
|
240
591
|
let Model = _Model.bindConnection(this, options);
|
|
241
592
|
|
|
@@ -244,6 +595,37 @@ class ConnectionBase extends EventEmitter {
|
|
|
244
595
|
return Model;
|
|
245
596
|
}
|
|
246
597
|
|
|
598
|
+
/// Register multiple models at the same time.
|
|
599
|
+
///
|
|
600
|
+
/// This will register the provided models with this
|
|
601
|
+
/// connection. The models provided must not already be bound to
|
|
602
|
+
/// another connection, or you must specify the `option`
|
|
603
|
+
/// `{ forceConnectionBinding: true }` if any of them are. You
|
|
604
|
+
/// can specify the `option` of `{ bindModels: false }`
|
|
605
|
+
/// if you don't wish to bind these models to this connection.
|
|
606
|
+
///
|
|
607
|
+
/// Any `options` provided are optional, and will override
|
|
608
|
+
/// the same options provided to the connection itself when
|
|
609
|
+
/// it was created.
|
|
610
|
+
///
|
|
611
|
+
/// Arguments:
|
|
612
|
+
/// Model: Array<class <see>Model</see>> | { [key: string]: class <see>Model</see> }
|
|
613
|
+
/// The model classes to register with this connection. If no models are bound, then
|
|
614
|
+
/// they will simply exist in the model pool for this connection. If bound, then
|
|
615
|
+
/// this connection will bind itself to every model being registered.
|
|
616
|
+
/// options?: object
|
|
617
|
+
/// Options looks like `{ forceConnectionBinding: boolean; bindModels: boolean; }`.
|
|
618
|
+
/// This is an optional argument. Both options will default to the same options
|
|
619
|
+
/// provided to the connection when it was created. If you specify either of these
|
|
620
|
+
/// options they simply override the connection's default.
|
|
621
|
+
///
|
|
622
|
+
/// Return: class <see>Model</see>
|
|
623
|
+
/// The registered model classes, **which may have changed during registration**.
|
|
624
|
+
/// It is not uncommon for the connection driver itself to modify the model
|
|
625
|
+
/// classes, or to return a new model classes that inherit from your model classes.
|
|
626
|
+
/// The classes that are returned should be the classes that you use for this connection,
|
|
627
|
+
/// and will be the same classes returned by a call to <see>Connection.getModel</see>,
|
|
628
|
+
/// or <see>Connection.getModels</see>.
|
|
247
629
|
registerModels(models, options) {
|
|
248
630
|
if (!models)
|
|
249
631
|
return;
|
|
@@ -310,6 +692,30 @@ class ConnectionBase extends EventEmitter {
|
|
|
310
692
|
return Utils.setContextValue(key, value);
|
|
311
693
|
}
|
|
312
694
|
|
|
695
|
+
/// This builds a "connection context" to provide to
|
|
696
|
+
/// the [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html) context
|
|
697
|
+
/// of a <see>Connection.createContext</see> call.
|
|
698
|
+
///
|
|
699
|
+
/// By default, this will set a `connection` property on the context,
|
|
700
|
+
/// which will be the value of this connection instance. It also sets
|
|
701
|
+
/// a `connection` property on the sub-contexts for each model. This
|
|
702
|
+
/// is because models might have different connections, and so need
|
|
703
|
+
/// a context per-model to work properly.
|
|
704
|
+
///
|
|
705
|
+
/// "How could a model have different connections?" you ask? Well, it
|
|
706
|
+
/// probably won't. But being as this is an [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html)
|
|
707
|
+
/// context, it provides the connection to **every** model inside the context.
|
|
708
|
+
/// Your application might be using other models that aren't part of this connection,
|
|
709
|
+
/// and we wouldn't want those to get the wrong connection for those models.
|
|
710
|
+
///
|
|
711
|
+
/// Arguments:
|
|
712
|
+
/// connection?: <see>Connection</see> = this
|
|
713
|
+
/// The connection to create the context for. This can be provided, and
|
|
714
|
+
/// is used in place of `this` instance, for example, in the case of transactions.
|
|
715
|
+
/// Transactions generally are the "same" *connection*, but not the same *instance*.
|
|
716
|
+
///
|
|
717
|
+
/// Return: Map<any, any>
|
|
718
|
+
/// The new context that will be used for <see>Connection.createContext</see>.
|
|
313
719
|
buildConnectionContext(_connection) {
|
|
314
720
|
let connection = _connection || this;
|
|
315
721
|
let models = connection._models;
|
|
@@ -329,38 +735,118 @@ class ConnectionBase extends EventEmitter {
|
|
|
329
735
|
return newContext;
|
|
330
736
|
}
|
|
331
737
|
|
|
738
|
+
/// Create a connection context to serve all code
|
|
739
|
+
/// running inside it this connection.
|
|
740
|
+
///
|
|
741
|
+
/// This uses [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html)
|
|
742
|
+
/// to create a context that is passed through the entire call stack of the callback. In this
|
|
743
|
+
/// way, a connection can be provided to every model and every operation within the call.
|
|
744
|
+
///
|
|
745
|
+
/// Arguments:
|
|
746
|
+
/// callback: async Function
|
|
747
|
+
/// The method to provide the context to. Every call inside this call stack
|
|
748
|
+
/// will be provided the connection.
|
|
749
|
+
/// connection?: <see>Connection</see> = this
|
|
750
|
+
/// The connection to provide. Generally this will just be `this` connection instance,
|
|
751
|
+
/// however, it can be specified, and is for example inside transactions.
|
|
752
|
+
/// thisArg?: any = this
|
|
753
|
+
/// The `this` value to provide to the given `callback`.
|
|
754
|
+
///
|
|
755
|
+
/// Return: any
|
|
756
|
+
/// The return value of the given `callback`.
|
|
332
757
|
async createContext(callback, _connection, thisArg) {
|
|
333
758
|
let connection = _connection || this;
|
|
334
759
|
let context = this.buildConnectionContext(connection);
|
|
335
760
|
|
|
336
761
|
return await Utils.runInContext(context, async () => {
|
|
337
|
-
return await callback.call(thisArg, connection);
|
|
762
|
+
return await callback.call(thisArg || this, connection);
|
|
338
763
|
});
|
|
339
764
|
}
|
|
340
765
|
|
|
766
|
+
/// Find a specific field across all registered models.
|
|
767
|
+
///
|
|
768
|
+
/// This method is similar to [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find),
|
|
769
|
+
/// except that the arguments to this `finder` method are those provided by
|
|
770
|
+
/// <see name="Model.iterateFields">Model.static iterateFields</see>. If this `finder` method
|
|
771
|
+
/// returns a truthy value for a given field, then that is the field that will be returned.
|
|
772
|
+
///
|
|
773
|
+
/// Note:
|
|
774
|
+
/// This will search for the field across all models registered to the connection.
|
|
775
|
+
/// To find a specific field for a known model use <see>Connection.getField</see> instead.
|
|
776
|
+
///
|
|
777
|
+
/// Arguments:
|
|
778
|
+
/// finder: Function
|
|
779
|
+
/// A function to assist in finding the specified field. The signature for this
|
|
780
|
+
/// function must match that used by <see name="Model.iterateFields">Model.static iterateFields</see>.
|
|
781
|
+
///
|
|
782
|
+
/// Return: Field | undefined
|
|
783
|
+
/// The field found, if any.
|
|
341
784
|
findModelField(finder) {
|
|
342
785
|
let modelMap = this.getModels();
|
|
343
786
|
let modelNames = Object.keys(modelMap);
|
|
344
|
-
let results = [];
|
|
345
787
|
|
|
346
788
|
for (let i = 0, il = modelNames.length; i < il; i++) {
|
|
347
789
|
let modelName = modelNames[i];
|
|
348
790
|
let Model = modelMap[modelName];
|
|
791
|
+
let value = Model.iterateFields(finder, null, false, true);
|
|
349
792
|
|
|
350
|
-
|
|
793
|
+
if (value)
|
|
794
|
+
return value;
|
|
351
795
|
}
|
|
352
|
-
|
|
353
|
-
return results;
|
|
354
796
|
}
|
|
355
797
|
|
|
798
|
+
/// This is simply a convenience method that
|
|
799
|
+
/// calls <see>ModelUtils.parseQualifiedName</see>.
|
|
800
|
+
///
|
|
801
|
+
/// See: ModelUtils.parseQualifiedName
|
|
802
|
+
///
|
|
803
|
+
/// Arguments:
|
|
804
|
+
/// fieldName: string
|
|
805
|
+
/// The field name, fully qualified field name, or model name to parse.
|
|
806
|
+
/// See <see>ModelUtils.parseQualifiedName</see> for more information.
|
|
807
|
+
///
|
|
808
|
+
/// Return: object
|
|
809
|
+
/// The result. See <see>ModelUtils.parseQualifiedName</see> for more information.
|
|
356
810
|
parseQualifiedName(str) {
|
|
357
811
|
return Utils.parseQualifiedName(str);
|
|
358
812
|
}
|
|
359
813
|
|
|
814
|
+
/// Get all models known to this connection.
|
|
815
|
+
/// Models are returned as a raw `Object`, and
|
|
816
|
+
/// so can be destructured. The keys of the returned
|
|
817
|
+
/// object are the model's names.
|
|
818
|
+
///
|
|
819
|
+
/// Models can be registered to a connection with the
|
|
820
|
+
/// <see>ConnectionBase.registerModel</see> or
|
|
821
|
+
/// <see>ConnectionBase.registerModels</see> methods.
|
|
822
|
+
///
|
|
823
|
+
/// Return: object
|
|
824
|
+
/// An object of all models known to the connection, where
|
|
825
|
+
/// each key is a model name, and each property value is
|
|
826
|
+
/// the model's class.
|
|
360
827
|
getModels() {
|
|
361
828
|
return this._models;
|
|
362
829
|
}
|
|
363
830
|
|
|
831
|
+
/// Retrieve a single model by its name.
|
|
832
|
+
/// The model must be registered with this
|
|
833
|
+
/// connection to be found.
|
|
834
|
+
///
|
|
835
|
+
/// Models can be registered to a connection with the
|
|
836
|
+
/// <see>ConnectionBase.registerModel</see> or
|
|
837
|
+
/// <see>ConnectionBase.registerModels</see> methods.
|
|
838
|
+
///
|
|
839
|
+
/// This method is "fully qualified aware", meaning you
|
|
840
|
+
/// can pass a fully qualified name, such as "User:id"
|
|
841
|
+
/// and it will fetch the "User" model.
|
|
842
|
+
///
|
|
843
|
+
/// Return: class <see>Model</see>
|
|
844
|
+
/// The model class found by the model's name, or
|
|
845
|
+
/// `undefined` if no model is found.
|
|
846
|
+
///
|
|
847
|
+
/// Arguments:
|
|
848
|
+
/// modelName: string
|
|
849
|
+
/// The model's name, or a fully qualified field name.
|
|
364
850
|
getModel(modelName) {
|
|
365
851
|
if (typeof modelName === 'symbol')
|
|
366
852
|
return;
|
|
@@ -369,6 +855,20 @@ class ConnectionBase extends EventEmitter {
|
|
|
369
855
|
return this._models[def.modelName];
|
|
370
856
|
}
|
|
371
857
|
|
|
858
|
+
/// Get a field by its fully qualified name,
|
|
859
|
+
/// or by a fieldName + a modelName.
|
|
860
|
+
///
|
|
861
|
+
/// Return: <see>Field</see>
|
|
862
|
+
/// The field found, or `undefined` if the specified field is
|
|
863
|
+
/// not found.
|
|
864
|
+
///
|
|
865
|
+
/// Arguments:
|
|
866
|
+
/// fieldName: string
|
|
867
|
+
/// Fully qualified field name. If a fully qualified field name
|
|
868
|
+
/// isn't provided, then you *must* provide the `modelName` argument.
|
|
869
|
+
/// modelName?: string
|
|
870
|
+
/// The name of the model that the field exists on. This argument is
|
|
871
|
+
/// optional if the provided `fieldName` is a fully qualified name.
|
|
372
872
|
getField(fieldName, modelName) {
|
|
373
873
|
let def = this.parseQualifiedName(fieldName);
|
|
374
874
|
if (def.modelName == null)
|
|
@@ -381,19 +881,86 @@ class ConnectionBase extends EventEmitter {
|
|
|
381
881
|
return Model.getField(def.fieldNames[0]);
|
|
382
882
|
}
|
|
383
883
|
|
|
884
|
+
/// Return the <see>QueryEngine</see> class used
|
|
885
|
+
/// for this connection, all its models, and all
|
|
886
|
+
/// query operations. By default this is just the
|
|
887
|
+
/// built-in <see>QueryEngine</see> that Mythix ORM
|
|
888
|
+
/// provides. You can create your own, and provide
|
|
889
|
+
/// it as the `QueryEngine` option to the connection
|
|
890
|
+
/// when you create the connection.
|
|
891
|
+
///
|
|
892
|
+
/// Return: class <see>QueryEngine</see>
|
|
893
|
+
/// The QueryEngine to use for this connection, all
|
|
894
|
+
/// its models, and all query operations for this
|
|
895
|
+
/// connection.
|
|
384
896
|
getQueryEngineClass() {
|
|
385
897
|
let options = this.getOptions();
|
|
386
898
|
return options.QueryEngine;
|
|
387
899
|
}
|
|
388
900
|
|
|
901
|
+
/// Get the <see>QueryGenerator</see> instance
|
|
902
|
+
/// for this connection, if it has one.
|
|
903
|
+
///
|
|
904
|
+
/// All connection drivers may not have a query generator.
|
|
905
|
+
/// The query generator is the class that takes care of
|
|
906
|
+
/// generating queries for the underlying database (i.e. SQL).
|
|
907
|
+
/// If a query generator exists on a connection, it is very
|
|
908
|
+
/// likely to be unique to the connection (i.e. PostgreSQL and MySQL
|
|
909
|
+
/// have different query generators).
|
|
910
|
+
///
|
|
911
|
+
/// Return: <see>QueryGenerator</see> | null
|
|
912
|
+
/// Return the <see>QueryGenerator</see> for this connection,
|
|
913
|
+
/// or return `null` if none is defined for this connection.
|
|
389
914
|
getQueryGenerator() {
|
|
390
915
|
return this.queryGenerator;
|
|
391
916
|
}
|
|
392
917
|
|
|
918
|
+
/// Set the <see>QueryGenerator</see> instance for this
|
|
919
|
+
/// connection. This is rarely used as the <see>QueryGenerator</see>
|
|
920
|
+
/// is often supplied as connection options when creating
|
|
921
|
+
/// the connection (as the `queryGenerator` option). However,
|
|
922
|
+
/// it can be set to a new instance at any time with this
|
|
923
|
+
/// method.
|
|
924
|
+
///
|
|
925
|
+
/// Return: undefined
|
|
926
|
+
///
|
|
927
|
+
/// Arguments:
|
|
928
|
+
/// queryGenerator: <see>QueryGenerator</see> | null
|
|
929
|
+
/// The new <see>QueryGenerator</see> instance to use
|
|
930
|
+
/// for generating underlying database queries. Set
|
|
931
|
+
/// to `null` to specify no query generator (note:
|
|
932
|
+
/// this might break whatever connection you are using
|
|
933
|
+
/// as most connections require their query generator).
|
|
393
934
|
setQueryGenerator(queryGenerator) {
|
|
394
935
|
this.queryGenerator = queryGenerator;
|
|
395
936
|
}
|
|
396
937
|
|
|
938
|
+
/// The low-level DB interface for escaping a
|
|
939
|
+
/// value. By default this function uses the
|
|
940
|
+
/// [sqlstring](https://www.npmjs.com/package/sqlstring)
|
|
941
|
+
/// module to escape values. However, the `escape`
|
|
942
|
+
/// method for whatever database the connection is
|
|
943
|
+
/// using should be used instead of this. This is
|
|
944
|
+
/// a "default implementation" that is meant as a
|
|
945
|
+
/// fallback when a connection doesn't provide its
|
|
946
|
+
/// own, but each connection should provide its own
|
|
947
|
+
/// when it is able.
|
|
948
|
+
///
|
|
949
|
+
/// Note:
|
|
950
|
+
/// This method escapes "values" that are given in
|
|
951
|
+
/// the underlying query language of the database.
|
|
952
|
+
/// To escape identifiers, use the <see>ConnectionBase._escapeID</see>
|
|
953
|
+
/// instead.
|
|
954
|
+
///
|
|
955
|
+
/// Return: string
|
|
956
|
+
/// The value provided, escaped for the specific
|
|
957
|
+
/// underlying database driver.
|
|
958
|
+
///
|
|
959
|
+
/// Arguments:
|
|
960
|
+
/// value: any
|
|
961
|
+
/// The value to escape. This could be a number, a boolean,
|
|
962
|
+
/// a string, or anything else that can be provided to your
|
|
963
|
+
/// specific database.
|
|
397
964
|
_escape(value) {
|
|
398
965
|
if (Nife.instanceOf(value, 'string'))
|
|
399
966
|
return `'${value.replace(/'/g, '\'\'')}'`;
|
|
@@ -401,6 +968,64 @@ class ConnectionBase extends EventEmitter {
|
|
|
401
968
|
return SqlString.escape(value);
|
|
402
969
|
}
|
|
403
970
|
|
|
971
|
+
/// Unlike <see>ConnectionBase._escape</see> --which is
|
|
972
|
+
/// a low-level interface for the database-- this method
|
|
973
|
+
/// will escape specific values in specific ways needed
|
|
974
|
+
/// by Mythix ORM. Said another way, whereas <see>ConnectionBase._escape</see>
|
|
975
|
+
/// is a "low level database method", this is a "high level
|
|
976
|
+
/// Mythix ORM" method.
|
|
977
|
+
///
|
|
978
|
+
/// If this method is provided a literal, then it will convert
|
|
979
|
+
/// the literal into a string, and return the resulting string.
|
|
980
|
+
/// This is the purpose of the `options` argument. The `options`
|
|
981
|
+
/// argument will be passed to the literal's `toString` method.
|
|
982
|
+
///
|
|
983
|
+
/// For any non-literal value, it is first passed through the
|
|
984
|
+
/// field's `serialize` method, for example `value = field.type.serialize(value, thisConnection);`.
|
|
985
|
+
/// This generally won't modify the incoming value, but it might,
|
|
986
|
+
/// for example, with DATE, or DATETIME types, that are modified
|
|
987
|
+
/// to match an acceptable format for the underlying database.
|
|
988
|
+
///
|
|
989
|
+
/// If this method is provided a boolean, then it will return
|
|
990
|
+
/// an upper-cased version of the boolean as a string, i.e. `true` will be returned
|
|
991
|
+
/// as `'TRUE'`, and `false` will be returned as `'FALSE'`.
|
|
992
|
+
///
|
|
993
|
+
/// If this method is provided a BigInt, then it will convert the
|
|
994
|
+
/// bigint into a string representation of the number, i.e. 42n will
|
|
995
|
+
/// be returned as `'42'`.
|
|
996
|
+
///
|
|
997
|
+
/// If this method is provided an `Array` value, then the array
|
|
998
|
+
/// is processed by the connection-specific `prepareArrayValuesForSQL`
|
|
999
|
+
/// method. By default, this method will complete the following operations
|
|
1000
|
+
/// on the provided array:
|
|
1001
|
+
///
|
|
1002
|
+
/// 1. It will flatten the provided array into a 1D array
|
|
1003
|
+
/// 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`
|
|
1004
|
+
/// 3. It will further filter out duplicate values from the array, such that the processed array only contains unique values
|
|
1005
|
+
///
|
|
1006
|
+
/// After the array is processed with the `prepareArrayValuesForSQL` method,
|
|
1007
|
+
/// it will then be mapped such that each value is passed through this
|
|
1008
|
+
/// `escape` method, and then all remaining values in the array will be
|
|
1009
|
+
/// joined with a `,` character between each element. The idea here is that
|
|
1010
|
+
/// if you are providing an array to the underlying database, it is usually
|
|
1011
|
+
/// for an `IN` or `NOT IN` operator, so the result will generally be used for
|
|
1012
|
+
/// one of these. Keep in mind however that each connection driver might escape
|
|
1013
|
+
/// values (including arrays) differently.
|
|
1014
|
+
///
|
|
1015
|
+
/// All other provided values are simply handed off to <see>ConnectionBase._escape</see>.
|
|
1016
|
+
///
|
|
1017
|
+
/// Return: string
|
|
1018
|
+
/// The escaped value, as a string.
|
|
1019
|
+
///
|
|
1020
|
+
/// Arguments:
|
|
1021
|
+
/// field: <see>Field</see>
|
|
1022
|
+
/// The field this value is coming from.
|
|
1023
|
+
/// value: any
|
|
1024
|
+
/// The value to escape.
|
|
1025
|
+
/// options?: object
|
|
1026
|
+
/// The options to provide to a Literal's `toString`
|
|
1027
|
+
/// method. This `options` object is only ever used
|
|
1028
|
+
/// if the provided `value` is a Literal.
|
|
404
1029
|
escape(field, _value, options) {
|
|
405
1030
|
var value = _value;
|
|
406
1031
|
if (LiteralBase.isLiteral(value))
|
|
@@ -425,11 +1050,49 @@ class ConnectionBase extends EventEmitter {
|
|
|
425
1050
|
return this._escape(value);
|
|
426
1051
|
}
|
|
427
1052
|
|
|
1053
|
+
/// Low-level database method for escaping an identifier.
|
|
1054
|
+
/// Each database driver should provide its own version of
|
|
1055
|
+
/// this method. This is the "default" method Mythix ORM
|
|
1056
|
+
/// provides as a "fallback" to database drivers that don't
|
|
1057
|
+
/// supply their own.
|
|
1058
|
+
///
|
|
1059
|
+
/// It works by first stripping all quotes (single `'`, double `"`, and backtick `` ` ``)
|
|
1060
|
+
/// from the provided `value`. After this, it will split on the period (dot) character
|
|
1061
|
+
/// `.`, and then will map each resulting part through [sqlstring](https://www.npmjs.com/package/sqlstring)
|
|
1062
|
+
/// `escapeId` method, finally re-joining the parts with a period `.` character.
|
|
1063
|
+
///
|
|
1064
|
+
/// The extra processing is to allow for already escaped identifiers to not be double-escaped.
|
|
1065
|
+
///
|
|
1066
|
+
/// Return: string
|
|
1067
|
+
/// The provided identifier, escaped for the underlying database.
|
|
1068
|
+
///
|
|
1069
|
+
/// Arguments:
|
|
1070
|
+
/// value: string
|
|
1071
|
+
/// The identifier to escape.
|
|
428
1072
|
_escapeID(value) {
|
|
429
1073
|
let parts = value.replace(/['"`]/g, '').split(/\.+/g);
|
|
430
1074
|
return parts.map((part) => SqlString.escapeId(part).replace(/^`/, '"').replace(/`$/, '"')).join('.');
|
|
431
1075
|
}
|
|
432
1076
|
|
|
1077
|
+
/// This method is very similar to <see>ConnectionBase._escapeID</see>,
|
|
1078
|
+
/// except that instead of being a "low level database method" that the
|
|
1079
|
+
/// database driver itself provides, this is the "Mythix ORM" implementation
|
|
1080
|
+
/// of escaping identifiers. The only difference from <see>ConnectionBase._escapeID</see>
|
|
1081
|
+
/// is that if the provided value is a Literal, it will be converted to a
|
|
1082
|
+
/// string and returned *without* being escaped. Literals are never modified,
|
|
1083
|
+
/// and are always provided to the underlying database exactly as they were defined.
|
|
1084
|
+
///
|
|
1085
|
+
/// Return: string
|
|
1086
|
+
/// The escaped identifier, or if `value` is a Literal, the Literal
|
|
1087
|
+
/// converted to a string.
|
|
1088
|
+
///
|
|
1089
|
+
/// Arguments:
|
|
1090
|
+
/// value: string
|
|
1091
|
+
/// The identifier to escape. If this is a Literal instead of a string,
|
|
1092
|
+
/// then the Literal will be converted to a string and returned.
|
|
1093
|
+
/// options?: object
|
|
1094
|
+
/// The options to pass to `Literal.toString`. This options object is only
|
|
1095
|
+
/// used if the provided `value` is a Literal instance.
|
|
433
1096
|
escapeID(value, options) {
|
|
434
1097
|
if (LiteralBase.isLiteral(value))
|
|
435
1098
|
return value.toString(this.connection, options);
|
|
@@ -437,6 +1100,34 @@ class ConnectionBase extends EventEmitter {
|
|
|
437
1100
|
return this._escapeID(value);
|
|
438
1101
|
}
|
|
439
1102
|
|
|
1103
|
+
/// Convert the provided <see>AverageLiteral</see> to a string
|
|
1104
|
+
/// for the underlying database driver. The conversion
|
|
1105
|
+
/// will be database specific. The database driver connection
|
|
1106
|
+
/// is free to override this method.
|
|
1107
|
+
///
|
|
1108
|
+
/// Note:
|
|
1109
|
+
/// This method is a proxy method for <see>QueryGenerator._averageLiteralToString</see>.
|
|
1110
|
+
/// If the connection has no instance of a `queryGenerator` available to it,
|
|
1111
|
+
/// then this method will simply return `undefined`.
|
|
1112
|
+
///
|
|
1113
|
+
/// Note:
|
|
1114
|
+
/// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
|
|
1115
|
+
/// needed or used directly by the user, but instead are used by the underlying
|
|
1116
|
+
/// connection itself, to define context specific options. For example, the underlying
|
|
1117
|
+
/// connection might have an option to tell a literal that it is the "DEFAULT" value
|
|
1118
|
+
/// of a field, instead of just a raw value to inject in the generated query stream,
|
|
1119
|
+
/// and this might change the output of the literal when converted to a string.
|
|
1120
|
+
///
|
|
1121
|
+
/// Return: string
|
|
1122
|
+
/// The provided <see>AverageLiteral</see> converted to
|
|
1123
|
+
/// a string for the underlying database driver.
|
|
1124
|
+
///
|
|
1125
|
+
/// Arguments:
|
|
1126
|
+
/// literal: <see>AverageLiteral</see>
|
|
1127
|
+
/// The literal to convert to a string for the database.
|
|
1128
|
+
/// options?: object
|
|
1129
|
+
/// Optional options to pass to the <see>QueryGenerator._averageLiteralToString</see>
|
|
1130
|
+
/// method.
|
|
440
1131
|
_averageLiteralToString(literal, options) {
|
|
441
1132
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
442
1133
|
return;
|
|
@@ -448,6 +1139,34 @@ class ConnectionBase extends EventEmitter {
|
|
|
448
1139
|
return queryGenerator._averageLiteralToString(literal, options);
|
|
449
1140
|
}
|
|
450
1141
|
|
|
1142
|
+
/// Convert the provided <see>CountLiteral</see> to a string
|
|
1143
|
+
/// for the underlying database driver. The conversion
|
|
1144
|
+
/// will be database specific. The database driver connection
|
|
1145
|
+
/// is free to override this method.
|
|
1146
|
+
///
|
|
1147
|
+
/// Note:
|
|
1148
|
+
/// This method is a proxy method for <see>QueryGenerator._countLiteralToString</see>.
|
|
1149
|
+
/// If the connection has no instance of a `queryGenerator` available to it,
|
|
1150
|
+
/// then this method will simply return `undefined`.
|
|
1151
|
+
///
|
|
1152
|
+
/// Note:
|
|
1153
|
+
/// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
|
|
1154
|
+
/// needed or used directly by the user, but instead are used by the underlying
|
|
1155
|
+
/// connection itself, to define context specific options. For example, the underlying
|
|
1156
|
+
/// connection might have an option to tell a literal that it is the "DEFAULT" value
|
|
1157
|
+
/// of a field, instead of just a raw value to inject in the generated query stream,
|
|
1158
|
+
/// and this might change the output of the literal when converted to a string.
|
|
1159
|
+
///
|
|
1160
|
+
/// Return: string
|
|
1161
|
+
/// The provided <see>CountLiteral</see> converted to
|
|
1162
|
+
/// a string for the underlying database driver.
|
|
1163
|
+
///
|
|
1164
|
+
/// Arguments:
|
|
1165
|
+
/// literal: <see>CountLiteral</see>
|
|
1166
|
+
/// The literal to convert to a string for the database.
|
|
1167
|
+
/// options?: object
|
|
1168
|
+
/// Optional options to pass to the <see>QueryGenerator._countLiteralToString</see>
|
|
1169
|
+
/// method.
|
|
451
1170
|
_countLiteralToString(literal, options) {
|
|
452
1171
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
453
1172
|
return;
|
|
@@ -459,6 +1178,34 @@ class ConnectionBase extends EventEmitter {
|
|
|
459
1178
|
return queryGenerator._countLiteralToString(literal, options);
|
|
460
1179
|
}
|
|
461
1180
|
|
|
1181
|
+
/// Convert the provided <see>DistinctLiteral</see> to a string
|
|
1182
|
+
/// for the underlying database driver. The conversion
|
|
1183
|
+
/// will be database specific. The database driver connection
|
|
1184
|
+
/// is free to override this method.
|
|
1185
|
+
///
|
|
1186
|
+
/// Note:
|
|
1187
|
+
/// This method is a proxy method for <see>QueryGenerator._distinctLiteralToString</see>.
|
|
1188
|
+
/// If the connection has no instance of a `queryGenerator` available to it,
|
|
1189
|
+
/// then this method will simply return `undefined`.
|
|
1190
|
+
///
|
|
1191
|
+
/// Note:
|
|
1192
|
+
/// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
|
|
1193
|
+
/// needed or used directly by the user, but instead are used by the underlying
|
|
1194
|
+
/// connection itself, to define context specific options. For example, the underlying
|
|
1195
|
+
/// connection might have an option to tell a literal that it is the "DEFAULT" value
|
|
1196
|
+
/// of a field, instead of just a raw value to inject in the generated query stream,
|
|
1197
|
+
/// and this might change the output of the literal when converted to a string.
|
|
1198
|
+
///
|
|
1199
|
+
/// Return: string
|
|
1200
|
+
/// The provided <see>DistinctLiteral</see> converted to
|
|
1201
|
+
/// a string for the underlying database driver.
|
|
1202
|
+
///
|
|
1203
|
+
/// Arguments:
|
|
1204
|
+
/// literal: <see>DistinctLiteral</see>
|
|
1205
|
+
/// The literal to convert to a string for the database.
|
|
1206
|
+
/// options?: object
|
|
1207
|
+
/// Optional options to pass to the <see>QueryGenerator._distinctLiteralToString</see>
|
|
1208
|
+
/// method.
|
|
462
1209
|
_distinctLiteralToString(literal, options) {
|
|
463
1210
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
464
1211
|
return;
|
|
@@ -470,6 +1217,34 @@ class ConnectionBase extends EventEmitter {
|
|
|
470
1217
|
return queryGenerator._distinctLiteralToString(literal, options);
|
|
471
1218
|
}
|
|
472
1219
|
|
|
1220
|
+
/// Convert the provided <see>FieldLiteral</see> to a string
|
|
1221
|
+
/// for the underlying database driver. The conversion
|
|
1222
|
+
/// will be database specific. The database driver connection
|
|
1223
|
+
/// is free to override this method.
|
|
1224
|
+
///
|
|
1225
|
+
/// Note:
|
|
1226
|
+
/// This method is a proxy method for <see>QueryGenerator._fieldLiteralToString</see>.
|
|
1227
|
+
/// If the connection has no instance of a `queryGenerator` available to it,
|
|
1228
|
+
/// then this method will simply return `undefined`.
|
|
1229
|
+
///
|
|
1230
|
+
/// Note:
|
|
1231
|
+
/// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
|
|
1232
|
+
/// needed or used directly by the user, but instead are used by the underlying
|
|
1233
|
+
/// connection itself, to define context specific options. For example, the underlying
|
|
1234
|
+
/// connection might have an option to tell a literal that it is the "DEFAULT" value
|
|
1235
|
+
/// of a field, instead of just a raw value to inject in the generated query stream,
|
|
1236
|
+
/// and this might change the output of the literal when converted to a string.
|
|
1237
|
+
///
|
|
1238
|
+
/// Return: string
|
|
1239
|
+
/// The provided <see>FieldLiteral</see> converted to
|
|
1240
|
+
/// a string for the underlying database driver.
|
|
1241
|
+
///
|
|
1242
|
+
/// Arguments:
|
|
1243
|
+
/// literal: <see>FieldLiteral</see>
|
|
1244
|
+
/// The literal to convert to a string for the database.
|
|
1245
|
+
/// options?: object
|
|
1246
|
+
/// Optional options to pass to the <see>QueryGenerator._fieldLiteralToString</see>
|
|
1247
|
+
/// method.
|
|
473
1248
|
_fieldLiteralToString(literal, options) {
|
|
474
1249
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
475
1250
|
return;
|
|
@@ -481,6 +1256,34 @@ class ConnectionBase extends EventEmitter {
|
|
|
481
1256
|
return queryGenerator._fieldLiteralToString(literal, options);
|
|
482
1257
|
}
|
|
483
1258
|
|
|
1259
|
+
/// Convert the provided <see>MaxLiteral</see> to a string
|
|
1260
|
+
/// for the underlying database driver. The conversion
|
|
1261
|
+
/// will be database specific. The database driver connection
|
|
1262
|
+
/// is free to override this method.
|
|
1263
|
+
///
|
|
1264
|
+
/// Note:
|
|
1265
|
+
/// This method is a proxy method for <see>QueryGenerator._maxLiteralToString</see>.
|
|
1266
|
+
/// If the connection has no instance of a `queryGenerator` available to it,
|
|
1267
|
+
/// then this method will simply return `undefined`.
|
|
1268
|
+
///
|
|
1269
|
+
/// Note:
|
|
1270
|
+
/// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
|
|
1271
|
+
/// needed or used directly by the user, but instead are used by the underlying
|
|
1272
|
+
/// connection itself, to define context specific options. For example, the underlying
|
|
1273
|
+
/// connection might have an option to tell a literal that it is the "DEFAULT" value
|
|
1274
|
+
/// of a field, instead of just a raw value to inject in the generated query stream,
|
|
1275
|
+
/// and this might change the output of the literal when converted to a string.
|
|
1276
|
+
///
|
|
1277
|
+
/// Return: string
|
|
1278
|
+
/// The provided <see>MaxLiteral</see> converted to
|
|
1279
|
+
/// a string for the underlying database driver.
|
|
1280
|
+
///
|
|
1281
|
+
/// Arguments:
|
|
1282
|
+
/// literal: <see>MaxLiteral</see>
|
|
1283
|
+
/// The literal to convert to a string for the database.
|
|
1284
|
+
/// options?: object
|
|
1285
|
+
/// Optional options to pass to the <see>QueryGenerator._maxLiteralToString</see>
|
|
1286
|
+
/// method.
|
|
484
1287
|
_maxLiteralToString(literal, options) {
|
|
485
1288
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
486
1289
|
return;
|
|
@@ -492,6 +1295,34 @@ class ConnectionBase extends EventEmitter {
|
|
|
492
1295
|
return queryGenerator._maxLiteralToString(literal, options);
|
|
493
1296
|
}
|
|
494
1297
|
|
|
1298
|
+
/// Convert the provided <see>MinLiteral</see> to a string
|
|
1299
|
+
/// for the underlying database driver. The conversion
|
|
1300
|
+
/// will be database specific. The database driver connection
|
|
1301
|
+
/// is free to override this method.
|
|
1302
|
+
///
|
|
1303
|
+
/// Note:
|
|
1304
|
+
/// This method is a proxy method for <see>QueryGenerator._minLiteralToString</see>.
|
|
1305
|
+
/// If the connection has no instance of a `queryGenerator` available to it,
|
|
1306
|
+
/// then this method will simply return `undefined`.
|
|
1307
|
+
///
|
|
1308
|
+
/// Note:
|
|
1309
|
+
/// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
|
|
1310
|
+
/// needed or used directly by the user, but instead are used by the underlying
|
|
1311
|
+
/// connection itself, to define context specific options. For example, the underlying
|
|
1312
|
+
/// connection might have an option to tell a literal that it is the "DEFAULT" value
|
|
1313
|
+
/// of a field, instead of just a raw value to inject in the generated query stream,
|
|
1314
|
+
/// and this might change the output of the literal when converted to a string.
|
|
1315
|
+
///
|
|
1316
|
+
/// Return: string
|
|
1317
|
+
/// The provided <see>MinLiteral</see> converted to
|
|
1318
|
+
/// a string for the underlying database driver.
|
|
1319
|
+
///
|
|
1320
|
+
/// Arguments:
|
|
1321
|
+
/// literal: <see>MinLiteral</see>
|
|
1322
|
+
/// The literal to convert to a string for the database.
|
|
1323
|
+
/// options?: object
|
|
1324
|
+
/// Optional options to pass to the <see>QueryGenerator._minLiteralToString</see>
|
|
1325
|
+
/// method.
|
|
495
1326
|
_minLiteralToString(literal, options) {
|
|
496
1327
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
497
1328
|
return;
|
|
@@ -503,6 +1334,34 @@ class ConnectionBase extends EventEmitter {
|
|
|
503
1334
|
return queryGenerator._minLiteralToString(literal, options);
|
|
504
1335
|
}
|
|
505
1336
|
|
|
1337
|
+
/// Convert the provided <see>SumLiteral</see> to a string
|
|
1338
|
+
/// for the underlying database driver. The conversion
|
|
1339
|
+
/// will be database specific. The database driver connection
|
|
1340
|
+
/// is free to override this method.
|
|
1341
|
+
///
|
|
1342
|
+
/// Note:
|
|
1343
|
+
/// This method is a proxy method for <see>QueryGenerator._sumLiteralToString</see>.
|
|
1344
|
+
/// If the connection has no instance of a `queryGenerator` available to it,
|
|
1345
|
+
/// then this method will simply return `undefined`.
|
|
1346
|
+
///
|
|
1347
|
+
/// Note:
|
|
1348
|
+
/// Generally speaking, Literal "options" are literal (and connection) specific. They often aren't
|
|
1349
|
+
/// needed or used directly by the user, but instead are used by the underlying
|
|
1350
|
+
/// connection itself, to define context specific options. For example, the underlying
|
|
1351
|
+
/// connection might have an option to tell a literal that it is the "DEFAULT" value
|
|
1352
|
+
/// of a field, instead of just a raw value to inject in the generated query stream,
|
|
1353
|
+
/// and this might change the output of the literal when converted to a string.
|
|
1354
|
+
///
|
|
1355
|
+
/// Return: string
|
|
1356
|
+
/// The provided <see>SumLiteral</see> converted to
|
|
1357
|
+
/// a string for the underlying database driver.
|
|
1358
|
+
///
|
|
1359
|
+
/// Arguments:
|
|
1360
|
+
/// literal: <see>SumLiteral</see>
|
|
1361
|
+
/// The literal to convert to a string for the database.
|
|
1362
|
+
/// options?: object
|
|
1363
|
+
/// Optional options to pass to the <see>QueryGenerator._sumLiteralToString</see>
|
|
1364
|
+
/// method.
|
|
506
1365
|
_sumLiteralToString(literal, options) {
|
|
507
1366
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
508
1367
|
return;
|
|
@@ -514,6 +1373,35 @@ class ConnectionBase extends EventEmitter {
|
|
|
514
1373
|
return queryGenerator._sumLiteralToString(literal, options);
|
|
515
1374
|
}
|
|
516
1375
|
|
|
1376
|
+
/// Convert the provided Literal to a string
|
|
1377
|
+
/// for the underlying database driver. The conversion
|
|
1378
|
+
/// will be database specific. The database driver connection
|
|
1379
|
+
/// is free to override this method.
|
|
1380
|
+
///
|
|
1381
|
+
/// This method will convert a <see>AverageLiteral</see>, a
|
|
1382
|
+
/// <see>CountLiteral</see>, a <see>DistinctLiteral</see>,
|
|
1383
|
+
/// a <see>FieldLiteral</see>, a <see>MaxLiteral</see>, a
|
|
1384
|
+
/// <see>MinLiteral</see>, a <see>SumLiteral</see>, or a
|
|
1385
|
+
/// <see>Literal</see> to a string. If the provided literal
|
|
1386
|
+
/// is not one of these types, than an exception will be thrown.
|
|
1387
|
+
///
|
|
1388
|
+
/// If you want to add custom literals to your application, then
|
|
1389
|
+
/// you will need to overload this method, and handle those custom
|
|
1390
|
+
/// literals manually (or simply stick to using <see>Literal</see>).
|
|
1391
|
+
///
|
|
1392
|
+
/// Return: string
|
|
1393
|
+
/// The provided literal, converted to a string for the underlying
|
|
1394
|
+
/// database driver.
|
|
1395
|
+
///
|
|
1396
|
+
/// Arguments:
|
|
1397
|
+
/// literal: <see>LiteralBase</see>
|
|
1398
|
+
/// The literal to convert.
|
|
1399
|
+
/// options?: object
|
|
1400
|
+
/// Optional options that can be passed to the literal conversion
|
|
1401
|
+
/// method. These are generally not provided by the user, but rather
|
|
1402
|
+
/// are often provided by the connection itself, for context-specific
|
|
1403
|
+
/// literal conversions. These options can and will changed based on
|
|
1404
|
+
/// the literal being converted, and the underlying connection.
|
|
517
1405
|
literalToString(literal, options) {
|
|
518
1406
|
if (Literals.AverageLiteral.isLiteralType(literal))
|
|
519
1407
|
return this._averageLiteralToString(literal, options);
|
|
@@ -535,86 +1423,308 @@ class ConnectionBase extends EventEmitter {
|
|
|
535
1423
|
throw new Error(`${this.constructor.name}::literalToString: Unsupported literal ${literal}.`);
|
|
536
1424
|
}
|
|
537
1425
|
|
|
1426
|
+
/// Convert a "BIGINT" field type to a type
|
|
1427
|
+
/// acceptable by the underlying database driver.
|
|
1428
|
+
///
|
|
1429
|
+
/// For most SQL connections this would be `BIGINT`,
|
|
1430
|
+
/// however, it may be different based on what database you are using.
|
|
1431
|
+
///
|
|
1432
|
+
/// Return: string
|
|
1433
|
+
/// The field type needed by the underlying database driver.
|
|
1434
|
+
///
|
|
1435
|
+
/// Arguments:
|
|
1436
|
+
/// type: <see>Type</see>
|
|
1437
|
+
/// The field type to convert to use in the underlying database.
|
|
538
1438
|
// eslint-disable-next-line no-unused-vars
|
|
539
1439
|
_bigintTypeToString(type) {
|
|
540
1440
|
return 'BIGINT';
|
|
541
1441
|
}
|
|
542
1442
|
|
|
1443
|
+
/// Convert a "BLOB" field type to a type
|
|
1444
|
+
/// acceptable by the underlying database driver.
|
|
1445
|
+
///
|
|
1446
|
+
/// For most SQL connections this would be `BLOB`,
|
|
1447
|
+
/// however, it may be different based on what database you are using.
|
|
1448
|
+
///
|
|
1449
|
+
/// Return: string
|
|
1450
|
+
/// The field type needed by the underlying database driver.
|
|
1451
|
+
///
|
|
1452
|
+
/// Arguments:
|
|
1453
|
+
/// type: <see>Type</see>
|
|
1454
|
+
/// The field type to convert to use in the underlying database.
|
|
543
1455
|
// eslint-disable-next-line no-unused-vars
|
|
544
1456
|
_blobTypeToString(type) {
|
|
545
1457
|
return 'BLOB';
|
|
546
1458
|
}
|
|
547
1459
|
|
|
1460
|
+
/// Convert a "BOOLEAN" field type to a type
|
|
1461
|
+
/// acceptable by the underlying database driver.
|
|
1462
|
+
///
|
|
1463
|
+
/// For most SQL connections this would be `BOOLEAN`,
|
|
1464
|
+
/// however, it may be different based on what database you are using.
|
|
1465
|
+
///
|
|
1466
|
+
/// Return: string
|
|
1467
|
+
/// The field type needed by the underlying database driver.
|
|
1468
|
+
///
|
|
1469
|
+
/// Arguments:
|
|
1470
|
+
/// type: <see>Type</see>
|
|
1471
|
+
/// The field type to convert to use in the underlying database.
|
|
548
1472
|
// eslint-disable-next-line no-unused-vars
|
|
549
1473
|
_booleanTypeToString(type) {
|
|
550
1474
|
return 'BOOLEAN';
|
|
551
1475
|
}
|
|
552
1476
|
|
|
1477
|
+
/// Convert a "CHAR" field type to a type
|
|
1478
|
+
/// acceptable by the underlying database driver.
|
|
1479
|
+
///
|
|
1480
|
+
/// For most SQL connections this would be `CHAR`,
|
|
1481
|
+
/// however, it may be different based on what database you are using.
|
|
1482
|
+
///
|
|
1483
|
+
/// Return: string
|
|
1484
|
+
/// The field type needed by the underlying database driver.
|
|
1485
|
+
///
|
|
1486
|
+
/// Arguments:
|
|
1487
|
+
/// type: <see>Type</see>
|
|
1488
|
+
/// The field type to convert to use in the underlying database.
|
|
553
1489
|
// eslint-disable-next-line no-unused-vars
|
|
554
1490
|
_charTypeToString(type) {
|
|
555
1491
|
return 'CHAR';
|
|
556
1492
|
}
|
|
557
1493
|
|
|
1494
|
+
/// Convert a "DATE" field type to a type
|
|
1495
|
+
/// acceptable by the underlying database driver.
|
|
1496
|
+
///
|
|
1497
|
+
/// For most SQL connections this would be `BIGINT`,
|
|
1498
|
+
/// however, it may be different based on what database you are using.
|
|
1499
|
+
///
|
|
1500
|
+
/// Note:
|
|
1501
|
+
/// Mythix ORM always stores DATE and DATETIME types as a timestamp
|
|
1502
|
+
/// (in milliseconds from the UNIX Epoch) whenever it is able to.
|
|
1503
|
+
/// This is why the default type for most connection drivers is
|
|
1504
|
+
/// `BIGINT`. Another common type for this conversion is `TIMESTAMP`.
|
|
1505
|
+
///
|
|
1506
|
+
/// Return: string
|
|
1507
|
+
/// The field type needed by the underlying database driver.
|
|
1508
|
+
///
|
|
1509
|
+
/// Arguments:
|
|
1510
|
+
/// type: <see>Type</see>
|
|
1511
|
+
/// The field type to convert to use in the underlying database.
|
|
558
1512
|
// eslint-disable-next-line no-unused-vars
|
|
559
1513
|
_dateTypeToString(type) {
|
|
560
1514
|
return 'TIMESTAMP';
|
|
561
1515
|
}
|
|
562
1516
|
|
|
1517
|
+
/// Convert a "DATETIME" field type to a type
|
|
1518
|
+
/// acceptable by the underlying database driver.
|
|
1519
|
+
///
|
|
1520
|
+
/// For most SQL connections this would be `BIGINT`,
|
|
1521
|
+
/// however, it may be different based on what database you are using.
|
|
1522
|
+
///
|
|
1523
|
+
/// Note:
|
|
1524
|
+
/// Mythix ORM always stores DATE and DATETIME types as a timestamp
|
|
1525
|
+
/// (in milliseconds from the UNIX Epoch) whenever it is able to.
|
|
1526
|
+
/// This is why the default type for most connection drivers is
|
|
1527
|
+
/// `BIGINT`. Another common type for this conversion is `TIMESTAMP`.
|
|
1528
|
+
///
|
|
1529
|
+
/// Return: string
|
|
1530
|
+
/// The field type needed by the underlying database driver.
|
|
1531
|
+
///
|
|
1532
|
+
/// Arguments:
|
|
1533
|
+
/// type: <see>Type</see>
|
|
1534
|
+
/// The field type to convert to use in the underlying database.
|
|
563
1535
|
// eslint-disable-next-line no-unused-vars
|
|
564
1536
|
_datetimeTypeToString(type) {
|
|
565
1537
|
return 'TIMESTAMP';
|
|
566
1538
|
}
|
|
567
1539
|
|
|
1540
|
+
/// Convert a "NUMERIC" field type to a type
|
|
1541
|
+
/// acceptable by the underlying database driver.
|
|
1542
|
+
///
|
|
1543
|
+
/// For most SQL connections this would be `NUMERIC`, `DECIMAL`,
|
|
1544
|
+
/// or `NUMBER`, however, it may be different based on what database
|
|
1545
|
+
/// you are using.
|
|
1546
|
+
///
|
|
1547
|
+
/// Return: string
|
|
1548
|
+
/// The field type needed by the underlying database driver.
|
|
1549
|
+
///
|
|
1550
|
+
/// Arguments:
|
|
1551
|
+
/// type: <see>Type</see>
|
|
1552
|
+
/// The field type to convert to use in the underlying database.
|
|
568
1553
|
// eslint-disable-next-line no-unused-vars
|
|
569
1554
|
_numericTypeToString(type) {
|
|
570
1555
|
return `NUMERIC(${type.precision}, ${type.scale})`;
|
|
571
1556
|
}
|
|
572
1557
|
|
|
1558
|
+
/// Convert a "REAL" field type to a type
|
|
1559
|
+
/// acceptable by the underlying database driver.
|
|
1560
|
+
///
|
|
1561
|
+
/// For most SQL connections this would be `FLOAT`,
|
|
1562
|
+
/// however, it may be different based on what database you are using.
|
|
1563
|
+
///
|
|
1564
|
+
/// Return: string
|
|
1565
|
+
/// The field type needed by the underlying database driver.
|
|
1566
|
+
///
|
|
1567
|
+
/// Arguments:
|
|
1568
|
+
/// type: <see>Type</see>
|
|
1569
|
+
/// The field type to convert to use in the underlying database.
|
|
573
1570
|
// eslint-disable-next-line no-unused-vars
|
|
574
1571
|
_realTypeToString(type) {
|
|
575
1572
|
return 'FLOAT';
|
|
576
1573
|
}
|
|
577
1574
|
|
|
1575
|
+
/// Convert a "INTEGER" field type to a type
|
|
1576
|
+
/// acceptable by the underlying database driver.
|
|
1577
|
+
///
|
|
1578
|
+
/// For most SQL connections this would be `INTEGER`,
|
|
1579
|
+
/// however, it may be different based on what database you are using.
|
|
1580
|
+
///
|
|
1581
|
+
/// Return: string
|
|
1582
|
+
/// The field type needed by the underlying database driver.
|
|
1583
|
+
///
|
|
1584
|
+
/// Arguments:
|
|
1585
|
+
/// type: <see>Type</see>
|
|
1586
|
+
/// The field type to convert to use in the underlying database.
|
|
578
1587
|
// eslint-disable-next-line no-unused-vars
|
|
579
1588
|
_integerTypeToString(type) {
|
|
580
1589
|
return 'INTEGER';
|
|
581
1590
|
}
|
|
582
1591
|
|
|
1592
|
+
/// Convert a "STRING" field type to a type
|
|
1593
|
+
/// acceptable by the underlying database driver.
|
|
1594
|
+
///
|
|
1595
|
+
/// For most SQL connections this would be `VARCHAR`,
|
|
1596
|
+
/// however, it may be different based on what database you are using.
|
|
1597
|
+
///
|
|
1598
|
+
/// Return: string
|
|
1599
|
+
/// The field type needed by the underlying database driver.
|
|
1600
|
+
///
|
|
1601
|
+
/// Arguments:
|
|
1602
|
+
/// type: <see>Type</see>
|
|
1603
|
+
/// The field type to convert to use in the underlying database.
|
|
583
1604
|
// eslint-disable-next-line no-unused-vars
|
|
584
1605
|
_stringTypeToString(type) {
|
|
585
1606
|
return `VARCHAR(${type.length})`;
|
|
586
1607
|
}
|
|
587
1608
|
|
|
1609
|
+
/// Convert a "TEXT" field type to a type
|
|
1610
|
+
/// acceptable by the underlying database driver.
|
|
1611
|
+
///
|
|
1612
|
+
/// For most SQL connections this would be `TEXT`,
|
|
1613
|
+
/// however, it may be different based on what database you are using.
|
|
1614
|
+
///
|
|
1615
|
+
/// Return: string
|
|
1616
|
+
/// The field type needed by the underlying database driver.
|
|
1617
|
+
///
|
|
1618
|
+
/// Arguments:
|
|
1619
|
+
/// type: <see>Type</see>
|
|
1620
|
+
/// The field type to convert to use in the underlying database.
|
|
588
1621
|
// eslint-disable-next-line no-unused-vars
|
|
589
1622
|
_textTypeToString(type) {
|
|
590
1623
|
return 'TEXT';
|
|
591
1624
|
}
|
|
592
1625
|
|
|
1626
|
+
/// Convert a "UUIDV1" field type to a type
|
|
1627
|
+
/// acceptable by the underlying database driver.
|
|
1628
|
+
///
|
|
1629
|
+
/// For most SQL connections this would be `VARCHAR`,
|
|
1630
|
+
/// however, it may be different based on what database you are using.
|
|
1631
|
+
///
|
|
1632
|
+
/// Return: string
|
|
1633
|
+
/// The field type needed by the underlying database driver.
|
|
1634
|
+
///
|
|
1635
|
+
/// Arguments:
|
|
1636
|
+
/// type: <see>Type</see>
|
|
1637
|
+
/// The field type to convert to use in the underlying database.
|
|
593
1638
|
// eslint-disable-next-line no-unused-vars
|
|
594
1639
|
_uuidV1TypeToString(type) {
|
|
595
1640
|
return `VARCHAR(${type.getTotalLength()})`;
|
|
596
1641
|
}
|
|
597
1642
|
|
|
1643
|
+
/// Convert a "UUIDV3" field type to a type
|
|
1644
|
+
/// acceptable by the underlying database driver.
|
|
1645
|
+
///
|
|
1646
|
+
/// For most SQL connections this would be `VARCHAR`,
|
|
1647
|
+
/// however, it may be different based on what database you are using.
|
|
1648
|
+
///
|
|
1649
|
+
/// Return: string
|
|
1650
|
+
/// The field type needed by the underlying database driver.
|
|
1651
|
+
///
|
|
1652
|
+
/// Arguments:
|
|
1653
|
+
/// type: <see>Type</see>
|
|
1654
|
+
/// The field type to convert to use in the underlying database.
|
|
598
1655
|
// eslint-disable-next-line no-unused-vars
|
|
599
1656
|
_uuidV3TypeToString(type) {
|
|
600
1657
|
return `VARCHAR(${type.getTotalLength()})`;
|
|
601
1658
|
}
|
|
602
1659
|
|
|
1660
|
+
/// Convert a "UUIDV4" field type to a type
|
|
1661
|
+
/// acceptable by the underlying database driver.
|
|
1662
|
+
///
|
|
1663
|
+
/// For most SQL connections this would be `VARCHAR`,
|
|
1664
|
+
/// however, it may be different based on what database you are using.
|
|
1665
|
+
///
|
|
1666
|
+
/// Return: string
|
|
1667
|
+
/// The field type needed by the underlying database driver.
|
|
1668
|
+
///
|
|
1669
|
+
/// Arguments:
|
|
1670
|
+
/// type: <see>Type</see>
|
|
1671
|
+
/// The field type to convert to use in the underlying database.
|
|
603
1672
|
// eslint-disable-next-line no-unused-vars
|
|
604
1673
|
_uuidV4TypeToString(type) {
|
|
605
1674
|
return `VARCHAR(${type.getTotalLength()})`;
|
|
606
1675
|
}
|
|
607
1676
|
|
|
1677
|
+
/// Convert a "UUIDV5" field type to a type
|
|
1678
|
+
/// acceptable by the underlying database driver.
|
|
1679
|
+
///
|
|
1680
|
+
/// For most SQL connections this would be `VARCHAR`,
|
|
1681
|
+
/// however, it may be different based on what database you are using.
|
|
1682
|
+
///
|
|
1683
|
+
/// Return: string
|
|
1684
|
+
/// The field type needed by the underlying database driver.
|
|
1685
|
+
///
|
|
1686
|
+
/// Arguments:
|
|
1687
|
+
/// type: <see>Type</see>
|
|
1688
|
+
/// The field type to convert to use in the underlying database.
|
|
608
1689
|
// eslint-disable-next-line no-unused-vars
|
|
609
1690
|
_uuidV5TypeToString(type) {
|
|
610
1691
|
return `VARCHAR(${type.getTotalLength()})`;
|
|
611
1692
|
}
|
|
612
1693
|
|
|
1694
|
+
/// Convert a "XID" field type to a type
|
|
1695
|
+
/// acceptable by the underlying database driver.
|
|
1696
|
+
///
|
|
1697
|
+
/// For most SQL connections this would be `VARCHAR`,
|
|
1698
|
+
/// however, it may be different based on what database you are using.
|
|
1699
|
+
///
|
|
1700
|
+
/// Return: string
|
|
1701
|
+
/// The field type needed by the underlying database driver.
|
|
1702
|
+
///
|
|
1703
|
+
/// Arguments:
|
|
1704
|
+
/// type: <see>Type</see>
|
|
1705
|
+
/// The field type to convert to use in the underlying database.
|
|
613
1706
|
// eslint-disable-next-line no-unused-vars
|
|
614
1707
|
_xidTypeToString(type) {
|
|
615
1708
|
return `VARCHAR(${type.getTotalLength()})`;
|
|
616
1709
|
}
|
|
617
1710
|
|
|
1711
|
+
/// Convert any field type to the type needed for the underlying
|
|
1712
|
+
/// database driver. Only built-in Mythix ORM fields are supported.
|
|
1713
|
+
/// If a custom field type that is not supported is provided then
|
|
1714
|
+
/// an exception will be thrown.
|
|
1715
|
+
///
|
|
1716
|
+
/// If you need to support a custom field type, simply subclass the
|
|
1717
|
+
/// connection you are using, and overload this method to handle
|
|
1718
|
+
/// your custom field types.
|
|
1719
|
+
///
|
|
1720
|
+
/// Return: string
|
|
1721
|
+
/// The field type needed by the underlying database driver.
|
|
1722
|
+
///
|
|
1723
|
+
/// Arguments:
|
|
1724
|
+
/// type: <see>Type</see>
|
|
1725
|
+
/// The field type to convert to use in the underlying database.
|
|
1726
|
+
/// options?: object
|
|
1727
|
+
/// Optional options to pass to the underlying conversion method.
|
|
618
1728
|
typeToString(type, options) {
|
|
619
1729
|
if (Types.BigIntType.isSameType(type))
|
|
620
1730
|
return this._bigintTypeToString(type, options);
|
|
@@ -652,6 +1762,37 @@ class ConnectionBase extends EventEmitter {
|
|
|
652
1762
|
throw new Error(`${this.constructor.name}::typeToString: Unsupported type ${type}.`);
|
|
653
1763
|
}
|
|
654
1764
|
|
|
1765
|
+
/// Convert a given "time" type object to
|
|
1766
|
+
/// the value needed by the underlying database.
|
|
1767
|
+
///
|
|
1768
|
+
/// By default this method will take a
|
|
1769
|
+
/// Luxon `DateTime` instance, or a `Date` instance,
|
|
1770
|
+
/// and convert it to the value needed by the
|
|
1771
|
+
/// underlying field in the database. This is
|
|
1772
|
+
/// generally a `BIGINT`, or `TIMESTAMP` value,
|
|
1773
|
+
/// as Mythix ORM will always try to store dates
|
|
1774
|
+
/// and times as millisecond timestamps
|
|
1775
|
+
/// (number of milliseconds since the UNIX Epoch).
|
|
1776
|
+
///
|
|
1777
|
+
/// If a `number`, `bigint`, or a `string` type is
|
|
1778
|
+
/// provided, then Mythix ORM will use Luxon to try
|
|
1779
|
+
/// and parse the provided value. If the value is parsed
|
|
1780
|
+
/// correctly, it will then be converted to the proper
|
|
1781
|
+
/// value as needed by the underlying field in the database.
|
|
1782
|
+
///
|
|
1783
|
+
/// Return: any
|
|
1784
|
+
/// Return the value needed by the underlying database field.
|
|
1785
|
+
/// Generally this will be a `bigint` type that is returned,
|
|
1786
|
+
/// but may be something different depending on the field and
|
|
1787
|
+
/// the database itself.
|
|
1788
|
+
///
|
|
1789
|
+
/// Arguments:
|
|
1790
|
+
/// value: any
|
|
1791
|
+
/// The incoming date/time type to convert to the proper
|
|
1792
|
+
/// database value for the underlying field.
|
|
1793
|
+
/// type: <see>Type</see>
|
|
1794
|
+
/// The field type that this conversion is for. This will
|
|
1795
|
+
/// generally be a `DATE` or `DATETIME` type.
|
|
655
1796
|
convertDateToDBTime(value, type) {
|
|
656
1797
|
if (Nife.instanceOf(value, 'number'))
|
|
657
1798
|
return value;
|
|
@@ -667,6 +1808,35 @@ class ConnectionBase extends EventEmitter {
|
|
|
667
1808
|
return value;
|
|
668
1809
|
}
|
|
669
1810
|
|
|
1811
|
+
/// This method will ensure all provided "models"
|
|
1812
|
+
/// are instances of the provided model class.
|
|
1813
|
+
///
|
|
1814
|
+
/// This method is used by the `insert`, `upsert`, and `update`
|
|
1815
|
+
/// methods of the connection to ensure every model
|
|
1816
|
+
/// provided by the user is an actual model instance.
|
|
1817
|
+
///
|
|
1818
|
+
/// For example, it is perfectly valid to create a model
|
|
1819
|
+
/// like `await Model.create({ ...attributes })`. As you
|
|
1820
|
+
/// can see, the provided "model" is actually just a raw
|
|
1821
|
+
/// object. Nearly any call in Mythix ORM will accept a
|
|
1822
|
+
/// raw object in-place of a model instance, and this
|
|
1823
|
+
/// method is used to ensure all provided "models" are
|
|
1824
|
+
/// actually model instances.
|
|
1825
|
+
///
|
|
1826
|
+
/// Return: Array<Model>
|
|
1827
|
+
/// Return all provided models, converted to model instances.
|
|
1828
|
+
/// Any provided model that is already a model instance will
|
|
1829
|
+
/// not be modified, and instead will simply be returned.
|
|
1830
|
+
///
|
|
1831
|
+
/// Arguments:
|
|
1832
|
+
/// Model: class <see>Model</see>
|
|
1833
|
+
/// The model class to use for instantiating models.
|
|
1834
|
+
/// models: object | <see>Model</see> | Array<Model | object>
|
|
1835
|
+
/// The models to convert to model instances (if needed).
|
|
1836
|
+
/// options: object
|
|
1837
|
+
/// Options for the operation. This options object is used
|
|
1838
|
+
/// to pass the `startIndex` and `endIndex` (or `batchSize`)
|
|
1839
|
+
/// as provided by the user when calling `insert`, `upsert`, or `update`.
|
|
670
1840
|
ensureAllModelsAreInstances(Model, _models, options) {
|
|
671
1841
|
if (!_models)
|
|
672
1842
|
return [];
|
|
@@ -696,6 +1866,38 @@ class ConnectionBase extends EventEmitter {
|
|
|
696
1866
|
return instantiatedModels;
|
|
697
1867
|
}
|
|
698
1868
|
|
|
1869
|
+
/// This method will prepare all provided models for
|
|
1870
|
+
/// an `insert`, `upsert`, or `update` operation.
|
|
1871
|
+
///
|
|
1872
|
+
/// What it does is ensure every provided model is a model
|
|
1873
|
+
/// instance, checks if the model is persisted, and if each
|
|
1874
|
+
/// model has dirty fields.
|
|
1875
|
+
///
|
|
1876
|
+
/// Models that are persisted and not dirty will be filtered out,
|
|
1877
|
+
/// so that proceeding operations will "ignore" them entirely.
|
|
1878
|
+
///
|
|
1879
|
+
/// All dirty fields across all models are combined into a unified
|
|
1880
|
+
/// list of dirty fields. This unified list is then used for the list
|
|
1881
|
+
/// of columns in an `insert`, `upsert`, or `updateAll` operation.
|
|
1882
|
+
///
|
|
1883
|
+
/// Return: PreparedModels
|
|
1884
|
+
/// Return an object with the shape `{ models: Array<Model>, dirtyFields: Array<Field>, dirtyModels: Array<Model> }`
|
|
1885
|
+
/// which is known to Mythix ORM as "prepared models". Mythix ORM can understand
|
|
1886
|
+
/// "prepared models" verses simple "models" in most contexts. PreparedModels are often
|
|
1887
|
+
/// passed around after first receiving models from the user, so as not to "prepare" them
|
|
1888
|
+
/// more than once.
|
|
1889
|
+
///
|
|
1890
|
+
/// Arguments:
|
|
1891
|
+
/// Model: class <see>Model</see>
|
|
1892
|
+
/// The model class to use for preparing the provided models. All models
|
|
1893
|
+
/// provided must be of this model type.
|
|
1894
|
+
/// models: object | <see>Model</see> | Array<Model | object>
|
|
1895
|
+
/// The models to prepare. Any model that is a "raw object" will
|
|
1896
|
+
/// be instantiated into the Model class provided.
|
|
1897
|
+
/// options: object
|
|
1898
|
+
/// Options for the operation. These include `startIndex`, `endIndex`
|
|
1899
|
+
/// (or `batchSize`) for batch operations, and `skipPersisted`, `isUpdateOperation`,
|
|
1900
|
+
/// or `isInsertOperation` for other context-specific operations.
|
|
699
1901
|
prepareAllModelsForOperation(Model, _models, _options) {
|
|
700
1902
|
if (!_models)
|
|
701
1903
|
return {};
|
|
@@ -775,6 +1977,32 @@ class ConnectionBase extends EventEmitter {
|
|
|
775
1977
|
return finalResult;
|
|
776
1978
|
}
|
|
777
1979
|
|
|
1980
|
+
/// Recursively walk all provided models and split models into a map
|
|
1981
|
+
/// of model name and model instances.
|
|
1982
|
+
///
|
|
1983
|
+
/// This method is used to split apart provided models by the user.
|
|
1984
|
+
/// For example, it is fully valid to provide "sub models" during most persisting
|
|
1985
|
+
/// operations, such as `new User({ primaryRole: new Role({ name: 'admin' }) })`.
|
|
1986
|
+
///
|
|
1987
|
+
/// This method would find the sub model "Role" in the above example, and split
|
|
1988
|
+
/// it out to be processed separately in the persisting operation.
|
|
1989
|
+
///
|
|
1990
|
+
/// Return: Map<string, Set<Model>>
|
|
1991
|
+
/// Return a map of all models found, where the model name is the key for the
|
|
1992
|
+
/// `Map`, and each model instance is added to the `Set` for that key.
|
|
1993
|
+
/// Using the above example, the return value would be: `new Map({ User: new Set([ user ]), Role: new Set([ role ]) })`.
|
|
1994
|
+
///
|
|
1995
|
+
/// Arguments:
|
|
1996
|
+
/// Model: class <see>Model</see>
|
|
1997
|
+
/// The model class of the primary model being scanned. The primary model could
|
|
1998
|
+
/// also be called the "root model". In our example above the primary model is `User`.
|
|
1999
|
+
/// primaryModel: <see>Model</see>
|
|
2000
|
+
/// The model instance to scan for "sub models". In the example above this would be
|
|
2001
|
+
/// `User` (though `Role` itself will also be passed through this method to check if
|
|
2002
|
+
/// it also has any sub models).
|
|
2003
|
+
/// _relationMap?: Map<string, Set<Model>>
|
|
2004
|
+
/// This argument is provided internally while recursing, and should **not** be provided
|
|
2005
|
+
/// unless you know exactly what you are doing.
|
|
778
2006
|
splitModelAndSubModels(Model, primaryModel, _relationMap) {
|
|
779
2007
|
const addModelInstance = (modelName, self) => {
|
|
780
2008
|
let relatedModels = relationMap.get(modelName);
|
|
@@ -832,6 +2060,56 @@ class ConnectionBase extends EventEmitter {
|
|
|
832
2060
|
return relationMap;
|
|
833
2061
|
}
|
|
834
2062
|
|
|
2063
|
+
/// Recursively prepare all models for a persisting operation
|
|
2064
|
+
/// while also splitting each model out into its own separate
|
|
2065
|
+
/// list, and finally sorting the models based on insertion order.
|
|
2066
|
+
///
|
|
2067
|
+
/// This method will use <see>ConnectionBase.splitModelAndSubModels</see>
|
|
2068
|
+
/// to split provided models out into their own separate space. See this
|
|
2069
|
+
/// method for a better explanation of what this means.
|
|
2070
|
+
///
|
|
2071
|
+
/// It will also assign any foreign key values across models that it is able to.
|
|
2072
|
+
/// For example, in the example provided in the documentation for <see>ConnectionBase.splitModelAndSubModels</see>,
|
|
2073
|
+
/// we had `new User({ primaryRole: new Role({ name: 'admin' }) })`, where the `Role`
|
|
2074
|
+
/// model is being persisted (as a child of `User`) at the same time the `User` is being
|
|
2075
|
+
/// persisted. If `Role` has a generated id, such as one of the `UUID` or `XID` types,
|
|
2076
|
+
/// then in our example here the `primaryRoleID` of the `User` could be set before `User`
|
|
2077
|
+
/// is persisted, saving an extra query to the database to update this foreign key after
|
|
2078
|
+
/// `Role` is persisted. In short, this method will also assign any foreign key values
|
|
2079
|
+
/// that it already has before persisting any models.
|
|
2080
|
+
///
|
|
2081
|
+
/// Finally, after it has "prepared" the models, and split all models into their own
|
|
2082
|
+
/// space, it will sort the resulting `Map` such that the models are in the correct
|
|
2083
|
+
/// order for insertion. In the example we have been using, if `User` has a `primaryRoleID`
|
|
2084
|
+
/// that is a foreign key, then it might require a non-null value before the `User`
|
|
2085
|
+
/// model can be persisted. Because of this, it is important that the `Role` model
|
|
2086
|
+
/// is stored first, so that we have the value we need for this `primaryRoleID` foreign key.
|
|
2087
|
+
/// This is why the models are sorted in what is known as "creation order", or "insertion order".
|
|
2088
|
+
/// This order is defined by the foreign keys themselves. Mythix ORM will walk all foreign keys
|
|
2089
|
+
/// involved in the operation, and decide based on these what the "creation order" should be.
|
|
2090
|
+
/// If you have two models that both have foreign keys pointing to each other, then the sort
|
|
2091
|
+
/// order is undefined. If this is the case, the work-around is to simply manually persist
|
|
2092
|
+
/// your models in the correct order (i.e. save `Role` first, and then supply the foreign key
|
|
2093
|
+
/// to `User` yourself from the result).
|
|
2094
|
+
///
|
|
2095
|
+
/// Return: Map<string, Set<Model>>
|
|
2096
|
+
/// The models processed, and put into their own named `Set`. The keys for
|
|
2097
|
+
/// the `Map` are the names of the models themselves.
|
|
2098
|
+
///
|
|
2099
|
+
/// Arguments:
|
|
2100
|
+
/// Model: class <see>Model</see>
|
|
2101
|
+
/// The model class of the primary model being persisted. The primary model could
|
|
2102
|
+
/// also be called the "root model". In our example above the primary model is `User`.
|
|
2103
|
+
/// models: object | <see>Model</see> | Array<Model | object>
|
|
2104
|
+
/// The models to prepare. Any model that is a "raw object" will
|
|
2105
|
+
/// be instantiated into the Model class provided. Any "sub models" will be
|
|
2106
|
+
/// split into their own space in the resulting `Map`.
|
|
2107
|
+
/// options?: object
|
|
2108
|
+
/// Optional options to supply to this operation. This options object
|
|
2109
|
+
/// isn't used by Mythix ORM, but is provided in case any driver specific
|
|
2110
|
+
/// connection needs them when overloading this model. These options come
|
|
2111
|
+
/// from the options provided to a database operation, such as the options
|
|
2112
|
+
/// provided to an `insert`, `upsert`, or `update` call.
|
|
835
2113
|
// eslint-disable-next-line no-unused-vars
|
|
836
2114
|
prepareAllModelsAndSubModelsForOperation(Model, models, _options) {
|
|
837
2115
|
let primaryModelRelationMap = new Map();
|
|
@@ -908,6 +2186,60 @@ class ConnectionBase extends EventEmitter {
|
|
|
908
2186
|
return sortedGroupedModelMap;
|
|
909
2187
|
}
|
|
910
2188
|
|
|
2189
|
+
/// This is a low-level "helper" method that is used by all
|
|
2190
|
+
/// "bulk operations", such as `insert`, `upsert`, `update`,
|
|
2191
|
+
/// or `destroyModels`. It prepares all provided models for operation,
|
|
2192
|
+
/// splits out sub-models provided, skips already persisted models,
|
|
2193
|
+
/// and also calls the model hooks `onBeforeSave`, `onAfterSave`, etc...
|
|
2194
|
+
/// This method will also always operate in batches, as defined by the
|
|
2195
|
+
/// `batchSize` option (default is `500` if not provided).
|
|
2196
|
+
///
|
|
2197
|
+
/// Lastly, when it is all done running the "batch operation" on all models,
|
|
2198
|
+
/// it will update any foreign keys on each model, and if any model has again
|
|
2199
|
+
/// been marked dirty from this update it will finally persist those updated
|
|
2200
|
+
/// models.
|
|
2201
|
+
///
|
|
2202
|
+
/// When it is fully complete, this method will return all "primary" models supplied
|
|
2203
|
+
/// to the method (i.e. if saving `User` models, then all supplied users will be returned
|
|
2204
|
+
/// and if any sub models were involved those won't be returned). The "primary model" is
|
|
2205
|
+
/// the model whose model class was specified as the `Model` argument on invocation of this
|
|
2206
|
+
/// method, and should match the type of the input `models`.
|
|
2207
|
+
///
|
|
2208
|
+
/// Return: Array<Model>
|
|
2209
|
+
/// Return all input models, converted to model instances, and updated. How they
|
|
2210
|
+
/// are updated depends on the operation being performed.
|
|
2211
|
+
///
|
|
2212
|
+
/// Arguments:
|
|
2213
|
+
/// Model: class <see>Model</see>
|
|
2214
|
+
/// The model class for the input models being provided.
|
|
2215
|
+
/// models: Array<Model>
|
|
2216
|
+
/// The models to bulk operate on. All of them must be instances of the class
|
|
2217
|
+
/// provided as the `Model` argument.
|
|
2218
|
+
/// options?: object
|
|
2219
|
+
/// Options to supply to the method. Refer to the following table for a list of
|
|
2220
|
+
/// possible options.
|
|
2221
|
+
/// | Option | Type | Default Value | Description |
|
|
2222
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2223
|
+
/// | `batchSize` | `number` | `500` | The number of models for each batch |
|
|
2224
|
+
/// | `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. |
|
|
2225
|
+
/// | `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. |
|
|
2226
|
+
/// beforeCallback?: (Model: typeof <see>Model</see>, batchModelInstances: Array<Model>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
|
|
2227
|
+
/// Callback that is called for each batch of models, before the current operation (i.e. insert) operates on them.
|
|
2228
|
+
/// It is generally in this callback that `onBefore*` model hooks are called.
|
|
2229
|
+
/// callback: (Model: typeof <see>Model</see>, preparedModels: <see name="PreparedModels">ConnectionBase.prepareAllModelsForOperation</see>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
|
|
2230
|
+
/// Callback to call to process each batch of models. The models are in "prepared model" format, meaning they
|
|
2231
|
+
/// are supplied as an object with `models`, `dirtyFields`, and `dirtyModels` properties.
|
|
2232
|
+
/// afterCallback?: (Model: typeof <see>Model</see>, models: Array<Model>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
|
|
2233
|
+
/// Callback that is called for each entire model set (not in batches). For example, if you bulk insert
|
|
2234
|
+
/// 1000 users, and your `batchSize` is `100`, then this will be called once, with all
|
|
2235
|
+
/// 1000 processed users, not 10 times with 100 users each. It is generally in this callback
|
|
2236
|
+
/// that `onAfter*` model hooks are called.
|
|
2237
|
+
/// afterOperationCallback?: (Model: typeof <see>Model</see>, dirtyModels: Set<Model>, options: object, queryGenerator: <see>QueryGenerator</see>) => Promise<void>
|
|
2238
|
+
/// Callback that is called after the entire operation completes successfully. This will only be called
|
|
2239
|
+
/// if `dirtyModels` is not empty. This method generally will re-save any models that got dirty during
|
|
2240
|
+
/// the operation... for example, when foreign keys have been updated on the models being processed.
|
|
2241
|
+
/// Models won't be added to the `dirtyModels` set if they are marked dirty in `onAfter*` model hooks,
|
|
2242
|
+
/// but only if the foreign key update process marked the model as dirty.
|
|
911
2243
|
async bulkModelOperation(Model, _models, _options, beforeCallback, callback, afterCallback, afterOperationCallback) {
|
|
912
2244
|
let models = _models;
|
|
913
2245
|
if (!models)
|
|
@@ -1057,6 +2389,26 @@ class ConnectionBase extends EventEmitter {
|
|
|
1057
2389
|
return (inputIsArray || !primaryResult) ? primaryResult : primaryResult[0];
|
|
1058
2390
|
}
|
|
1059
2391
|
|
|
2392
|
+
/// Mark all models provided as "persisted".
|
|
2393
|
+
///
|
|
2394
|
+
/// Every Mythix ORM model instance has a non-enumerable property `_persisted`.
|
|
2395
|
+
/// If this is `true`, then Mythix ORM will treat the model as persisted.
|
|
2396
|
+
///
|
|
2397
|
+
/// This method iterates all provided models, and marks each as persisted
|
|
2398
|
+
/// by setting this `_persisted` property to `true`.
|
|
2399
|
+
/// For each model iterated, this method checks if the instance property
|
|
2400
|
+
/// `_mythixModelInstance` is `true`. If this is not the case, then that
|
|
2401
|
+
/// instance (whatever it is) will be silently skipped.
|
|
2402
|
+
///
|
|
2403
|
+
/// Return: undefined
|
|
2404
|
+
/// This method modifies `models` directly, and returns nothing.
|
|
2405
|
+
///
|
|
2406
|
+
/// Arguments:
|
|
2407
|
+
/// models: Array<Model> | <see name="PreparedModels">ConnectionBase.prepareAllModelsForOperation</see>
|
|
2408
|
+
/// Models to mark as persisted.
|
|
2409
|
+
/// value:
|
|
2410
|
+
/// If `true`, models will be marked as persisted. If `false`, models will be marked
|
|
2411
|
+
/// as not-persisted.
|
|
1060
2412
|
setPersisted(_models, value) {
|
|
1061
2413
|
let models = _models;
|
|
1062
2414
|
if (models._mythixPreparedModels)
|
|
@@ -1074,14 +2426,83 @@ class ConnectionBase extends EventEmitter {
|
|
|
1074
2426
|
}
|
|
1075
2427
|
}
|
|
1076
2428
|
|
|
2429
|
+
/// Start this connection.
|
|
2430
|
+
///
|
|
2431
|
+
/// The default implementation will throw an exception.
|
|
2432
|
+
///
|
|
2433
|
+
/// Every connection is expected to overload this
|
|
2434
|
+
/// and provide connection specific startup code
|
|
2435
|
+
/// (such as connecting to the database).
|
|
2436
|
+
///
|
|
2437
|
+
/// Return: Promise<void>
|
|
1077
2438
|
async start() {
|
|
1078
2439
|
throw new Error(`${this.constructor.name}::start: Child class is required to implement "start".`);
|
|
1079
2440
|
}
|
|
1080
2441
|
|
|
2442
|
+
/// Stop (shutdown) this connection.
|
|
2443
|
+
///
|
|
2444
|
+
/// The default implementation will throw an exception.
|
|
2445
|
+
///
|
|
2446
|
+
/// Every connection is expected to overload this
|
|
2447
|
+
/// and provide connection specific shutdown code
|
|
2448
|
+
/// (such as disconnecting from the database).
|
|
2449
|
+
///
|
|
2450
|
+
/// Return: Promise<void>
|
|
1081
2451
|
async stop() {
|
|
1082
2452
|
this.removeAllListeners();
|
|
1083
2453
|
}
|
|
1084
2454
|
|
|
2455
|
+
/// Run model hooks by name.
|
|
2456
|
+
///
|
|
2457
|
+
/// This method will run the hooks for a model instance.
|
|
2458
|
+
/// `operationHookName` will be one of `onBeforeCreate`, `onBeforeUpdate`,
|
|
2459
|
+
/// `onAfterCreate`, or `onAfterUpdate`.
|
|
2460
|
+
///
|
|
2461
|
+
/// `operationHookName` will be one of `onBeforeSave`, or `onAfterSave`.
|
|
2462
|
+
/// The idea is that any of the `onBefore*` operations will always be
|
|
2463
|
+
/// followed by an `onBeforeSave`, whereas the `onAfter*` operations
|
|
2464
|
+
/// are all followed by an `onAfterSave`.
|
|
2465
|
+
///
|
|
2466
|
+
/// Note:
|
|
2467
|
+
/// Hooks for models are run serially for a given model, but all model
|
|
2468
|
+
/// hooks are run in parallel across all models.
|
|
2469
|
+
///
|
|
2470
|
+
/// Note:
|
|
2471
|
+
/// The `onValidate` hook is called from the `onBeforeSave` hook itself.
|
|
2472
|
+
/// This is so that the user can decide if model validations should be
|
|
2473
|
+
/// ran or not (simply by calling `this.onValidate` themselves... or not).
|
|
2474
|
+
/// **If you overload the `onBeforeSave` method, make certain you call
|
|
2475
|
+
/// `super.onBeforeSave.apply(this, arguments)` (or `this.onValidate.apply(this, arguments)`
|
|
2476
|
+
/// directly), because if you don't
|
|
2477
|
+
/// your model validations will be skipped.**
|
|
2478
|
+
///
|
|
2479
|
+
/// Return: Promise<Array<any>>
|
|
2480
|
+
/// The result of all model hooks. Mythix ORM ignores the return value
|
|
2481
|
+
/// from model hooks, but it collects them and returns them for the user.
|
|
2482
|
+
///
|
|
2483
|
+
/// Arguments:
|
|
2484
|
+
/// Model: class <see>Model</see>
|
|
2485
|
+
/// The model class we are running hooks for. All `models` provided should
|
|
2486
|
+
/// be instances of this class.
|
|
2487
|
+
/// models: Array<<see>Model</see>>
|
|
2488
|
+
/// All model instances to run hooks on. These should all be instances of the
|
|
2489
|
+
/// provided `Model` class.
|
|
2490
|
+
/// operationHookName: `'onBeforeCreate'` | `'onBeforeUpdate'` | `'onAfterCreate'` | `'onAfterUpdate'`
|
|
2491
|
+
/// The hook to call (if not skipped by the `skipHooks` option).
|
|
2492
|
+
/// saveHookName: `'onBeforeSave'` | `'onAfterSave'`
|
|
2493
|
+
/// The name of the save hook to call after the operation hook
|
|
2494
|
+
/// has completed (if not skipped by the `skipHooks` option).
|
|
2495
|
+
/// options: object
|
|
2496
|
+
/// Options for the operation being completed. For example, if this is an
|
|
2497
|
+
/// `insert` operation, then these "options" will be the options for the
|
|
2498
|
+
/// `insert` operation. One other useful option that can be supplied here
|
|
2499
|
+
/// is the `skipHooks: boolean | { [key: 'onBeforeCreate' | 'onBeforeUpdate' | 'onAfterCreate' | 'onAfterUpdate' | 'onBeforeSave' | 'onAfterSave' ]: boolean; }` option.
|
|
2500
|
+
/// If this is `true`, then all hooks will be bypassed (not called).
|
|
2501
|
+
/// If this is an object, then each key should be a hook name, and if it has
|
|
2502
|
+
/// a `true` value, then that specific hook will be bypassed (not called).
|
|
2503
|
+
///
|
|
2504
|
+
/// This allows the caller of an operation such as `insert`, or `update` to
|
|
2505
|
+
/// request that specific hooks not be called.
|
|
1085
2506
|
async runSaveHooks(Model, models, operationHookName, saveHookName, _options) {
|
|
1086
2507
|
const throwError = (error) => {
|
|
1087
2508
|
throw error;
|
|
@@ -1125,10 +2546,68 @@ class ConnectionBase extends EventEmitter {
|
|
|
1125
2546
|
await Promise.all(promises);
|
|
1126
2547
|
}
|
|
1127
2548
|
|
|
2549
|
+
/// Drop a table/bucket from the database.
|
|
2550
|
+
///
|
|
2551
|
+
/// This uses the provided `Model` class to
|
|
2552
|
+
/// find the table/bucket name to drop, and then
|
|
2553
|
+
/// will drop it from the underlying database.
|
|
2554
|
+
///
|
|
2555
|
+
/// The `options` argument is database specific,
|
|
2556
|
+
/// but might contain options such as `ifExists`,
|
|
2557
|
+
/// or `cascade`, for example.
|
|
2558
|
+
///
|
|
2559
|
+
/// Return: any
|
|
2560
|
+
/// A database specific return value for the drop table
|
|
2561
|
+
/// operation.
|
|
2562
|
+
///
|
|
2563
|
+
/// Arguments:
|
|
2564
|
+
/// Model: class <see>Model</see>
|
|
2565
|
+
/// The model to drop from the database. The method <see name="Model.getTableName">Model.static getTableName</see>
|
|
2566
|
+
/// is called on the model class to figure out what table/bucket to
|
|
2567
|
+
/// drop from the database.
|
|
2568
|
+
/// options?: object
|
|
2569
|
+
/// Database specific operations for dropping the table/bucket. Please
|
|
2570
|
+
/// refer to the documentation of the driver you are using for further
|
|
2571
|
+
/// information.
|
|
2572
|
+
// eslint-disable-next-line no-unused-vars
|
|
1128
2573
|
async dropTable(Model, options) {
|
|
1129
2574
|
throw new Error(`${this.constructor.name}::dropTable: This operation is not supported for this connection type.`);
|
|
1130
2575
|
}
|
|
1131
2576
|
|
|
2577
|
+
/// Drop all specified tables/buckets from the database.
|
|
2578
|
+
///
|
|
2579
|
+
/// This uses the provided `Models` classes to
|
|
2580
|
+
/// find the table/bucket names to drop, and then
|
|
2581
|
+
/// will drop all of them from the underlying database.
|
|
2582
|
+
///
|
|
2583
|
+
/// The `options` argument is database specific,
|
|
2584
|
+
/// but might contain options such as `ifExists`,
|
|
2585
|
+
/// or `cascade`, for example.
|
|
2586
|
+
///
|
|
2587
|
+
/// The model classes provided are first sorted in
|
|
2588
|
+
/// "creation order" using the <see>Utils.sortModelNamesByCreationOrder</see>
|
|
2589
|
+
/// method, and then the tables/buckets are dropped in the
|
|
2590
|
+
/// reverse order. This is to ensure that any foreign key
|
|
2591
|
+
/// constraints in play will play nicely with the operation
|
|
2592
|
+
/// and not throw errors.
|
|
2593
|
+
///
|
|
2594
|
+
/// This method simply calls <see>ConnectionBase.dropTable</see> for every
|
|
2595
|
+
/// model provided--after sorting the models based on their
|
|
2596
|
+
/// foreign keys.
|
|
2597
|
+
///
|
|
2598
|
+
/// Return: any
|
|
2599
|
+
/// A database specific return value for the drop tables
|
|
2600
|
+
/// operation.
|
|
2601
|
+
///
|
|
2602
|
+
/// Arguments:
|
|
2603
|
+
/// Models: Array<class <see>Model</see>>
|
|
2604
|
+
/// All the models to drop from the database. The method <see name="Model.getTableName">Model.static getTableName</see>
|
|
2605
|
+
/// is called on each model class to figure out what table/bucket to
|
|
2606
|
+
/// drop from the database.
|
|
2607
|
+
/// options?: object
|
|
2608
|
+
/// Database specific operations for dropping the table/bucket. Please
|
|
2609
|
+
/// refer to the documentation of the driver you are using for further
|
|
2610
|
+
/// information.
|
|
1132
2611
|
async dropTables(_Models, options) {
|
|
1133
2612
|
if (!_Models)
|
|
1134
2613
|
return;
|
|
@@ -1165,10 +2644,67 @@ class ConnectionBase extends EventEmitter {
|
|
|
1165
2644
|
return results;
|
|
1166
2645
|
}
|
|
1167
2646
|
|
|
2647
|
+
/// Create a table/bucket using the provided model class.
|
|
2648
|
+
///
|
|
2649
|
+
/// The provided `options` are database specific,
|
|
2650
|
+
/// but might contain things like `ifExists`, for
|
|
2651
|
+
/// example.
|
|
2652
|
+
///
|
|
2653
|
+
/// Return: any
|
|
2654
|
+
/// A connection specific return value for the operation.
|
|
2655
|
+
///
|
|
2656
|
+
/// Arguments:
|
|
2657
|
+
/// Model: class <see>Model</see>
|
|
2658
|
+
/// The model class used to create the table/bucket. The <see name="Model.getTableName">Model.static getTableName</see>
|
|
2659
|
+
/// method will be called to get the table/bucket name to create. Then
|
|
2660
|
+
/// the `static fields` property on the model class is used to create the
|
|
2661
|
+
/// columns/fields for the table/bucket. Only "concrete" fields are created
|
|
2662
|
+
/// in the underlying database. Any "virtual" or "relational" fields will
|
|
2663
|
+
/// be skipped.
|
|
2664
|
+
/// options?: object
|
|
2665
|
+
/// Database specific operations for creating the table/bucket. Please
|
|
2666
|
+
/// refer to the documentation of the driver you are using for further
|
|
2667
|
+
/// information.
|
|
1168
2668
|
async createTable(Model, options) {
|
|
1169
2669
|
throw new Error(`${this.constructor.name}::createTable: This operation is not supported for this connection type.`);
|
|
1170
2670
|
}
|
|
1171
2671
|
|
|
2672
|
+
/// Create all specified tables/buckets in the database.
|
|
2673
|
+
///
|
|
2674
|
+
/// This uses the provided `Models` classes to
|
|
2675
|
+
/// create the tables/buckets specified.
|
|
2676
|
+
///
|
|
2677
|
+
/// The `options` argument is database specific,
|
|
2678
|
+
/// but might contain options such as `ifNotExists`,
|
|
2679
|
+
/// for example.
|
|
2680
|
+
///
|
|
2681
|
+
/// The model classes provided are first sorted in
|
|
2682
|
+
/// "creation order" using the <see>Utils.sortModelNamesByCreationOrder</see>
|
|
2683
|
+
/// method, and then the tables/buckets are created in the
|
|
2684
|
+
/// that order. This is to ensure that any foreign key
|
|
2685
|
+
/// constraints in play will play nicely with the operation
|
|
2686
|
+
/// and not throw errors.
|
|
2687
|
+
///
|
|
2688
|
+
/// This method simply calls <see>ConnectionBase.createTable</see> for every
|
|
2689
|
+
/// model provided--after sorting the models based on their
|
|
2690
|
+
/// foreign keys.
|
|
2691
|
+
///
|
|
2692
|
+
/// Return: any
|
|
2693
|
+
/// A database specific return value for the create tables
|
|
2694
|
+
/// operation.
|
|
2695
|
+
///
|
|
2696
|
+
/// Arguments:
|
|
2697
|
+
/// Models: Array<class <see>Model</see>>
|
|
2698
|
+
/// The model classes used to create the tables/buckets. The <see name="Model.getTableName">Model.static getTableName</see>
|
|
2699
|
+
/// method will be called for each model to get the table/bucket name to create. Then
|
|
2700
|
+
/// the `static fields` property on each model class is used to create the
|
|
2701
|
+
/// columns/fields for the table/bucket. Only "concrete" fields are created
|
|
2702
|
+
/// in the underlying database. Any "virtual" or "relational" fields will
|
|
2703
|
+
/// be skipped.
|
|
2704
|
+
/// options?: object
|
|
2705
|
+
/// Database specific operations for dropping the table/bucket. Please
|
|
2706
|
+
/// refer to the documentation of the driver you are using for further
|
|
2707
|
+
/// information.
|
|
1172
2708
|
async createTables(_Models, options) {
|
|
1173
2709
|
if (!_Models)
|
|
1174
2710
|
return;
|
|
@@ -1220,125 +2756,886 @@ class ConnectionBase extends EventEmitter {
|
|
|
1220
2756
|
|
|
1221
2757
|
// Alter operations
|
|
1222
2758
|
|
|
2759
|
+
/// Alter a table/bucket based on the provided attributes for
|
|
2760
|
+
/// the model.
|
|
2761
|
+
///
|
|
2762
|
+
/// For SQL based drivers this might run a statement like the following
|
|
2763
|
+
/// `ALTER TABLE "users" RENAME TO "old_users";`
|
|
2764
|
+
///
|
|
2765
|
+
/// Please refer to the documentation of the database driver
|
|
2766
|
+
/// you are using for more information.
|
|
2767
|
+
///
|
|
2768
|
+
/// Return: Promise<void>
|
|
2769
|
+
///
|
|
2770
|
+
/// Arguments:
|
|
2771
|
+
/// Model: class <see>Model</see>
|
|
2772
|
+
/// The model to alter. This is used to alter the underlying
|
|
2773
|
+
/// table/bucket in the database.
|
|
2774
|
+
/// newAttributes: object
|
|
2775
|
+
/// The attributes to alter. Please refer to the documentation
|
|
2776
|
+
/// of the database driver you are using for more information.
|
|
1223
2777
|
async alterTable(Model, newModelAttributes, options) {
|
|
1224
2778
|
throw new Error(`${this.constructor.name}::renameTable: This operation is not supported for this connection type.`);
|
|
1225
2779
|
}
|
|
1226
2780
|
|
|
2781
|
+
/// Drop the specified column/field from the database.
|
|
2782
|
+
///
|
|
2783
|
+
/// The table/bucket to drop the field from is known
|
|
2784
|
+
/// by the `Model` property (model class) on the field
|
|
2785
|
+
/// itself.
|
|
2786
|
+
///
|
|
2787
|
+
/// The provided `options` are specific to the database
|
|
2788
|
+
/// you are using.
|
|
2789
|
+
/// Please refer to the documentation of the database driver
|
|
2790
|
+
/// you are using for more information.
|
|
2791
|
+
///
|
|
2792
|
+
/// Return: any
|
|
2793
|
+
/// A database specific return value for the operation completed.
|
|
2794
|
+
///
|
|
2795
|
+
/// Arguments:
|
|
2796
|
+
/// Field: <see>Field</see>
|
|
2797
|
+
/// The column/field to drop from the database.
|
|
2798
|
+
/// options?: object
|
|
2799
|
+
/// Database specific option for the operation. Please refer to the
|
|
2800
|
+
/// documentation of the database driver you are using for more information.
|
|
1227
2801
|
async dropColumn(Field, options) {
|
|
1228
2802
|
throw new Error(`${this.constructor.name}::dropColumn: This operation is not supported for this connection type.`);
|
|
1229
2803
|
}
|
|
1230
2804
|
|
|
2805
|
+
/// Alter the specified column/field in the database.
|
|
2806
|
+
///
|
|
2807
|
+
/// This will take the two fields, `Field` and `NewField`,
|
|
2808
|
+
/// and will compare them. It will generate multiple alter
|
|
2809
|
+
/// table statements internally, and will alter the column/field
|
|
2810
|
+
/// based on the differences it detects between the two fields.
|
|
2811
|
+
///
|
|
2812
|
+
/// If `NewField` is provided as a raw object, then it will be
|
|
2813
|
+
/// converted into a <see>Field</see>.
|
|
2814
|
+
///
|
|
2815
|
+
/// This method will check for the following differences between
|
|
2816
|
+
/// the two fields, in this order:
|
|
2817
|
+
/// 1. `allowNull`
|
|
2818
|
+
/// 2. `type`
|
|
2819
|
+
/// 3. `defaultValue`
|
|
2820
|
+
/// 4. `primaryKey`
|
|
2821
|
+
/// 5. `unique`
|
|
2822
|
+
/// 6. `index` (will calculate index differences, and do the minimum work required)
|
|
2823
|
+
/// 7. `columnName`
|
|
2824
|
+
///
|
|
2825
|
+
/// Return: Promise<void>
|
|
2826
|
+
///
|
|
2827
|
+
/// Arguments:
|
|
2828
|
+
/// Field: <see>Field</see>
|
|
2829
|
+
/// The current column/field (as it is in the database) that we are changing.
|
|
2830
|
+
/// NewField: <see>Field</see> | object
|
|
2831
|
+
/// The new field properties to compare. Only the provided properties will be compared.
|
|
2832
|
+
/// For example, if you only supply a `defaultValue` property, then only that will be
|
|
2833
|
+
/// altered (if it differs from `Field`).
|
|
2834
|
+
/// options?: object
|
|
2835
|
+
/// Operation specific options. These will change depending on the database
|
|
2836
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
2837
|
+
/// driver for more information.
|
|
1231
2838
|
async alterColumn(Field, newFieldAttributes, options) {
|
|
1232
2839
|
throw new Error(`${this.constructor.name}::alterColumn: This operation is not supported for this connection type.`);
|
|
1233
2840
|
}
|
|
1234
2841
|
|
|
2842
|
+
/// Add the column/field specified to the database.
|
|
2843
|
+
///
|
|
2844
|
+
/// The table/bucket to add the field to is fetched from the
|
|
2845
|
+
/// `Model` property on the supplied field.
|
|
2846
|
+
///
|
|
2847
|
+
/// Return: Promise<void>
|
|
2848
|
+
///
|
|
2849
|
+
/// Arguments:
|
|
2850
|
+
/// Field: <see>Field</see>
|
|
2851
|
+
/// The new field to add to the underlying database.
|
|
2852
|
+
/// options?: object
|
|
2853
|
+
/// Operation specific options. These will change depending on the database
|
|
2854
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
2855
|
+
/// driver for more information.
|
|
1235
2856
|
async addColumn(Field, options) {
|
|
1236
2857
|
throw new Error(`${this.constructor.name}::addColumn: This operation is not supported for this connection type.`);
|
|
1237
2858
|
}
|
|
1238
2859
|
|
|
2860
|
+
/// Create an index (or combo index) in the database.
|
|
2861
|
+
///
|
|
2862
|
+
/// This will create a new index for the field(s) specified.
|
|
2863
|
+
/// The `indexFields` argument must be an array of field names
|
|
2864
|
+
/// as strings. It can contain more than one field. If it does
|
|
2865
|
+
/// contain more than one field, then a combo index will be created
|
|
2866
|
+
/// for all specified fields (if the database you are using supports
|
|
2867
|
+
/// combined indexes).
|
|
2868
|
+
///
|
|
2869
|
+
/// All the provided field names must exist on the provided `Model`.
|
|
2870
|
+
/// If they don't, then an exception will be thrown. The field names
|
|
2871
|
+
/// can be fully qualified, but they don't need to be. If they are
|
|
2872
|
+
/// fully qualified, then they must all still be owned by the provided
|
|
2873
|
+
/// `Model`. You can not for example use a fully qualified field name
|
|
2874
|
+
/// from another model.
|
|
2875
|
+
///
|
|
2876
|
+
/// Combo indexes are created by combining two or more fields to create
|
|
2877
|
+
/// the index. For example, you could create a combo index for Users
|
|
2878
|
+
/// like `[ 'firstName', 'lastName', 'email' ]` if it is common for your
|
|
2879
|
+
/// application to query on all three of these fields at once.
|
|
2880
|
+
///
|
|
2881
|
+
/// If you just want to index a single column/field, simply provide only
|
|
2882
|
+
/// one field name, i.e. `[ 'firstName' ]`.
|
|
2883
|
+
///
|
|
2884
|
+
/// Return: Promise<void>
|
|
2885
|
+
///
|
|
2886
|
+
/// Arguments:
|
|
2887
|
+
/// Model: class <see>Model</see>
|
|
2888
|
+
/// The model that owns the specified fields.
|
|
2889
|
+
/// indexFields: Array<string>
|
|
2890
|
+
/// The field names to use to create the index. One field name
|
|
2891
|
+
/// is valid if you only wish to index a single field. These are
|
|
2892
|
+
/// used to generate the index name, along with which fields to
|
|
2893
|
+
/// index.
|
|
2894
|
+
/// options?: object
|
|
2895
|
+
/// Operation specific options. These will change depending on the database
|
|
2896
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
2897
|
+
/// driver for more information.
|
|
1239
2898
|
async addIndex(Model, indexFields, options) {
|
|
1240
2899
|
throw new Error(`${this.constructor.name}::addIndex: This operation is not supported for this connection type.`);
|
|
1241
2900
|
}
|
|
1242
2901
|
|
|
2902
|
+
/// Drop the index from the database based on the specified fields.
|
|
2903
|
+
///
|
|
2904
|
+
/// This is the exact inverse of <see>ConnectionBase.addIndex</see>,
|
|
2905
|
+
/// and it functions nearly identically, except that it will drop
|
|
2906
|
+
/// the specified index instead of creating it.
|
|
2907
|
+
///
|
|
2908
|
+
/// Return: Promise<void>
|
|
2909
|
+
///
|
|
2910
|
+
/// Arguments:
|
|
2911
|
+
/// Model: class <see>Model</see>
|
|
2912
|
+
/// The model that owns the specified fields.
|
|
2913
|
+
/// indexFields: Array<string>
|
|
2914
|
+
/// The field names to used to drop the index. These are used
|
|
2915
|
+
/// to generate the index name, which will then be dropped.
|
|
2916
|
+
/// options?: object
|
|
2917
|
+
/// Operation specific options. These will change depending on the database
|
|
2918
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
2919
|
+
/// driver for more information.
|
|
1243
2920
|
async dropIndex(Model, indexFields, options) {
|
|
1244
2921
|
throw new Error(`${this.constructor.name}::addIndex: This operation is not supported for this connection type.`);
|
|
1245
2922
|
}
|
|
1246
2923
|
|
|
2924
|
+
/// Insert the specified models into the specified
|
|
2925
|
+
/// table/bucket (based on the provided `Model`).
|
|
2926
|
+
///
|
|
2927
|
+
/// This will insert one or more models into the database.
|
|
2928
|
+
/// Like nearly all such Mythix ORM methods, bulk operations are supported
|
|
2929
|
+
/// out-of-the-box. You can provide a single model to `models`,
|
|
2930
|
+
/// or you can provide an array of models.
|
|
2931
|
+
///
|
|
2932
|
+
/// The provided "models" can be either an object, an array of
|
|
2933
|
+
/// objects, a model instance, or an array of model instances,
|
|
2934
|
+
/// or a mix of both. Mythix ORM will ensure any provided raw
|
|
2935
|
+
/// objects are first converted into model instances using the
|
|
2936
|
+
/// provided `Model` before it inserts anything.
|
|
2937
|
+
///
|
|
2938
|
+
/// You can also supply "sub models", and those will also be
|
|
2939
|
+
/// inserted in the correct order (and any foreign keys will
|
|
2940
|
+
/// also be updated for you). For example, if you have a `User`
|
|
2941
|
+
/// model that has a virtual `Type.Model` `primaryRole` field,
|
|
2942
|
+
/// then you can supply a new `Role` model upon insertion and
|
|
2943
|
+
/// Mythix ORM will handle this properly for you. For example:
|
|
2944
|
+
/// `await connection.insert(User, new User({ primaryRole: new Role({ ... }) }))`.
|
|
2945
|
+
/// This type of sub model save also works on through-tables.
|
|
2946
|
+
/// If `primaryRole` was targeting a `Role` model, but through
|
|
2947
|
+
/// another table(s), then Mythix ORM will also create the through-table
|
|
2948
|
+
/// relationships (if it is able to).
|
|
2949
|
+
///
|
|
2950
|
+
/// This **will not work** for `Types.Models` (multi-relations).
|
|
2951
|
+
/// Mythix ORM doesn't know what you intend for multi-relations
|
|
2952
|
+
/// (overwrite the set? add to the set? what?) so it will deliberately
|
|
2953
|
+
/// skip multi-relational fields. "sub models on insert" only work for
|
|
2954
|
+
/// single-relation fields defined with `Types.Model`. For multi-relation
|
|
2955
|
+
/// fields you must manually work through the relation yourself. For example,
|
|
2956
|
+
/// if our user instead had a `Types.Models` `roles` field (plural), then you
|
|
2957
|
+
/// would instead need to:
|
|
2958
|
+
///
|
|
2959
|
+
/// Example:
|
|
2960
|
+
/// let user = await connection.insert(User, new User({ ... }));
|
|
2961
|
+
/// let role = await connection.insert(Role, { ... }); // model instance is not required
|
|
2962
|
+
/// await user.addToRoles(role);
|
|
2963
|
+
///
|
|
2964
|
+
///
|
|
2965
|
+
/// Return: Promise<Array<Model> | Model>
|
|
2966
|
+
/// If you provide an array of models, then an array of models will be
|
|
2967
|
+
/// returned. If you provide only a single model, then a single
|
|
2968
|
+
/// model will be returned. If you provided "sub models" then those
|
|
2969
|
+
/// will be returned as "related models" on the primary model. For example,
|
|
2970
|
+
/// using the above `User` example, the newly created `Role` model that was
|
|
2971
|
+
/// stored for the `primaryRole` would be available on the returned `User`
|
|
2972
|
+
/// model as `user.Roles[0]`, or you could also access it via the field you
|
|
2973
|
+
/// set it on `user.primaryRole`.
|
|
2974
|
+
///
|
|
2975
|
+
/// Arguments:
|
|
2976
|
+
/// Model: class <see>Model</see>
|
|
2977
|
+
/// The model class used for the operation. This defines what
|
|
2978
|
+
/// table/bucket to insert the specified models into.
|
|
2979
|
+
/// models: Array<Model | object> | object | <see>Model</see>
|
|
2980
|
+
/// The model(s) to insert into the database. If raw objects are provided,
|
|
2981
|
+
/// then the properties of each object must match the required attributes
|
|
2982
|
+
/// for the model class.
|
|
2983
|
+
/// options?: object
|
|
2984
|
+
/// Most of these options are database/driver specific. However, the following
|
|
2985
|
+
/// options are common across all database drivers:
|
|
2986
|
+
/// | Option | Type | Default Value | Description |
|
|
2987
|
+
/// | ------------- | ---- | ------------- | ----------- |
|
|
2988
|
+
/// | `skipHooks` | `boolean` | `object` | `undefined` | Skip specific hooks. See <see>ConnectionBase.runSaveHooks</see> for more information. |
|
|
2989
|
+
/// | `batchSize` | `number` | `500` | The size of each batch during a multi-model insert operation. |
|
|
1247
2990
|
// eslint-disable-next-line no-unused-vars
|
|
1248
2991
|
async insert(Model, models, _options) {
|
|
1249
2992
|
throw new Error(`${this.constructor.name}::insert: This operation is not supported for this connection type.`);
|
|
1250
2993
|
}
|
|
1251
2994
|
|
|
2995
|
+
/// Insert or update (upsert) models into the database.
|
|
2996
|
+
///
|
|
2997
|
+
/// This method is only supported by some databases. Database
|
|
2998
|
+
/// drivers that don't support `upsert` natively may attempt to emulate
|
|
2999
|
+
/// the operation (at the cost of speed).
|
|
3000
|
+
///
|
|
3001
|
+
/// This method should function identically to <see>ConnectionBase.insert</see>,
|
|
3002
|
+
/// with the exception that it should update rows that already exist in the database
|
|
3003
|
+
/// instead of inserting new rows.
|
|
3004
|
+
///
|
|
3005
|
+
/// See: ConnectionBase.insert
|
|
3006
|
+
///
|
|
3007
|
+
/// Return: Promise<Array<Model> | Model>
|
|
3008
|
+
/// If you provide an array of models, then an array of models will be
|
|
3009
|
+
/// returned. If you provide only a single model, then a single
|
|
3010
|
+
/// model will be returned. If you provided "sub models" then those
|
|
3011
|
+
/// will be returned as "related models" on the primary model. For example,
|
|
3012
|
+
/// using the above `User` example, the newly created `Role` model that was
|
|
3013
|
+
/// stored for the `primaryRole` would be available on the returned `User`
|
|
3014
|
+
/// model as `user.Roles[0]`, or you could also access it via the field you
|
|
3015
|
+
/// set it on `user.primaryRole`.
|
|
3016
|
+
///
|
|
3017
|
+
/// Arguments:
|
|
3018
|
+
/// Model: class <see>Model</see>
|
|
3019
|
+
/// The model class used for the operation. This defines what
|
|
3020
|
+
/// table/bucket to insert the specified models into.
|
|
3021
|
+
/// models: Array<Model | object> | object | <see>Model</see>
|
|
3022
|
+
/// The model(s) to insert into the database. If raw objects are provided,
|
|
3023
|
+
/// then the properties of each object must match the required attributes
|
|
3024
|
+
/// for the model class.
|
|
3025
|
+
/// options?: object
|
|
3026
|
+
/// Most of these options are database/driver specific. However, the following
|
|
3027
|
+
/// options are common across all database drivers:
|
|
3028
|
+
/// | Option | Type | Default Value | Description |
|
|
3029
|
+
/// | ------------- | ---- | ------------- | ----------- |
|
|
3030
|
+
/// | `skipHooks` | `boolean` | `object` | `undefined` | Skip specific hooks. See <see>ConnectionBase.runSaveHooks</see> for more information. |
|
|
3031
|
+
/// | `batchSize` | `number` | `500` | The size of each batch during a multi-model upsert operation. |
|
|
1252
3032
|
// eslint-disable-next-line no-unused-vars
|
|
1253
3033
|
async upsert(Model, models, _options) {
|
|
1254
3034
|
throw new Error(`${this.constructor.name}::upsert: This operation is not supported for this connection type.`);
|
|
1255
3035
|
}
|
|
1256
3036
|
|
|
3037
|
+
/// Update the specified models in the database.
|
|
3038
|
+
///
|
|
3039
|
+
/// Many databases don't have good (or even decent) support
|
|
3040
|
+
/// for bulk updates, so unfortunately this method is fairly
|
|
3041
|
+
/// slow, and will usually make a query to the database for each
|
|
3042
|
+
/// model updated.
|
|
3043
|
+
///
|
|
3044
|
+
/// If you want to update many models at the same time (using the same
|
|
3045
|
+
/// attributes across all models), then consider using the <see>ConnectionBase.updateAll</see>
|
|
3046
|
+
/// method instead.
|
|
3047
|
+
///
|
|
3048
|
+
/// Note:
|
|
3049
|
+
/// Models will only be updated if they are dirty. Also, only the
|
|
3050
|
+
/// dirty attributes for each model will be updated (some attributes
|
|
3051
|
+
/// are always dirty, for example `updatedAt` fields are forced to
|
|
3052
|
+
/// always be dirty based on the configuration of their `defaultValue`).
|
|
3053
|
+
///
|
|
3054
|
+
/// Return: Promise<Array<Model> | Model>
|
|
3055
|
+
/// If you provide an array of models, then an array of models will be
|
|
3056
|
+
/// returned. If you provide only a single model, then a single
|
|
3057
|
+
/// model will be returned.
|
|
3058
|
+
///
|
|
3059
|
+
/// Arguments:
|
|
3060
|
+
/// Model: class <see>Model</see>
|
|
3061
|
+
/// The model class used for the operation. This defines what
|
|
3062
|
+
/// table/bucket to update.
|
|
3063
|
+
/// models: Array<Model | object> | object | <see>Model</see>
|
|
3064
|
+
/// The model(s) to update in the database. If raw objects are provided,
|
|
3065
|
+
/// then the properties of each object must match the required attributes
|
|
3066
|
+
/// for the model class.
|
|
3067
|
+
/// options?: object
|
|
3068
|
+
/// Most of these options are database/driver specific. However, the following
|
|
3069
|
+
/// options are common across all database drivers:
|
|
3070
|
+
/// | Option | Type | Default Value | Description |
|
|
3071
|
+
/// | ------------- | ---- | ------------- | ----------- |
|
|
3072
|
+
/// | `skipHooks` | `boolean` | `object` | `undefined` | Skip specific hooks. See <see>ConnectionBase.runSaveHooks</see> for more information. |
|
|
3073
|
+
/// | `batchSize` | `number` | `500` | The size of each batch during a multi-model update operation. |
|
|
1257
3074
|
// eslint-disable-next-line no-unused-vars
|
|
1258
3075
|
async update(Model, models, _options) {
|
|
1259
3076
|
throw new Error(`${this.constructor.name}::update: This operation is not supported for this connection type.`);
|
|
1260
3077
|
}
|
|
1261
3078
|
|
|
3079
|
+
/// Update multiple models at the same time (bulk update).
|
|
3080
|
+
///
|
|
3081
|
+
/// This will update multiple models at the same time
|
|
3082
|
+
/// using the provided `query` to select which models to update.
|
|
3083
|
+
/// All matching rows will set the provided `attributes` upon them.
|
|
3084
|
+
///
|
|
3085
|
+
/// The provided `attributes` can be a model instance, or
|
|
3086
|
+
/// a raw object. If a raw object is provided, then they
|
|
3087
|
+
/// will be converted into a model instance using the provided
|
|
3088
|
+
/// `Model` class. This also means that you can *only* bulk update
|
|
3089
|
+
/// columns/fields that exist on the model itself (i.e. you might have
|
|
3090
|
+
/// other columns in your table not related to this model, and
|
|
3091
|
+
/// those can **not** be updated using this method).
|
|
3092
|
+
///
|
|
3093
|
+
/// Note:
|
|
3094
|
+
/// As always with Mythix ORM, you will **never** supply
|
|
3095
|
+
/// raw column names as the `attributes`. You must always
|
|
3096
|
+
/// provide model field names in Mythix ORM.
|
|
3097
|
+
///
|
|
3098
|
+
/// Note:
|
|
3099
|
+
/// This will be an update operation across all matching rows,
|
|
3100
|
+
/// using the data provided. This method is really only useful
|
|
3101
|
+
/// when you want to update multiple rows to the **same values**.
|
|
3102
|
+
/// If you need to update each row to different values per-row,
|
|
3103
|
+
/// then use the <see>ConnectionBase.update</see> method instead.
|
|
3104
|
+
///
|
|
3105
|
+
/// Return: Promise<any>
|
|
3106
|
+
/// A database specific result from the `UPDATE` statement.
|
|
3107
|
+
/// In the future all "database specific" results will be
|
|
3108
|
+
/// abstracted away. So in the future, this will likely return
|
|
3109
|
+
/// the number of rows updated as a `number` (**HELP WANTED**).
|
|
3110
|
+
///
|
|
3111
|
+
/// Arguments:
|
|
3112
|
+
/// query: <see>QueryEngine</see>
|
|
3113
|
+
/// The query used to select which models/rows to update.
|
|
3114
|
+
/// The "root model" of the query is the table/bucket that
|
|
3115
|
+
/// will be updated.
|
|
3116
|
+
/// attributes: object | Model
|
|
3117
|
+
/// The attributes to set across all updated rows.
|
|
3118
|
+
/// options?: object
|
|
3119
|
+
/// Operation specific options. These will change depending on the database
|
|
3120
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3121
|
+
/// driver for more information.
|
|
1262
3122
|
// eslint-disable-next-line no-unused-vars
|
|
1263
3123
|
async updateAll(_queryEngine, model, _options) {
|
|
1264
3124
|
throw new Error(`${this.constructor.name}::updateAll: This operation is not supported for this connection type.`);
|
|
1265
3125
|
}
|
|
1266
3126
|
|
|
3127
|
+
/// Destroy the provided models.
|
|
3128
|
+
///
|
|
3129
|
+
/// This method will bulk-iterate the specified
|
|
3130
|
+
/// models and will destroy each one. A primary key field
|
|
3131
|
+
/// is required for every model, or this method will throw
|
|
3132
|
+
/// an exception.
|
|
3133
|
+
///
|
|
3134
|
+
/// The `skipHooks` option (see <see>ConnectionBase.runSaveHooks</see>) won't
|
|
3135
|
+
/// do anything here, because Mythix ORM doesn't have any `on*Destroy` hooks.
|
|
3136
|
+
/// Mythix ORM doesn't have any destroy hooks for performance reasons.
|
|
3137
|
+
/// However, the `batchSize` option is still useful for this method.
|
|
3138
|
+
///
|
|
3139
|
+
/// Note:
|
|
3140
|
+
/// **WARNING!!!**: If you supply `null` or `undefined` as the `models`
|
|
3141
|
+
/// argument then this method will silently return. If you also supply
|
|
3142
|
+
/// the option `{ truncate: true }` then the entire table will be truncated.
|
|
3143
|
+
/// This option is an "opt-in", to make sure you don't truncate an entire
|
|
3144
|
+
/// table on accident.
|
|
3145
|
+
///
|
|
3146
|
+
/// Note:
|
|
3147
|
+
/// Some databases (i.e. SQLite) don't support a `TRUNCATE` statement,
|
|
3148
|
+
/// and so will deliberately call this method with `null` for the `models`
|
|
3149
|
+
/// argument for `truncate` operations. When doing so they will also
|
|
3150
|
+
/// deliberately supply the `{ truncate: true }` option.
|
|
3151
|
+
///
|
|
3152
|
+
/// Return: Promise<Array<Model> | Model>
|
|
3153
|
+
/// If you provide an array of models, then an array of models will be
|
|
3154
|
+
/// returned. If you provide only a single model, then a single
|
|
3155
|
+
/// model will be returned.
|
|
3156
|
+
///
|
|
3157
|
+
/// Arguments:
|
|
3158
|
+
/// Model: class <see>Model</see>
|
|
3159
|
+
/// The model class used for the operation. This defines what
|
|
3160
|
+
/// table/bucket to delete from.
|
|
3161
|
+
/// models: Array<Model | object> | object | <see>Model</see>
|
|
3162
|
+
/// The model(s) to delete from the database. If raw objects are provided,
|
|
3163
|
+
/// then they must contain a `primaryKey` for each model. If any of the
|
|
3164
|
+
/// models provided don't contain a `primaryKey` field, then an exception
|
|
3165
|
+
/// will be thrown. If you have a table/bucket that has no primary key column,
|
|
3166
|
+
/// then you will need to destroy rows manually yourself using a manual query
|
|
3167
|
+
/// with <see>ConnectionBase.query</see>, or by using the <see>ConnectionBase.destroy</see> method.
|
|
3168
|
+
/// options?: object
|
|
3169
|
+
/// Most of these options are database/driver specific. However, the following
|
|
3170
|
+
/// options are common across all database drivers (`skipHooks` is not supported in this context):
|
|
3171
|
+
/// | Option | Type | Default Value | Description |
|
|
3172
|
+
/// | ------------- | ---- | ------------- | ----------- |
|
|
3173
|
+
/// | `batchSize` | `number` | `500` | The size of each batch during a multi-model destroy operation. |
|
|
1267
3174
|
// eslint-disable-next-line no-unused-vars
|
|
1268
3175
|
async destroyModels(Model, _models, _options) {
|
|
1269
3176
|
throw new Error(`${this.constructor.name}::destroyModels: This operation is not supported for this connection type.`);
|
|
1270
3177
|
}
|
|
1271
3178
|
|
|
3179
|
+
/// Destroy multiple models by query, or by the
|
|
3180
|
+
/// provided models themselves. If models are provided,
|
|
3181
|
+
/// then each model must have a valid primary key field,
|
|
3182
|
+
/// or an exception will be thrown.
|
|
3183
|
+
///
|
|
3184
|
+
/// If models are provided as the second argument, then
|
|
3185
|
+
/// it is required that the first argument be a <see>Model</see>
|
|
3186
|
+
/// class. In this case, this method simply calls
|
|
3187
|
+
/// <see>ConnectionBase.destroyModels</see> to complete the operation.
|
|
3188
|
+
///
|
|
3189
|
+
/// If the first argument is a <see>QueryEngine</see> instance,
|
|
3190
|
+
/// then rows will be deleted from the database using the provided query.
|
|
3191
|
+
/// In this case, it is expected that the second argument
|
|
3192
|
+
/// will be the "options" for this operation instead of an array of models.
|
|
3193
|
+
///
|
|
3194
|
+
/// Return: Promise<Array<Models> | Model | number>
|
|
3195
|
+
/// Return the models deleted (if models were provided),
|
|
3196
|
+
/// or the number of rows deleted (if a query was provided).
|
|
3197
|
+
///
|
|
3198
|
+
/// Arguments:
|
|
3199
|
+
/// queryOrModel: class <see>Model</see> | <see>QueryEngine</see>
|
|
3200
|
+
/// A <see>QueryEngine</see> instance to specify which models to
|
|
3201
|
+
/// delete via a query, or a <see>Model</see> class if models are
|
|
3202
|
+
/// being provided to be deleted.
|
|
3203
|
+
/// modelsOrOptions: Array<Model> | Model | object
|
|
3204
|
+
/// If a <see>QueryEngine</see> instance is provided as the first argument
|
|
3205
|
+
/// then this is expected to be the "options" for the operation. If however
|
|
3206
|
+
/// a <see>Model</see> class is provided as the first argument, then this
|
|
3207
|
+
/// should be a <see>Model</see> instance, or an array of <see>Model</see> instances.
|
|
3208
|
+
/// options?: object | undefined
|
|
3209
|
+
/// Most of these options are database/driver specific.
|
|
3210
|
+
/// The `batchSize` option is ignored if a <see>QueryEngine</see> instance is provided as the
|
|
3211
|
+
/// first argument to the call. If a <see>Model</see> class is provided as the first argument to
|
|
3212
|
+
/// the call, then this `options` object will be at argument index `1` instead (the second argument, `modelsOrOptions`).
|
|
3213
|
+
/// The following options are common across all database drivers
|
|
3214
|
+
/// (`skipHooks` is not supported in this context):
|
|
3215
|
+
/// | Option | Type | Default Value | Description |
|
|
3216
|
+
/// | ------------- | ---- | ------------- | ----------- |
|
|
3217
|
+
/// | `batchSize` | `number` | `500` | The size of each batch during a multi-model destroy operation. |
|
|
1272
3218
|
// eslint-disable-next-line no-unused-vars
|
|
1273
3219
|
async destroy(_queryEngineOrModel, modelsOrOptions, _options) {
|
|
1274
3220
|
throw new Error(`${this.constructor.name}::destroy: This operation is not supported for this connection type.`);
|
|
1275
3221
|
}
|
|
1276
3222
|
|
|
3223
|
+
/// Select data from the underlying database.
|
|
3224
|
+
///
|
|
3225
|
+
/// To select data from the database you will use this method,
|
|
3226
|
+
/// providing a `query` as a <see>QueryEngine</see> instance.
|
|
3227
|
+
/// The provided query will be used to generate the underlying
|
|
3228
|
+
/// request to the database, will collect the response, and return
|
|
3229
|
+
/// the results to the caller.
|
|
3230
|
+
///
|
|
3231
|
+
/// This method is an async generator method, and is designed for
|
|
3232
|
+
/// "streaming" results from the database, one "row" at a time. Many
|
|
3233
|
+
/// methods that call this method (such as <see>QueryEngine.all</see>)
|
|
3234
|
+
/// collect all the results from the async generator to return an array
|
|
3235
|
+
/// of results to the caller. This is because it is often tedious to
|
|
3236
|
+
/// collect the results yourself from the async generator, and often the
|
|
3237
|
+
/// caller simply wants a small amount of data from the database.
|
|
3238
|
+
/// However, if you intend to fetch large amounts of data from your database,
|
|
3239
|
+
/// it is a good idea to call this method directly, and iterate the results
|
|
3240
|
+
/// of the async generator manually. All methods that in-turn call this
|
|
3241
|
+
/// method (such as <see>QueryEngine.all</see>) will generally have a
|
|
3242
|
+
/// `{ stream: true }` option that can be provided, causing the method to
|
|
3243
|
+
/// return the async generator, instead of the collected results.
|
|
3244
|
+
///
|
|
3245
|
+
///
|
|
3246
|
+
/// Return: AsyncGenerator<Model>
|
|
3247
|
+
///
|
|
3248
|
+
/// Arguments:
|
|
3249
|
+
/// query: <see>QueryEngine</see>
|
|
3250
|
+
/// The query to run against the underlying database. This is generated
|
|
3251
|
+
/// from a <see>QueryEngine</see> interface. The result of this <see>QueryEngine</see>
|
|
3252
|
+
/// instance will then be converted to a query, or generated code to
|
|
3253
|
+
/// interact with the underlying database.
|
|
3254
|
+
/// options?: object
|
|
3255
|
+
/// Operation specific options. These will change depending on the database
|
|
3256
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3257
|
+
/// driver for more information.
|
|
1277
3258
|
// eslint-disable-next-line no-unused-vars, require-yield
|
|
1278
3259
|
async *select(_queryEngine, _options) {
|
|
1279
3260
|
throw new Error(`${this.constructor.name}::select: This operation is not supported for this connection type.`);
|
|
1280
3261
|
}
|
|
1281
3262
|
|
|
3263
|
+
/// Aggregate data across rows.
|
|
3264
|
+
///
|
|
3265
|
+
/// Though this method can be called directly, it is generally called from
|
|
3266
|
+
/// one of <see>ConnectionBase.average</see>, <see>ConnectionBase.sum</see>,
|
|
3267
|
+
/// <see>ConnectionBase.count</see>, <see>ConnectionBase.min</see>,
|
|
3268
|
+
/// or <see>ConnectionBase.max</see>, or one of the other aggregate methods
|
|
3269
|
+
/// provided by the connection.
|
|
3270
|
+
///
|
|
3271
|
+
/// It takes a `query` which is used to generate a query for the underlying
|
|
3272
|
+
/// database, and sets the query `PROJECTION` to the aggregate `literal` provided.
|
|
3273
|
+
/// For example, a `sum` method call would call this method with a `SumLiteral`,
|
|
3274
|
+
/// which would change the `query` projection to the expanded result of the
|
|
3275
|
+
/// `SumLiteral`, returning the "sum" of all column values targeted by the literal field.
|
|
3276
|
+
/// The results will then be collected, and always returned as a `number` primitive
|
|
3277
|
+
/// to the caller.
|
|
3278
|
+
///
|
|
3279
|
+
/// Return: Promise<number>
|
|
3280
|
+
/// The result of the aggregate operation, as a number.
|
|
3281
|
+
///
|
|
3282
|
+
/// Arguments:
|
|
3283
|
+
/// query: <see>QueryEngine</see>
|
|
3284
|
+
/// The query used to select which rows to aggregate across.
|
|
3285
|
+
/// literal: <see>LiteralBase</see>
|
|
3286
|
+
/// A literal, used as the aggregate function. For example, if a
|
|
3287
|
+
/// <see>CountLiteral</see> is provided, then the count of all rows
|
|
3288
|
+
/// matching the provided query will be the result.
|
|
3289
|
+
/// options?: object
|
|
3290
|
+
/// Operation specific options. These will change depending on the database
|
|
3291
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3292
|
+
/// driver for more information.
|
|
1282
3293
|
// eslint-disable-next-line no-unused-vars
|
|
1283
3294
|
async aggregate(_queryEngine, _literal, options) {
|
|
1284
3295
|
throw new Error(`${this.constructor.name}::aggregate: This operation is not supported for this connection type.`);
|
|
1285
3296
|
}
|
|
1286
3297
|
|
|
3298
|
+
/// Get the average for a single column, spanning all matching rows.
|
|
3299
|
+
///
|
|
3300
|
+
/// This will return the average of all values in a column,
|
|
3301
|
+
/// across all matching rows, as a `number` primitive.
|
|
3302
|
+
///
|
|
3303
|
+
/// Return: Promise<number>
|
|
3304
|
+
/// The average of all matching columns.
|
|
3305
|
+
///
|
|
3306
|
+
/// Arguments:
|
|
3307
|
+
/// query: <see>QueryEngine</see>
|
|
3308
|
+
/// The query used to select which rows are used to calculate the average.
|
|
3309
|
+
/// field: <see>Field</see> | string
|
|
3310
|
+
/// A field instance, or a fully qualified field name, used as the target
|
|
3311
|
+
/// column in the underlying database to calculate an average across all matching values.
|
|
3312
|
+
/// options?: object
|
|
3313
|
+
/// Operation specific options. These will change depending on the database
|
|
3314
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3315
|
+
/// driver for more information.
|
|
1287
3316
|
// eslint-disable-next-line no-unused-vars
|
|
1288
3317
|
async average(_queryEngine, _field, options) {
|
|
1289
3318
|
throw new Error(`${this.constructor.name}::average: This operation is not supported for this connection type.`);
|
|
1290
3319
|
}
|
|
1291
3320
|
|
|
3321
|
+
/// Get the number of rows matching the query.
|
|
3322
|
+
///
|
|
3323
|
+
/// This will return the number of rows matching
|
|
3324
|
+
/// the provided query, as a `number` primitive.
|
|
3325
|
+
///
|
|
3326
|
+
/// Note:
|
|
3327
|
+
/// In most databases, if the `field` argument is not
|
|
3328
|
+
/// specified, then the count operation will be across
|
|
3329
|
+
/// all table columns (`COUNT(*)`).
|
|
3330
|
+
///
|
|
3331
|
+
/// Return: Promise<number>
|
|
3332
|
+
/// The count (number) of all rows matching the provided query.
|
|
3333
|
+
///
|
|
3334
|
+
/// Arguments:
|
|
3335
|
+
/// query: <see>QueryEngine</see>
|
|
3336
|
+
/// The query used to select which rows to count.
|
|
3337
|
+
/// field: <see>Field</see> | string
|
|
3338
|
+
/// A field instance, or a fully qualified field name, used as the target
|
|
3339
|
+
/// column in the underlying database to count the rows. If not specified,
|
|
3340
|
+
/// then most database drivers will count across all columns (i.e. `COUNT(*)`).
|
|
3341
|
+
/// options?: object
|
|
3342
|
+
/// Operation specific options. These will change depending on the database
|
|
3343
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3344
|
+
/// driver for more information.
|
|
1292
3345
|
// eslint-disable-next-line no-unused-vars
|
|
1293
3346
|
async count(_queryEngine, _field, options) {
|
|
1294
3347
|
throw new Error(`${this.constructor.name}::count: This operation is not supported for this connection type.`);
|
|
1295
3348
|
}
|
|
1296
3349
|
|
|
3350
|
+
/// Get the minimum value for a column, spanning all matching rows.
|
|
3351
|
+
///
|
|
3352
|
+
/// This will return the minimum of all values in a column,
|
|
3353
|
+
/// across all matching rows, as a `number` primitive.
|
|
3354
|
+
///
|
|
3355
|
+
/// Return: Promise<number>
|
|
3356
|
+
/// The minimum value found across all matching rows.
|
|
3357
|
+
///
|
|
3358
|
+
/// Arguments:
|
|
3359
|
+
/// query: <see>QueryEngine</see>
|
|
3360
|
+
/// The query used to select which rows are used to calculate the minimum.
|
|
3361
|
+
/// field: <see>Field</see> | string
|
|
3362
|
+
/// A field instance, or a fully qualified field name, used as the target
|
|
3363
|
+
/// column in the underlying database to find the minimum across all matching values.
|
|
3364
|
+
/// options?: object
|
|
3365
|
+
/// Operation specific options. These will change depending on the database
|
|
3366
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3367
|
+
/// driver for more information.
|
|
1297
3368
|
// eslint-disable-next-line no-unused-vars
|
|
1298
3369
|
async min(_queryEngine, _field, options) {
|
|
1299
3370
|
throw new Error(`${this.constructor.name}::min: This operation is not supported for this connection type.`);
|
|
1300
3371
|
}
|
|
1301
3372
|
|
|
3373
|
+
/// Get the maximum value for a column, spanning all matching rows.
|
|
3374
|
+
///
|
|
3375
|
+
/// This will return the maximum of all values in a column,
|
|
3376
|
+
/// across all matching rows, as a `number` primitive.
|
|
3377
|
+
///
|
|
3378
|
+
/// Return: Promise<number>
|
|
3379
|
+
/// The maximum value found across all matching rows.
|
|
3380
|
+
///
|
|
3381
|
+
/// Arguments:
|
|
3382
|
+
/// query: <see>QueryEngine</see>
|
|
3383
|
+
/// The query used to select which rows are used to calculate the maximum.
|
|
3384
|
+
/// field: <see>Field</see> | string
|
|
3385
|
+
/// A field instance, or a fully qualified field name, used as the target
|
|
3386
|
+
/// column in the underlying database to find the maximum across all matching values.
|
|
3387
|
+
/// options?: object
|
|
3388
|
+
/// Operation specific options. These will change depending on the database
|
|
3389
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3390
|
+
/// driver for more information.
|
|
1302
3391
|
// eslint-disable-next-line no-unused-vars
|
|
1303
3392
|
async max(_queryEngine, _field, options) {
|
|
1304
3393
|
throw new Error(`${this.constructor.name}::max: This operation is not supported for this connection type.`);
|
|
1305
3394
|
}
|
|
1306
3395
|
|
|
3396
|
+
/// Get the sum of all values for a column, spanning all matching rows.
|
|
3397
|
+
///
|
|
3398
|
+
/// This will return the sum of all values in a column,
|
|
3399
|
+
/// across all matching rows, as a `number` primitive.
|
|
3400
|
+
///
|
|
3401
|
+
/// Return: Promise<number>
|
|
3402
|
+
/// The sum of all values found across all matching rows.
|
|
3403
|
+
///
|
|
3404
|
+
/// Arguments:
|
|
3405
|
+
/// query: <see>QueryEngine</see>
|
|
3406
|
+
/// The query used to select which rows are used to calculate the sum.
|
|
3407
|
+
/// field: <see>Field</see> | string
|
|
3408
|
+
/// A field instance, or a fully qualified field name, used as the target
|
|
3409
|
+
/// column in the underlying database to find the sum of all matching values.
|
|
3410
|
+
/// options?: object
|
|
3411
|
+
/// Operation specific options. These will change depending on the database
|
|
3412
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3413
|
+
/// driver for more information.
|
|
1307
3414
|
// eslint-disable-next-line no-unused-vars
|
|
1308
3415
|
async sum(_queryEngine, _field, options) {
|
|
1309
3416
|
throw new Error(`${this.constructor.name}::sum: This operation is not supported for this connection type.`);
|
|
1310
3417
|
}
|
|
1311
3418
|
|
|
3419
|
+
/// Pluck only specific columns/fields from the
|
|
3420
|
+
/// underlying database, using the provided `query`.
|
|
3421
|
+
///
|
|
3422
|
+
/// This method will return only the specified `fields`
|
|
3423
|
+
/// from the database--as raw values--from rows matched
|
|
3424
|
+
/// on by the provided query.
|
|
3425
|
+
///
|
|
3426
|
+
/// This method is often much faster than a normal `select` operation,
|
|
3427
|
+
/// in that only the data requested will be transmitted from the database,
|
|
3428
|
+
/// and models won't be constructed and stitched together on load. Use this
|
|
3429
|
+
/// when you just need an "array of values" across certain columns from a table.
|
|
3430
|
+
///
|
|
3431
|
+
/// Return: Array<any> | Array<Array<any>> | Array<object>
|
|
3432
|
+
/// If the provided `fields` argument is an array of fields
|
|
3433
|
+
/// (fully qualified field names, or <see>Field</see> instances),
|
|
3434
|
+
/// then the result will be an array of arrays, where each item
|
|
3435
|
+
/// in the top-level array is a "row", and each sub-array is the
|
|
3436
|
+
/// values for the columns (fields) specified. If a single field
|
|
3437
|
+
/// is specified, then an one dimensional array is returned, where
|
|
3438
|
+
/// each item is the column value for each row fetched.
|
|
3439
|
+
/// For example, if we call `pluck` like: `let result = await connection.pluck(User.where.firstName.EQ('Bob'), 'User:id')`
|
|
3440
|
+
/// then the `result` would look like `[ 'USER_id_1`, `USER_id_2`, ... ]`
|
|
3441
|
+
/// where each value in the array is a user id. If however we call pluck like:
|
|
3442
|
+
/// `let result = await connection.pluck(User.where.firstName.EQ('Bob'), [ 'User:id', 'User:firstName' ])`
|
|
3443
|
+
/// then the `result` would look like `[ [ 'USER_id_1', 'Bob' ], [ 'USER_id_2', 'Bob' ], ... ]`, because
|
|
3444
|
+
/// the provided `fields` is an array, an array of field values will be returned from each row.
|
|
3445
|
+
/// If the `option` `mapToObjects` is `true`, then an array of objects will be returned,
|
|
3446
|
+
/// where each object is a "row", and each property one of the specified fields. Note that
|
|
3447
|
+
/// the properties of each returned object will be the fully qualified field name of each field
|
|
3448
|
+
/// specified. So, for example, specifying a pluck field of `User:id` means that each returned
|
|
3449
|
+
/// object in the array will look like `[ { 'User:id': 'USER_id_1' }, { 'User:id': 'USER_id_2' }, ... ]`.
|
|
3450
|
+
///
|
|
3451
|
+
/// Arguments:
|
|
3452
|
+
/// query: <see>QueryEngine</see>
|
|
3453
|
+
/// The query used to select rows from which columns will be plucked.
|
|
3454
|
+
/// fields: <see>Field</see> | string | Array<Field> | Array<string>
|
|
3455
|
+
/// Which fields to "pluck" from the matching rows. If an array is provided (even if
|
|
3456
|
+
/// it only contains a single field), then an array of arrays will be returned
|
|
3457
|
+
/// as the result. If a single field is provided (not an array), then an array
|
|
3458
|
+
/// of raw plucked column values will be returned instead.
|
|
3459
|
+
/// options?: object
|
|
3460
|
+
/// Operation specified options. These might change based on the database driver you
|
|
3461
|
+
/// are using, so please refer to your specific database driver documentation. One
|
|
3462
|
+
/// option that is common across all drivers is the `mapToObjects` boolean option.
|
|
3463
|
+
/// If `true`, then each row in the returned array will be an object instead of
|
|
3464
|
+
/// raw column values, where the property of each "row object" will be the fully
|
|
3465
|
+
/// qualified names of each field provided as the `fields` argument.
|
|
1312
3466
|
// eslint-disable-next-line no-unused-vars
|
|
1313
3467
|
async pluck(_queryEngine, _fields, _options) {
|
|
1314
3468
|
throw new Error(`${this.constructor.name}::pluck: This operation is not supported for this connection type.`);
|
|
1315
3469
|
}
|
|
1316
3470
|
|
|
3471
|
+
/// Check if any rows match the provided `query`.
|
|
3472
|
+
///
|
|
3473
|
+
/// Return: boolean
|
|
3474
|
+
/// `true` if one or more rows match the provided query, or `false` otherwise.
|
|
3475
|
+
///
|
|
3476
|
+
/// Arguments:
|
|
3477
|
+
/// query: <see>QueryEngine</see>
|
|
3478
|
+
/// The query used to select rows, to check if said rows exist in the database.
|
|
3479
|
+
/// options?: object
|
|
3480
|
+
/// Operation specific options. These will change depending on the database
|
|
3481
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3482
|
+
/// driver for more information.
|
|
1317
3483
|
// eslint-disable-next-line no-unused-vars
|
|
1318
3484
|
async exists(queryEngine, options) {
|
|
1319
3485
|
throw new Error(`${this.constructor.name}::exists: This operation is not supported for this connection type.`);
|
|
1320
3486
|
}
|
|
1321
3487
|
|
|
3488
|
+
/// Truncate (erase/clear) the entire table/bucket defined
|
|
3489
|
+
/// by the provided `Model`. All rows/objects from the underlying
|
|
3490
|
+
/// table/bucket will be destroyed, leaving you with an empty
|
|
3491
|
+
/// table/bucket.
|
|
3492
|
+
///
|
|
3493
|
+
/// Return: Promise<void>
|
|
3494
|
+
///
|
|
3495
|
+
/// Arguments:
|
|
3496
|
+
/// Model: class <see>Model</see>
|
|
3497
|
+
/// The model class that defines the underlying table/bucket to wipe clean/erase.
|
|
3498
|
+
/// options?: object
|
|
3499
|
+
/// Operation specific options. These will change depending on the database
|
|
3500
|
+
/// driver you are using. Please refer to the documentation for your specific
|
|
3501
|
+
/// driver for more information.
|
|
1322
3502
|
// eslint-disable-next-line no-unused-vars
|
|
1323
3503
|
async truncate(Model, options) {
|
|
1324
3504
|
throw new Error(`${this.constructor.name}::truncate: This operation is not supported for this connection type.`);
|
|
1325
3505
|
}
|
|
1326
3506
|
|
|
3507
|
+
/// "raw" database/driver specific query interface.
|
|
3508
|
+
///
|
|
3509
|
+
/// For SQL based databases, this would send a direct
|
|
3510
|
+
/// query string to the database. For other drivers, the
|
|
3511
|
+
/// arguments and operations that are executed might change.
|
|
3512
|
+
///
|
|
3513
|
+
/// Use this method to directly interact with the underlying
|
|
3514
|
+
/// database, in its own native query language.
|
|
3515
|
+
///
|
|
3516
|
+
/// The arguments and return value from this method is database/driver
|
|
3517
|
+
/// specific. Any `options` argument the database provides are also
|
|
3518
|
+
/// specific to the underlying database driver. However, one option
|
|
3519
|
+
/// is common across all drivers, and this is the `logger` option. If
|
|
3520
|
+
/// set, it is expected to have a `log` method in the provided `logger`
|
|
3521
|
+
/// object. Oftentimes, this will simply be `{ logger: console }`, but
|
|
3522
|
+
/// you can provided any custom `logger` instance you want, as long as it
|
|
3523
|
+
/// has a `log` method that can be called to log the results of the query.
|
|
3524
|
+
/// Most drivers also support a `{ logger }` option as a connection option
|
|
3525
|
+
/// when the connection is first instantiated, which will provided logging
|
|
3526
|
+
/// to every query that goes through the connection.
|
|
3527
|
+
///
|
|
3528
|
+
/// Return: database specific
|
|
3529
|
+
/// A database/driver specific return value, based on the query provided.
|
|
1327
3530
|
// eslint-disable-next-line no-unused-vars
|
|
1328
3531
|
async query(sql, options) {
|
|
1329
3532
|
throw new Error(`${this.constructor.name}::query: This operation is not supported for this connection type.`);
|
|
1330
3533
|
}
|
|
1331
3534
|
|
|
3535
|
+
/// Initiate a transaction (or snapshot/sub-transaction)
|
|
3536
|
+
/// if the database driver supports transactions.
|
|
3537
|
+
///
|
|
3538
|
+
/// This will initiate a transaction in the underlying database,
|
|
3539
|
+
/// if the database supports it. For SQL type databases this would
|
|
3540
|
+
/// be a `BEGIN/COMMIT/ROLLBACK` block. If this method is called
|
|
3541
|
+
/// when a transaction is already in-progress, then a snapshot/sub-transaction
|
|
3542
|
+
/// will be started instead.
|
|
3543
|
+
///
|
|
3544
|
+
/// This method will start a transaction in the underlying database,
|
|
3545
|
+
/// and call the provided asynchronous callback. If the callback throws
|
|
3546
|
+
/// an error, then the transaction (or snapshot) will be automatically
|
|
3547
|
+
/// rolled-back. There is a single `connection` argument that will be
|
|
3548
|
+
/// provided to the callback function when called. This `connection` argument
|
|
3549
|
+
/// will be the transaction connection itself, which for many database drivers is simply
|
|
3550
|
+
/// the same connection the transaction was started from. At a lower-level,
|
|
3551
|
+
/// Mythix ORM will use an [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html)
|
|
3552
|
+
/// context to provide the transaction connection to all code executed inside
|
|
3553
|
+
/// the callback, so the provided `connection` argument can generally be ignored.
|
|
3554
|
+
/// However, if [AsyncLocalStorage](https://nodejs.org/docs/latest-v16.x/api/async_context.html) isn't
|
|
3555
|
+
/// supported in your environment, or the specific driver you are using requires that you use
|
|
3556
|
+
/// the supplied `connection` argument, then you must use the supplied `connection`
|
|
3557
|
+
/// for all your operations, and provide it as the `{ connection }` option to all Mythix ORM
|
|
3558
|
+
/// calls made inside the callback.
|
|
3559
|
+
///
|
|
3560
|
+
/// Return: Promise<any>
|
|
3561
|
+
/// Return whatever return value is returned from the provided callback.
|
|
3562
|
+
///
|
|
3563
|
+
/// Arguments:
|
|
3564
|
+
/// callback: (connection: <see>Connection</see>) => any
|
|
3565
|
+
/// The async callback to call for the transaction operation. This should return as quickly as
|
|
3566
|
+
/// possible to avoid deadlocks in the underlying database. Whatever value this method
|
|
3567
|
+
/// returns will be the return value from the `transaction` call itself. If an exception is
|
|
3568
|
+
/// thrown in this method, then the transaction will be automatically rolled-back. If no
|
|
3569
|
+
/// exception is thrown from this method, then when done executing, a `COMMIT` will be sent
|
|
3570
|
+
/// to the underlying database automatically for you.
|
|
3571
|
+
/// options?: object
|
|
3572
|
+
/// Optional database specific options to supply for the transaction operation. There are two
|
|
3573
|
+
/// options that are supported across most database drivers, and those are `connection` and `lock`.
|
|
3574
|
+
/// The `connection` option supplies the the connection to initiate the transaction from, which for
|
|
3575
|
+
/// example might be another transaction connection (initiating a sub-transaction). If no `connection`
|
|
3576
|
+
/// option is supplied, then the `connection` this method was called from is used instead. The second
|
|
3577
|
+
/// common option is `lock`, which specifies how/if to lock the table for the transaction.
|
|
3578
|
+
/// See <see>ConnectionBase.getLockMode</see> for your specific driver for more information on this `lock` option.
|
|
1332
3579
|
// eslint-disable-next-line no-unused-vars
|
|
1333
3580
|
async transaction(callback, options) {
|
|
1334
3581
|
throw new Error(`${this.constructor.name}::transaction: This operation is not supported for this connection type.`);
|
|
1335
3582
|
}
|
|
1336
3583
|
|
|
3584
|
+
/// Translate the `defaultValue` as provided by each models field's
|
|
3585
|
+
/// into a `DEFAULT` value for the underlying database.
|
|
3586
|
+
///
|
|
3587
|
+
/// For example, if you were to specify a `defaultValue` for one of your
|
|
3588
|
+
/// models field's, such as `defaultValue: Types.INTEGER.Defaults.AUTOINCREMENT`,
|
|
3589
|
+
/// then this method would return a database specific `autoincrement` default for
|
|
3590
|
+
/// the column defined by your field. For date/time fields, this might be a database
|
|
3591
|
+
/// specific `NOW()` default. For non-database specific "defaults", the default value
|
|
3592
|
+
/// as defined by your `defaultValue` on your fields is simply returned.
|
|
3593
|
+
///
|
|
3594
|
+
/// Return: any
|
|
3595
|
+
/// Your defined field's `defaultValue`, intercepted, and possibly translated to
|
|
3596
|
+
/// a proper value for the underlying database. It is common for many database
|
|
3597
|
+
/// drivers that only date/time and auto-increment default values are intercepted
|
|
3598
|
+
/// and translated. Most other "default values" are simply returned.
|
|
3599
|
+
///
|
|
3600
|
+
/// Arguments:
|
|
3601
|
+
/// type: <see>Type</see>
|
|
3602
|
+
/// The field's `type` instance, as defined by the field itself.
|
|
3603
|
+
/// context: DefaultValueContext
|
|
3604
|
+
/// A `DefaultValueContext` as is normally provided to all `defaultValue` methods
|
|
3605
|
+
/// defined on <see name="fields">Field</see>. See the documentation for the `defaultValue`
|
|
3606
|
+
/// property of <see>Field</see> for more information.
|
|
1337
3607
|
// eslint-disable-next-line no-unused-vars
|
|
1338
3608
|
async getDefaultFieldValue(type, context) {
|
|
1339
3609
|
throw new Error(`${this.constructor.name}::getDefaultFieldValue: This operation is not supported for this connection type.`);
|
|
1340
3610
|
}
|
|
1341
3611
|
|
|
3612
|
+
/// A connection specific "helper" to force "dirty" fields
|
|
3613
|
+
/// for all models.
|
|
3614
|
+
///
|
|
3615
|
+
/// This method, when present on a connection, will assist in
|
|
3616
|
+
/// defining which fields are "dirty" for a model. It is used,
|
|
3617
|
+
/// for example, by `Types.DATETIME.Defaults.NOW.UPDATED` default values.
|
|
3618
|
+
/// In the case presented, DATETIME fields that should always be updated
|
|
3619
|
+
/// are always marked dirty by this method, even though they might
|
|
3620
|
+
/// not actually be "dirty" client-side.
|
|
3621
|
+
///
|
|
3622
|
+
/// If this method returns _any_ value other than `undefined`, then
|
|
3623
|
+
/// the field being operated upon will be marked "dirty" with the value
|
|
3624
|
+
/// returned, even if the field would otherwise not be marked "dirty".
|
|
3625
|
+
///
|
|
3626
|
+
/// Return: any
|
|
3627
|
+
/// If _any_ value is returned that is not `undefined`, then the field
|
|
3628
|
+
/// will be marked "dirty" with the value returned. Return `undefined`
|
|
3629
|
+
/// if you do not wish to mark a specific field as "dirty". Note however
|
|
3630
|
+
/// that the field _might_ actually still be dirty because the user modified
|
|
3631
|
+
/// the field, in which case this method will not even be called for that field.
|
|
3632
|
+
/// In short, this method is only called for fields that are not already marked
|
|
3633
|
+
/// as dirty, and will force a field to be marked dirty if any value other than
|
|
3634
|
+
/// `undefined` is returned.
|
|
3635
|
+
///
|
|
3636
|
+
/// Arguments:
|
|
3637
|
+
/// context: DefaultValueContext
|
|
3638
|
+
/// See <see>Field</see> for documentation on the `DefaultValueContext` interface.
|
|
1342
3639
|
// eslint-disable-next-line no-unused-vars
|
|
1343
3640
|
dirtyFieldHelper(context) {
|
|
1344
3641
|
|