mythix-orm-sql-base 1.9.6 → 1.10.1
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/.biblorc.js +30 -0
- package/README.md +2 -4
- package/docs/Home.md +3 -0
- package/lib/sql-connection-base.js +249 -11
- package/lib/sql-query-generator-base.d.ts +4 -13
- package/lib/sql-query-generator-base.js +1499 -116
- package/package.json +3 -2
|
@@ -14,7 +14,33 @@ const {
|
|
|
14
14
|
const DefaultHelpers = Types.DefaultHelpers;
|
|
15
15
|
const LiteralBase = Literals.LiteralBase;
|
|
16
16
|
|
|
17
|
+
/// The "base" SQL generator for all SQL-type databases.
|
|
17
18
|
class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
19
|
+
/// Escape a field name, usually for a projection alias.
|
|
20
|
+
/// This method is primarily used for generating aliases
|
|
21
|
+
/// for projected fields.
|
|
22
|
+
///
|
|
23
|
+
/// This method will take the field it is given, and turn
|
|
24
|
+
/// it into a fully qualified field name, escaped as an identifier
|
|
25
|
+
/// for the underlying database.
|
|
26
|
+
///
|
|
27
|
+
/// For example, given the field `User.fields.id`, this method will return
|
|
28
|
+
/// `"User:id"`--assuming that double quotes are used in the underlying
|
|
29
|
+
/// database to escape an identifier.
|
|
30
|
+
///
|
|
31
|
+
/// Arguments:
|
|
32
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
33
|
+
/// The model that owns the `field` provided.
|
|
34
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
35
|
+
/// The field to operate on.
|
|
36
|
+
/// options?: object
|
|
37
|
+
/// Options for the operation.
|
|
38
|
+
/// | Option | Type | Default Value | Description |
|
|
39
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
40
|
+
/// | `fieldNameOnly` | `boolean` | `false` | If `true`, then only use the `fieldName` of the field, ignoring the model name in the operation (resulting in a non-fully-qualified field name) |
|
|
41
|
+
///
|
|
42
|
+
/// Return: string
|
|
43
|
+
/// The field's name, escaped for the underlying database. i.e. `"User:id"`.
|
|
18
44
|
getEscapedFieldName(_Model, field, options) {
|
|
19
45
|
let isString = Nife.instanceOf(field, 'string');
|
|
20
46
|
let fieldName = (isString) ? field : field.fieldName;
|
|
@@ -29,6 +55,34 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
29
55
|
return `"${field.Model.getModelName()}:${fieldName}"`;
|
|
30
56
|
}
|
|
31
57
|
|
|
58
|
+
/// Get the escaped column name for the field provided.
|
|
59
|
+
///
|
|
60
|
+
/// Given a field, return the full column name (including the table)
|
|
61
|
+
/// of that field, escaped for the underlying databases.
|
|
62
|
+
/// For example, given the field `User.fields.id`, return `"users"."id"`--assuming
|
|
63
|
+
/// the underlying database uses double quotes for escaping identifiers.
|
|
64
|
+
///
|
|
65
|
+
/// This method will use the `columnName` defined on the field for the name
|
|
66
|
+
/// of the column, if defined, or will use `fieldName` as defined on the field
|
|
67
|
+
/// as the column name if no `columnName` is defined. To get the name of the table,
|
|
68
|
+
/// this method will use [getTableName](https://github.com/th317erd/mythix-orm/wiki/Model#method-static-getTableName)
|
|
69
|
+
/// on the model that owns the `field` provided.
|
|
70
|
+
///
|
|
71
|
+
/// Arguments:
|
|
72
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
73
|
+
/// The model that owns the `field` provided.
|
|
74
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
75
|
+
/// The field to operate on.
|
|
76
|
+
/// options?: object
|
|
77
|
+
/// Options for the operation.
|
|
78
|
+
/// | Option | Type | Default Value | Description |
|
|
79
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
80
|
+
/// | `columnNameOnly` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the name of the table. |
|
|
81
|
+
/// | `columnNamePrefix` | `string` | `''` | Prefix the column name with this value before escaping it. |
|
|
82
|
+
/// | `tableNamePrefix` | `string` | `''` | Only applicable if `columnNameOnly` is `false`. Used to prefix the table name before escaping it. |
|
|
83
|
+
///
|
|
84
|
+
/// Return: string
|
|
85
|
+
/// The fully escaped column name, including the table the column exists on. i.e. `"users"."id"`.
|
|
32
86
|
getEscapedColumnName(_Model, field, options) {
|
|
33
87
|
let isString = Nife.instanceOf(field, 'string');
|
|
34
88
|
let columnName = (isString) ? field : (field.columnName || field.fieldName);
|
|
@@ -46,6 +100,27 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
46
100
|
return `${this.getEscapedTableName(Model)}.${this.escapeID(columnName)}`;
|
|
47
101
|
}
|
|
48
102
|
|
|
103
|
+
/// Get the escaped table name for the model or field provided.
|
|
104
|
+
///
|
|
105
|
+
/// Give a model or field, access the model to get the table name
|
|
106
|
+
/// for the model, and escape it for the underlying database.
|
|
107
|
+
/// If given a field, then the parent model for that field will be
|
|
108
|
+
/// retrieved via `field.Model`. Once a model is ascertained, then
|
|
109
|
+
/// call [getTableName](https://github.com/th317erd/mythix-orm/wiki/Model#method-static-getTableName)
|
|
110
|
+
/// on the model to get the table name in the underlying database for this
|
|
111
|
+
/// model, escaping it before it is returned.
|
|
112
|
+
///
|
|
113
|
+
/// Arguments:
|
|
114
|
+
/// modelOrField: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model) | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
115
|
+
/// A model class, or a field to fetch the model class from.
|
|
116
|
+
/// options?: object
|
|
117
|
+
/// Options for the operation.
|
|
118
|
+
/// | Option | Type | Default Value | Description |
|
|
119
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
120
|
+
/// | `tableNamePrefix` | `string` | `''` | Used to prefix the table name before escaping it. |
|
|
121
|
+
///
|
|
122
|
+
/// Return: string
|
|
123
|
+
/// The table name for the given model, escaped for the underlying database. i.e. `"users"`.
|
|
49
124
|
getEscapedTableName(_modelOrField, options) {
|
|
50
125
|
let Model = (_modelOrField.Model) ? _modelOrField.Model : _modelOrField;
|
|
51
126
|
let tableName = Model.getTableName(this.connection);
|
|
@@ -56,6 +131,33 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
56
131
|
return this.escapeID(tableName);
|
|
57
132
|
}
|
|
58
133
|
|
|
134
|
+
/// Given a field, escape it for the projection,
|
|
135
|
+
/// optionally including an alias for the field.
|
|
136
|
+
///
|
|
137
|
+
/// For example, given the field `User.fields.id`, return
|
|
138
|
+
/// the projected field with an alias: `"users"."id" AS "User:id"`.
|
|
139
|
+
/// By default, this will use <see>SQLQueryGeneratorBase.getEscapedFieldName</see>
|
|
140
|
+
/// for the alias, unless the `as` `options` is provided. If `as`
|
|
141
|
+
/// is provided to the `options`, then use that as the literal field
|
|
142
|
+
/// alias instead.
|
|
143
|
+
///
|
|
144
|
+
/// Arguments:
|
|
145
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
146
|
+
/// The model that owns the `field` provided.
|
|
147
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
148
|
+
/// The field to operate on.
|
|
149
|
+
/// options?: object
|
|
150
|
+
/// Options for the operation.
|
|
151
|
+
/// | Option | Type | Default Value | Description |
|
|
152
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
153
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the alias for the projection. |
|
|
154
|
+
/// | `columnNameOnly` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the name of the table. |
|
|
155
|
+
/// | `columnNamePrefix` | `string` | `''` | Prefix the column name with this value before escaping it. |
|
|
156
|
+
/// | `tableNamePrefix` | `string` | `''` | Only applicable if `columnNameOnly` is `false`. Used to prefix the table name before escaping it. |
|
|
157
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
158
|
+
///
|
|
159
|
+
/// Return: string
|
|
160
|
+
/// The fully escaped column name, for use in the projection. i.e. `"users"."id" AS "User:id"`.
|
|
59
161
|
// eslint-disable-next-line no-unused-vars
|
|
60
162
|
getEscapedProjectionName(Model, field, options) {
|
|
61
163
|
if (options && options.noProjectionAliases)
|
|
@@ -64,8 +166,39 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
64
166
|
return `${this.getEscapedColumnName(Model, field, options)} AS ${(options && options.as) ? this.escapeID(options.as) : this.getEscapedFieldName(Model, field, options)}`;
|
|
65
167
|
}
|
|
66
168
|
|
|
169
|
+
/// Pass all non-virtual model fields through
|
|
170
|
+
/// <see>SQLQueryGeneratorBase.getEscapedFieldName</see>,
|
|
171
|
+
/// <see>SQLQueryGeneratorBase.getEscapedColumnName</see>,
|
|
172
|
+
/// or <see>SQLQueryGeneratorBase.getEscapedProjectionName</see>.
|
|
173
|
+
///
|
|
174
|
+
/// This method is used to bulk-escape all model fields, using one
|
|
175
|
+
/// of the methods listed above. If the `asProjection` `options` is
|
|
176
|
+
/// used, then all fields will be escaped using <see>SQLQueryGeneratorBase.getEscapedProjectionName</see>.
|
|
177
|
+
/// If the `asColumn` `options` is used, then escape all fields using
|
|
178
|
+
/// <see>SQLQueryGeneratorBase.getEscapedColumnName</see>. Otherwise,
|
|
179
|
+
/// if no `options` are specified, then escape all model fields using
|
|
180
|
+
/// <see>SQLQueryGeneratorBase.getEscapedFieldName</see> instead.
|
|
181
|
+
///
|
|
182
|
+
/// Arguments:
|
|
183
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
184
|
+
/// The model whose fields are to be escaped. Only non-virtual fields are operated upon.
|
|
185
|
+
/// options?: object
|
|
186
|
+
/// Options for the operation.
|
|
187
|
+
/// | Option | Type | Default Value | Description |
|
|
188
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
189
|
+
/// | `asProjection` | `boolean` | `false` | If `true`, then use <see>SQLQueryGeneratorBase.getEscapedProjectionName</see> to escape the model's fields. |
|
|
190
|
+
/// | `asColumn` | `boolean` | `false` | If `true`, then use <see>SQLQueryGeneratorBase.getEscapedColumnName</see> to escape the model's fields. |
|
|
191
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the alias for the projection. |
|
|
192
|
+
/// | `columnNameOnly` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the name of the table. |
|
|
193
|
+
/// | `columnNamePrefix` | `string` | `''` | Prefix the column name with this value before escaping it. |
|
|
194
|
+
/// | `tableNamePrefix` | `string` | `''` | Only applicable if `columnNameOnly` is `false`. Used to prefix the table name before escaping it. |
|
|
195
|
+
///
|
|
196
|
+
/// Return: object
|
|
197
|
+
/// Return an object that maps all escaped model fields. Each key will be the fully qualified name of the field,
|
|
198
|
+
/// each value will be the escaped field as a string.
|
|
67
199
|
// eslint-disable-next-line no-unused-vars
|
|
68
|
-
getEscapedModelFields(Model,
|
|
200
|
+
getEscapedModelFields(Model, _options) {
|
|
201
|
+
let options = Object.assign(_options || {}, { as: null });
|
|
69
202
|
let fields = {};
|
|
70
203
|
let modelName = Model.getModelName();
|
|
71
204
|
|
|
@@ -88,10 +221,21 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
88
221
|
return fields;
|
|
89
222
|
}
|
|
90
223
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
224
|
+
/// Get the `ORDER` clause from the provided [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine).
|
|
225
|
+
/// If none is found, then call [Connection.getDefaultOrder](https://github.com/th317erd/mythix-orm/wiki/ConnectionBase#method-getDefaultOrder)
|
|
226
|
+
/// to get the default order for the operation.
|
|
227
|
+
///
|
|
228
|
+
/// Arguments:
|
|
229
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
230
|
+
/// The query engine to fetch the `ORDER` clause from.
|
|
231
|
+
/// options?: object
|
|
232
|
+
/// The options object provided to the operation that is taking place. This isn't used
|
|
233
|
+
/// by this method, but instead is passed off to [Connection.getDefaultOrder](https://github.com/th317erd/mythix-orm/wiki/ConnectionBase#method-getDefaultOrder)
|
|
234
|
+
/// in case the connection (or user) needs the options to produce a default ordering.
|
|
235
|
+
///
|
|
236
|
+
/// Return: Map<string, { value: Field | Literal | string; direction?: '+' | '-'; ... }>
|
|
237
|
+
/// Return the field-set for the default ordering to apply to the operation taking place.
|
|
238
|
+
/// This `Map` should have the same format as is returned by [ModelScope.mergeFields](https://github.com/th317erd/mythix-orm/wiki/ModelScope#method-mergeFields).
|
|
95
239
|
getQueryEngineOrder(queryEngine, _options) {
|
|
96
240
|
let options = _options || {};
|
|
97
241
|
let context = queryEngine.getOperationContext();
|
|
@@ -100,6 +244,35 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
100
244
|
return (order && order.size) ? order : this.connection.getDefaultOrder(context.rootModel, options);
|
|
101
245
|
}
|
|
102
246
|
|
|
247
|
+
/// Get the field projection for the operation taking place.
|
|
248
|
+
///
|
|
249
|
+
/// This will prepare all fields in the projection, along with
|
|
250
|
+
/// any literals, and will also merge any `ORDER BY` clause fields
|
|
251
|
+
/// into the projection. The result will be either a `Map`, containing
|
|
252
|
+
/// all projected fields and literals, or will be an `Array` of just
|
|
253
|
+
/// the projected fields, escaped and prepared for the underlying database.
|
|
254
|
+
/// A `Map` of the fields will be returned instead of an array if the `asMap`
|
|
255
|
+
/// argument is set to `true`.
|
|
256
|
+
///
|
|
257
|
+
/// Arguments:
|
|
258
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
259
|
+
/// The query engine to fetch the field projection (and order) from.
|
|
260
|
+
/// options?: object
|
|
261
|
+
/// Options for the operation. These options aren't used directly by this method,
|
|
262
|
+
/// but instead are passed off to the sub-methods that are called to complete the
|
|
263
|
+
/// operation, such as the `toString` method for literals, the <see>SQLQueryGeneratorBase.getQueryEngineOrder</see>
|
|
264
|
+
/// to get the field ordering, and to the <see>SQLQueryGeneratorBase.getEscapedProjectionName</see> to
|
|
265
|
+
/// project the fields.
|
|
266
|
+
/// asMap: boolean
|
|
267
|
+
/// If `true`, then return a `Map` of the projected fields, instead of an `Array`. This
|
|
268
|
+
/// is used for example internally by `SELECT` operations to know which fields were
|
|
269
|
+
/// projected. Each key in this `Map` is a fully qualified field name (to link the projection
|
|
270
|
+
/// back to its field), or a fully expanded literal string for literals. The value for each
|
|
271
|
+
/// property in this map in the projected field or literal value itself, as a string.
|
|
272
|
+
///
|
|
273
|
+
/// Return: Map<string, string> | Array<string>
|
|
274
|
+
/// A `Map` of the projected fields if the `asMap` argument is `true`, or an `Array` of the
|
|
275
|
+
/// projected fields otherwise.
|
|
103
276
|
getProjectedFields(queryEngine, _options, asMap) {
|
|
104
277
|
let options = this.stackAssign(_options || {}, { isProjection: true });
|
|
105
278
|
let context = queryEngine.getOperationContext();
|
|
@@ -145,6 +318,50 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
145
318
|
return Array.from(allProjectionFields.values());
|
|
146
319
|
}
|
|
147
320
|
|
|
321
|
+
/// Given two "operation contexts" from a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
322
|
+
/// instance, collection the information required to join two tables.
|
|
323
|
+
///
|
|
324
|
+
/// Using the "left side" context of the operation being calculated, find the "root model"
|
|
325
|
+
/// of the query, and compile table-join information with the "right side" context of
|
|
326
|
+
/// the operation, joining the "root model" on the left-side with the model and field specified on
|
|
327
|
+
/// the right-side of the operation.
|
|
328
|
+
///
|
|
329
|
+
/// A table-join looks like `User.where.id.EQ(Role.where.userID)`. In this context, the `User.where.id`
|
|
330
|
+
/// would be the "left side", and `Role.where.userID` would be the "right side".
|
|
331
|
+
///
|
|
332
|
+
/// Interface:
|
|
333
|
+
/// interface TableJoinInformation {
|
|
334
|
+
/// operator: string; // The operator used for the table-join, i.e. "EQ"
|
|
335
|
+
/// joinType: string; // The database specific join-type for the table-join, i.e. "INNER JOIN"
|
|
336
|
+
/// rootModelName: string; // The name of the "root model" for the query
|
|
337
|
+
/// joinModel: class Model; // The the model being joined to the "root model"
|
|
338
|
+
/// joinModelName: string; // The name of the model being joined to the "root model"
|
|
339
|
+
/// leftSideModel: class Model; // The model on the left-side of the table-join
|
|
340
|
+
/// leftSideModelName: string; // The name of the model on the left-side of the table-join
|
|
341
|
+
/// leftQueryContext: object; // The "operation context" of the left-side of the operation
|
|
342
|
+
/// leftSideField: Field; // The field on the left side of the table-join
|
|
343
|
+
/// rightSideModel: class Model; // The model on the right-side of the table-join
|
|
344
|
+
/// rightSideModelName: string; // The model name of the model on the right-side of the table-join
|
|
345
|
+
/// rightQueryContext: object; // The "operation context" of the right-side of the operation
|
|
346
|
+
/// rightSideField: Field; // The field on the right-side of the table-join
|
|
347
|
+
/// }
|
|
348
|
+
///
|
|
349
|
+
/// Arguments:
|
|
350
|
+
/// leftQueryContext: object
|
|
351
|
+
/// The left-side "operation context" of the query engine to compile the "root model" information
|
|
352
|
+
/// from.
|
|
353
|
+
/// rightQueryContext: object
|
|
354
|
+
/// The right-side "operation context" of the query engine to compile the "join model" information
|
|
355
|
+
/// from.
|
|
356
|
+
/// joinType: string
|
|
357
|
+
/// The join-type (LEFT, RIGHT, INNER, CROSS, etc...) for the join-table operation.
|
|
358
|
+
/// options?: object
|
|
359
|
+
/// The options for the operation. These aren't used by default by Mythix ORM, and instead are
|
|
360
|
+
/// provided for the user if the user should overload this method. These will be the options for
|
|
361
|
+
/// the operation taking place (i.e. a `SELECT` operation).
|
|
362
|
+
///
|
|
363
|
+
/// Return: TableJoinInformation
|
|
364
|
+
/// Return an object containing all information needed to generate a table-join query.
|
|
148
365
|
// eslint-disable-next-line no-unused-vars
|
|
149
366
|
getJoinTableInfoFromQueryContexts(leftQueryContext, rightQueryContext, joinType, options) {
|
|
150
367
|
let rootModel = leftQueryContext.rootModel;
|
|
@@ -193,6 +410,30 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
193
410
|
};
|
|
194
411
|
}
|
|
195
412
|
|
|
413
|
+
/// Get an `AS` projection alias for the literal being stringified,
|
|
414
|
+
/// but only if a projection alias is applicable.
|
|
415
|
+
///
|
|
416
|
+
/// If the literal is a "sub-field" (i.e. the `FieldLiteral` in `new CountLiteral(new FieldLiteral(...))`)
|
|
417
|
+
/// then don't return a projection alias (i.e. the alias needs to be on `CountLiteral` in this example, not
|
|
418
|
+
/// on the sub-field `FieldLiteral`).
|
|
419
|
+
///
|
|
420
|
+
/// Also don't return an alias if the `noProjectionAliases` `options` is set to `true`. This might
|
|
421
|
+
/// be the case for example if we are "projecting" the literal for an `ORDER BY` clause.
|
|
422
|
+
///
|
|
423
|
+
/// Arguments:
|
|
424
|
+
/// literal: inherits from [LiteralBase](https://github.com/th317erd/mythix-orm/wiki/LiteralBase)
|
|
425
|
+
/// The literal that is being stringified.
|
|
426
|
+
/// options?: object
|
|
427
|
+
/// Options for the operation.
|
|
428
|
+
/// | Option | Type | Default Value | Description |
|
|
429
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
430
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
431
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
432
|
+
/// | `as` | `string` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
433
|
+
///
|
|
434
|
+
/// Return: string
|
|
435
|
+
/// An empty string if a field alias isn't allowed, or an ` AS ...` postfix string
|
|
436
|
+
/// to apply to the stringified `literal` provided if an alias is allowed and requested.
|
|
196
437
|
_getLiteralAlias(literal, options) {
|
|
197
438
|
if (options && options.isSubField)
|
|
198
439
|
return '';
|
|
@@ -207,6 +448,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
207
448
|
return ` AS ${this.escapeID(as)}`;
|
|
208
449
|
}
|
|
209
450
|
|
|
451
|
+
/// Convert an [AverageLiteral](https://github.com/th317erd/mythix-orm/wiki/AverageLiteral) to
|
|
452
|
+
/// a string for use in the underlying database.
|
|
453
|
+
///
|
|
454
|
+
/// Arguments:
|
|
455
|
+
/// literal: [AverageLiteral](https://github.com/th317erd/mythix-orm/wiki/AverageLiteral)
|
|
456
|
+
/// The [AverageLiteral](https://github.com/th317erd/mythix-orm/wiki/AverageLiteral) to stringify.
|
|
457
|
+
/// options?: object
|
|
458
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
459
|
+
/// literal or connection specific options that can be supplied.
|
|
460
|
+
/// | Option | Type | Default Value | Description |
|
|
461
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
462
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
463
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
464
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
465
|
+
///
|
|
466
|
+
/// Return: string
|
|
467
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
210
468
|
_averageLiteralToString(literal, options) {
|
|
211
469
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
212
470
|
return;
|
|
@@ -222,6 +480,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
222
480
|
return `AVG(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
223
481
|
}
|
|
224
482
|
|
|
483
|
+
/// Convert an [CountLiteral](https://github.com/th317erd/mythix-orm/wiki/CountLiteral) to
|
|
484
|
+
/// a string for use in the underlying database.
|
|
485
|
+
///
|
|
486
|
+
/// Arguments:
|
|
487
|
+
/// literal: [CountLiteral](https://github.com/th317erd/mythix-orm/wiki/CountLiteral)
|
|
488
|
+
/// The [CountLiteral](https://github.com/th317erd/mythix-orm/wiki/CountLiteral) to stringify.
|
|
489
|
+
/// options?: object
|
|
490
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
491
|
+
/// literal or connection specific options that can be supplied.
|
|
492
|
+
/// | Option | Type | Default Value | Description |
|
|
493
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
494
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
495
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
496
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
497
|
+
///
|
|
498
|
+
/// Return: string
|
|
499
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
225
500
|
_countLiteralToString(literal, options) {
|
|
226
501
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
227
502
|
return;
|
|
@@ -241,6 +516,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
241
516
|
return `COUNT(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
242
517
|
}
|
|
243
518
|
|
|
519
|
+
/// Convert an [DistinctLiteral](https://github.com/th317erd/mythix-orm/wiki/DistinctLiteral) to
|
|
520
|
+
/// a string for use in the underlying database.
|
|
521
|
+
///
|
|
522
|
+
/// Arguments:
|
|
523
|
+
/// literal: [DistinctLiteral](https://github.com/th317erd/mythix-orm/wiki/DistinctLiteral)
|
|
524
|
+
/// The [DistinctLiteral](https://github.com/th317erd/mythix-orm/wiki/DistinctLiteral) to stringify.
|
|
525
|
+
/// options?: object
|
|
526
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
527
|
+
/// literal or connection specific options that can be supplied.
|
|
528
|
+
/// | Option | Type | Default Value | Description |
|
|
529
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
530
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
531
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
532
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
533
|
+
///
|
|
534
|
+
/// Return: string
|
|
535
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
244
536
|
_distinctLiteralToString(literal, options) {
|
|
245
537
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
246
538
|
return;
|
|
@@ -270,6 +562,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
270
562
|
return `DISTINCT ON(${escapedColumnName})`;
|
|
271
563
|
}
|
|
272
564
|
|
|
565
|
+
/// Convert an [FieldLiteral](https://github.com/th317erd/mythix-orm/wiki/FieldLiteral) to
|
|
566
|
+
/// a string for use in the underlying database.
|
|
567
|
+
///
|
|
568
|
+
/// Arguments:
|
|
569
|
+
/// literal: [FieldLiteral](https://github.com/th317erd/mythix-orm/wiki/FieldLiteral)
|
|
570
|
+
/// The [FieldLiteral](https://github.com/th317erd/mythix-orm/wiki/FieldLiteral) to stringify.
|
|
571
|
+
/// options?: object
|
|
572
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
573
|
+
/// literal or connection specific options that can be supplied.
|
|
574
|
+
/// | Option | Type | Default Value | Description |
|
|
575
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
576
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
577
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
578
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
579
|
+
///
|
|
580
|
+
/// Return: string
|
|
581
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
273
582
|
_fieldLiteralToString(literal, options) {
|
|
274
583
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
275
584
|
return;
|
|
@@ -282,6 +591,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
282
591
|
return this.getEscapedProjectionName(field.Model, field, this.stackAssign(options, { noProjectionAliases }, literal.options));
|
|
283
592
|
}
|
|
284
593
|
|
|
594
|
+
/// Convert an [MaxLiteral](https://github.com/th317erd/mythix-orm/wiki/MaxLiteral) to
|
|
595
|
+
/// a string for use in the underlying database.
|
|
596
|
+
///
|
|
597
|
+
/// Arguments:
|
|
598
|
+
/// literal: [MaxLiteral](https://github.com/th317erd/mythix-orm/wiki/MaxLiteral)
|
|
599
|
+
/// The [MaxLiteral](https://github.com/th317erd/mythix-orm/wiki/MaxLiteral) to stringify.
|
|
600
|
+
/// options?: object
|
|
601
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
602
|
+
/// literal or connection specific options that can be supplied.
|
|
603
|
+
/// | Option | Type | Default Value | Description |
|
|
604
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
605
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
606
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
607
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
608
|
+
///
|
|
609
|
+
/// Return: string
|
|
610
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
285
611
|
_maxLiteralToString(literal, options) {
|
|
286
612
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
287
613
|
return;
|
|
@@ -297,6 +623,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
297
623
|
return `MAX(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
298
624
|
}
|
|
299
625
|
|
|
626
|
+
/// Convert an [MinLiteral](https://github.com/th317erd/mythix-orm/wiki/MinLiteral) to
|
|
627
|
+
/// a string for use in the underlying database.
|
|
628
|
+
///
|
|
629
|
+
/// Arguments:
|
|
630
|
+
/// literal: [MinLiteral](https://github.com/th317erd/mythix-orm/wiki/MinLiteral)
|
|
631
|
+
/// The [MinLiteral](https://github.com/th317erd/mythix-orm/wiki/MinLiteral) to stringify.
|
|
632
|
+
/// options?: object
|
|
633
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
634
|
+
/// literal or connection specific options that can be supplied.
|
|
635
|
+
/// | Option | Type | Default Value | Description |
|
|
636
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
637
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
638
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
639
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
640
|
+
///
|
|
641
|
+
/// Return: string
|
|
642
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
300
643
|
_minLiteralToString(literal, options) {
|
|
301
644
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
302
645
|
return;
|
|
@@ -312,6 +655,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
312
655
|
return `MIN(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
313
656
|
}
|
|
314
657
|
|
|
658
|
+
/// Convert an [SumLiteral](https://github.com/th317erd/mythix-orm/wiki/SumLiteral) to
|
|
659
|
+
/// a string for use in the underlying database.
|
|
660
|
+
///
|
|
661
|
+
/// Arguments:
|
|
662
|
+
/// literal: [SumLiteral](https://github.com/th317erd/mythix-orm/wiki/SumLiteral)
|
|
663
|
+
/// The [SumLiteral](https://github.com/th317erd/mythix-orm/wiki/SumLiteral) to stringify.
|
|
664
|
+
/// options?: object
|
|
665
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
666
|
+
/// literal or connection specific options that can be supplied.
|
|
667
|
+
/// | Option | Type | Default Value | Description |
|
|
668
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
669
|
+
/// | `isSubField` | `boolean` | `false` | If `true`, the engine is reporting that this is a "sub-field", or literal inside a literal... if this is the case, then don't return an `AS` field alias. |
|
|
670
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, the engine is reporting that this is part of the query that shouldn't have field aliases, such as an `ORDER BY` clause. |
|
|
671
|
+
/// | `as` | `string` | `undefined` | If set to a valid string, then this will be used for the `AS` alias of the column instead of the default. |
|
|
672
|
+
///
|
|
673
|
+
/// Return: string
|
|
674
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
315
675
|
_sumLiteralToString(literal, options) {
|
|
316
676
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
317
677
|
return;
|
|
@@ -327,106 +687,86 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
327
687
|
return `SUM(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
328
688
|
}
|
|
329
689
|
|
|
690
|
+
/// A convenience method that proxies to <see>SQLConnectionBase.prepareArrayValuesForSQL</see>.
|
|
691
|
+
///
|
|
692
|
+
/// See: SQLConnectionBase.prepareArrayValuesForSQL
|
|
330
693
|
prepareArrayValuesForSQL(array) {
|
|
331
694
|
return this.connection.prepareArrayValuesForSQL(array);
|
|
332
695
|
}
|
|
333
696
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
modelName = field.Model.getModelName();
|
|
365
|
-
fieldName = field.fieldName;
|
|
366
|
-
|
|
367
|
-
stop();
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
if (getRawField && projectionField)
|
|
372
|
-
return projectionField;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (getRawField && modelName && fieldName) {
|
|
376
|
-
let field = this.connection.getField(fieldName, modelName);
|
|
377
|
-
if (field)
|
|
378
|
-
return field;
|
|
379
|
-
} else if (!modelName || !fieldName) {
|
|
380
|
-
return str;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return `${modelName}:${fieldName}`;
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
parseFieldProjectionToFieldMap(selectStatement) {
|
|
387
|
-
let firstPart = selectStatement.replace(/[\r\n]/g, ' ').split(/\s+FROM\s+/i)[0].replace(/^SELECT\s+/i, '').trim();
|
|
388
|
-
let fieldParts = firstPart.split(',');
|
|
389
|
-
let projectionFieldMap = new Map();
|
|
390
|
-
|
|
391
|
-
for (let i = 0, il = fieldParts.length; i < il; i++) {
|
|
392
|
-
let fieldPart = fieldParts[i].trim();
|
|
393
|
-
let field = this.parseFieldProjection(fieldPart, true);
|
|
394
|
-
|
|
395
|
-
if (field !== fieldPart)
|
|
396
|
-
projectionFieldMap.set(`${field.Model.getModelName()}:${field.fieldName}`, this.getEscapedProjectionName(field.Model, field));
|
|
397
|
-
else
|
|
398
|
-
projectionFieldMap.set(field, field);
|
|
399
|
-
|
|
400
|
-
// If this isn't a field, then add it
|
|
401
|
-
if (!this.isFieldIdentifier(fieldPart))
|
|
402
|
-
projectionFieldMap.set(fieldPart, fieldPart);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return projectionFieldMap;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
generateSelectQueryFieldProjection(queryEngine, options, asMap) {
|
|
409
|
-
let projectedFields = this.getProjectedFields(queryEngine, options, asMap);
|
|
410
|
-
|
|
411
|
-
if (asMap === true) {
|
|
412
|
-
return projectedFields;
|
|
413
|
-
} else {
|
|
414
|
-
let projectedFieldList = Array.from(projectedFields.values()).join(',');
|
|
415
|
-
|
|
416
|
-
let distinct = queryEngine.getOperationContext().distinct;
|
|
417
|
-
if (distinct) {
|
|
418
|
-
let result = distinct.toString(this.connection, { isProjection: true });
|
|
419
|
-
return `${result} ${projectedFieldList}`;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return projectedFieldList;
|
|
697
|
+
/// Generate a field projection for a `SELECT` statement.
|
|
698
|
+
/// If a `DISTINCT` operation is in-use, then this will always
|
|
699
|
+
/// prefix any and all fields projected.
|
|
700
|
+
///
|
|
701
|
+
/// Arguments:
|
|
702
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
703
|
+
/// The query engine to use to generate the field projection from.
|
|
704
|
+
/// options?: object
|
|
705
|
+
/// Options that are passed through the operation. These options are
|
|
706
|
+
/// simply passed to all other sub-methods used in this operation, including
|
|
707
|
+
/// when stringifying literals.
|
|
708
|
+
/// projectedFields?: Map<string, string>
|
|
709
|
+
/// Provide the projected fields if they are already known, instead of compiling them
|
|
710
|
+
/// again via a call to <see>SQLQueryGeneratorBase.getProjectedFields</see>.
|
|
711
|
+
///
|
|
712
|
+
/// Return: string
|
|
713
|
+
/// Return a comma-separated list of projected fields. If any `DISTINCT`
|
|
714
|
+
/// clause is set on the `queryEngine`, then that will always come first
|
|
715
|
+
/// in the list of projected fields.
|
|
716
|
+
generateSelectQueryFieldProjection(queryEngine, options, _projectedFields) {
|
|
717
|
+
let projectedFields = (_projectedFields) ? _projectedFields : this.getProjectedFields(queryEngine, options, false);
|
|
718
|
+
let projectedFieldList = Array.from(projectedFields.values()).join(',');
|
|
719
|
+
|
|
720
|
+
let distinct = queryEngine.getOperationContext().distinct;
|
|
721
|
+
if (distinct) {
|
|
722
|
+
let result = distinct.toString(this.connection, { isProjection: true });
|
|
723
|
+
return `${result} ${projectedFieldList}`;
|
|
423
724
|
}
|
|
424
|
-
}
|
|
425
725
|
|
|
426
|
-
|
|
726
|
+
return projectedFieldList;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/// Convert a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) conditional
|
|
730
|
+
/// operator into the equivalent SQL conditional operator. For example, `EQ` will be converted
|
|
731
|
+
/// to `=` for most values, `IS` (in the case of `null`, `true`, and `false`), or an `IN` operator
|
|
732
|
+
/// if an array of values is provided.
|
|
733
|
+
///
|
|
734
|
+
/// If a literal is provided, then it will be converted to a string using the literal's `toString`
|
|
735
|
+
/// method and returned.
|
|
736
|
+
///
|
|
737
|
+
/// Standard conversion table for most SQL connections (results might differ based on the SQL
|
|
738
|
+
/// connection being used):
|
|
739
|
+
/// | `QueryEngine` Operator | `Array<any>` | `null` | `true` | `false` | Table Join | Other |
|
|
740
|
+
/// | -------------------- | ------------ | ------ | ------ | ------- | ---------- | ----- |
|
|
741
|
+
/// | `EQ` | `IN` | `IS NULL` | `IS TRUE` | `IS FALSE` | `=` | `=` |
|
|
742
|
+
/// | `NEQ` | `NOT IN` | `IS NOT NULL` | `IS NOT TRUE` | `IS NOT FALSE` | `!=` | `!=` |
|
|
743
|
+
/// | `GT` | `throw TypeError` | `>` | `>` | `>` | `>` | `>` |
|
|
744
|
+
/// | `GTE` | `throw TypeError` | `>=` | `>=` | `>=` | `>=` | `>=` |
|
|
745
|
+
/// | `LT` | `throw TypeError` | `<` | `<` | `<` | `<` | `<` |
|
|
746
|
+
/// | `LTE` | `throw TypeError` | `<=` | `<=` | `<=` | `<=` | `<=` |
|
|
747
|
+
/// | `LIKE` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `LIKE` |
|
|
748
|
+
/// | `NOT_LIKE` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `NOT LIKE` |
|
|
749
|
+
///
|
|
750
|
+
/// Arguments:
|
|
751
|
+
/// queryPart: object
|
|
752
|
+
/// The `QueryEngine` "operation frame" for this conditional operation.
|
|
753
|
+
/// operator: string | Literal
|
|
754
|
+
/// The `QueryEngine` operator to convert to SQL syntax. If a literal is provided,
|
|
755
|
+
/// then it will simply be stringified and returned (as the literal operator the user
|
|
756
|
+
/// specified... whatever that might be).
|
|
757
|
+
/// value: any
|
|
758
|
+
/// The right-hand-side value for this conditional operator.
|
|
759
|
+
/// valueIsReference: boolean
|
|
760
|
+
/// If `true`, then this operator is being converted for a table-join operation. If this is
|
|
761
|
+
/// the case, then `value` will be the "operation context" for the right-side of the table-join.
|
|
762
|
+
/// options?: object
|
|
763
|
+
/// Options for the operation. This is only used by this method for converting provided literals to strings.
|
|
764
|
+
///
|
|
765
|
+
/// Return: string
|
|
766
|
+
/// Return SQL syntax for this context-specific conditional operator.
|
|
427
767
|
generateSelectQueryOperatorFromQueryEngineOperator(queryPart, operator, value, valueIsReference, options) {
|
|
428
768
|
if (LiteralBase.isLiteral(operator))
|
|
429
|
-
return operator.toString(this.connection);
|
|
769
|
+
return operator.toString(this.connection, options);
|
|
430
770
|
|
|
431
771
|
switch (operator) {
|
|
432
772
|
case 'EQ':
|
|
@@ -450,12 +790,24 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
450
790
|
else
|
|
451
791
|
return '!=';
|
|
452
792
|
case 'GT':
|
|
793
|
+
if (Array.isArray(value))
|
|
794
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "GT" (greater than) operator.`);
|
|
795
|
+
|
|
453
796
|
return '>';
|
|
454
797
|
case 'GTE':
|
|
798
|
+
if (Array.isArray(value))
|
|
799
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "GTE" (greater than or equal to) operator.`);
|
|
800
|
+
|
|
455
801
|
return '>=';
|
|
456
802
|
case 'LT':
|
|
803
|
+
if (Array.isArray(value))
|
|
804
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "LT" (less than) operator.`);
|
|
805
|
+
|
|
457
806
|
return '<';
|
|
458
807
|
case 'LTE':
|
|
808
|
+
if (Array.isArray(value))
|
|
809
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "LTE" (less than or equal to) operator.`);
|
|
810
|
+
|
|
459
811
|
return '<=';
|
|
460
812
|
case 'LIKE':
|
|
461
813
|
if (valueIsReference)
|
|
@@ -478,15 +830,89 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
478
830
|
}
|
|
479
831
|
}
|
|
480
832
|
|
|
833
|
+
/// Format a `LIKE` or `NOT LIKE` value.
|
|
834
|
+
///
|
|
835
|
+
/// Mythix ORM requires that `%` and `_` characters be used for
|
|
836
|
+
/// wildcard characters in `LIKE` and `NOT_LIKE` operations. This is to
|
|
837
|
+
/// create a unified standard for `LIKE` operations across databases.
|
|
838
|
+
/// If the underlying database uses different wildcard characters for
|
|
839
|
+
/// a `LIKE` operation, then it is required to convert them to its native
|
|
840
|
+
/// format here in this method.
|
|
841
|
+
///
|
|
842
|
+
/// Interface:
|
|
843
|
+
/// interface QueryConditionContext {
|
|
844
|
+
/// queryPart: object; // The "operation frame" or "operation context" for this condition
|
|
845
|
+
/// field: Field; // The field for this conditional operator
|
|
846
|
+
/// sqlOperator: string; // The SQL operator that matches "operator" in the given context
|
|
847
|
+
/// operator: string; // The QueryEngine operator for this condition, i.e. "EQ"
|
|
848
|
+
/// value: any; // The conditional operator's value (right-hand-side value)
|
|
849
|
+
/// }
|
|
850
|
+
///
|
|
851
|
+
/// Arguments:
|
|
852
|
+
/// context: QueryConditionContext
|
|
853
|
+
/// The "conditional operator" context for this `LIKE` or `NOT LIKE` condition.
|
|
854
|
+
///
|
|
855
|
+
/// Return: string
|
|
856
|
+
/// By default simply return `context.value`. Other database drivers may
|
|
857
|
+
/// format `context.value` before returning it, in a format suitable for
|
|
858
|
+
/// the underlying database.
|
|
481
859
|
formatLikeValue({ value }) {
|
|
482
860
|
return value;
|
|
483
861
|
}
|
|
484
862
|
|
|
863
|
+
/// Generate an optional postfix for any given conditional operator.
|
|
864
|
+
///
|
|
865
|
+
/// This might be used by any given underlying database should it need
|
|
866
|
+
/// it. It is most commonly used by `LIKE` conditional operators to tag
|
|
867
|
+
/// on an `ESCAPE` clause, specifying the escape character for the `LIKE`
|
|
868
|
+
/// operator. However, it may be used for any operator where the database
|
|
869
|
+
/// needs a "postfix" for the condition.
|
|
870
|
+
///
|
|
871
|
+
/// Interface:
|
|
872
|
+
/// interface QueryConditionContext {
|
|
873
|
+
/// queryPart: object; // The "operation frame" or "operation context" for this condition
|
|
874
|
+
/// field: Field; // The field for this conditional operator
|
|
875
|
+
/// sqlOperator: string; // The SQL operator that matches "operator" in the given context
|
|
876
|
+
/// operator: string; // The QueryEngine operator for this condition, i.e. "EQ"
|
|
877
|
+
/// value: any; // The conditional operator's value (right-hand-side value)
|
|
878
|
+
/// }
|
|
879
|
+
///
|
|
880
|
+
/// Arguments:
|
|
881
|
+
/// context: QueryConditionContext
|
|
882
|
+
/// The "conditional operator" context for the current operator being generated.
|
|
883
|
+
///
|
|
884
|
+
/// Return: string
|
|
885
|
+
/// By default, simply return an empty string, meaning that there is no postfix
|
|
886
|
+
/// for the condition being generated. Optionally, the database driver can return any postfix
|
|
887
|
+
/// for the conditional operator being generated.
|
|
485
888
|
// eslint-disable-next-line no-unused-vars
|
|
486
889
|
generateConditionPostfix(context) {
|
|
487
890
|
return '';
|
|
488
891
|
}
|
|
489
892
|
|
|
893
|
+
/// Generate a SQL "conditional operator" for a `WHERE` clause.
|
|
894
|
+
///
|
|
895
|
+
/// Even though this is generally used for `SELECT` statements, it
|
|
896
|
+
/// may also be used for `UPDATE WHERE ...`, or `DELETE WHERE ...`
|
|
897
|
+
/// statements as well.
|
|
898
|
+
///
|
|
899
|
+
/// This method should return a fully formatted "conditional" statement
|
|
900
|
+
/// for the query's `WHERE` clause.
|
|
901
|
+
///
|
|
902
|
+
/// Arguments:
|
|
903
|
+
/// queryPart: object
|
|
904
|
+
/// The "operation frame" or "operation context" of the conditional
|
|
905
|
+
/// operation as found on the `QueryEngine` being used to generate the
|
|
906
|
+
/// query.
|
|
907
|
+
/// value: any
|
|
908
|
+
/// The value (right-hand-side) of the conditional operator being generated.
|
|
909
|
+
/// options?: object
|
|
910
|
+
/// Options for the current database operation.
|
|
911
|
+
///
|
|
912
|
+
/// Return: string
|
|
913
|
+
/// A fully formatted SQL conditional statement. This may be an `EXISTS`,
|
|
914
|
+
/// an `ANY` or `ALL`, an `IN`, or some other valid condition for the query.
|
|
915
|
+
/// i.e. `"users"."id" = 1`.
|
|
490
916
|
generateSelectQueryCondition(queryPart, _value, options) {
|
|
491
917
|
let value = _value;
|
|
492
918
|
let field = queryPart.Field;
|
|
@@ -565,7 +991,24 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
565
991
|
return `${escapedColumnName} ${sqlOperator} ${this.escape(field, value)}${(conditionPostfix) ? ` ${conditionPostfix}` : ''}`;
|
|
566
992
|
}
|
|
567
993
|
|
|
568
|
-
|
|
994
|
+
/// Generate a table join statement, such as
|
|
995
|
+
/// `INNER JOIN "table_name"`, or a `FROM` statement
|
|
996
|
+
/// if `joinType` is falsy, such as `FROM "table_name"`.
|
|
997
|
+
///
|
|
998
|
+
/// Arguments:
|
|
999
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1000
|
+
/// The model that defines the table for the operation.
|
|
1001
|
+
/// joinType: string | null
|
|
1002
|
+
/// If a falsy value, then generate a `FROM "table_name"` statement, using
|
|
1003
|
+
/// the provided `Model` to know the table name. If a string, then this will
|
|
1004
|
+
/// be a join-type, such as `INNER JOIN`, which will be used instead of `FROM`,
|
|
1005
|
+
/// i.e. `INNER JOIN "table_name"`.
|
|
1006
|
+
/// options?: object
|
|
1007
|
+
/// Options to provide to <see>SQLQueryGeneratorBase.getEscapedTableName</see> for the operation.
|
|
1008
|
+
///
|
|
1009
|
+
/// Return: string
|
|
1010
|
+
/// A `FROM "table_name"` statement, or a table join statement, such as
|
|
1011
|
+
/// `INNER JOIN "table_name"`.
|
|
569
1012
|
generateFromTableOrTableJoin(Model, _joinType, options) {
|
|
570
1013
|
if (!Model)
|
|
571
1014
|
throw new Error(`${this.constructor.name}::generateFromTableOrTableJoin: No valid model provided.`);
|
|
@@ -578,14 +1021,63 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
578
1021
|
return (joinType) ? `${joinType} ${escapedTableName}` : `FROM ${escapedTableName}`;
|
|
579
1022
|
}
|
|
580
1023
|
|
|
1024
|
+
/// Given a table-join query operation, such as `User.where.id.EQ(Role.where.userID)`,
|
|
1025
|
+
/// generate the table-join statement.
|
|
1026
|
+
///
|
|
1027
|
+
/// Continuing with the example provided, this would generate the following SQL,
|
|
1028
|
+
/// `"users"."id" = "roles"."userID"`.
|
|
1029
|
+
///
|
|
1030
|
+
/// Arguments:
|
|
1031
|
+
/// leftQueryPart: object
|
|
1032
|
+
/// The "operation frame" or "operation context" for the left-side of the statement.
|
|
1033
|
+
/// In this example this would be the `EQ` "operation context" of `User.where.id.EQ`.
|
|
1034
|
+
/// rightQueryPart: object
|
|
1035
|
+
/// The "operation frame" or "operation context" for the right-side of the statement.
|
|
1036
|
+
/// In this example this would be the `userID` "operation context" of `Role.where.userID`.
|
|
1037
|
+
/// leftField: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
1038
|
+
/// The left-hand side field for the condition. In this example this would be `User.fields.id`.
|
|
1039
|
+
/// rightField: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
1040
|
+
/// The right-hand side field for the condition. In this example this would be `Role.fields.userID`.
|
|
1041
|
+
/// operator: string
|
|
1042
|
+
/// The [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) operator to join the
|
|
1043
|
+
/// table columns on... i.e. `EQ`. This will be passed through <see>SQLQueryGeneratorBase.generateSelectQueryOperatorFromQueryEngineOperator</see>
|
|
1044
|
+
/// to get the related SQL operator for the condition.
|
|
1045
|
+
/// options?: object
|
|
1046
|
+
/// Options for the operation.
|
|
1047
|
+
///
|
|
1048
|
+
/// Return: string
|
|
1049
|
+
/// Return the table-join condition, i.e. `"users"."id" = "roles"."userID"`.
|
|
581
1050
|
generateSelectJoinOnTableQueryCondition(leftQueryPart, rightQueryPart, leftField, rightField, operator, options) {
|
|
582
1051
|
let leftSideEscapedColumnName = this.getEscapedColumnName(leftField.Model, leftField, options);
|
|
583
1052
|
let rightSideEscapedColumnName = this.getEscapedColumnName(rightField.Model, rightField, options);
|
|
584
|
-
let sqlOperator = this.generateSelectQueryOperatorFromQueryEngineOperator(leftQueryPart, operator,
|
|
1053
|
+
let sqlOperator = this.generateSelectQueryOperatorFromQueryEngineOperator(leftQueryPart, operator, rightQueryPart, true, options);
|
|
585
1054
|
|
|
586
1055
|
return `${leftSideEscapedColumnName} ${sqlOperator} ${rightSideEscapedColumnName}`;
|
|
587
1056
|
}
|
|
588
1057
|
|
|
1058
|
+
/// Take the join table information from a call to
|
|
1059
|
+
/// <see>SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts</see>
|
|
1060
|
+
/// and generate all table-join conditions for the two
|
|
1061
|
+
/// tables being joined.
|
|
1062
|
+
///
|
|
1063
|
+
/// The will generate one or more conditions for the table-join,
|
|
1064
|
+
/// using `AND` or `OR` to combine the conditions.
|
|
1065
|
+
/// For example, this might generate the following SQL code:
|
|
1066
|
+
/// `INNER JOIN "roles" ON "users"."id" = "roles"."userID" OR "users"."fullName" = "roles"."userFullName"`.
|
|
1067
|
+
///
|
|
1068
|
+
/// Arguments:
|
|
1069
|
+
/// joinInfos: Array<TableJoinInformation>
|
|
1070
|
+
/// All collected table-join information for joining tables. The join table
|
|
1071
|
+
/// information at index zero `joinInfos[0]` is the table being joined against,
|
|
1072
|
+
/// which is commonly the "root model" of the query... but it doesn't have to be.
|
|
1073
|
+
/// options?: object
|
|
1074
|
+
/// Options for the operation.
|
|
1075
|
+
///
|
|
1076
|
+
/// Return: string
|
|
1077
|
+
/// The full list of conditions for joining the tables together, i.e.
|
|
1078
|
+
/// `INNER JOIN "roles" ON "users"."id" = "roles"."userID" OR "users"."fullName" = "roles"."userFullName"`.
|
|
1079
|
+
///
|
|
1080
|
+
/// See: SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts
|
|
589
1081
|
generateJoinOnTableQueryConditions(joinInfos, options) {
|
|
590
1082
|
if (Nife.isEmpty(joinInfos))
|
|
591
1083
|
return '';
|
|
@@ -608,7 +1100,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
608
1100
|
return sqlParts.join(' ');
|
|
609
1101
|
}
|
|
610
1102
|
|
|
611
|
-
|
|
1103
|
+
/// Take a join type from a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1104
|
+
/// instance, and convert it to the proper join type for the underlying database.
|
|
1105
|
+
///
|
|
1106
|
+
/// Arguments:
|
|
1107
|
+
/// joinType: string
|
|
1108
|
+
/// The join type, as specified by the [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine). This
|
|
1109
|
+
/// will generally be one of `'inner'`, `'left'`, `'right'`, `'full'`, or `'cross'`, but
|
|
1110
|
+
/// it might also be a user-defined table join type (in which case is is expected to already
|
|
1111
|
+
/// be in the correct format for the underlying database).
|
|
1112
|
+
/// outer: boolean
|
|
1113
|
+
/// If `true`, then this is an "outer join", instead of an "inner join". i.e. a `'left'` join
|
|
1114
|
+
/// type would be converted to a `LEFT OUTER JOIN` instead of a `LEFT INNER JOIN`.
|
|
1115
|
+
/// options?: object
|
|
1116
|
+
/// Options for the operation.
|
|
1117
|
+
///
|
|
1118
|
+
/// Return: string
|
|
1119
|
+
/// The SQL join type, used to join tables. i.e. `LEFT JOIN`.
|
|
612
1120
|
// eslint-disable-next-line no-unused-vars
|
|
613
1121
|
generateSQLJoinTypeFromQueryEngineJoinType(joinType, outer, options) {
|
|
614
1122
|
if (!joinType || joinType === 'inner')
|
|
@@ -625,6 +1133,32 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
625
1133
|
return joinType;
|
|
626
1134
|
}
|
|
627
1135
|
|
|
1136
|
+
/// Sort the table joins into a predictable order.
|
|
1137
|
+
///
|
|
1138
|
+
/// Since table-join operations can exist anywhere in a query,
|
|
1139
|
+
/// this will take all table-join operations for the query, and
|
|
1140
|
+
/// sort them so that they are in a predictable order.
|
|
1141
|
+
/// By default the order will be in "dependency order", so if for
|
|
1142
|
+
/// example there is a join against the `Role` table, and the `Role`
|
|
1143
|
+
/// table "depends on" the `User` table, then the `Role` table will
|
|
1144
|
+
/// come first in the list of table joins.
|
|
1145
|
+
///
|
|
1146
|
+
/// Why sort the table joins at all? Mythix ORM always does its best to
|
|
1147
|
+
/// keep all queries consistent, if for no other reason than for caching
|
|
1148
|
+
/// purposes (so the query itself can be used as a cache key).
|
|
1149
|
+
///
|
|
1150
|
+
/// Arguments:
|
|
1151
|
+
/// joins: Map<string, Array<TableJoinInformation>>
|
|
1152
|
+
/// A map of all table-joins taking place. Each key in this map is the name
|
|
1153
|
+
/// of a model being joined. Each value is an array of `TableJoinInformation`
|
|
1154
|
+
/// that defines how two tables will be joined to each other. This array is
|
|
1155
|
+
/// what is sorted with this operation.
|
|
1156
|
+
///
|
|
1157
|
+
/// Return: Array<string>
|
|
1158
|
+
/// An array of model names, sorted in order, used as "ordered keys"
|
|
1159
|
+
/// into the provided `Map` to generate the table-joins for the query.
|
|
1160
|
+
///
|
|
1161
|
+
/// See: SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts
|
|
628
1162
|
sortJoinRelationOrder(joins) {
|
|
629
1163
|
let modelNames = Array.from(joins.keys());
|
|
630
1164
|
|
|
@@ -646,6 +1180,22 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
646
1180
|
});
|
|
647
1181
|
}
|
|
648
1182
|
|
|
1183
|
+
/// Generate the SQL syntax needed to join all tables in the operation.
|
|
1184
|
+
///
|
|
1185
|
+
/// For example, this might generate the following SQL
|
|
1186
|
+
/// `INNER JOIN "roles" ON "users"."id" = "roles"."userID" RIGHT JOIN "organizations" ON "organization"."id" = "roles"."organizationID"`.
|
|
1187
|
+
///
|
|
1188
|
+
/// Arguments:
|
|
1189
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1190
|
+
/// The query engine to pull table-join operations from.
|
|
1191
|
+
/// options?: object
|
|
1192
|
+
/// Options for the operation.
|
|
1193
|
+
///
|
|
1194
|
+
/// Return: string
|
|
1195
|
+
/// A complete join of all tables in the operation that are being joined, including
|
|
1196
|
+
/// the conditions used to join each table.
|
|
1197
|
+
///
|
|
1198
|
+
/// See: SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts
|
|
649
1199
|
generateSelectQueryJoinTables(queryEngine, options) {
|
|
650
1200
|
const addToJoins = (joinInfo) => {
|
|
651
1201
|
let items = joins.get(joinInfo.joinModelName);
|
|
@@ -696,6 +1246,33 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
696
1246
|
return sqlParts.join(' ');
|
|
697
1247
|
}
|
|
698
1248
|
|
|
1249
|
+
/// Generate all `WHERE` conditions using the provided
|
|
1250
|
+
/// [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine).
|
|
1251
|
+
///
|
|
1252
|
+
/// This will take all conditional operations defined by the query engine,
|
|
1253
|
+
/// and generate a full `WHERE` condition, `AND`ing or `OR`ing all conditions
|
|
1254
|
+
/// together, including grouping and sub-grouping conditions where needed.
|
|
1255
|
+
///
|
|
1256
|
+
/// Note:
|
|
1257
|
+
/// This method can be recursively called if a sub-query is encountered that
|
|
1258
|
+
/// also has `WHERE` conditions.
|
|
1259
|
+
///
|
|
1260
|
+
/// Note:
|
|
1261
|
+
/// Even though this method's name implies generating `WHERE` conditions for a `SELECT`
|
|
1262
|
+
/// statement, it is also used for non-SELECT statements, such as `UPDATE WHERE ...`,
|
|
1263
|
+
/// and `DELETE WHERE ...`.
|
|
1264
|
+
///
|
|
1265
|
+
/// Arguments:
|
|
1266
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1267
|
+
/// The query engine to pull conditions from.
|
|
1268
|
+
/// options?: object
|
|
1269
|
+
/// Options for the operation.
|
|
1270
|
+
///
|
|
1271
|
+
/// Return: string
|
|
1272
|
+
/// All SQL conditional operators for a `WHERE` statement, not including the
|
|
1273
|
+
/// `WHERE` prefix. i.e. `"users"."id" = 1 OR "users"."firstName" = 'Bob'`. An
|
|
1274
|
+
/// empty string will be returned if there are no conditional operators used in
|
|
1275
|
+
/// the provided query engine.
|
|
699
1276
|
generateSelectWhereConditions(queryEngine, options) {
|
|
700
1277
|
const logicalCondition = (sqlParts, queryPart) => {
|
|
701
1278
|
if (sqlParts.length === 0)
|
|
@@ -770,6 +1347,27 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
770
1347
|
return sqlParts.join(' ');
|
|
771
1348
|
}
|
|
772
1349
|
|
|
1350
|
+
/// Generate an `ORDER BY` clause, listing all columns
|
|
1351
|
+
/// and their sort-direction.
|
|
1352
|
+
///
|
|
1353
|
+
/// Arguments:
|
|
1354
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1355
|
+
/// The query engine to pull the "order by" fields from.
|
|
1356
|
+
/// options?: object
|
|
1357
|
+
/// Options for the operation. Though these might be database specific, there are some
|
|
1358
|
+
/// common options that can be supplied to this method:
|
|
1359
|
+
/// | Option | Type | Default Value | Description |
|
|
1360
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1361
|
+
/// | `onlyProjectedFields` | `boolean` | `true` | If `true`, then only list fields that are also in the projection. |
|
|
1362
|
+
/// | `projectionFields` | `Map<string, object>` | Result of `getProjectedFields` | The fields that have been projected, to be used in combination with the `onlyProjectedFields` option. |
|
|
1363
|
+
/// | `rawOrder` | `boolean` | `false` | If `true`, then return the order fields (and literals) as a raw Array instead of a comma-separated list of fields. |
|
|
1364
|
+
/// | `reverseOrder` | `boolean` | `false` | If `true`, then reverse the sort order of all fields. |
|
|
1365
|
+
///
|
|
1366
|
+
/// Return: string | Array<string>
|
|
1367
|
+
/// If the `rawOrder` `options` is `false`, then return a fully completed `ORDER BY` clause,
|
|
1368
|
+
/// listing all the fields and their sort order. If no order has been specified by the query engine
|
|
1369
|
+
/// (or the connection), then return an empty string instead. If the `rawOrder` `options` is `true`,
|
|
1370
|
+
/// then return an array of the ordered fields instead.
|
|
773
1371
|
generateOrderClause(queryEngine, _options) {
|
|
774
1372
|
if (!queryEngine || typeof queryEngine.getOperationContext !== 'function')
|
|
775
1373
|
return (_options && _options.rawOrder) ? [] : '';
|
|
@@ -829,6 +1427,24 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
829
1427
|
return (options.rawOrder) ? orderByParts : `ORDER BY ${orderByParts.join(',')}`;
|
|
830
1428
|
}
|
|
831
1429
|
|
|
1430
|
+
/// Generate a `GROUP BY` clause, listing all columns
|
|
1431
|
+
/// to group by.
|
|
1432
|
+
///
|
|
1433
|
+
/// Arguments:
|
|
1434
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1435
|
+
/// The query engine to pull the "group by" fields from.
|
|
1436
|
+
/// options?: object
|
|
1437
|
+
/// Options for the operation. Though these might be database specific, there are some
|
|
1438
|
+
/// common options that can be supplied to this method:
|
|
1439
|
+
/// | Option | Type | Default Value | Description |
|
|
1440
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1441
|
+
/// | `rawGroupBy` | `boolean` | `false` | If `true`, then return the group by fields (and literals) as a raw Array instead of a comma-separated list of fields. |
|
|
1442
|
+
///
|
|
1443
|
+
/// Return: string | Array<string>
|
|
1444
|
+
/// If the `rawGroupBy` `options` is `false`, then return a fully completed `GROUP BY` clause,
|
|
1445
|
+
/// listing all the columns and literals to group by. If no "group by" has been specified by the query engine
|
|
1446
|
+
/// then return an empty string instead. If the `rawGroupBy` `options` is `true`,
|
|
1447
|
+
/// then return an array of the "group by" fields instead.
|
|
832
1448
|
generateGroupByClause(queryEngine, _options) {
|
|
833
1449
|
if (!queryEngine || typeof queryEngine.getOperationContext !== 'function')
|
|
834
1450
|
return (_options && _options.rawGroupBy) ? [] : '';
|
|
@@ -862,11 +1478,54 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
862
1478
|
return (options.rawGroupBy) ? groupByParts : `GROUP BY ${groupByParts.join(',')}`;
|
|
863
1479
|
}
|
|
864
1480
|
|
|
1481
|
+
/// Generate a `HAVING` clause to be used in combination with a
|
|
1482
|
+
/// `GROUP BY` clause.
|
|
1483
|
+
///
|
|
1484
|
+
/// This simple calls <see>SQLQueryGeneratorBase.generateSelectWhereConditions</see>
|
|
1485
|
+
/// on the provided `queryEngine`, and if there is a result, wraps the conditions generated
|
|
1486
|
+
/// inside a `HAVING (...)` clause. If no conditions are generated, then an empty string will
|
|
1487
|
+
/// be returned instead.
|
|
1488
|
+
///
|
|
1489
|
+
/// Arguments:
|
|
1490
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1491
|
+
/// The query engine to pull the "group by" conditions from.
|
|
1492
|
+
/// options?: object
|
|
1493
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1494
|
+
/// <see>SQLQueryGeneratorBase.generateSelectWhereConditions</see> call.
|
|
1495
|
+
///
|
|
1496
|
+
/// Return: string
|
|
1497
|
+
/// A `HAVING (...)` clause if conditions were found on the provided `queryEngine`, or
|
|
1498
|
+
/// an empty string if no conditions were found.
|
|
1499
|
+
///
|
|
1500
|
+
/// See: SQLQueryGeneratorBase.generateSelectWhereConditions
|
|
865
1501
|
generateHavingClause(queryEngine, options) {
|
|
866
1502
|
let where = this.generateSelectWhereConditions(queryEngine, options);
|
|
867
1503
|
return (where) ? `HAVING (${where})` : '';
|
|
868
1504
|
}
|
|
869
1505
|
|
|
1506
|
+
/// Generate both a `GROUP BY` and `HAVING` clause
|
|
1507
|
+
/// together. If no `GROUP_BY` operation is set on the
|
|
1508
|
+
/// provided `queryEngine`, then nothing will be generated,
|
|
1509
|
+
/// and an empty string will be returned instead. The `HAVING`
|
|
1510
|
+
/// clause will be automatically skipped if there is no
|
|
1511
|
+
/// `GROUP_BY` operation to work off of.
|
|
1512
|
+
///
|
|
1513
|
+
/// Arguments:
|
|
1514
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1515
|
+
/// The query engine to pull the "group by" clause, and "having" conditions from.
|
|
1516
|
+
/// options?: object
|
|
1517
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1518
|
+
/// <see>SQLQueryGeneratorBase.generateGroupByClause</see> and <see>SQLQueryGeneratorBase.generateHavingClause</see>
|
|
1519
|
+
/// internal calls this method makes.
|
|
1520
|
+
///
|
|
1521
|
+
/// Return: string
|
|
1522
|
+
/// A full `GROUP BY` clause, including any `HAVING` clause specified. An empty string
|
|
1523
|
+
/// will be returned if there is no `GROUP_BY` operation specified on the `queryEngine`
|
|
1524
|
+
/// provided.
|
|
1525
|
+
///
|
|
1526
|
+
/// See: SQLQueryGeneratorBase.generateGroupByClause
|
|
1527
|
+
///
|
|
1528
|
+
/// See: SQLQueryGeneratorBase.generateHavingClause
|
|
870
1529
|
generateGroupByAndHavingClause(queryEngine, options) {
|
|
871
1530
|
if (!queryEngine)
|
|
872
1531
|
return '';
|
|
@@ -888,22 +1547,61 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
888
1547
|
return sqlParts.join(' ');
|
|
889
1548
|
}
|
|
890
1549
|
|
|
891
|
-
|
|
1550
|
+
/// Generate a `LIMIT` clause.
|
|
1551
|
+
///
|
|
1552
|
+
/// Arguments:
|
|
1553
|
+
/// limit: number | Literal
|
|
1554
|
+
/// If `limit` is a literal, simply stringify and return it. Otherwise, if `limit`
|
|
1555
|
+
/// is a `number`, generate a `LIMIT` clause and return it, using the `limit` provided.
|
|
1556
|
+
/// options?: object
|
|
1557
|
+
/// Options for the operation. These are passed to `toString` for stringifying literals.
|
|
1558
|
+
///
|
|
1559
|
+
/// Return: string
|
|
1560
|
+
/// A `LIMIT` clause to apply to the query.
|
|
892
1561
|
generateLimitClause(limit, options) {
|
|
893
1562
|
if (LiteralBase.isLiteral(limit))
|
|
894
|
-
return limit.toString(this.connection);
|
|
1563
|
+
return limit.toString(this.connection, options);
|
|
895
1564
|
|
|
896
1565
|
return `LIMIT ${limit}`;
|
|
897
1566
|
}
|
|
898
1567
|
|
|
899
|
-
|
|
1568
|
+
/// Generate an `OFFSET` clause.
|
|
1569
|
+
///
|
|
1570
|
+
/// Arguments:
|
|
1571
|
+
/// offset: number | Literal
|
|
1572
|
+
/// If `offset` is a literal, simply stringify and return it. Otherwise, if `offset`
|
|
1573
|
+
/// is a `number`, generate an `OFFSET` clause and return it, using the `offset` provided.
|
|
1574
|
+
/// options?: object
|
|
1575
|
+
/// Options for the operation. These are passed to `toString` for stringifying literals.
|
|
1576
|
+
///
|
|
1577
|
+
/// Return: string
|
|
1578
|
+
/// An `OFFSET` clause to apply to the query.
|
|
900
1579
|
generateOffsetClause(offset, options) {
|
|
901
1580
|
if (LiteralBase.isLiteral(offset))
|
|
902
|
-
return offset.toString(this.connection);
|
|
1581
|
+
return offset.toString(this.connection, options);
|
|
903
1582
|
|
|
904
1583
|
return `OFFSET ${offset}`;
|
|
905
1584
|
}
|
|
906
1585
|
|
|
1586
|
+
/// Generate the `ORDER`, `LIMIT`, and `OFFSET` clauses
|
|
1587
|
+
/// to apply to the query. If any one of these clauses is
|
|
1588
|
+
/// blank, then it will be skipped. If there is no order,
|
|
1589
|
+
/// limit, or offset applied to the query, then an empty
|
|
1590
|
+
/// string will be returned.
|
|
1591
|
+
///
|
|
1592
|
+
/// Arguments:
|
|
1593
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1594
|
+
/// The query engine to pull the "order by", "limit", and "offset" clauses from.
|
|
1595
|
+
/// options?: object
|
|
1596
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1597
|
+
/// the respective calls that generate the sub-parts of this operation.
|
|
1598
|
+
///
|
|
1599
|
+
/// Return: string
|
|
1600
|
+
/// A combo `ORDER BY ... LIMIT ... OFFSET ...` clause to apply to the query.
|
|
1601
|
+
/// If any one of these sub-parts is empty or invalid, they will be skipped.
|
|
1602
|
+
/// i.e. if there is no `LIMIT` applied to the query, then the `LIMIT` and `OFFSET`
|
|
1603
|
+
/// will be skipped. If there is no output because all sub-parts (clauses) were skipped,
|
|
1604
|
+
/// then an empty string will be returned instead.
|
|
907
1605
|
generateSelectOrderLimitOffset(queryEngine, _options) {
|
|
908
1606
|
if (!queryEngine)
|
|
909
1607
|
return '';
|
|
@@ -952,6 +1650,29 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
952
1650
|
return sqlParts.join(' ');
|
|
953
1651
|
}
|
|
954
1652
|
|
|
1653
|
+
/// Generate the `WHERE`, `ORDER`, `LIMIT`, and `OFFSET` clauses
|
|
1654
|
+
/// to apply to the query. If any one of these clauses is
|
|
1655
|
+
/// blank, then it will be skipped. If there is no output because
|
|
1656
|
+
/// all clauses were skipped, then an empty string will be returned instead.
|
|
1657
|
+
///
|
|
1658
|
+
/// Arguments:
|
|
1659
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1660
|
+
/// The query engine to pull the conditions, "order by", "limit", and "offset" clauses from.
|
|
1661
|
+
/// options?: object
|
|
1662
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1663
|
+
/// the respective calls that generate the sub-parts of this operation. One
|
|
1664
|
+
/// common option that can be used here for all connections is the `separateWhereAndOrder`
|
|
1665
|
+
/// option. If `true`, then an object with the following shape will be returned:
|
|
1666
|
+
/// `{ where: string; orderLimitOffset: string; }`, splitting the clauses apart and
|
|
1667
|
+
/// returning them separately.
|
|
1668
|
+
///
|
|
1669
|
+
/// Return: string
|
|
1670
|
+
/// A combo `WHERE ... ORDER BY ... LIMIT ... OFFSET ...` clause to apply to the query.
|
|
1671
|
+
/// If any one of these sub-parts is empty or invalid, they will be skipped.
|
|
1672
|
+
/// i.e. if there is no `LIMIT` applied to the query, then the `LIMIT` and `OFFSET`
|
|
1673
|
+
/// will be skipped. If there are no conditions for the query, then the `WHERE` clause
|
|
1674
|
+
/// will be skipped. If there is no output because all sub-parts (clauses) were skipped,
|
|
1675
|
+
/// then an empty string will be returned instead.
|
|
955
1676
|
generateWhereAndOrderLimitOffset(queryEngine, _options) {
|
|
956
1677
|
let options = _options || {};
|
|
957
1678
|
let sqlParts = [];
|
|
@@ -970,6 +1691,34 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
970
1691
|
return sqlParts.join(' ');
|
|
971
1692
|
}
|
|
972
1693
|
|
|
1694
|
+
/// Generate a full `SELECT` statement using the provided
|
|
1695
|
+
/// `queryEngine`.
|
|
1696
|
+
///
|
|
1697
|
+
/// This will generate a `SELECT` statement for the underlying
|
|
1698
|
+
/// database that will include the field projection, table joins,
|
|
1699
|
+
/// any `GROUP BY` clause that is applied, all the `WHERE` conditions,
|
|
1700
|
+
/// any sub-queries involved, and an `ORDER BY`, `LIMIT`, and `OFFSET`
|
|
1701
|
+
/// if those are in-use in the query. This method will be recursively
|
|
1702
|
+
/// called for any sub-queries encountered.
|
|
1703
|
+
///
|
|
1704
|
+
/// Arguments:
|
|
1705
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1706
|
+
/// The query engine to use to generate the `SELECT` statement.
|
|
1707
|
+
/// options?: object
|
|
1708
|
+
/// Options for the operation. These options are passed through all generation calls
|
|
1709
|
+
/// invoked inside this method, and so impact all methods used to generate the statement,
|
|
1710
|
+
/// including methods used for column escaping, literal conversion, etc...
|
|
1711
|
+
/// Though these options are often connection-specific,
|
|
1712
|
+
/// the following options are available across all connections:
|
|
1713
|
+
/// | Option | Type | Default Value | Description |
|
|
1714
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1715
|
+
/// | `includeRelations` | `boolean` | `false` | If `true`, then a `.PROJECT('*')` will be applied for you, including all tables used in the operation in the output. |
|
|
1716
|
+
/// | `isSubQuery` | `boolean` | `false` | Though often not used directly by the user, if this option is `true`, then it will alter how the `SELECT` statement is generated... for example, the `ORDER BY` clause might be skipped entirely, or the field projection might be altered. |
|
|
1717
|
+
/// | `returnFieldProjection` | `boolean` | `false` | If `true`, then return an object with the shape `{ sql, projectionFields }`, where `sql` is the `SELECT` statement, and `projectionFields` are the fields that were projected. |
|
|
1718
|
+
///
|
|
1719
|
+
/// Return: string
|
|
1720
|
+
/// A fully generated `SELECT` statement that can be used directly in the underlying database
|
|
1721
|
+
/// to query data.
|
|
973
1722
|
generateSelectStatement(_queryEngine, _options) {
|
|
974
1723
|
let queryEngine = _queryEngine;
|
|
975
1724
|
if (!QueryEngine.isQuery(queryEngine))
|
|
@@ -988,8 +1737,8 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
988
1737
|
|
|
989
1738
|
options.selectStatement = true;
|
|
990
1739
|
|
|
991
|
-
projectionFields = this.
|
|
992
|
-
sqlParts.push(this.generateSelectQueryFieldProjection(queryEngine, options));
|
|
1740
|
+
projectionFields = this.getProjectedFields(queryEngine, options, true);
|
|
1741
|
+
sqlParts.push(this.generateSelectQueryFieldProjection(queryEngine, options, projectionFields));
|
|
993
1742
|
|
|
994
1743
|
sqlParts.push(this.generateFromTableOrTableJoin(rootModel, undefined, options));
|
|
995
1744
|
sqlParts.push(this.generateSelectQueryJoinTables(queryEngine, options));
|
|
@@ -1010,6 +1759,51 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1010
1759
|
return sql;
|
|
1011
1760
|
}
|
|
1012
1761
|
|
|
1762
|
+
/// Get the default value for a field.
|
|
1763
|
+
///
|
|
1764
|
+
/// This method is used for `CREATE TABLE`, `ALTER TABLE`, `UPDATE`, and `INSERT`
|
|
1765
|
+
/// statements. It uses the `defaultValue` of the `field` provided
|
|
1766
|
+
/// to fetch any `DEFAULT` that might be applicable to the field
|
|
1767
|
+
/// at the database level for a `CREATE TABLE` or `ALTER TABLE` statement. It might
|
|
1768
|
+
/// also be used for things like `created_at` and `updated_at` fields during `UPDATE`
|
|
1769
|
+
/// or `INSERT` statements.
|
|
1770
|
+
///
|
|
1771
|
+
/// Most default values for fields are applied client-side by Mythix ORM
|
|
1772
|
+
/// immediately before an `INSERT` or `UPDATE` statement is executed.
|
|
1773
|
+
/// However, some of them are set directly at the database level for field
|
|
1774
|
+
/// defaults, such as `AUTOINCREMENT`, and some date and times types (i.e. `NOW`).
|
|
1775
|
+
/// This method will return a string representing the default value that
|
|
1776
|
+
/// should be applied to a column (i.e. `DEFAULT NOW()`), or it will return
|
|
1777
|
+
/// a literal defining the default value that might change the entire statement.
|
|
1778
|
+
/// For example, `AUTOINCREMENT` in PostgreSQL is actually handled by converting
|
|
1779
|
+
/// the data type of the field to a `SERIAL` type.
|
|
1780
|
+
///
|
|
1781
|
+
/// This method is also used to fetch the default value for columns during an
|
|
1782
|
+
/// `UPDATE` or `INSERT` statement. For example, for `created_at` and `updated_at`
|
|
1783
|
+
/// fields, the default might be set during `INSERT` or always set on `UPDATE` operations.
|
|
1784
|
+
///
|
|
1785
|
+
/// Arguments:
|
|
1786
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
1787
|
+
/// The field to fetch the `defaultValue` from, if any.
|
|
1788
|
+
/// fieldName: string
|
|
1789
|
+
/// The name of the field the default value is being fetched for. This should always be
|
|
1790
|
+
/// the same as `field.fieldName`.
|
|
1791
|
+
/// options?: object
|
|
1792
|
+
/// Options for the operation.
|
|
1793
|
+
/// | Option | Type | Default Value | Description |
|
|
1794
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1795
|
+
/// | `escape` | `boolean` | `true` | If `true`, then Mythix ORM will escape the default value found (i.e. with single quotes) so it is treated as a "value" in the underlying database. |
|
|
1796
|
+
/// | `isInsertOperation` | `boolean` | `false` | If `true`, then Mythix ORM is reporting that this is for an `INSERT` operation. |
|
|
1797
|
+
/// | `isUpdateOperation` | `boolean` | `false` | If `true`, then Mythix ORM is reporting that this is for an `UPDATE` operation. |
|
|
1798
|
+
/// | `rawLiterals` | `boolean` | `false` | If `true`, then Mythix ORM will return the literal raw without stringifying it--if the default value is a literal. |
|
|
1799
|
+
/// | `remoteOnly` | `boolean` | `false` | If `true`, then Mythix ORM will only return a default for the field if it is flagged as a "remote" or "literal" default value (i.e. an `AUTOINCREMENT` default would be flagged "remote"). |
|
|
1800
|
+
/// | `useDefaultKeyword` | `boolean` | `true` | If `true`, then Mythix ORM will prefix any default value found with a `DEFAULT` statement (for use in `CREATE TABLE` statements). |
|
|
1801
|
+
///
|
|
1802
|
+
/// Return: undefined | string | Literal
|
|
1803
|
+
/// Return a string representing the escaped default value, a Literal if the `rawLiterals` option is `true`,
|
|
1804
|
+
/// or `undefined` if the field has no default value. A default value will not always be returned from this
|
|
1805
|
+
/// method simply because the provided `field` has a `defaultValue` property. Only default values applicable
|
|
1806
|
+
/// at the database level, or applicable to the operation being carried out will be returned.
|
|
1013
1807
|
getFieldDefaultValue(field, fieldName, _options) {
|
|
1014
1808
|
let options = _options || {};
|
|
1015
1809
|
let defaultValue = field.defaultValue;
|
|
@@ -1060,6 +1854,38 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1060
1854
|
return `${defaultValue}`;
|
|
1061
1855
|
}
|
|
1062
1856
|
|
|
1857
|
+
/// Generate an index name for creating an index on
|
|
1858
|
+
/// one or more columns.
|
|
1859
|
+
///
|
|
1860
|
+
/// This will take one or more field names from the `Model`
|
|
1861
|
+
/// provided and generate an index name for creating an index
|
|
1862
|
+
/// in the underlying database. This method can generate an index
|
|
1863
|
+
/// name for indexing a single column (if a single field name is provided),
|
|
1864
|
+
/// or it can generate an index name for indexing multiple columns
|
|
1865
|
+
/// as a "combo index".
|
|
1866
|
+
///
|
|
1867
|
+
/// Arguments:
|
|
1868
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1869
|
+
/// The model to use for the table to index on. This model should also be
|
|
1870
|
+
/// the model that owns all fields to be indexed. It isn't possible to index
|
|
1871
|
+
/// columns across different tables, so the fields provided must all be from
|
|
1872
|
+
/// this same `Model`.
|
|
1873
|
+
/// indexFieldNames: Array<string>
|
|
1874
|
+
/// The field names that will be used to create the single or combo index. A
|
|
1875
|
+
/// single field name will generate an index name for a single column, whereas
|
|
1876
|
+
/// more than one field name will generate an index name for a combo-index that
|
|
1877
|
+
/// indexes all columns requested. These can be fully qualified field names, but
|
|
1878
|
+
/// they don't have to be, since the owning `Model` is already known. If fully qualified
|
|
1879
|
+
/// field names are used, then the model name for each field must match the `Model`
|
|
1880
|
+
/// provided (making it pointless to use fully qualified field names).
|
|
1881
|
+
/// options?: object
|
|
1882
|
+
/// Options for the operation. These are not used by this method, and instead are
|
|
1883
|
+
/// just provided for the user--should they overload this method and need the options.
|
|
1884
|
+
///
|
|
1885
|
+
/// Return: string
|
|
1886
|
+
/// Return an index name, in the format `'idx_tableName_column1_column2_column3_...'`. If
|
|
1887
|
+
/// the `indexFieldNames` provided is empty--or result in an empty set of field names after
|
|
1888
|
+
/// filtering out invalid field names--then an empty string will be returned instead.
|
|
1063
1889
|
// eslint-disable-next-line no-unused-vars
|
|
1064
1890
|
generateIndexName(Model, _indexFieldNames, options) {
|
|
1065
1891
|
let indexFieldNames = Nife.toArray(_indexFieldNames).filter((index) => {
|
|
@@ -1081,6 +1907,40 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1081
1907
|
return this.escapeID(`idx_${tableName}_${columnNames.sort().join('_')}`);
|
|
1082
1908
|
}
|
|
1083
1909
|
|
|
1910
|
+
/// Generate a `CREATE INDEX` statement.
|
|
1911
|
+
///
|
|
1912
|
+
/// This will generate a `CREATE INDEX` statement, indexing
|
|
1913
|
+
/// all fields (columns) provided. If a single field name is
|
|
1914
|
+
/// provided, then a `CREATE INDEX` statement for a single column
|
|
1915
|
+
/// will be generated. If more than one field name is provided, then
|
|
1916
|
+
/// a `CREATE INDEX` statement for a combo-index (indexing across more
|
|
1917
|
+
/// than one column at once) will be generated instead.
|
|
1918
|
+
///
|
|
1919
|
+
/// Arguments:
|
|
1920
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1921
|
+
/// The model to use for the table to index on. This model should also be
|
|
1922
|
+
/// the model that owns all fields to be indexed. It isn't possible to index
|
|
1923
|
+
/// columns across different tables, so the fields provided must all be from
|
|
1924
|
+
/// this same `Model`.
|
|
1925
|
+
/// indexFieldNames: Array<string>
|
|
1926
|
+
/// The field names that will be used to create the single or combo index. A
|
|
1927
|
+
/// single field name will generate a statement for a single column, whereas
|
|
1928
|
+
/// more than one field name will generate a statement for a combo-index that
|
|
1929
|
+
/// indexes all columns requested. These can be fully qualified field names, but
|
|
1930
|
+
/// they don't have to be, since the owning `Model` is already known. If fully qualified
|
|
1931
|
+
/// field names are used, then the model name for each field must match the `Model`
|
|
1932
|
+
/// provided (making it pointless to use fully qualified field names).
|
|
1933
|
+
/// options?: object
|
|
1934
|
+
/// Options for the operation.
|
|
1935
|
+
/// | Option | Type | Default Value | Description |
|
|
1936
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1937
|
+
/// | `concurrently` | `boolean` | `false` | If `true`, then add a `CONCURRENTLY` clause to the `CREATE INDEX` statement (if the database supports it). |
|
|
1938
|
+
/// | `ifNotExists` | `boolean` | `false` | If `true`, then add an `IF NOT EXISTS` clause to the `CREATE INDEX` statement. |
|
|
1939
|
+
///
|
|
1940
|
+
/// Return: string
|
|
1941
|
+
/// Return a fully formatted `CREATE INDEX` statement for the fields (columns)
|
|
1942
|
+
/// requested. An empty string will be returned if `indexFieldNames` is empty,
|
|
1943
|
+
/// or contains no valid field names.
|
|
1084
1944
|
generateCreateIndexStatement(Model, _indexFieldNames, _options) {
|
|
1085
1945
|
let indexFieldNames = Nife.toArray(_indexFieldNames).filter((fieldName) => {
|
|
1086
1946
|
if (Nife.isEmpty(fieldName))
|
|
@@ -1116,6 +1976,43 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1116
1976
|
return `CREATE INDEX${(flags) ? ` ${flags}` : ''} ${indexName} ON ${escapedTableName} (${escapedColumnNames.join(',')})`;
|
|
1117
1977
|
}
|
|
1118
1978
|
|
|
1979
|
+
/// Generate a `DROP INDEX` statement.
|
|
1980
|
+
///
|
|
1981
|
+
/// This will generate a `DROP INDEX` statement, using the provided
|
|
1982
|
+
/// `indexFieldNames` to generate the name of the index to be dropped.
|
|
1983
|
+
/// The provided `indexFieldNames` are passed off to <see>SQLQueryGeneratorBase.generateIndexName</see>
|
|
1984
|
+
/// to get the name of the index to drop.
|
|
1985
|
+
///
|
|
1986
|
+
/// Arguments:
|
|
1987
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1988
|
+
/// The model to use for the table to index on. This model should also be
|
|
1989
|
+
/// the model that owns all fields to be indexed. It isn't possible to index
|
|
1990
|
+
/// columns across different tables, so the fields provided must all be from
|
|
1991
|
+
/// this same `Model`.
|
|
1992
|
+
/// indexFieldNames: Array<string>
|
|
1993
|
+
/// The field names that will be used to create the single or combo index. A
|
|
1994
|
+
/// single field name will generate a statement for a single column, whereas
|
|
1995
|
+
/// more than one field name will generate a statement for a combo-index that
|
|
1996
|
+
/// indexes all columns requested. These can be fully qualified field names, but
|
|
1997
|
+
/// they don't have to be, since the owning `Model` is already known. If fully qualified
|
|
1998
|
+
/// field names are used, then the model name for each field must match the `Model`
|
|
1999
|
+
/// provided (making it pointless to use fully qualified field names).
|
|
2000
|
+
/// options?: object
|
|
2001
|
+
/// Options for the operation.
|
|
2002
|
+
/// | Option | Type | Default Value | Description |
|
|
2003
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2004
|
+
/// | `concurrently` | `boolean` | `false` | If `true`, then add a `CONCURRENTLY` clause to the `DROP INDEX` statement (if the database supports it). |
|
|
2005
|
+
/// | `ifExists` | `boolean` | `false` | If `true`, then add an `IF EXISTS` clause to the `DROP INDEX` statement. |
|
|
2006
|
+
/// | `cascade` | `boolean` | `true` | If `true`, then add a `CASCADE` clause to the `DROP INDEX` statement (if the database supports it). |
|
|
2007
|
+
///
|
|
2008
|
+
/// Return: string
|
|
2009
|
+
/// Return a fully formatted `DROP INDEX` statement for the fields (columns)
|
|
2010
|
+
/// requested. An empty string will be returned if `indexFieldNames` is empty,
|
|
2011
|
+
/// or contains no valid field names. <see>SQLQueryGeneratorBase.generateIndexName</see> is called
|
|
2012
|
+
/// with the provided `indexFieldNames` to generate the name of the index that should
|
|
2013
|
+
/// be dropped.
|
|
2014
|
+
///
|
|
2015
|
+
/// See: SQLQueryGeneratorBase.generateIndexName
|
|
1119
2016
|
generateDropIndexStatement(Model, _indexFieldNames, _options) {
|
|
1120
2017
|
let indexFieldNames = Nife.toArray(_indexFieldNames).filter((fieldName) => {
|
|
1121
2018
|
if (Nife.isEmpty(fieldName))
|
|
@@ -1149,6 +2046,31 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1149
2046
|
return `DROP INDEX${(flags) ? ` ${flags}` : ''} ${indexName}${(postFlags) ? ` ${postFlags}` : ''}`;
|
|
1150
2047
|
}
|
|
1151
2048
|
|
|
2049
|
+
/// Generate zero or more `CREATE INDEX` statements,
|
|
2050
|
+
/// using `field.index` to generate the statements.
|
|
2051
|
+
///
|
|
2052
|
+
/// A [Field](https://github.com/th317erd/mythix-orm/wiki/Field) in Mythix ORM
|
|
2053
|
+
/// can have an `index` property (see [Field.index](https://github.com/th317erd/mythix-orm/wiki/Field#property-index))
|
|
2054
|
+
/// that defines the indexes to be created for the field. A `true` value is short for
|
|
2055
|
+
/// "index this field". Other field names in the `index` array mean
|
|
2056
|
+
/// "index this field combined with the fields specified, creating a combined index".
|
|
2057
|
+
///
|
|
2058
|
+
/// This method will turn the `index` property on the provided `field` into one or more `CREATE INDEX`
|
|
2059
|
+
/// statements. If the `index` property on the `field` is falsy, or empty, then an empty array
|
|
2060
|
+
/// will be returned instead.
|
|
2061
|
+
///
|
|
2062
|
+
/// Arguments:
|
|
2063
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2064
|
+
/// The model that owns the `field` provided.
|
|
2065
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2066
|
+
/// The field to generate indexes for, using the `index` property of this field.
|
|
2067
|
+
/// options?: object
|
|
2068
|
+
/// Options for the operation. These options are passed off to <see>SQLQueryGeneratorBase.generateCreateIndexStatement</see>
|
|
2069
|
+
/// to generate each `CREATE INDEX` statement.
|
|
2070
|
+
///
|
|
2071
|
+
/// Return: Array<string>
|
|
2072
|
+
/// Return an array of `CREATE INDEX` statements. If the `index` property on the provided
|
|
2073
|
+
/// `field` is falsy or empty, then an empty array will be returned instead.
|
|
1152
2074
|
generateColumnIndexes(Model, field, _options) {
|
|
1153
2075
|
let indexes = Nife.toArray(field.index).filter((index) => {
|
|
1154
2076
|
if (index === true)
|
|
@@ -1170,6 +2092,20 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1170
2092
|
});
|
|
1171
2093
|
}
|
|
1172
2094
|
|
|
2095
|
+
/// Generate a `DROP TABLE` statement.
|
|
2096
|
+
///
|
|
2097
|
+
/// Arguments:
|
|
2098
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2099
|
+
/// The model that defines the table to be dropped.
|
|
2100
|
+
/// options?: object
|
|
2101
|
+
/// Options for the operation.
|
|
2102
|
+
/// | Option | Type | Default Value | Description |
|
|
2103
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2104
|
+
/// | `ifExists` | `boolean` | `false` | If `true`, then add an `IF EXISTS` clause to the `DROP TABLE` statement. |
|
|
2105
|
+
///
|
|
2106
|
+
/// Return: string
|
|
2107
|
+
/// Return a fully formatted `DROP TABLE` statement, using the `Model` provided
|
|
2108
|
+
/// to define which table should be dropped.
|
|
1173
2109
|
generateDropTableStatement(Model, _options) {
|
|
1174
2110
|
let options = _options || {};
|
|
1175
2111
|
let escapedTableName = this.getEscapedTableName(Model, options);
|
|
@@ -1183,6 +2119,30 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1183
2119
|
return `DROP TABLE ${flags} ${escapedTableName}${(options.cascade !== false) ? ' CASCADE' : ''}`;
|
|
1184
2120
|
}
|
|
1185
2121
|
|
|
2122
|
+
/// Generate foreign key constraints for a column
|
|
2123
|
+
/// in a `CREATE TABLE` statement.
|
|
2124
|
+
///
|
|
2125
|
+
/// This method will generate database specific syntax
|
|
2126
|
+
/// for foreign key constraints to apply to a column
|
|
2127
|
+
/// in a `CREATE TABLE` statement.
|
|
2128
|
+
///
|
|
2129
|
+
/// Arguments:
|
|
2130
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2131
|
+
/// The field to generate foreign key constraints for. This field should
|
|
2132
|
+
/// have a [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType)
|
|
2133
|
+
/// `type`.
|
|
2134
|
+
/// type: [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType)
|
|
2135
|
+
/// The `type` of the `field` provided, which should always be a [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType).
|
|
2136
|
+
/// options?: object
|
|
2137
|
+
/// Options for the operation. These options are simply passed through to any
|
|
2138
|
+
/// <see>SQLQueryGeneratorBase.getEscapedColumnName</see>, or <see>SQLQueryGeneratorBase.getEscapedTableName</see>
|
|
2139
|
+
/// calls that are made internally by this method.
|
|
2140
|
+
///
|
|
2141
|
+
/// Return: string
|
|
2142
|
+
/// A database specific string for defining foreign key constraints for a column.
|
|
2143
|
+
/// Any `ON DELETE` or `ON UPDATE` clauses will be generated from the `onDelete`
|
|
2144
|
+
/// and `onUpdate` properties set on the [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType)
|
|
2145
|
+
/// `type` for the field.
|
|
1186
2146
|
generateForeignKeyConstraint(field, type, options) {
|
|
1187
2147
|
let typeOptions = type.getOptions();
|
|
1188
2148
|
let targetModel = type.getTargetModel(this.connection);
|
|
@@ -1216,6 +2176,39 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1216
2176
|
return sqlParts.join('');
|
|
1217
2177
|
}
|
|
1218
2178
|
|
|
2179
|
+
/// Generate an "inner tail" for a `CREATE TABLE`
|
|
2180
|
+
/// statement.
|
|
2181
|
+
///
|
|
2182
|
+
/// An "inner tail" is the trailing part of the `CREATE TABLE`
|
|
2183
|
+
/// statement that is still inside the parenthesis of the statement,
|
|
2184
|
+
/// after any columns have been defined. For example:
|
|
2185
|
+
/// ```sql
|
|
2186
|
+
/// CREATE TABLE table_name (
|
|
2187
|
+
/// column1 datatype(length) column_contraint,
|
|
2188
|
+
/// column2 datatype(length) column_contraint,
|
|
2189
|
+
/// ... // <---- this is the "inner tail"
|
|
2190
|
+
/// );
|
|
2191
|
+
///
|
|
2192
|
+
/// ... // <---- this is the "outer tail"
|
|
2193
|
+
/// ```
|
|
2194
|
+
///
|
|
2195
|
+
/// This is often database specific, and by default will be
|
|
2196
|
+
/// used to generate any foreign key constraints used by columns
|
|
2197
|
+
/// in the table.
|
|
2198
|
+
///
|
|
2199
|
+
/// Arguments:
|
|
2200
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2201
|
+
/// The model that defines the table being created.
|
|
2202
|
+
/// options?: object
|
|
2203
|
+
/// Any options for the `CREATE TABLE` operation being carried out.
|
|
2204
|
+
///
|
|
2205
|
+
/// Return: Array<string>
|
|
2206
|
+
/// Return an "inner tail" for the `CREATE TABLE` statement, or an empty
|
|
2207
|
+
/// array if there should be no "inner tail". An array of SQL statements
|
|
2208
|
+
/// is returned by this method, which will be added to the `CREATE TABLE`
|
|
2209
|
+
/// statement (inside its parenthesis).
|
|
2210
|
+
///
|
|
2211
|
+
/// See: SQLQueryGeneratorBase.generateForeignKeyConstraint
|
|
1219
2212
|
// eslint-disable-next-line no-unused-vars
|
|
1220
2213
|
generateCreateTableStatementInnerTail(Model, options) {
|
|
1221
2214
|
let fieldParts = [];
|
|
@@ -1236,6 +2229,40 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1236
2229
|
return fieldParts;
|
|
1237
2230
|
}
|
|
1238
2231
|
|
|
2232
|
+
/// Generate an "outer tail" for a `CREATE TABLE`
|
|
2233
|
+
/// statement.
|
|
2234
|
+
///
|
|
2235
|
+
/// An "outer tail" is the trailing part of the `CREATE TABLE`
|
|
2236
|
+
/// statement that is outside the parenthesis of the statement,
|
|
2237
|
+
/// after the column list. For example:
|
|
2238
|
+
/// ```sql
|
|
2239
|
+
/// CREATE TABLE table_name (
|
|
2240
|
+
/// column1 datatype(length) column_contraint,
|
|
2241
|
+
/// column2 datatype(length) column_contraint,
|
|
2242
|
+
/// ... // <---- this is the "inner tail"
|
|
2243
|
+
/// );
|
|
2244
|
+
///
|
|
2245
|
+
/// ... // <---- this is the "outer tail"
|
|
2246
|
+
/// ```
|
|
2247
|
+
///
|
|
2248
|
+
/// This is often database specific, and by default will be
|
|
2249
|
+
/// used to generate any `CREATE INDEX` statements for columns
|
|
2250
|
+
/// that have indexes.
|
|
2251
|
+
///
|
|
2252
|
+
/// Arguments:
|
|
2253
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2254
|
+
/// The model that defines the table being created.
|
|
2255
|
+
/// options?: object
|
|
2256
|
+
/// Any options for the `CREATE TABLE` operation being carried out.
|
|
2257
|
+
///
|
|
2258
|
+
/// Return: Array<string>
|
|
2259
|
+
/// Return an "outer tail" for the `CREATE TABLE` statement, or an empty
|
|
2260
|
+
/// array if there should be no "outer tail". An array of SQL statements
|
|
2261
|
+
/// is returned by this method, which will either be added to the `CREATE TABLE`
|
|
2262
|
+
/// statement, or executed separately after the `CREATE TABLE` statement is
|
|
2263
|
+
/// executed--depending on the underlying database.
|
|
2264
|
+
///
|
|
2265
|
+
/// See: SQLQueryGeneratorBase.generateColumnIndexes
|
|
1239
2266
|
// eslint-disable-next-line no-unused-vars
|
|
1240
2267
|
generateCreateTableStatementOuterTail(Model, options) {
|
|
1241
2268
|
let fieldParts = [];
|
|
@@ -1257,6 +2284,27 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1257
2284
|
return Nife.uniq(fieldParts);
|
|
1258
2285
|
}
|
|
1259
2286
|
|
|
2287
|
+
/// Generate a column definition for use inside a `CREATE TABLE`
|
|
2288
|
+
/// statement, or an `ALTER TABLE` statement. The generated
|
|
2289
|
+
/// column definition will include any `DEFAULT` defined, as well
|
|
2290
|
+
/// as any constraints that should be applied to the column, and
|
|
2291
|
+
/// will define at least the column's name and type.
|
|
2292
|
+
///
|
|
2293
|
+
/// Arguments:
|
|
2294
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2295
|
+
/// The model that defines the table the column definition is for.
|
|
2296
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2297
|
+
/// The field that defines the column whose definition is being generated.
|
|
2298
|
+
/// options?: object
|
|
2299
|
+
/// Options for the operation. These are simply passed off to other generate
|
|
2300
|
+
/// methods that are used internally, such as <see>SQLQueryGeneratorBase.getEscapedColumnName</see>,
|
|
2301
|
+
/// and [Type.toConnectionType](https://github.com/th317erd/mythix-orm/wiki/Type#method-toConnectionType)
|
|
2302
|
+
/// for stringifying the column's type. There may be connection-specific options that
|
|
2303
|
+
/// can be supplied as well.
|
|
2304
|
+
///
|
|
2305
|
+
/// Return: string
|
|
2306
|
+
/// A fully formatted "column definition" statement, for use in
|
|
2307
|
+
/// a `CREATE TABLE` or `ALTER TABLE` statement. i.e. `"id" BIGINT PRIMARY KEY AUTOINCREMENT`.
|
|
1260
2308
|
generateColumnDeclarationStatement(Model, field, _options) {
|
|
1261
2309
|
let options = _options || {};
|
|
1262
2310
|
let constraintParts = [];
|
|
@@ -1292,6 +2340,26 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1292
2340
|
return `${this.getEscapedColumnName(Model, field, { ...options, columnNameOnly: true })} ${field.type.toConnectionType(this.connection, { ...options, createTable: true, defaultValue })}${constraintParts}`;
|
|
1293
2341
|
}
|
|
1294
2342
|
|
|
2343
|
+
/// Generate a full `CREATE TABLE` statement using
|
|
2344
|
+
/// the provided `Model` and its fields.
|
|
2345
|
+
///
|
|
2346
|
+
/// Arguments:
|
|
2347
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2348
|
+
/// The model that defines the table being created.
|
|
2349
|
+
/// options?: object
|
|
2350
|
+
/// Options for the operation. Though these might contain connection-specific
|
|
2351
|
+
/// options, the following options are common across all connections:
|
|
2352
|
+
/// | Option | Type | Default Value | Description |
|
|
2353
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2354
|
+
/// | `ifNotExists` | `boolean` | `false` | If `true`, then add an `IF NOT EXISTS` clause to the `CREATE TABLE` statement. |
|
|
2355
|
+
///
|
|
2356
|
+
/// Return: string
|
|
2357
|
+
/// Return a fully formatted `CREATE TABLE` statement, to create
|
|
2358
|
+
/// the table defined by the provided `Model`.
|
|
2359
|
+
///
|
|
2360
|
+
/// See: SQLQueryGeneratorBase.generateColumnDeclarationStatement
|
|
2361
|
+
///
|
|
2362
|
+
/// See: SQLQueryGeneratorBase.generateCreateTableStatementInnerTail
|
|
1295
2363
|
generateCreateTableStatement(Model, _options) {
|
|
1296
2364
|
let options = _options || {};
|
|
1297
2365
|
let fieldParts = [];
|
|
@@ -1315,6 +2383,42 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1315
2383
|
return finalStatement;
|
|
1316
2384
|
}
|
|
1317
2385
|
|
|
2386
|
+
/// Generate a comma-separated list of values for
|
|
2387
|
+
/// use in an `INSERT` statement.
|
|
2388
|
+
///
|
|
2389
|
+
/// Only "dirty" fields are inserted into the table, which might seem
|
|
2390
|
+
/// odd at first. However, Mythix ORM model instances have all (or most) their
|
|
2391
|
+
/// fields set to dirty when they are first instantiated, except fields
|
|
2392
|
+
/// such as auto-incrementing ids. This makes sense, because we would want
|
|
2393
|
+
/// to insert all columns for a given model instance, but not columns such
|
|
2394
|
+
/// as an auto-incrementing "id" that we would want the database to provide
|
|
2395
|
+
/// a value for. Any field on a model that should be inserted should already
|
|
2396
|
+
/// be marked "dirty", and any field that isn't dirty should instead be provided
|
|
2397
|
+
/// the "default value" that is already defined for the column.
|
|
2398
|
+
///
|
|
2399
|
+
/// The `dirtyFields` option that can be provided is to provide the fields that
|
|
2400
|
+
/// are marked as dirty across **all** model instances being inserted (for bulk-inserts).
|
|
2401
|
+
/// If provide, this option will override the "dirty" fields reported by each model
|
|
2402
|
+
/// instance, since the values for insertion must be aligned across all rows.
|
|
2403
|
+
///
|
|
2404
|
+
/// Arguments:
|
|
2405
|
+
/// model: [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2406
|
+
/// The model instance to pull field values from. Only "dirty" values
|
|
2407
|
+
/// will be pulled from the model and compiled into output.
|
|
2408
|
+
/// options?: object
|
|
2409
|
+
/// Options for the operation. Though these might contain connection-specific
|
|
2410
|
+
/// options, the following options are common across all connections:
|
|
2411
|
+
/// | Option | Type | Default Value | Description |
|
|
2412
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2413
|
+
/// | `dirtyFields` | `Array<Field>` | `undefined` | If more than one row is being inserted, then define all columns being inserted for the operation. |
|
|
2414
|
+
///
|
|
2415
|
+
/// Return: undefined | { modelChanges: object; rowValues: string; }
|
|
2416
|
+
/// Return `undefined` if no model instance is provided, or if the model
|
|
2417
|
+
/// instance is marked as "clean" (meaning no insert needs to happen).
|
|
2418
|
+
/// Otherwise, return an object with the shape: `{ modelChanges: object; rowValues: string; }`,
|
|
2419
|
+
/// where `modelChanges` is an object, where each key is a field name, and each value is the
|
|
2420
|
+
/// value that will be inserted into the database. `rowValues` is a string, that is a
|
|
2421
|
+
/// comma-separated list of all values to be inserted for this row.
|
|
1318
2422
|
generateInsertFieldValuesFromModel(model, _options) {
|
|
1319
2423
|
if (!model)
|
|
1320
2424
|
return;
|
|
@@ -1359,6 +2463,29 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1359
2463
|
return { modelChanges, rowValues: sqlParts.join(',') };
|
|
1360
2464
|
}
|
|
1361
2465
|
|
|
2466
|
+
/// Generate multiple rows of comma-separated values for
|
|
2467
|
+
/// a bulk `INSERT` operation.
|
|
2468
|
+
///
|
|
2469
|
+
/// Arguments:
|
|
2470
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2471
|
+
/// The model class of all `models` being inserted.
|
|
2472
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2473
|
+
/// An array of model instances, or a single model instance to generate insertion
|
|
2474
|
+
/// values for. Each model (if dirty) will have a single row created for it in the
|
|
2475
|
+
/// underlying database table defined by the provided `Model`.
|
|
2476
|
+
/// options?: object
|
|
2477
|
+
/// Options for the operation. The only option that is really useful here is the
|
|
2478
|
+
/// `newlines` option. If `false`, then newlines won't be used to separate the rows
|
|
2479
|
+
/// of values. By default, newlines will be used to separate each row of values.
|
|
2480
|
+
///
|
|
2481
|
+
/// Return: undefined | { modelChanges: Array<object>; values: string; }
|
|
2482
|
+
/// Return `undefined` if the provided `models` is empty. Otherwise,
|
|
2483
|
+
/// return an object with the shape `{ modelChanges: Array<object>; values: string; }`,
|
|
2484
|
+
/// where `modelChanges` are the fields being inserted for each model (key = field name, value = field value),
|
|
2485
|
+
/// and where `values` is the list of row-values to insert into the table, i.e.
|
|
2486
|
+
/// `(value1,value2,value3),(value1,value2,value3),...`.
|
|
2487
|
+
///
|
|
2488
|
+
/// See: SQLQueryGeneratorBase.generateInsertFieldValuesFromModel
|
|
1362
2489
|
generateInsertValuesFromModels(Model, _models, _options) {
|
|
1363
2490
|
let options = _options || {};
|
|
1364
2491
|
let preparedModels = this.connection.prepareAllModelsForOperation(Model, _models, options);
|
|
@@ -1388,10 +2515,55 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1388
2515
|
};
|
|
1389
2516
|
}
|
|
1390
2517
|
|
|
2518
|
+
/// Generate a "tail" for an `INSERT` statement.
|
|
2519
|
+
///
|
|
2520
|
+
/// This method is provided to allow the connection
|
|
2521
|
+
/// itself for any given database to "tack on extra" to
|
|
2522
|
+
/// an `INSERT` statement. This is commonly used by databases
|
|
2523
|
+
/// to add on a `RETURNING` clause to the `INSERT` statement.
|
|
2524
|
+
/// However, its primary purpose is just to allow the engine
|
|
2525
|
+
/// (or the user via overloading) to add on any "extra" to
|
|
2526
|
+
/// an `INSERT` statement.
|
|
2527
|
+
///
|
|
2528
|
+
/// Arguments:
|
|
2529
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2530
|
+
/// The model class of all `models` being inserted.
|
|
2531
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2532
|
+
/// An array of model instances, or a single model instance. These are the models
|
|
2533
|
+
/// that are being inserted into the database.
|
|
2534
|
+
/// options: object
|
|
2535
|
+
/// Options for the operation.
|
|
2536
|
+
/// context: object
|
|
2537
|
+
/// Useful information about the insert operation taking place. This is an
|
|
2538
|
+
/// object with the shape: `{ escapedTableName: string; modelChanges: Array<object>; dirtyFields: Array<Field>; }`.
|
|
2539
|
+
///
|
|
2540
|
+
/// Return: string
|
|
2541
|
+
/// Any "extra" SQL to add onto the end of the `INSERT` statement.
|
|
2542
|
+
/// Most connection drivers will usually use this for a `RETURNING` clause.
|
|
1391
2543
|
// eslint-disable-next-line no-unused-vars
|
|
1392
|
-
generateInsertStatementTail(Model,
|
|
1393
|
-
}
|
|
1394
|
-
|
|
2544
|
+
generateInsertStatementTail(Model, models, options, context) {
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
/// Generate an `INSERT` statement, for inserting
|
|
2548
|
+
/// one or more model instances into the database.
|
|
2549
|
+
///
|
|
2550
|
+
/// Note:
|
|
2551
|
+
/// "clean" models will be skipped, and won't result
|
|
2552
|
+
/// in any output.
|
|
2553
|
+
///
|
|
2554
|
+
/// Arguments:
|
|
2555
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2556
|
+
/// The model class of all `models` being inserted.
|
|
2557
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2558
|
+
/// An array of model instances, or a single model instance. These are the models
|
|
2559
|
+
/// that are being inserted into the database.
|
|
2560
|
+
/// options: object
|
|
2561
|
+
/// Options for the operation.
|
|
2562
|
+
///
|
|
2563
|
+
/// Return: string
|
|
2564
|
+
/// If all models are clean, or no model instances are provided,
|
|
2565
|
+
/// then an empty string will be returned. Otherwise, a fully
|
|
2566
|
+
/// formatted `INSERT` statement will be returned.
|
|
1395
2567
|
generateInsertStatement(Model, _models, _options) {
|
|
1396
2568
|
let options = _options || {};
|
|
1397
2569
|
let preparedModels = this.connection.prepareAllModelsForOperation(Model, _models, options);
|
|
@@ -1430,10 +2602,92 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1430
2602
|
return `INSERT INTO ${escapedTableName} (${escapedFieldNames}) VALUES ${values}`;
|
|
1431
2603
|
}
|
|
1432
2604
|
|
|
2605
|
+
/// Generate a "tail" for an `UPDATE` statement.
|
|
2606
|
+
///
|
|
2607
|
+
/// This method is provided to allow the connection
|
|
2608
|
+
/// itself for any given database to "tack on extra" to
|
|
2609
|
+
/// an `UPDATE` statement. This is commonly used by databases
|
|
2610
|
+
/// to add on a `RETURNING` clause to the `UPDATE` statement.
|
|
2611
|
+
/// However, its primary purpose is just to allow the engine
|
|
2612
|
+
/// (or the user via overloading) to add on any "extra" to
|
|
2613
|
+
/// an `UPDATE` statement.
|
|
2614
|
+
///
|
|
2615
|
+
/// Arguments:
|
|
2616
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2617
|
+
/// The model class of all `models` being updated.
|
|
2618
|
+
/// model: object | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2619
|
+
/// The model instance being updated. Bulk-updates aren't really supported
|
|
2620
|
+
/// well by any SQL database, so Mythix ORM takes the long route and
|
|
2621
|
+
/// updates model instances one-by-one. If `queryEngine` is a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance,
|
|
2622
|
+
/// then this should be a raw object listing the attributes (field names and values)
|
|
2623
|
+
/// that should be applied across all matching rows.
|
|
2624
|
+
/// queryEngine: null | [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2625
|
+
/// The query engine used for the update statement--if any. Updates have
|
|
2626
|
+
/// two primary paths: 1) update a single model instance, or 2) update across
|
|
2627
|
+
/// multiple rows at once. For the latter, a query engine will be used to
|
|
2628
|
+
/// select which rows to update. In this case, the `queryEngine` argument
|
|
2629
|
+
/// here will be a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance.
|
|
2630
|
+
/// In the case that we are updating a single model instance, then this
|
|
2631
|
+
/// `queryEngine` will be `null`.
|
|
2632
|
+
/// options: object
|
|
2633
|
+
/// Options for the operation.
|
|
2634
|
+
/// context: object
|
|
2635
|
+
/// Useful information about the update operation taking place. This is an
|
|
2636
|
+
/// object with the shape:
|
|
2637
|
+
/// ```javascript
|
|
2638
|
+
/// {
|
|
2639
|
+
/// queryEngine: QueryEngine | null;
|
|
2640
|
+
/// escapedTableName: string;
|
|
2641
|
+
/// modelChanges: Array<object>;
|
|
2642
|
+
/// dirtyFields: Array<Field>;
|
|
2643
|
+
/// where: string | null;
|
|
2644
|
+
/// }
|
|
2645
|
+
/// ```
|
|
2646
|
+
///
|
|
2647
|
+
/// Return: string
|
|
2648
|
+
/// Any "extra" SQL to add onto the end of the `UPDATE` statement.
|
|
2649
|
+
/// Most connection drivers will usually use this for a `RETURNING` clause.
|
|
1433
2650
|
// eslint-disable-next-line no-unused-vars
|
|
1434
2651
|
generateUpdateStatementTail(Model, model, queryEngine, options, context) {
|
|
1435
2652
|
}
|
|
1436
2653
|
|
|
2654
|
+
/// Generate an `UPDATE` statement.
|
|
2655
|
+
///
|
|
2656
|
+
/// Update statements in Mythix ORM generally take one of
|
|
2657
|
+
/// two forms: 1) Update a single model instance, or 2) Update
|
|
2658
|
+
/// one or more columns across multiple rows at once.
|
|
2659
|
+
///
|
|
2660
|
+
/// When updating a single model instance, the provided `model`
|
|
2661
|
+
/// argument should the model instance to update, and is expected
|
|
2662
|
+
/// to have dirty fields. If on the other hand the `queryEngine`
|
|
2663
|
+
/// argument is provided, and is a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance,
|
|
2664
|
+
/// then the provided `model` argument should be a raw object
|
|
2665
|
+
/// of attributes (field names) to update across all matching rows.
|
|
2666
|
+
///
|
|
2667
|
+
/// Arguments:
|
|
2668
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2669
|
+
/// The model class of the model being updated.
|
|
2670
|
+
/// model: object | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2671
|
+
/// The model instance being updated. Bulk-updates aren't really supported
|
|
2672
|
+
/// well by any SQL database, so Mythix ORM takes the long route and
|
|
2673
|
+
/// updates model instances one-by-one. If `queryEngine` is a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance,
|
|
2674
|
+
/// then this should be a raw object listing the attributes (field names and values)
|
|
2675
|
+
/// that should be applied across all matching rows.
|
|
2676
|
+
/// queryEngine: null | [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2677
|
+
/// The query engine used for the update statement--if any. Updates have
|
|
2678
|
+
/// two primary paths: 1) update a single model instance, or 2) update across
|
|
2679
|
+
/// multiple rows at once. For the latter, a query engine will be used to
|
|
2680
|
+
/// select which rows to update. In this case, the `queryEngine` argument
|
|
2681
|
+
/// here will be a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance.
|
|
2682
|
+
/// In the case that we are updating a single model instance, then this
|
|
2683
|
+
/// `queryEngine` will be `null`.
|
|
2684
|
+
/// options: object
|
|
2685
|
+
/// Options for the operation.
|
|
2686
|
+
///
|
|
2687
|
+
/// Return: string
|
|
2688
|
+
/// Return a fully formatted `UPDATE` statement, either for
|
|
2689
|
+
/// updating a single model instance, or for updating multiple
|
|
2690
|
+
/// rows at once using the provided attributes.
|
|
1437
2691
|
generateUpdateStatement(Model, _model, _queryEngine, _options) {
|
|
1438
2692
|
if (!_model)
|
|
1439
2693
|
return '';
|
|
@@ -1518,6 +2772,30 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1518
2772
|
return sqlParts.join('');
|
|
1519
2773
|
}
|
|
1520
2774
|
|
|
2775
|
+
/// Generate a `RETURNING` clause for a `DELETE` statement.
|
|
2776
|
+
///
|
|
2777
|
+
/// Arguments:
|
|
2778
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2779
|
+
/// The model class defining the table that is being deleted from.
|
|
2780
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2781
|
+
/// The query engine being used to specify which rows to delete.
|
|
2782
|
+
/// pkField: undefined | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2783
|
+
/// The primary key field of the provided `Model`, if it has one. If the model has
|
|
2784
|
+
/// no primary key field, then this will be `undefined`.
|
|
2785
|
+
/// escapedColumnName: string
|
|
2786
|
+
/// The full column name (usually including the table name) of the column to use for the `RETURNING`
|
|
2787
|
+
/// clause. If the provided `Model` has a primary key field, then this should be that column name
|
|
2788
|
+
/// (though the name might be an alias of that column name, depending on how the `DELETE` statement
|
|
2789
|
+
/// is generated). If the provided `Model` has no primary key field, then this will be `*`.
|
|
2790
|
+
/// This column name might differ from the field's column name, because the `DELETE` statement
|
|
2791
|
+
/// might be constructed such that an alias name is needed for the column name.
|
|
2792
|
+
/// options?: object
|
|
2793
|
+
/// Options for the operation.
|
|
2794
|
+
///
|
|
2795
|
+
/// Return: string
|
|
2796
|
+
/// Return a `RETURNING` clause to apply to the end of a `DELETE` statement. If
|
|
2797
|
+
/// `escapedColumnName` is empty, then an empty string will be returned.
|
|
2798
|
+
// eslint-disable-next-line no-unused-vars
|
|
1521
2799
|
generateDeleteStatementReturningClause(Model, queryEngine, pkField, escapedColumnName, options) {
|
|
1522
2800
|
if (!escapedColumnName)
|
|
1523
2801
|
return '';
|
|
@@ -1525,8 +2803,43 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1525
2803
|
return `RETURNING ${escapedColumnName}`;
|
|
1526
2804
|
}
|
|
1527
2805
|
|
|
1528
|
-
|
|
1529
|
-
|
|
2806
|
+
/// Generate a `DELETE` statement to delete rows from
|
|
2807
|
+
/// the table defined by `Model`, either by using a
|
|
2808
|
+
/// query provided by the user, or by generating a query
|
|
2809
|
+
/// based on the provided model instances. If no query
|
|
2810
|
+
/// or model instances are provided, then generate a
|
|
2811
|
+
/// `DELETE` statement that will delete every row from
|
|
2812
|
+
/// the table, truncating the table.
|
|
2813
|
+
///
|
|
2814
|
+
/// Arguments:
|
|
2815
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2816
|
+
/// The model class defining the table that is being deleted from.
|
|
2817
|
+
/// modelsOrQueryEngine?: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model) | [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2818
|
+
/// Model instance(s) to delete, or a query engine specifying which rows to delete.
|
|
2819
|
+
/// If model instances are provided, then their primary key field will be used to
|
|
2820
|
+
/// create a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2821
|
+
/// used to delete those specific primary keys from the database. If the `Model` provided
|
|
2822
|
+
/// has no primary key field, then an exception will be thrown, as deleting model instances
|
|
2823
|
+
/// this way requires the model have a primary key field. If your model has no primary key
|
|
2824
|
+
/// field, then it is required that the user generate their own query to select which rows
|
|
2825
|
+
/// to delete from the underlying table. Instead of provided model instances, the user
|
|
2826
|
+
/// can provide a raw [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance
|
|
2827
|
+
/// that will be used to select which rows to delete instead. If neither is provided, then
|
|
2828
|
+
/// the entire table will be truncated.
|
|
2829
|
+
/// options?: object
|
|
2830
|
+
/// Options for the operation. These are simply passed through to any sub-calls
|
|
2831
|
+
/// this method makes internally.
|
|
2832
|
+
///
|
|
2833
|
+
/// Return: string
|
|
2834
|
+
/// Return a fully formatted `DELETE` statement to delete rows from the
|
|
2835
|
+
/// table defined by the provided `Model`. If no model instances or [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2836
|
+
/// are provided, then a simple `DELETE FROM "table_name";` statement will be
|
|
2837
|
+
/// generated, truncating the entire table. If model instances or a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2838
|
+
/// are provided, then a `DELETE` statement in the form of
|
|
2839
|
+
/// `DELETE FROM "table_name" WHERE EXISTS(SELECT ...)` will be returned,
|
|
2840
|
+
/// selecting which rows to delete with the provided query.
|
|
2841
|
+
generateDeleteStatement(Model, _modelsOrQueryEngine, _options) {
|
|
2842
|
+
let queryEngine = _modelsOrQueryEngine;
|
|
1530
2843
|
let options = _options;
|
|
1531
2844
|
|
|
1532
2845
|
if (queryEngine) {
|
|
@@ -1588,7 +2901,34 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1588
2901
|
}
|
|
1589
2902
|
}
|
|
1590
2903
|
|
|
1591
|
-
|
|
2904
|
+
/// Iterate all fields of the provided `Model`, and
|
|
2905
|
+
/// collect and return all fields that have a `defaultValue`
|
|
2906
|
+
/// with the `remote` flag set. The `remote` flag on
|
|
2907
|
+
/// the `defaultValue` of a field tells Mythix ORM that the
|
|
2908
|
+
/// default value is provided by the database itself. This
|
|
2909
|
+
/// would be the case for example for `AUTOINCREMENT` ids,
|
|
2910
|
+
/// and for `NOW()` date columns--among others.
|
|
2911
|
+
///
|
|
2912
|
+
/// Any field that is marked with a `remote` default (a value
|
|
2913
|
+
/// provided by the database itself) should always be part of any
|
|
2914
|
+
/// `RETURNING` clause in-play, so this method is used to ensure
|
|
2915
|
+
/// all `remote` fields are part of the `RETURNING` clause.
|
|
2916
|
+
/// See [Helpers](https://github.com/th317erd/mythix-orm/wiki/Helpers) in
|
|
2917
|
+
/// the Mythix ORM documentation for a better explanation of "remote" fields
|
|
2918
|
+
/// and flags.
|
|
2919
|
+
///
|
|
2920
|
+
/// Arguments:
|
|
2921
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2922
|
+
/// The model whose "remote" fields should be collected.
|
|
2923
|
+
/// options?: object
|
|
2924
|
+
/// Options for the operation.
|
|
2925
|
+
///
|
|
2926
|
+
/// Return: Array<string>
|
|
2927
|
+
/// Return an array of escaped column names for direct use on
|
|
2928
|
+
/// a `RETURNING` clause. If the provided `Model` has no "remote"
|
|
2929
|
+
/// fields, then an empty array will be returned.
|
|
2930
|
+
// eslint-disable-next-line no-unused-vars
|
|
2931
|
+
_collectRemoteReturningFields(Model, options) {
|
|
1592
2932
|
let remoteFieldNames = [];
|
|
1593
2933
|
|
|
1594
2934
|
Model.iterateFields(({ field }) => {
|
|
@@ -1607,7 +2947,40 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1607
2947
|
return remoteFieldNames;
|
|
1608
2948
|
}
|
|
1609
2949
|
|
|
1610
|
-
|
|
2950
|
+
/// Generate a `RETURNING` clause for `UPDATE`
|
|
2951
|
+
/// and `INSERT` statements.
|
|
2952
|
+
///
|
|
2953
|
+
/// This will generate a `RETURNING` clause that
|
|
2954
|
+
/// will always includes all "remote" fields for the `Model`
|
|
2955
|
+
/// provided, will always include the primary key of the
|
|
2956
|
+
/// model (if the model has one), and will include all
|
|
2957
|
+
/// fields marked as "dirty" across all models being inserted
|
|
2958
|
+
/// or updated.
|
|
2959
|
+
///
|
|
2960
|
+
/// Arguments:
|
|
2961
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2962
|
+
/// The model that defines the table for the insert or update operation.
|
|
2963
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2964
|
+
/// An array of model instances, or a single model instance. These are the models
|
|
2965
|
+
/// that are being inserted or updated.
|
|
2966
|
+
/// options: object
|
|
2967
|
+
/// Options for the operation.
|
|
2968
|
+
/// context: object
|
|
2969
|
+
/// The same `context` that is provided to <see>SQLQueryGeneratorBase.generateInsertStatementTail</see> or
|
|
2970
|
+
/// <see>SQLQueryGeneratorBase.generateUpdateStatementTail</see>, depending on if this is an
|
|
2971
|
+
/// insert or update operation.
|
|
2972
|
+
///
|
|
2973
|
+
/// Return: string
|
|
2974
|
+
/// Return a `RETURNING` clause to apply to the end of an `UPDATE`
|
|
2975
|
+
/// or `INSERT` statement. If no fields are found for this clause,
|
|
2976
|
+
/// then an empty string will be returned.
|
|
2977
|
+
///
|
|
2978
|
+
/// See: SQLQueryGeneratorBase.generateInsertStatementTail
|
|
2979
|
+
///
|
|
2980
|
+
/// See: SQLQueryGeneratorBase.generateUpdateStatementTail
|
|
2981
|
+
///
|
|
2982
|
+
/// See: SQLQueryGeneratorBase._collectRemoteReturningFields
|
|
2983
|
+
generateReturningClause(Model, models, options, context) {
|
|
1611
2984
|
let {
|
|
1612
2985
|
modelChanges,
|
|
1613
2986
|
dirtyFields,
|
|
@@ -1631,7 +3004,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1631
3004
|
if (!fieldValue.options.remote)
|
|
1632
3005
|
continue;
|
|
1633
3006
|
|
|
1634
|
-
let escapedColumnName = this.getEscapedColumnName(dirtyField.Model, dirtyField);
|
|
3007
|
+
let escapedColumnName = this.getEscapedColumnName(dirtyField.Model, dirtyField, options);
|
|
1635
3008
|
returnFieldsMap[escapedColumnName] = true;
|
|
1636
3009
|
|
|
1637
3010
|
break;
|
|
@@ -1651,11 +3024,21 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1651
3024
|
|
|
1652
3025
|
let returnFields = Object.keys(returnFieldsMap);
|
|
1653
3026
|
if (!returnFields.length)
|
|
1654
|
-
return;
|
|
3027
|
+
return '';
|
|
1655
3028
|
|
|
1656
3029
|
return `RETURNING ${returnFields.join(',')}`;
|
|
1657
3030
|
}
|
|
1658
3031
|
|
|
3032
|
+
/// Generate a `TRUNCATE TABLE` statement.
|
|
3033
|
+
///
|
|
3034
|
+
/// Arguments:
|
|
3035
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
3036
|
+
/// The model that defines the table being truncated.
|
|
3037
|
+
/// options?: object
|
|
3038
|
+
/// Options for the operation.
|
|
3039
|
+
///
|
|
3040
|
+
/// Return: string
|
|
3041
|
+
/// Return a fully formatted `TRUNCATE TABLE` statement.
|
|
1659
3042
|
// eslint-disable-next-line no-unused-vars
|
|
1660
3043
|
generateTruncateTableStatement(Model, _options) {
|
|
1661
3044
|
let escapedTableName = this.escapeID(Model.getTableName(this.connection));
|
|
@@ -1847,7 +3230,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1847
3230
|
let options = _options || {};
|
|
1848
3231
|
let prefix = `ALTER TABLE ${this.getEscapedTableName(Model, options)}`;
|
|
1849
3232
|
|
|
1850
|
-
return `${prefix} ADD COLUMN ${this.generateColumnDeclarationStatement(Model, field, options)}`;
|
|
3233
|
+
return `${prefix} ADD COLUMN${(options.ifNotExists) ? ' IF NOT EXISTS' : ''} ${this.generateColumnDeclarationStatement(Model, field, options)}`;
|
|
1851
3234
|
}
|
|
1852
3235
|
|
|
1853
3236
|
toConnectionString(queryEngine, options) {
|