mythix-orm-sql-base 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/sql-connection-base.js +12 -5
- package/lib/sql-query-generator-base.d.ts +4 -13
- package/lib/sql-query-generator-base.js +1693 -118
- package/package.json +2 -2
|
@@ -15,7 +15,38 @@ const DefaultHelpers = Types.DefaultHelpers;
|
|
|
15
15
|
const LiteralBase = Literals.LiteralBase;
|
|
16
16
|
|
|
17
17
|
/// The "base" SQL generator for all SQL-type databases.
|
|
18
|
+
///
|
|
19
|
+
/// This class is used to generate SQL statements for the
|
|
20
|
+
/// underlying SQL database. Database drivers can and often
|
|
21
|
+
/// will create their own class that extends from this class.
|
|
22
|
+
///
|
|
23
|
+
/// Extends: [QueryGeneratorBase](https://github.com/th317erd/mythix-orm/wiki/QueryGeneratorBase)
|
|
18
24
|
class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
25
|
+
/// Escape a field name, usually for a projection alias.
|
|
26
|
+
/// This method is primarily used for generating aliases
|
|
27
|
+
/// for projected fields.
|
|
28
|
+
///
|
|
29
|
+
/// This method will take the field it is given, and turn
|
|
30
|
+
/// it into a fully qualified field name, escaped as an identifier
|
|
31
|
+
/// for the underlying database.
|
|
32
|
+
///
|
|
33
|
+
/// For example, given the field `User.fields.id`, this method will return
|
|
34
|
+
/// `"User:id"`--assuming that double quotes are used in the underlying
|
|
35
|
+
/// database to escape an identifier.
|
|
36
|
+
///
|
|
37
|
+
/// Arguments:
|
|
38
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
39
|
+
/// The model that owns the `field` provided.
|
|
40
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
41
|
+
/// The field to operate on.
|
|
42
|
+
/// options?: object
|
|
43
|
+
/// Options for the operation.
|
|
44
|
+
/// | Option | Type | Default Value | Description |
|
|
45
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
46
|
+
/// | `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) |
|
|
47
|
+
///
|
|
48
|
+
/// Return: string
|
|
49
|
+
/// The field's name, escaped for the underlying database. i.e. `"User:id"`.
|
|
19
50
|
getEscapedFieldName(_Model, field, options) {
|
|
20
51
|
let isString = Nife.instanceOf(field, 'string');
|
|
21
52
|
let fieldName = (isString) ? field : field.fieldName;
|
|
@@ -30,6 +61,34 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
30
61
|
return `"${field.Model.getModelName()}:${fieldName}"`;
|
|
31
62
|
}
|
|
32
63
|
|
|
64
|
+
/// Get the escaped column name for the field provided.
|
|
65
|
+
///
|
|
66
|
+
/// Given a field, return the full column name (including the table)
|
|
67
|
+
/// of that field, escaped for the underlying databases.
|
|
68
|
+
/// For example, given the field `User.fields.id`, return `"users"."id"`--assuming
|
|
69
|
+
/// the underlying database uses double quotes for escaping identifiers.
|
|
70
|
+
///
|
|
71
|
+
/// This method will use the `columnName` defined on the field for the name
|
|
72
|
+
/// of the column, if defined, or will use `fieldName` as defined on the field
|
|
73
|
+
/// as the column name if no `columnName` is defined. To get the name of the table,
|
|
74
|
+
/// this method will use [getTableName](https://github.com/th317erd/mythix-orm/wiki/Model#method-static-getTableName)
|
|
75
|
+
/// on the model that owns the `field` provided.
|
|
76
|
+
///
|
|
77
|
+
/// Arguments:
|
|
78
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
79
|
+
/// The model that owns the `field` provided.
|
|
80
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
81
|
+
/// The field to operate on.
|
|
82
|
+
/// options?: object
|
|
83
|
+
/// Options for the operation.
|
|
84
|
+
/// | Option | Type | Default Value | Description |
|
|
85
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
86
|
+
/// | `columnNameOnly` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the name of the table. |
|
|
87
|
+
/// | `columnNamePrefix` | `string` | `''` | Prefix the column name with this value before escaping it. |
|
|
88
|
+
/// | `tableNamePrefix` | `string` | `''` | Only applicable if `columnNameOnly` is `false`. Used to prefix the table name before escaping it. |
|
|
89
|
+
///
|
|
90
|
+
/// Return: string
|
|
91
|
+
/// The fully escaped column name, including the table the column exists on. i.e. `"users"."id"`.
|
|
33
92
|
getEscapedColumnName(_Model, field, options) {
|
|
34
93
|
let isString = Nife.instanceOf(field, 'string');
|
|
35
94
|
let columnName = (isString) ? field : (field.columnName || field.fieldName);
|
|
@@ -47,6 +106,27 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
47
106
|
return `${this.getEscapedTableName(Model)}.${this.escapeID(columnName)}`;
|
|
48
107
|
}
|
|
49
108
|
|
|
109
|
+
/// Get the escaped table name for the model or field provided.
|
|
110
|
+
///
|
|
111
|
+
/// Give a model or field, access the model to get the table name
|
|
112
|
+
/// for the model, and escape it for the underlying database.
|
|
113
|
+
/// If given a field, then the parent model for that field will be
|
|
114
|
+
/// retrieved via `field.Model`. Once a model is ascertained, then
|
|
115
|
+
/// call [getTableName](https://github.com/th317erd/mythix-orm/wiki/Model#method-static-getTableName)
|
|
116
|
+
/// on the model to get the table name in the underlying database for this
|
|
117
|
+
/// model, escaping it before it is returned.
|
|
118
|
+
///
|
|
119
|
+
/// Arguments:
|
|
120
|
+
/// modelOrField: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model) | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
121
|
+
/// A model class, or a field to fetch the model class from.
|
|
122
|
+
/// options?: object
|
|
123
|
+
/// Options for the operation.
|
|
124
|
+
/// | Option | Type | Default Value | Description |
|
|
125
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
126
|
+
/// | `tableNamePrefix` | `string` | `''` | Used to prefix the table name before escaping it. |
|
|
127
|
+
///
|
|
128
|
+
/// Return: string
|
|
129
|
+
/// The table name for the given model, escaped for the underlying database. i.e. `"users"`.
|
|
50
130
|
getEscapedTableName(_modelOrField, options) {
|
|
51
131
|
let Model = (_modelOrField.Model) ? _modelOrField.Model : _modelOrField;
|
|
52
132
|
let tableName = Model.getTableName(this.connection);
|
|
@@ -57,6 +137,33 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
57
137
|
return this.escapeID(tableName);
|
|
58
138
|
}
|
|
59
139
|
|
|
140
|
+
/// Given a field, escape it for the projection,
|
|
141
|
+
/// optionally including an alias for the field.
|
|
142
|
+
///
|
|
143
|
+
/// For example, given the field `User.fields.id`, return
|
|
144
|
+
/// the projected field with an alias: `"users"."id" AS "User:id"`.
|
|
145
|
+
/// By default, this will use <see>SQLQueryGeneratorBase.getEscapedFieldName</see>
|
|
146
|
+
/// for the alias, unless the `as` `options` is provided. If `as`
|
|
147
|
+
/// is provided to the `options`, then use that as the literal field
|
|
148
|
+
/// alias instead.
|
|
149
|
+
///
|
|
150
|
+
/// Arguments:
|
|
151
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
152
|
+
/// The model that owns the `field` provided.
|
|
153
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
154
|
+
/// The field to operate on.
|
|
155
|
+
/// options?: object
|
|
156
|
+
/// Options for the operation.
|
|
157
|
+
/// | Option | Type | Default Value | Description |
|
|
158
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
159
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the alias for the projection. |
|
|
160
|
+
/// | `columnNameOnly` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the name of the table. |
|
|
161
|
+
/// | `columnNamePrefix` | `string` | `''` | Prefix the column name with this value before escaping it. |
|
|
162
|
+
/// | `tableNamePrefix` | `string` | `''` | Only applicable if `columnNameOnly` is `false`. Used to prefix the table name before escaping it. |
|
|
163
|
+
/// | `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. |
|
|
164
|
+
///
|
|
165
|
+
/// Return: string
|
|
166
|
+
/// The fully escaped column name, for use in the projection. i.e. `"users"."id" AS "User:id"`.
|
|
60
167
|
// eslint-disable-next-line no-unused-vars
|
|
61
168
|
getEscapedProjectionName(Model, field, options) {
|
|
62
169
|
if (options && options.noProjectionAliases)
|
|
@@ -65,8 +172,39 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
65
172
|
return `${this.getEscapedColumnName(Model, field, options)} AS ${(options && options.as) ? this.escapeID(options.as) : this.getEscapedFieldName(Model, field, options)}`;
|
|
66
173
|
}
|
|
67
174
|
|
|
175
|
+
/// Pass all non-virtual model fields through
|
|
176
|
+
/// <see>SQLQueryGeneratorBase.getEscapedFieldName</see>,
|
|
177
|
+
/// <see>SQLQueryGeneratorBase.getEscapedColumnName</see>,
|
|
178
|
+
/// or <see>SQLQueryGeneratorBase.getEscapedProjectionName</see>.
|
|
179
|
+
///
|
|
180
|
+
/// This method is used to bulk-escape all model fields, using one
|
|
181
|
+
/// of the methods listed above. If the `asProjection` `options` is
|
|
182
|
+
/// used, then all fields will be escaped using <see>SQLQueryGeneratorBase.getEscapedProjectionName</see>.
|
|
183
|
+
/// If the `asColumn` `options` is used, then escape all fields using
|
|
184
|
+
/// <see>SQLQueryGeneratorBase.getEscapedColumnName</see>. Otherwise,
|
|
185
|
+
/// if no `options` are specified, then escape all model fields using
|
|
186
|
+
/// <see>SQLQueryGeneratorBase.getEscapedFieldName</see> instead.
|
|
187
|
+
///
|
|
188
|
+
/// Arguments:
|
|
189
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
190
|
+
/// The model whose fields are to be escaped. Only non-virtual fields are operated upon.
|
|
191
|
+
/// options?: object
|
|
192
|
+
/// Options for the operation.
|
|
193
|
+
/// | Option | Type | Default Value | Description |
|
|
194
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
195
|
+
/// | `asProjection` | `boolean` | `false` | If `true`, then use <see>SQLQueryGeneratorBase.getEscapedProjectionName</see> to escape the model's fields. |
|
|
196
|
+
/// | `asColumn` | `boolean` | `false` | If `true`, then use <see>SQLQueryGeneratorBase.getEscapedColumnName</see> to escape the model's fields. |
|
|
197
|
+
/// | `noProjectionAliases` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the alias for the projection. |
|
|
198
|
+
/// | `columnNameOnly` | `boolean` | `false` | If `true`, then escape only the column name, and don't include the name of the table. |
|
|
199
|
+
/// | `columnNamePrefix` | `string` | `''` | Prefix the column name with this value before escaping it. |
|
|
200
|
+
/// | `tableNamePrefix` | `string` | `''` | Only applicable if `columnNameOnly` is `false`. Used to prefix the table name before escaping it. |
|
|
201
|
+
///
|
|
202
|
+
/// Return: object
|
|
203
|
+
/// Return an object that maps all escaped model fields. Each key will be the fully qualified name of the field,
|
|
204
|
+
/// each value will be the escaped field as a string.
|
|
68
205
|
// eslint-disable-next-line no-unused-vars
|
|
69
|
-
getEscapedModelFields(Model,
|
|
206
|
+
getEscapedModelFields(Model, _options) {
|
|
207
|
+
let options = Object.assign(_options || {}, { as: null });
|
|
70
208
|
let fields = {};
|
|
71
209
|
let modelName = Model.getModelName();
|
|
72
210
|
|
|
@@ -89,10 +227,21 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
89
227
|
return fields;
|
|
90
228
|
}
|
|
91
229
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
230
|
+
/// Get the `ORDER` clause from the provided [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine).
|
|
231
|
+
/// If none is found, then call [Connection.getDefaultOrder](https://github.com/th317erd/mythix-orm/wiki/ConnectionBase#method-getDefaultOrder)
|
|
232
|
+
/// to get the default order for the operation.
|
|
233
|
+
///
|
|
234
|
+
/// Arguments:
|
|
235
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
236
|
+
/// The query engine to fetch the `ORDER` clause from.
|
|
237
|
+
/// options?: object
|
|
238
|
+
/// The options object provided to the operation that is taking place. This isn't used
|
|
239
|
+
/// by this method, but instead is passed off to [Connection.getDefaultOrder](https://github.com/th317erd/mythix-orm/wiki/ConnectionBase#method-getDefaultOrder)
|
|
240
|
+
/// in case the connection (or user) needs the options to produce a default ordering.
|
|
241
|
+
///
|
|
242
|
+
/// Return: Map<string, { value: Field | Literal | string; direction?: '+' | '-'; ... }>
|
|
243
|
+
/// Return the field-set for the default ordering to apply to the operation taking place.
|
|
244
|
+
/// This `Map` should have the same format as is returned by [ModelScope.mergeFields](https://github.com/th317erd/mythix-orm/wiki/ModelScope#method-mergeFields).
|
|
96
245
|
getQueryEngineOrder(queryEngine, _options) {
|
|
97
246
|
let options = _options || {};
|
|
98
247
|
let context = queryEngine.getOperationContext();
|
|
@@ -101,6 +250,35 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
101
250
|
return (order && order.size) ? order : this.connection.getDefaultOrder(context.rootModel, options);
|
|
102
251
|
}
|
|
103
252
|
|
|
253
|
+
/// Get the field projection for the operation taking place.
|
|
254
|
+
///
|
|
255
|
+
/// This will prepare all fields in the projection, along with
|
|
256
|
+
/// any literals, and will also merge any `ORDER BY` clause fields
|
|
257
|
+
/// into the projection. The result will be either a `Map`, containing
|
|
258
|
+
/// all projected fields and literals, or will be an `Array` of just
|
|
259
|
+
/// the projected fields, escaped and prepared for the underlying database.
|
|
260
|
+
/// A `Map` of the fields will be returned instead of an array if the `asMap`
|
|
261
|
+
/// argument is set to `true`.
|
|
262
|
+
///
|
|
263
|
+
/// Arguments:
|
|
264
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
265
|
+
/// The query engine to fetch the field projection (and order) from.
|
|
266
|
+
/// options?: object
|
|
267
|
+
/// Options for the operation. These options aren't used directly by this method,
|
|
268
|
+
/// but instead are passed off to the sub-methods that are called to complete the
|
|
269
|
+
/// operation, such as the `toString` method for literals, the <see>SQLQueryGeneratorBase.getQueryEngineOrder</see>
|
|
270
|
+
/// to get the field ordering, and to the <see>SQLQueryGeneratorBase.getEscapedProjectionName</see> to
|
|
271
|
+
/// project the fields.
|
|
272
|
+
/// asMap: boolean
|
|
273
|
+
/// If `true`, then return a `Map` of the projected fields, instead of an `Array`. This
|
|
274
|
+
/// is used for example internally by `SELECT` operations to know which fields were
|
|
275
|
+
/// projected. Each key in this `Map` is a fully qualified field name (to link the projection
|
|
276
|
+
/// back to its field), or a fully expanded literal string for literals. The value for each
|
|
277
|
+
/// property in this map in the projected field or literal value itself, as a string.
|
|
278
|
+
///
|
|
279
|
+
/// Return: Map<string, string> | Array<string>
|
|
280
|
+
/// A `Map` of the projected fields if the `asMap` argument is `true`, or an `Array` of the
|
|
281
|
+
/// projected fields otherwise.
|
|
104
282
|
getProjectedFields(queryEngine, _options, asMap) {
|
|
105
283
|
let options = this.stackAssign(_options || {}, { isProjection: true });
|
|
106
284
|
let context = queryEngine.getOperationContext();
|
|
@@ -146,6 +324,50 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
146
324
|
return Array.from(allProjectionFields.values());
|
|
147
325
|
}
|
|
148
326
|
|
|
327
|
+
/// Given two "operation contexts" from a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
328
|
+
/// instance, collection the information required to join two tables.
|
|
329
|
+
///
|
|
330
|
+
/// Using the "left side" context of the operation being calculated, find the "root model"
|
|
331
|
+
/// of the query, and compile table-join information with the "right side" context of
|
|
332
|
+
/// the operation, joining the "root model" on the left-side with the model and field specified on
|
|
333
|
+
/// the right-side of the operation.
|
|
334
|
+
///
|
|
335
|
+
/// A table-join looks like `User.where.id.EQ(Role.where.userID)`. In this context, the `User.where.id`
|
|
336
|
+
/// would be the "left side", and `Role.where.userID` would be the "right side".
|
|
337
|
+
///
|
|
338
|
+
/// Interface:
|
|
339
|
+
/// interface TableJoinInformation {
|
|
340
|
+
/// operator: string; // The operator used for the table-join, i.e. "EQ"
|
|
341
|
+
/// joinType: string; // The database specific join-type for the table-join, i.e. "INNER JOIN"
|
|
342
|
+
/// rootModelName: string; // The name of the "root model" for the query
|
|
343
|
+
/// joinModel: class Model; // The the model being joined to the "root model"
|
|
344
|
+
/// joinModelName: string; // The name of the model being joined to the "root model"
|
|
345
|
+
/// leftSideModel: class Model; // The model on the left-side of the table-join
|
|
346
|
+
/// leftSideModelName: string; // The name of the model on the left-side of the table-join
|
|
347
|
+
/// leftQueryContext: object; // The "operation context" of the left-side of the operation
|
|
348
|
+
/// leftSideField: Field; // The field on the left side of the table-join
|
|
349
|
+
/// rightSideModel: class Model; // The model on the right-side of the table-join
|
|
350
|
+
/// rightSideModelName: string; // The model name of the model on the right-side of the table-join
|
|
351
|
+
/// rightQueryContext: object; // The "operation context" of the right-side of the operation
|
|
352
|
+
/// rightSideField: Field; // The field on the right-side of the table-join
|
|
353
|
+
/// }
|
|
354
|
+
///
|
|
355
|
+
/// Arguments:
|
|
356
|
+
/// leftQueryContext: object
|
|
357
|
+
/// The left-side "operation context" of the query engine to compile the "root model" information
|
|
358
|
+
/// from.
|
|
359
|
+
/// rightQueryContext: object
|
|
360
|
+
/// The right-side "operation context" of the query engine to compile the "join model" information
|
|
361
|
+
/// from.
|
|
362
|
+
/// joinType: string
|
|
363
|
+
/// The join-type (LEFT, RIGHT, INNER, CROSS, etc...) for the join-table operation.
|
|
364
|
+
/// options?: object
|
|
365
|
+
/// The options for the operation. These aren't used by default by Mythix ORM, and instead are
|
|
366
|
+
/// provided for the user if the user should overload this method. These will be the options for
|
|
367
|
+
/// the operation taking place (i.e. a `SELECT` operation).
|
|
368
|
+
///
|
|
369
|
+
/// Return: TableJoinInformation
|
|
370
|
+
/// Return an object containing all information needed to generate a table-join query.
|
|
149
371
|
// eslint-disable-next-line no-unused-vars
|
|
150
372
|
getJoinTableInfoFromQueryContexts(leftQueryContext, rightQueryContext, joinType, options) {
|
|
151
373
|
let rootModel = leftQueryContext.rootModel;
|
|
@@ -194,6 +416,30 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
194
416
|
};
|
|
195
417
|
}
|
|
196
418
|
|
|
419
|
+
/// Get an `AS` projection alias for the literal being stringified,
|
|
420
|
+
/// but only if a projection alias is applicable.
|
|
421
|
+
///
|
|
422
|
+
/// If the literal is a "sub-field" (i.e. the `FieldLiteral` in `new CountLiteral(new FieldLiteral(...))`)
|
|
423
|
+
/// then don't return a projection alias (i.e. the alias needs to be on `CountLiteral` in this example, not
|
|
424
|
+
/// on the sub-field `FieldLiteral`).
|
|
425
|
+
///
|
|
426
|
+
/// Also don't return an alias if the `noProjectionAliases` `options` is set to `true`. This might
|
|
427
|
+
/// be the case for example if we are "projecting" the literal for an `ORDER BY` clause.
|
|
428
|
+
///
|
|
429
|
+
/// Arguments:
|
|
430
|
+
/// literal: inherits from [LiteralBase](https://github.com/th317erd/mythix-orm/wiki/LiteralBase)
|
|
431
|
+
/// The literal that is being stringified.
|
|
432
|
+
/// options?: object
|
|
433
|
+
/// Options for the operation.
|
|
434
|
+
/// | Option | Type | Default Value | Description |
|
|
435
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
436
|
+
/// | `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. |
|
|
437
|
+
/// | `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. |
|
|
438
|
+
/// | `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. |
|
|
439
|
+
///
|
|
440
|
+
/// Return: string
|
|
441
|
+
/// An empty string if a field alias isn't allowed, or an ` AS ...` postfix string
|
|
442
|
+
/// to apply to the stringified `literal` provided if an alias is allowed and requested.
|
|
197
443
|
_getLiteralAlias(literal, options) {
|
|
198
444
|
if (options && options.isSubField)
|
|
199
445
|
return '';
|
|
@@ -208,6 +454,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
208
454
|
return ` AS ${this.escapeID(as)}`;
|
|
209
455
|
}
|
|
210
456
|
|
|
457
|
+
/// Convert an [AverageLiteral](https://github.com/th317erd/mythix-orm/wiki/AverageLiteral) to
|
|
458
|
+
/// a string for use in the underlying database.
|
|
459
|
+
///
|
|
460
|
+
/// Arguments:
|
|
461
|
+
/// literal: [AverageLiteral](https://github.com/th317erd/mythix-orm/wiki/AverageLiteral)
|
|
462
|
+
/// The [AverageLiteral](https://github.com/th317erd/mythix-orm/wiki/AverageLiteral) to stringify.
|
|
463
|
+
/// options?: object
|
|
464
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
465
|
+
/// literal or connection specific options that can be supplied.
|
|
466
|
+
/// | Option | Type | Default Value | Description |
|
|
467
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
468
|
+
/// | `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. |
|
|
469
|
+
/// | `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. |
|
|
470
|
+
/// | `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. |
|
|
471
|
+
///
|
|
472
|
+
/// Return: string
|
|
473
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
211
474
|
_averageLiteralToString(literal, options) {
|
|
212
475
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
213
476
|
return;
|
|
@@ -223,6 +486,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
223
486
|
return `AVG(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
224
487
|
}
|
|
225
488
|
|
|
489
|
+
/// Convert an [CountLiteral](https://github.com/th317erd/mythix-orm/wiki/CountLiteral) to
|
|
490
|
+
/// a string for use in the underlying database.
|
|
491
|
+
///
|
|
492
|
+
/// Arguments:
|
|
493
|
+
/// literal: [CountLiteral](https://github.com/th317erd/mythix-orm/wiki/CountLiteral)
|
|
494
|
+
/// The [CountLiteral](https://github.com/th317erd/mythix-orm/wiki/CountLiteral) to stringify.
|
|
495
|
+
/// options?: object
|
|
496
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
497
|
+
/// literal or connection specific options that can be supplied.
|
|
498
|
+
/// | Option | Type | Default Value | Description |
|
|
499
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
500
|
+
/// | `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. |
|
|
501
|
+
/// | `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. |
|
|
502
|
+
/// | `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. |
|
|
503
|
+
///
|
|
504
|
+
/// Return: string
|
|
505
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
226
506
|
_countLiteralToString(literal, options) {
|
|
227
507
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
228
508
|
return;
|
|
@@ -242,6 +522,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
242
522
|
return `COUNT(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
243
523
|
}
|
|
244
524
|
|
|
525
|
+
/// Convert an [DistinctLiteral](https://github.com/th317erd/mythix-orm/wiki/DistinctLiteral) to
|
|
526
|
+
/// a string for use in the underlying database.
|
|
527
|
+
///
|
|
528
|
+
/// Arguments:
|
|
529
|
+
/// literal: [DistinctLiteral](https://github.com/th317erd/mythix-orm/wiki/DistinctLiteral)
|
|
530
|
+
/// The [DistinctLiteral](https://github.com/th317erd/mythix-orm/wiki/DistinctLiteral) to stringify.
|
|
531
|
+
/// options?: object
|
|
532
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
533
|
+
/// literal or connection specific options that can be supplied.
|
|
534
|
+
/// | Option | Type | Default Value | Description |
|
|
535
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
536
|
+
/// | `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. |
|
|
537
|
+
/// | `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. |
|
|
538
|
+
/// | `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. |
|
|
539
|
+
///
|
|
540
|
+
/// Return: string
|
|
541
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
245
542
|
_distinctLiteralToString(literal, options) {
|
|
246
543
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
247
544
|
return;
|
|
@@ -271,6 +568,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
271
568
|
return `DISTINCT ON(${escapedColumnName})`;
|
|
272
569
|
}
|
|
273
570
|
|
|
571
|
+
/// Convert an [FieldLiteral](https://github.com/th317erd/mythix-orm/wiki/FieldLiteral) to
|
|
572
|
+
/// a string for use in the underlying database.
|
|
573
|
+
///
|
|
574
|
+
/// Arguments:
|
|
575
|
+
/// literal: [FieldLiteral](https://github.com/th317erd/mythix-orm/wiki/FieldLiteral)
|
|
576
|
+
/// The [FieldLiteral](https://github.com/th317erd/mythix-orm/wiki/FieldLiteral) to stringify.
|
|
577
|
+
/// options?: object
|
|
578
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
579
|
+
/// literal or connection specific options that can be supplied.
|
|
580
|
+
/// | Option | Type | Default Value | Description |
|
|
581
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
582
|
+
/// | `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. |
|
|
583
|
+
/// | `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. |
|
|
584
|
+
/// | `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. |
|
|
585
|
+
///
|
|
586
|
+
/// Return: string
|
|
587
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
274
588
|
_fieldLiteralToString(literal, options) {
|
|
275
589
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
276
590
|
return;
|
|
@@ -283,6 +597,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
283
597
|
return this.getEscapedProjectionName(field.Model, field, this.stackAssign(options, { noProjectionAliases }, literal.options));
|
|
284
598
|
}
|
|
285
599
|
|
|
600
|
+
/// Convert an [MaxLiteral](https://github.com/th317erd/mythix-orm/wiki/MaxLiteral) to
|
|
601
|
+
/// a string for use in the underlying database.
|
|
602
|
+
///
|
|
603
|
+
/// Arguments:
|
|
604
|
+
/// literal: [MaxLiteral](https://github.com/th317erd/mythix-orm/wiki/MaxLiteral)
|
|
605
|
+
/// The [MaxLiteral](https://github.com/th317erd/mythix-orm/wiki/MaxLiteral) to stringify.
|
|
606
|
+
/// options?: object
|
|
607
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
608
|
+
/// literal or connection specific options that can be supplied.
|
|
609
|
+
/// | Option | Type | Default Value | Description |
|
|
610
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
611
|
+
/// | `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. |
|
|
612
|
+
/// | `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. |
|
|
613
|
+
/// | `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. |
|
|
614
|
+
///
|
|
615
|
+
/// Return: string
|
|
616
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
286
617
|
_maxLiteralToString(literal, options) {
|
|
287
618
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
288
619
|
return;
|
|
@@ -298,6 +629,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
298
629
|
return `MAX(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
299
630
|
}
|
|
300
631
|
|
|
632
|
+
/// Convert an [MinLiteral](https://github.com/th317erd/mythix-orm/wiki/MinLiteral) to
|
|
633
|
+
/// a string for use in the underlying database.
|
|
634
|
+
///
|
|
635
|
+
/// Arguments:
|
|
636
|
+
/// literal: [MinLiteral](https://github.com/th317erd/mythix-orm/wiki/MinLiteral)
|
|
637
|
+
/// The [MinLiteral](https://github.com/th317erd/mythix-orm/wiki/MinLiteral) to stringify.
|
|
638
|
+
/// options?: object
|
|
639
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
640
|
+
/// literal or connection specific options that can be supplied.
|
|
641
|
+
/// | Option | Type | Default Value | Description |
|
|
642
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
643
|
+
/// | `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. |
|
|
644
|
+
/// | `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. |
|
|
645
|
+
/// | `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. |
|
|
646
|
+
///
|
|
647
|
+
/// Return: string
|
|
648
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
301
649
|
_minLiteralToString(literal, options) {
|
|
302
650
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
303
651
|
return;
|
|
@@ -313,6 +661,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
313
661
|
return `MIN(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
314
662
|
}
|
|
315
663
|
|
|
664
|
+
/// Convert an [SumLiteral](https://github.com/th317erd/mythix-orm/wiki/SumLiteral) to
|
|
665
|
+
/// a string for use in the underlying database.
|
|
666
|
+
///
|
|
667
|
+
/// Arguments:
|
|
668
|
+
/// literal: [SumLiteral](https://github.com/th317erd/mythix-orm/wiki/SumLiteral)
|
|
669
|
+
/// The [SumLiteral](https://github.com/th317erd/mythix-orm/wiki/SumLiteral) to stringify.
|
|
670
|
+
/// options?: object
|
|
671
|
+
/// Options for the operation. Listed below are the common options for all literals. There may also be
|
|
672
|
+
/// literal or connection specific options that can be supplied.
|
|
673
|
+
/// | Option | Type | Default Value | Description |
|
|
674
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
675
|
+
/// | `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. |
|
|
676
|
+
/// | `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. |
|
|
677
|
+
/// | `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. |
|
|
678
|
+
///
|
|
679
|
+
/// Return: string
|
|
680
|
+
/// The literal provided, stringified for use in the underlying database.
|
|
316
681
|
_sumLiteralToString(literal, options) {
|
|
317
682
|
if (!literal || !LiteralBase.isLiteral(literal))
|
|
318
683
|
return;
|
|
@@ -328,106 +693,86 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
328
693
|
return `SUM(${escapedColumnName})${this._getLiteralAlias(literal, options)}`;
|
|
329
694
|
}
|
|
330
695
|
|
|
696
|
+
/// A convenience method that proxies to <see>SQLConnectionBase.prepareArrayValuesForSQL</see>.
|
|
697
|
+
///
|
|
698
|
+
/// See: SQLConnectionBase.prepareArrayValuesForSQL
|
|
331
699
|
prepareArrayValuesForSQL(array) {
|
|
332
700
|
return this.connection.prepareArrayValuesForSQL(array);
|
|
333
701
|
}
|
|
334
702
|
|
|
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
|
-
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
modelName = field.Model.getModelName();
|
|
366
|
-
fieldName = field.fieldName;
|
|
367
|
-
|
|
368
|
-
stop();
|
|
369
|
-
});
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
if (getRawField && projectionField)
|
|
373
|
-
return projectionField;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if (getRawField && modelName && fieldName) {
|
|
377
|
-
let field = this.connection.getField(fieldName, modelName);
|
|
378
|
-
if (field)
|
|
379
|
-
return field;
|
|
380
|
-
} else if (!modelName || !fieldName) {
|
|
381
|
-
return str;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
return `${modelName}:${fieldName}`;
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
parseFieldProjectionToFieldMap(selectStatement) {
|
|
388
|
-
let firstPart = selectStatement.replace(/[\r\n]/g, ' ').split(/\s+FROM\s+/i)[0].replace(/^SELECT\s+/i, '').trim();
|
|
389
|
-
let fieldParts = firstPart.split(',');
|
|
390
|
-
let projectionFieldMap = new Map();
|
|
391
|
-
|
|
392
|
-
for (let i = 0, il = fieldParts.length; i < il; i++) {
|
|
393
|
-
let fieldPart = fieldParts[i].trim();
|
|
394
|
-
let field = this.parseFieldProjection(fieldPart, true);
|
|
395
|
-
|
|
396
|
-
if (field !== fieldPart)
|
|
397
|
-
projectionFieldMap.set(`${field.Model.getModelName()}:${field.fieldName}`, this.getEscapedProjectionName(field.Model, field));
|
|
398
|
-
else
|
|
399
|
-
projectionFieldMap.set(field, field);
|
|
400
|
-
|
|
401
|
-
// If this isn't a field, then add it
|
|
402
|
-
if (!this.isFieldIdentifier(fieldPart))
|
|
403
|
-
projectionFieldMap.set(fieldPart, fieldPart);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return projectionFieldMap;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
generateSelectQueryFieldProjection(queryEngine, options, asMap) {
|
|
410
|
-
let projectedFields = this.getProjectedFields(queryEngine, options, asMap);
|
|
411
|
-
|
|
412
|
-
if (asMap === true) {
|
|
413
|
-
return projectedFields;
|
|
414
|
-
} else {
|
|
415
|
-
let projectedFieldList = Array.from(projectedFields.values()).join(',');
|
|
416
|
-
|
|
417
|
-
let distinct = queryEngine.getOperationContext().distinct;
|
|
418
|
-
if (distinct) {
|
|
419
|
-
let result = distinct.toString(this.connection, { isProjection: true });
|
|
420
|
-
return `${result} ${projectedFieldList}`;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
return projectedFieldList;
|
|
703
|
+
/// Generate a field projection for a `SELECT` statement.
|
|
704
|
+
/// If a `DISTINCT` operation is in-use, then this will always
|
|
705
|
+
/// prefix any and all fields projected.
|
|
706
|
+
///
|
|
707
|
+
/// Arguments:
|
|
708
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
709
|
+
/// The query engine to use to generate the field projection from.
|
|
710
|
+
/// options?: object
|
|
711
|
+
/// Options that are passed through the operation. These options are
|
|
712
|
+
/// simply passed to all other sub-methods used in this operation, including
|
|
713
|
+
/// when stringifying literals.
|
|
714
|
+
/// projectedFields?: Map<string, string>
|
|
715
|
+
/// Provide the projected fields if they are already known, instead of compiling them
|
|
716
|
+
/// again via a call to <see>SQLQueryGeneratorBase.getProjectedFields</see>.
|
|
717
|
+
///
|
|
718
|
+
/// Return: string
|
|
719
|
+
/// Return a comma-separated list of projected fields. If any `DISTINCT`
|
|
720
|
+
/// clause is set on the `queryEngine`, then that will always come first
|
|
721
|
+
/// in the list of projected fields.
|
|
722
|
+
generateSelectQueryFieldProjection(queryEngine, options, _projectedFields) {
|
|
723
|
+
let projectedFields = (_projectedFields) ? _projectedFields : this.getProjectedFields(queryEngine, options, false);
|
|
724
|
+
let projectedFieldList = Array.from(projectedFields.values()).join(',');
|
|
725
|
+
|
|
726
|
+
let distinct = queryEngine.getOperationContext().distinct;
|
|
727
|
+
if (distinct) {
|
|
728
|
+
let result = distinct.toString(this.connection, { isProjection: true });
|
|
729
|
+
return `${result} ${projectedFieldList}`;
|
|
424
730
|
}
|
|
425
|
-
}
|
|
426
731
|
|
|
427
|
-
|
|
732
|
+
return projectedFieldList;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/// Convert a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) conditional
|
|
736
|
+
/// operator into the equivalent SQL conditional operator. For example, `EQ` will be converted
|
|
737
|
+
/// to `=` for most values, `IS` (in the case of `null`, `true`, and `false`), or an `IN` operator
|
|
738
|
+
/// if an array of values is provided.
|
|
739
|
+
///
|
|
740
|
+
/// If a literal is provided, then it will be converted to a string using the literal's `toString`
|
|
741
|
+
/// method and returned.
|
|
742
|
+
///
|
|
743
|
+
/// Standard conversion table for most SQL connections (results might differ based on the SQL
|
|
744
|
+
/// connection being used):
|
|
745
|
+
/// | `QueryEngine` Operator | `Array<any>` | `null` | `true` | `false` | Table Join | Other |
|
|
746
|
+
/// | -------------------- | ------------ | ------ | ------ | ------- | ---------- | ----- |
|
|
747
|
+
/// | `EQ` | `IN` | `IS NULL` | `IS TRUE` | `IS FALSE` | `=` | `=` |
|
|
748
|
+
/// | `NEQ` | `NOT IN` | `IS NOT NULL` | `IS NOT TRUE` | `IS NOT FALSE` | `!=` | `!=` |
|
|
749
|
+
/// | `GT` | `throw TypeError` | `>` | `>` | `>` | `>` | `>` |
|
|
750
|
+
/// | `GTE` | `throw TypeError` | `>=` | `>=` | `>=` | `>=` | `>=` |
|
|
751
|
+
/// | `LT` | `throw TypeError` | `<` | `<` | `<` | `<` | `<` |
|
|
752
|
+
/// | `LTE` | `throw TypeError` | `<=` | `<=` | `<=` | `<=` | `<=` |
|
|
753
|
+
/// | `LIKE` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `LIKE` |
|
|
754
|
+
/// | `NOT_LIKE` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `throw TypeError` | `NOT LIKE` |
|
|
755
|
+
///
|
|
756
|
+
/// Arguments:
|
|
757
|
+
/// queryPart: object
|
|
758
|
+
/// The `QueryEngine` "operation frame" for this conditional operation.
|
|
759
|
+
/// operator: string | Literal
|
|
760
|
+
/// The `QueryEngine` operator to convert to SQL syntax. If a literal is provided,
|
|
761
|
+
/// then it will simply be stringified and returned (as the literal operator the user
|
|
762
|
+
/// specified... whatever that might be).
|
|
763
|
+
/// value: any
|
|
764
|
+
/// The right-hand-side value for this conditional operator.
|
|
765
|
+
/// valueIsReference: boolean
|
|
766
|
+
/// If `true`, then this operator is being converted for a table-join operation. If this is
|
|
767
|
+
/// the case, then `value` will be the "operation context" for the right-side of the table-join.
|
|
768
|
+
/// options?: object
|
|
769
|
+
/// Options for the operation. This is only used by this method for converting provided literals to strings.
|
|
770
|
+
///
|
|
771
|
+
/// Return: string
|
|
772
|
+
/// Return SQL syntax for this context-specific conditional operator.
|
|
428
773
|
generateSelectQueryOperatorFromQueryEngineOperator(queryPart, operator, value, valueIsReference, options) {
|
|
429
774
|
if (LiteralBase.isLiteral(operator))
|
|
430
|
-
return operator.toString(this.connection);
|
|
775
|
+
return operator.toString(this.connection, options);
|
|
431
776
|
|
|
432
777
|
switch (operator) {
|
|
433
778
|
case 'EQ':
|
|
@@ -451,12 +796,24 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
451
796
|
else
|
|
452
797
|
return '!=';
|
|
453
798
|
case 'GT':
|
|
799
|
+
if (Array.isArray(value))
|
|
800
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "GT" (greater than) operator.`);
|
|
801
|
+
|
|
454
802
|
return '>';
|
|
455
803
|
case 'GTE':
|
|
804
|
+
if (Array.isArray(value))
|
|
805
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "GTE" (greater than or equal to) operator.`);
|
|
806
|
+
|
|
456
807
|
return '>=';
|
|
457
808
|
case 'LT':
|
|
809
|
+
if (Array.isArray(value))
|
|
810
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "LT" (less than) operator.`);
|
|
811
|
+
|
|
458
812
|
return '<';
|
|
459
813
|
case 'LTE':
|
|
814
|
+
if (Array.isArray(value))
|
|
815
|
+
throw new TypeError(`${this.constructor.name}::generateSelectQueryOperatorFromQueryEngineOperator: Array of values provided to "LTE" (less than or equal to) operator.`);
|
|
816
|
+
|
|
460
817
|
return '<=';
|
|
461
818
|
case 'LIKE':
|
|
462
819
|
if (valueIsReference)
|
|
@@ -479,15 +836,89 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
479
836
|
}
|
|
480
837
|
}
|
|
481
838
|
|
|
839
|
+
/// Format a `LIKE` or `NOT LIKE` value.
|
|
840
|
+
///
|
|
841
|
+
/// Mythix ORM requires that `%` and `_` characters be used for
|
|
842
|
+
/// wildcard characters in `LIKE` and `NOT_LIKE` operations. This is to
|
|
843
|
+
/// create a unified standard for `LIKE` operations across databases.
|
|
844
|
+
/// If the underlying database uses different wildcard characters for
|
|
845
|
+
/// a `LIKE` operation, then it is required to convert them to its native
|
|
846
|
+
/// format here in this method.
|
|
847
|
+
///
|
|
848
|
+
/// Interface:
|
|
849
|
+
/// interface QueryConditionContext {
|
|
850
|
+
/// queryPart: object; // The "operation frame" or "operation context" for this condition
|
|
851
|
+
/// field: Field; // The field for this conditional operator
|
|
852
|
+
/// sqlOperator: string; // The SQL operator that matches "operator" in the given context
|
|
853
|
+
/// operator: string; // The QueryEngine operator for this condition, i.e. "EQ"
|
|
854
|
+
/// value: any; // The conditional operator's value (right-hand-side value)
|
|
855
|
+
/// }
|
|
856
|
+
///
|
|
857
|
+
/// Arguments:
|
|
858
|
+
/// context: QueryConditionContext
|
|
859
|
+
/// The "conditional operator" context for this `LIKE` or `NOT LIKE` condition.
|
|
860
|
+
///
|
|
861
|
+
/// Return: string
|
|
862
|
+
/// By default simply return `context.value`. Other database drivers may
|
|
863
|
+
/// format `context.value` before returning it, in a format suitable for
|
|
864
|
+
/// the underlying database.
|
|
482
865
|
formatLikeValue({ value }) {
|
|
483
866
|
return value;
|
|
484
867
|
}
|
|
485
868
|
|
|
869
|
+
/// Generate an optional postfix for any given conditional operator.
|
|
870
|
+
///
|
|
871
|
+
/// This might be used by any given underlying database should it need
|
|
872
|
+
/// it. It is most commonly used by `LIKE` conditional operators to tag
|
|
873
|
+
/// on an `ESCAPE` clause, specifying the escape character for the `LIKE`
|
|
874
|
+
/// operator. However, it may be used for any operator where the database
|
|
875
|
+
/// needs a "postfix" for the condition.
|
|
876
|
+
///
|
|
877
|
+
/// Interface:
|
|
878
|
+
/// interface QueryConditionContext {
|
|
879
|
+
/// queryPart: object; // The "operation frame" or "operation context" for this condition
|
|
880
|
+
/// field: Field; // The field for this conditional operator
|
|
881
|
+
/// sqlOperator: string; // The SQL operator that matches "operator" in the given context
|
|
882
|
+
/// operator: string; // The QueryEngine operator for this condition, i.e. "EQ"
|
|
883
|
+
/// value: any; // The conditional operator's value (right-hand-side value)
|
|
884
|
+
/// }
|
|
885
|
+
///
|
|
886
|
+
/// Arguments:
|
|
887
|
+
/// context: QueryConditionContext
|
|
888
|
+
/// The "conditional operator" context for the current operator being generated.
|
|
889
|
+
///
|
|
890
|
+
/// Return: string
|
|
891
|
+
/// By default, simply return an empty string, meaning that there is no postfix
|
|
892
|
+
/// for the condition being generated. Optionally, the database driver can return any postfix
|
|
893
|
+
/// for the conditional operator being generated.
|
|
486
894
|
// eslint-disable-next-line no-unused-vars
|
|
487
895
|
generateConditionPostfix(context) {
|
|
488
896
|
return '';
|
|
489
897
|
}
|
|
490
898
|
|
|
899
|
+
/// Generate a SQL "conditional operator" for a `WHERE` clause.
|
|
900
|
+
///
|
|
901
|
+
/// Even though this is generally used for `SELECT` statements, it
|
|
902
|
+
/// may also be used for `UPDATE WHERE ...`, or `DELETE WHERE ...`
|
|
903
|
+
/// statements as well.
|
|
904
|
+
///
|
|
905
|
+
/// This method should return a fully formatted "conditional" statement
|
|
906
|
+
/// for the query's `WHERE` clause.
|
|
907
|
+
///
|
|
908
|
+
/// Arguments:
|
|
909
|
+
/// queryPart: object
|
|
910
|
+
/// The "operation frame" or "operation context" of the conditional
|
|
911
|
+
/// operation as found on the `QueryEngine` being used to generate the
|
|
912
|
+
/// query.
|
|
913
|
+
/// value: any
|
|
914
|
+
/// The value (right-hand-side) of the conditional operator being generated.
|
|
915
|
+
/// options?: object
|
|
916
|
+
/// Options for the current database operation.
|
|
917
|
+
///
|
|
918
|
+
/// Return: string
|
|
919
|
+
/// A fully formatted SQL conditional statement. This may be an `EXISTS`,
|
|
920
|
+
/// an `ANY` or `ALL`, an `IN`, or some other valid condition for the query.
|
|
921
|
+
/// i.e. `"users"."id" = 1`.
|
|
491
922
|
generateSelectQueryCondition(queryPart, _value, options) {
|
|
492
923
|
let value = _value;
|
|
493
924
|
let field = queryPart.Field;
|
|
@@ -566,7 +997,24 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
566
997
|
return `${escapedColumnName} ${sqlOperator} ${this.escape(field, value)}${(conditionPostfix) ? ` ${conditionPostfix}` : ''}`;
|
|
567
998
|
}
|
|
568
999
|
|
|
569
|
-
|
|
1000
|
+
/// Generate a table join statement, such as
|
|
1001
|
+
/// `INNER JOIN "table_name"`, or a `FROM` statement
|
|
1002
|
+
/// if `joinType` is falsy, such as `FROM "table_name"`.
|
|
1003
|
+
///
|
|
1004
|
+
/// Arguments:
|
|
1005
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1006
|
+
/// The model that defines the table for the operation.
|
|
1007
|
+
/// joinType: string | null
|
|
1008
|
+
/// If a falsy value, then generate a `FROM "table_name"` statement, using
|
|
1009
|
+
/// the provided `Model` to know the table name. If a string, then this will
|
|
1010
|
+
/// be a join-type, such as `INNER JOIN`, which will be used instead of `FROM`,
|
|
1011
|
+
/// i.e. `INNER JOIN "table_name"`.
|
|
1012
|
+
/// options?: object
|
|
1013
|
+
/// Options to provide to <see>SQLQueryGeneratorBase.getEscapedTableName</see> for the operation.
|
|
1014
|
+
///
|
|
1015
|
+
/// Return: string
|
|
1016
|
+
/// A `FROM "table_name"` statement, or a table join statement, such as
|
|
1017
|
+
/// `INNER JOIN "table_name"`.
|
|
570
1018
|
generateFromTableOrTableJoin(Model, _joinType, options) {
|
|
571
1019
|
if (!Model)
|
|
572
1020
|
throw new Error(`${this.constructor.name}::generateFromTableOrTableJoin: No valid model provided.`);
|
|
@@ -579,14 +1027,63 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
579
1027
|
return (joinType) ? `${joinType} ${escapedTableName}` : `FROM ${escapedTableName}`;
|
|
580
1028
|
}
|
|
581
1029
|
|
|
1030
|
+
/// Given a table-join query operation, such as `User.where.id.EQ(Role.where.userID)`,
|
|
1031
|
+
/// generate the table-join statement.
|
|
1032
|
+
///
|
|
1033
|
+
/// Continuing with the example provided, this would generate the following SQL,
|
|
1034
|
+
/// `"users"."id" = "roles"."userID"`.
|
|
1035
|
+
///
|
|
1036
|
+
/// Arguments:
|
|
1037
|
+
/// leftQueryPart: object
|
|
1038
|
+
/// The "operation frame" or "operation context" for the left-side of the statement.
|
|
1039
|
+
/// In this example this would be the `EQ` "operation context" of `User.where.id.EQ`.
|
|
1040
|
+
/// rightQueryPart: object
|
|
1041
|
+
/// The "operation frame" or "operation context" for the right-side of the statement.
|
|
1042
|
+
/// In this example this would be the `userID` "operation context" of `Role.where.userID`.
|
|
1043
|
+
/// leftField: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
1044
|
+
/// The left-hand side field for the condition. In this example this would be `User.fields.id`.
|
|
1045
|
+
/// rightField: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
1046
|
+
/// The right-hand side field for the condition. In this example this would be `Role.fields.userID`.
|
|
1047
|
+
/// operator: string
|
|
1048
|
+
/// The [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) operator to join the
|
|
1049
|
+
/// table columns on... i.e. `EQ`. This will be passed through <see>SQLQueryGeneratorBase.generateSelectQueryOperatorFromQueryEngineOperator</see>
|
|
1050
|
+
/// to get the related SQL operator for the condition.
|
|
1051
|
+
/// options?: object
|
|
1052
|
+
/// Options for the operation.
|
|
1053
|
+
///
|
|
1054
|
+
/// Return: string
|
|
1055
|
+
/// Return the table-join condition, i.e. `"users"."id" = "roles"."userID"`.
|
|
582
1056
|
generateSelectJoinOnTableQueryCondition(leftQueryPart, rightQueryPart, leftField, rightField, operator, options) {
|
|
583
1057
|
let leftSideEscapedColumnName = this.getEscapedColumnName(leftField.Model, leftField, options);
|
|
584
1058
|
let rightSideEscapedColumnName = this.getEscapedColumnName(rightField.Model, rightField, options);
|
|
585
|
-
let sqlOperator = this.generateSelectQueryOperatorFromQueryEngineOperator(leftQueryPart, operator,
|
|
1059
|
+
let sqlOperator = this.generateSelectQueryOperatorFromQueryEngineOperator(leftQueryPart, operator, rightQueryPart, true, options);
|
|
586
1060
|
|
|
587
1061
|
return `${leftSideEscapedColumnName} ${sqlOperator} ${rightSideEscapedColumnName}`;
|
|
588
1062
|
}
|
|
589
1063
|
|
|
1064
|
+
/// Take the join table information from a call to
|
|
1065
|
+
/// <see>SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts</see>
|
|
1066
|
+
/// and generate all table-join conditions for the two
|
|
1067
|
+
/// tables being joined.
|
|
1068
|
+
///
|
|
1069
|
+
/// The will generate one or more conditions for the table-join,
|
|
1070
|
+
/// using `AND` or `OR` to combine the conditions.
|
|
1071
|
+
/// For example, this might generate the following SQL code:
|
|
1072
|
+
/// `INNER JOIN "roles" ON "users"."id" = "roles"."userID" OR "users"."fullName" = "roles"."userFullName"`.
|
|
1073
|
+
///
|
|
1074
|
+
/// Arguments:
|
|
1075
|
+
/// joinInfos: Array<TableJoinInformation>
|
|
1076
|
+
/// All collected table-join information for joining tables. The join table
|
|
1077
|
+
/// information at index zero `joinInfos[0]` is the table being joined against,
|
|
1078
|
+
/// which is commonly the "root model" of the query... but it doesn't have to be.
|
|
1079
|
+
/// options?: object
|
|
1080
|
+
/// Options for the operation.
|
|
1081
|
+
///
|
|
1082
|
+
/// Return: string
|
|
1083
|
+
/// The full list of conditions for joining the tables together, i.e.
|
|
1084
|
+
/// `INNER JOIN "roles" ON "users"."id" = "roles"."userID" OR "users"."fullName" = "roles"."userFullName"`.
|
|
1085
|
+
///
|
|
1086
|
+
/// See: SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts
|
|
590
1087
|
generateJoinOnTableQueryConditions(joinInfos, options) {
|
|
591
1088
|
if (Nife.isEmpty(joinInfos))
|
|
592
1089
|
return '';
|
|
@@ -609,7 +1106,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
609
1106
|
return sqlParts.join(' ');
|
|
610
1107
|
}
|
|
611
1108
|
|
|
612
|
-
|
|
1109
|
+
/// Take a join type from a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1110
|
+
/// instance, and convert it to the proper join type for the underlying database.
|
|
1111
|
+
///
|
|
1112
|
+
/// Arguments:
|
|
1113
|
+
/// joinType: string
|
|
1114
|
+
/// The join type, as specified by the [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine). This
|
|
1115
|
+
/// will generally be one of `'inner'`, `'left'`, `'right'`, `'full'`, or `'cross'`, but
|
|
1116
|
+
/// it might also be a user-defined table join type (in which case is is expected to already
|
|
1117
|
+
/// be in the correct format for the underlying database).
|
|
1118
|
+
/// outer: boolean
|
|
1119
|
+
/// If `true`, then this is an "outer join", instead of an "inner join". i.e. a `'left'` join
|
|
1120
|
+
/// type would be converted to a `LEFT OUTER JOIN` instead of a `LEFT INNER JOIN`.
|
|
1121
|
+
/// options?: object
|
|
1122
|
+
/// Options for the operation.
|
|
1123
|
+
///
|
|
1124
|
+
/// Return: string
|
|
1125
|
+
/// The SQL join type, used to join tables. i.e. `LEFT JOIN`.
|
|
613
1126
|
// eslint-disable-next-line no-unused-vars
|
|
614
1127
|
generateSQLJoinTypeFromQueryEngineJoinType(joinType, outer, options) {
|
|
615
1128
|
if (!joinType || joinType === 'inner')
|
|
@@ -626,6 +1139,32 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
626
1139
|
return joinType;
|
|
627
1140
|
}
|
|
628
1141
|
|
|
1142
|
+
/// Sort the table joins into a predictable order.
|
|
1143
|
+
///
|
|
1144
|
+
/// Since table-join operations can exist anywhere in a query,
|
|
1145
|
+
/// this will take all table-join operations for the query, and
|
|
1146
|
+
/// sort them so that they are in a predictable order.
|
|
1147
|
+
/// By default the order will be in "dependency order", so if for
|
|
1148
|
+
/// example there is a join against the `Role` table, and the `Role`
|
|
1149
|
+
/// table "depends on" the `User` table, then the `Role` table will
|
|
1150
|
+
/// come first in the list of table joins.
|
|
1151
|
+
///
|
|
1152
|
+
/// Why sort the table joins at all? Mythix ORM always does its best to
|
|
1153
|
+
/// keep all queries consistent, if for no other reason than for caching
|
|
1154
|
+
/// purposes (so the query itself can be used as a cache key).
|
|
1155
|
+
///
|
|
1156
|
+
/// Arguments:
|
|
1157
|
+
/// joins: Map<string, Array<TableJoinInformation>>
|
|
1158
|
+
/// A map of all table-joins taking place. Each key in this map is the name
|
|
1159
|
+
/// of a model being joined. Each value is an array of `TableJoinInformation`
|
|
1160
|
+
/// that defines how two tables will be joined to each other. This array is
|
|
1161
|
+
/// what is sorted with this operation.
|
|
1162
|
+
///
|
|
1163
|
+
/// Return: Array<string>
|
|
1164
|
+
/// An array of model names, sorted in order, used as "ordered keys"
|
|
1165
|
+
/// into the provided `Map` to generate the table-joins for the query.
|
|
1166
|
+
///
|
|
1167
|
+
/// See: SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts
|
|
629
1168
|
sortJoinRelationOrder(joins) {
|
|
630
1169
|
let modelNames = Array.from(joins.keys());
|
|
631
1170
|
|
|
@@ -647,6 +1186,22 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
647
1186
|
});
|
|
648
1187
|
}
|
|
649
1188
|
|
|
1189
|
+
/// Generate the SQL syntax needed to join all tables in the operation.
|
|
1190
|
+
///
|
|
1191
|
+
/// For example, this might generate the following SQL
|
|
1192
|
+
/// `INNER JOIN "roles" ON "users"."id" = "roles"."userID" RIGHT JOIN "organizations" ON "organization"."id" = "roles"."organizationID"`.
|
|
1193
|
+
///
|
|
1194
|
+
/// Arguments:
|
|
1195
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1196
|
+
/// The query engine to pull table-join operations from.
|
|
1197
|
+
/// options?: object
|
|
1198
|
+
/// Options for the operation.
|
|
1199
|
+
///
|
|
1200
|
+
/// Return: string
|
|
1201
|
+
/// A complete join of all tables in the operation that are being joined, including
|
|
1202
|
+
/// the conditions used to join each table.
|
|
1203
|
+
///
|
|
1204
|
+
/// See: SQLQueryGeneratorBase.getJoinTableInfoFromQueryContexts
|
|
650
1205
|
generateSelectQueryJoinTables(queryEngine, options) {
|
|
651
1206
|
const addToJoins = (joinInfo) => {
|
|
652
1207
|
let items = joins.get(joinInfo.joinModelName);
|
|
@@ -697,6 +1252,33 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
697
1252
|
return sqlParts.join(' ');
|
|
698
1253
|
}
|
|
699
1254
|
|
|
1255
|
+
/// Generate all `WHERE` conditions using the provided
|
|
1256
|
+
/// [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine).
|
|
1257
|
+
///
|
|
1258
|
+
/// This will take all conditional operations defined by the query engine,
|
|
1259
|
+
/// and generate a full `WHERE` condition, `AND`ing or `OR`ing all conditions
|
|
1260
|
+
/// together, including grouping and sub-grouping conditions where needed.
|
|
1261
|
+
///
|
|
1262
|
+
/// Note:
|
|
1263
|
+
/// This method can be recursively called if a sub-query is encountered that
|
|
1264
|
+
/// also has `WHERE` conditions.
|
|
1265
|
+
///
|
|
1266
|
+
/// Note:
|
|
1267
|
+
/// Even though this method's name implies generating `WHERE` conditions for a `SELECT`
|
|
1268
|
+
/// statement, it is also used for non-SELECT statements, such as `UPDATE WHERE ...`,
|
|
1269
|
+
/// and `DELETE WHERE ...`.
|
|
1270
|
+
///
|
|
1271
|
+
/// Arguments:
|
|
1272
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1273
|
+
/// The query engine to pull conditions from.
|
|
1274
|
+
/// options?: object
|
|
1275
|
+
/// Options for the operation.
|
|
1276
|
+
///
|
|
1277
|
+
/// Return: string
|
|
1278
|
+
/// All SQL conditional operators for a `WHERE` statement, not including the
|
|
1279
|
+
/// `WHERE` prefix. i.e. `"users"."id" = 1 OR "users"."firstName" = 'Bob'`. An
|
|
1280
|
+
/// empty string will be returned if there are no conditional operators used in
|
|
1281
|
+
/// the provided query engine.
|
|
700
1282
|
generateSelectWhereConditions(queryEngine, options) {
|
|
701
1283
|
const logicalCondition = (sqlParts, queryPart) => {
|
|
702
1284
|
if (sqlParts.length === 0)
|
|
@@ -771,6 +1353,27 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
771
1353
|
return sqlParts.join(' ');
|
|
772
1354
|
}
|
|
773
1355
|
|
|
1356
|
+
/// Generate an `ORDER BY` clause, listing all columns
|
|
1357
|
+
/// and their sort-direction.
|
|
1358
|
+
///
|
|
1359
|
+
/// Arguments:
|
|
1360
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1361
|
+
/// The query engine to pull the "order by" fields from.
|
|
1362
|
+
/// options?: object
|
|
1363
|
+
/// Options for the operation. Though these might be database specific, there are some
|
|
1364
|
+
/// common options that can be supplied to this method:
|
|
1365
|
+
/// | Option | Type | Default Value | Description |
|
|
1366
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1367
|
+
/// | `onlyProjectedFields` | `boolean` | `true` | If `true`, then only list fields that are also in the projection. |
|
|
1368
|
+
/// | `projectionFields` | `Map<string, object>` | Result of `getProjectedFields` | The fields that have been projected, to be used in combination with the `onlyProjectedFields` option. |
|
|
1369
|
+
/// | `rawOrder` | `boolean` | `false` | If `true`, then return the order fields (and literals) as a raw Array instead of a comma-separated list of fields. |
|
|
1370
|
+
/// | `reverseOrder` | `boolean` | `false` | If `true`, then reverse the sort order of all fields. |
|
|
1371
|
+
///
|
|
1372
|
+
/// Return: string | Array<string>
|
|
1373
|
+
/// If the `rawOrder` `options` is `false`, then return a fully completed `ORDER BY` clause,
|
|
1374
|
+
/// listing all the fields and their sort order. If no order has been specified by the query engine
|
|
1375
|
+
/// (or the connection), then return an empty string instead. If the `rawOrder` `options` is `true`,
|
|
1376
|
+
/// then return an array of the ordered fields instead.
|
|
774
1377
|
generateOrderClause(queryEngine, _options) {
|
|
775
1378
|
if (!queryEngine || typeof queryEngine.getOperationContext !== 'function')
|
|
776
1379
|
return (_options && _options.rawOrder) ? [] : '';
|
|
@@ -830,6 +1433,24 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
830
1433
|
return (options.rawOrder) ? orderByParts : `ORDER BY ${orderByParts.join(',')}`;
|
|
831
1434
|
}
|
|
832
1435
|
|
|
1436
|
+
/// Generate a `GROUP BY` clause, listing all columns
|
|
1437
|
+
/// to group by.
|
|
1438
|
+
///
|
|
1439
|
+
/// Arguments:
|
|
1440
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1441
|
+
/// The query engine to pull the "group by" fields from.
|
|
1442
|
+
/// options?: object
|
|
1443
|
+
/// Options for the operation. Though these might be database specific, there are some
|
|
1444
|
+
/// common options that can be supplied to this method:
|
|
1445
|
+
/// | Option | Type | Default Value | Description |
|
|
1446
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1447
|
+
/// | `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. |
|
|
1448
|
+
///
|
|
1449
|
+
/// Return: string | Array<string>
|
|
1450
|
+
/// If the `rawGroupBy` `options` is `false`, then return a fully completed `GROUP BY` clause,
|
|
1451
|
+
/// listing all the columns and literals to group by. If no "group by" has been specified by the query engine
|
|
1452
|
+
/// then return an empty string instead. If the `rawGroupBy` `options` is `true`,
|
|
1453
|
+
/// then return an array of the "group by" fields instead.
|
|
833
1454
|
generateGroupByClause(queryEngine, _options) {
|
|
834
1455
|
if (!queryEngine || typeof queryEngine.getOperationContext !== 'function')
|
|
835
1456
|
return (_options && _options.rawGroupBy) ? [] : '';
|
|
@@ -863,11 +1484,54 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
863
1484
|
return (options.rawGroupBy) ? groupByParts : `GROUP BY ${groupByParts.join(',')}`;
|
|
864
1485
|
}
|
|
865
1486
|
|
|
1487
|
+
/// Generate a `HAVING` clause to be used in combination with a
|
|
1488
|
+
/// `GROUP BY` clause.
|
|
1489
|
+
///
|
|
1490
|
+
/// This simple calls <see>SQLQueryGeneratorBase.generateSelectWhereConditions</see>
|
|
1491
|
+
/// on the provided `queryEngine`, and if there is a result, wraps the conditions generated
|
|
1492
|
+
/// inside a `HAVING (...)` clause. If no conditions are generated, then an empty string will
|
|
1493
|
+
/// be returned instead.
|
|
1494
|
+
///
|
|
1495
|
+
/// Arguments:
|
|
1496
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1497
|
+
/// The query engine to pull the "group by" conditions from.
|
|
1498
|
+
/// options?: object
|
|
1499
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1500
|
+
/// <see>SQLQueryGeneratorBase.generateSelectWhereConditions</see> call.
|
|
1501
|
+
///
|
|
1502
|
+
/// Return: string
|
|
1503
|
+
/// A `HAVING (...)` clause if conditions were found on the provided `queryEngine`, or
|
|
1504
|
+
/// an empty string if no conditions were found.
|
|
1505
|
+
///
|
|
1506
|
+
/// See: SQLQueryGeneratorBase.generateSelectWhereConditions
|
|
866
1507
|
generateHavingClause(queryEngine, options) {
|
|
867
1508
|
let where = this.generateSelectWhereConditions(queryEngine, options);
|
|
868
1509
|
return (where) ? `HAVING (${where})` : '';
|
|
869
1510
|
}
|
|
870
1511
|
|
|
1512
|
+
/// Generate both a `GROUP BY` and `HAVING` clause
|
|
1513
|
+
/// together. If no `GROUP_BY` operation is set on the
|
|
1514
|
+
/// provided `queryEngine`, then nothing will be generated,
|
|
1515
|
+
/// and an empty string will be returned instead. The `HAVING`
|
|
1516
|
+
/// clause will be automatically skipped if there is no
|
|
1517
|
+
/// `GROUP_BY` operation to work off of.
|
|
1518
|
+
///
|
|
1519
|
+
/// Arguments:
|
|
1520
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1521
|
+
/// The query engine to pull the "group by" clause, and "having" conditions from.
|
|
1522
|
+
/// options?: object
|
|
1523
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1524
|
+
/// <see>SQLQueryGeneratorBase.generateGroupByClause</see> and <see>SQLQueryGeneratorBase.generateHavingClause</see>
|
|
1525
|
+
/// internal calls this method makes.
|
|
1526
|
+
///
|
|
1527
|
+
/// Return: string
|
|
1528
|
+
/// A full `GROUP BY` clause, including any `HAVING` clause specified. An empty string
|
|
1529
|
+
/// will be returned if there is no `GROUP_BY` operation specified on the `queryEngine`
|
|
1530
|
+
/// provided.
|
|
1531
|
+
///
|
|
1532
|
+
/// See: SQLQueryGeneratorBase.generateGroupByClause
|
|
1533
|
+
///
|
|
1534
|
+
/// See: SQLQueryGeneratorBase.generateHavingClause
|
|
871
1535
|
generateGroupByAndHavingClause(queryEngine, options) {
|
|
872
1536
|
if (!queryEngine)
|
|
873
1537
|
return '';
|
|
@@ -889,22 +1553,61 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
889
1553
|
return sqlParts.join(' ');
|
|
890
1554
|
}
|
|
891
1555
|
|
|
892
|
-
|
|
1556
|
+
/// Generate a `LIMIT` clause.
|
|
1557
|
+
///
|
|
1558
|
+
/// Arguments:
|
|
1559
|
+
/// limit: number | Literal
|
|
1560
|
+
/// If `limit` is a literal, simply stringify and return it. Otherwise, if `limit`
|
|
1561
|
+
/// is a `number`, generate a `LIMIT` clause and return it, using the `limit` provided.
|
|
1562
|
+
/// options?: object
|
|
1563
|
+
/// Options for the operation. These are passed to `toString` for stringifying literals.
|
|
1564
|
+
///
|
|
1565
|
+
/// Return: string
|
|
1566
|
+
/// A `LIMIT` clause to apply to the query.
|
|
893
1567
|
generateLimitClause(limit, options) {
|
|
894
1568
|
if (LiteralBase.isLiteral(limit))
|
|
895
|
-
return limit.toString(this.connection);
|
|
1569
|
+
return limit.toString(this.connection, options);
|
|
896
1570
|
|
|
897
1571
|
return `LIMIT ${limit}`;
|
|
898
1572
|
}
|
|
899
1573
|
|
|
900
|
-
|
|
1574
|
+
/// Generate an `OFFSET` clause.
|
|
1575
|
+
///
|
|
1576
|
+
/// Arguments:
|
|
1577
|
+
/// offset: number | Literal
|
|
1578
|
+
/// If `offset` is a literal, simply stringify and return it. Otherwise, if `offset`
|
|
1579
|
+
/// is a `number`, generate an `OFFSET` clause and return it, using the `offset` provided.
|
|
1580
|
+
/// options?: object
|
|
1581
|
+
/// Options for the operation. These are passed to `toString` for stringifying literals.
|
|
1582
|
+
///
|
|
1583
|
+
/// Return: string
|
|
1584
|
+
/// An `OFFSET` clause to apply to the query.
|
|
901
1585
|
generateOffsetClause(offset, options) {
|
|
902
1586
|
if (LiteralBase.isLiteral(offset))
|
|
903
|
-
return offset.toString(this.connection);
|
|
1587
|
+
return offset.toString(this.connection, options);
|
|
904
1588
|
|
|
905
1589
|
return `OFFSET ${offset}`;
|
|
906
1590
|
}
|
|
907
1591
|
|
|
1592
|
+
/// Generate the `ORDER`, `LIMIT`, and `OFFSET` clauses
|
|
1593
|
+
/// to apply to the query. If any one of these clauses is
|
|
1594
|
+
/// blank, then it will be skipped. If there is no order,
|
|
1595
|
+
/// limit, or offset applied to the query, then an empty
|
|
1596
|
+
/// string will be returned.
|
|
1597
|
+
///
|
|
1598
|
+
/// Arguments:
|
|
1599
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1600
|
+
/// The query engine to pull the "order by", "limit", and "offset" clauses from.
|
|
1601
|
+
/// options?: object
|
|
1602
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1603
|
+
/// the respective calls that generate the sub-parts of this operation.
|
|
1604
|
+
///
|
|
1605
|
+
/// Return: string
|
|
1606
|
+
/// A combo `ORDER BY ... LIMIT ... OFFSET ...` clause to apply to the query.
|
|
1607
|
+
/// If any one of these sub-parts is empty or invalid, they will be skipped.
|
|
1608
|
+
/// i.e. if there is no `LIMIT` applied to the query, then the `LIMIT` and `OFFSET`
|
|
1609
|
+
/// will be skipped. If there is no output because all sub-parts (clauses) were skipped,
|
|
1610
|
+
/// then an empty string will be returned instead.
|
|
908
1611
|
generateSelectOrderLimitOffset(queryEngine, _options) {
|
|
909
1612
|
if (!queryEngine)
|
|
910
1613
|
return '';
|
|
@@ -953,6 +1656,29 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
953
1656
|
return sqlParts.join(' ');
|
|
954
1657
|
}
|
|
955
1658
|
|
|
1659
|
+
/// Generate the `WHERE`, `ORDER`, `LIMIT`, and `OFFSET` clauses
|
|
1660
|
+
/// to apply to the query. If any one of these clauses is
|
|
1661
|
+
/// blank, then it will be skipped. If there is no output because
|
|
1662
|
+
/// all clauses were skipped, then an empty string will be returned instead.
|
|
1663
|
+
///
|
|
1664
|
+
/// Arguments:
|
|
1665
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1666
|
+
/// The query engine to pull the conditions, "order by", "limit", and "offset" clauses from.
|
|
1667
|
+
/// options?: object
|
|
1668
|
+
/// Options for the operation. These options are simply passed through to the
|
|
1669
|
+
/// the respective calls that generate the sub-parts of this operation. One
|
|
1670
|
+
/// common option that can be used here for all connections is the `separateWhereAndOrder`
|
|
1671
|
+
/// option. If `true`, then an object with the following shape will be returned:
|
|
1672
|
+
/// `{ where: string; orderLimitOffset: string; }`, splitting the clauses apart and
|
|
1673
|
+
/// returning them separately.
|
|
1674
|
+
///
|
|
1675
|
+
/// Return: string
|
|
1676
|
+
/// A combo `WHERE ... ORDER BY ... LIMIT ... OFFSET ...` clause to apply to the query.
|
|
1677
|
+
/// If any one of these sub-parts is empty or invalid, they will be skipped.
|
|
1678
|
+
/// i.e. if there is no `LIMIT` applied to the query, then the `LIMIT` and `OFFSET`
|
|
1679
|
+
/// will be skipped. If there are no conditions for the query, then the `WHERE` clause
|
|
1680
|
+
/// will be skipped. If there is no output because all sub-parts (clauses) were skipped,
|
|
1681
|
+
/// then an empty string will be returned instead.
|
|
956
1682
|
generateWhereAndOrderLimitOffset(queryEngine, _options) {
|
|
957
1683
|
let options = _options || {};
|
|
958
1684
|
let sqlParts = [];
|
|
@@ -971,6 +1697,34 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
971
1697
|
return sqlParts.join(' ');
|
|
972
1698
|
}
|
|
973
1699
|
|
|
1700
|
+
/// Generate a full `SELECT` statement using the provided
|
|
1701
|
+
/// `queryEngine`.
|
|
1702
|
+
///
|
|
1703
|
+
/// This will generate a `SELECT` statement for the underlying
|
|
1704
|
+
/// database that will include the field projection, table joins,
|
|
1705
|
+
/// any `GROUP BY` clause that is applied, all the `WHERE` conditions,
|
|
1706
|
+
/// any sub-queries involved, and an `ORDER BY`, `LIMIT`, and `OFFSET`
|
|
1707
|
+
/// if those are in-use in the query. This method will be recursively
|
|
1708
|
+
/// called for any sub-queries encountered.
|
|
1709
|
+
///
|
|
1710
|
+
/// Arguments:
|
|
1711
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
1712
|
+
/// The query engine to use to generate the `SELECT` statement.
|
|
1713
|
+
/// options?: object
|
|
1714
|
+
/// Options for the operation. These options are passed through all generation calls
|
|
1715
|
+
/// invoked inside this method, and so impact all methods used to generate the statement,
|
|
1716
|
+
/// including methods used for column escaping, literal conversion, etc...
|
|
1717
|
+
/// Though these options are often connection-specific,
|
|
1718
|
+
/// the following options are available across all connections:
|
|
1719
|
+
/// | Option | Type | Default Value | Description |
|
|
1720
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1721
|
+
/// | `includeRelations` | `boolean` | `false` | If `true`, then a `.PROJECT('*')` will be applied for you, including all tables used in the operation in the output. |
|
|
1722
|
+
/// | `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. |
|
|
1723
|
+
/// | `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. |
|
|
1724
|
+
///
|
|
1725
|
+
/// Return: string
|
|
1726
|
+
/// A fully generated `SELECT` statement that can be used directly in the underlying database
|
|
1727
|
+
/// to query data.
|
|
974
1728
|
generateSelectStatement(_queryEngine, _options) {
|
|
975
1729
|
let queryEngine = _queryEngine;
|
|
976
1730
|
if (!QueryEngine.isQuery(queryEngine))
|
|
@@ -989,8 +1743,8 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
989
1743
|
|
|
990
1744
|
options.selectStatement = true;
|
|
991
1745
|
|
|
992
|
-
projectionFields = this.
|
|
993
|
-
sqlParts.push(this.generateSelectQueryFieldProjection(queryEngine, options));
|
|
1746
|
+
projectionFields = this.getProjectedFields(queryEngine, options, true);
|
|
1747
|
+
sqlParts.push(this.generateSelectQueryFieldProjection(queryEngine, options, projectionFields));
|
|
994
1748
|
|
|
995
1749
|
sqlParts.push(this.generateFromTableOrTableJoin(rootModel, undefined, options));
|
|
996
1750
|
sqlParts.push(this.generateSelectQueryJoinTables(queryEngine, options));
|
|
@@ -1011,6 +1765,51 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1011
1765
|
return sql;
|
|
1012
1766
|
}
|
|
1013
1767
|
|
|
1768
|
+
/// Get the default value for a field.
|
|
1769
|
+
///
|
|
1770
|
+
/// This method is used for `CREATE TABLE`, `ALTER TABLE`, `UPDATE`, and `INSERT`
|
|
1771
|
+
/// statements. It uses the `defaultValue` of the `field` provided
|
|
1772
|
+
/// to fetch any `DEFAULT` that might be applicable to the field
|
|
1773
|
+
/// at the database level for a `CREATE TABLE` or `ALTER TABLE` statement. It might
|
|
1774
|
+
/// also be used for things like `created_at` and `updated_at` fields during `UPDATE`
|
|
1775
|
+
/// or `INSERT` statements.
|
|
1776
|
+
///
|
|
1777
|
+
/// Most default values for fields are applied client-side by Mythix ORM
|
|
1778
|
+
/// immediately before an `INSERT` or `UPDATE` statement is executed.
|
|
1779
|
+
/// However, some of them are set directly at the database level for field
|
|
1780
|
+
/// defaults, such as `AUTOINCREMENT`, and some date and times types (i.e. `NOW`).
|
|
1781
|
+
/// This method will return a string representing the default value that
|
|
1782
|
+
/// should be applied to a column (i.e. `DEFAULT NOW()`), or it will return
|
|
1783
|
+
/// a literal defining the default value that might change the entire statement.
|
|
1784
|
+
/// For example, `AUTOINCREMENT` in PostgreSQL is actually handled by converting
|
|
1785
|
+
/// the data type of the field to a `SERIAL` type.
|
|
1786
|
+
///
|
|
1787
|
+
/// This method is also used to fetch the default value for columns during an
|
|
1788
|
+
/// `UPDATE` or `INSERT` statement. For example, for `created_at` and `updated_at`
|
|
1789
|
+
/// fields, the default might be set during `INSERT` or always set on `UPDATE` operations.
|
|
1790
|
+
///
|
|
1791
|
+
/// Arguments:
|
|
1792
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
1793
|
+
/// The field to fetch the `defaultValue` from, if any.
|
|
1794
|
+
/// fieldName: string
|
|
1795
|
+
/// The name of the field the default value is being fetched for. This should always be
|
|
1796
|
+
/// the same as `field.fieldName`.
|
|
1797
|
+
/// options?: object
|
|
1798
|
+
/// Options for the operation.
|
|
1799
|
+
/// | Option | Type | Default Value | Description |
|
|
1800
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1801
|
+
/// | `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. |
|
|
1802
|
+
/// | `isInsertOperation` | `boolean` | `false` | If `true`, then Mythix ORM is reporting that this is for an `INSERT` operation. |
|
|
1803
|
+
/// | `isUpdateOperation` | `boolean` | `false` | If `true`, then Mythix ORM is reporting that this is for an `UPDATE` operation. |
|
|
1804
|
+
/// | `rawLiterals` | `boolean` | `false` | If `true`, then Mythix ORM will return the literal raw without stringifying it--if the default value is a literal. |
|
|
1805
|
+
/// | `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"). |
|
|
1806
|
+
/// | `useDefaultKeyword` | `boolean` | `true` | If `true`, then Mythix ORM will prefix any default value found with a `DEFAULT` statement (for use in `CREATE TABLE` statements). |
|
|
1807
|
+
///
|
|
1808
|
+
/// Return: undefined | string | Literal
|
|
1809
|
+
/// Return a string representing the escaped default value, a Literal if the `rawLiterals` option is `true`,
|
|
1810
|
+
/// or `undefined` if the field has no default value. A default value will not always be returned from this
|
|
1811
|
+
/// method simply because the provided `field` has a `defaultValue` property. Only default values applicable
|
|
1812
|
+
/// at the database level, or applicable to the operation being carried out will be returned.
|
|
1014
1813
|
getFieldDefaultValue(field, fieldName, _options) {
|
|
1015
1814
|
let options = _options || {};
|
|
1016
1815
|
let defaultValue = field.defaultValue;
|
|
@@ -1061,6 +1860,38 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1061
1860
|
return `${defaultValue}`;
|
|
1062
1861
|
}
|
|
1063
1862
|
|
|
1863
|
+
/// Generate an index name for creating an index on
|
|
1864
|
+
/// one or more columns.
|
|
1865
|
+
///
|
|
1866
|
+
/// This will take one or more field names from the `Model`
|
|
1867
|
+
/// provided and generate an index name for creating an index
|
|
1868
|
+
/// in the underlying database. This method can generate an index
|
|
1869
|
+
/// name for indexing a single column (if a single field name is provided),
|
|
1870
|
+
/// or it can generate an index name for indexing multiple columns
|
|
1871
|
+
/// as a "combo index".
|
|
1872
|
+
///
|
|
1873
|
+
/// Arguments:
|
|
1874
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1875
|
+
/// The model to use for the table to index on. This model should also be
|
|
1876
|
+
/// the model that owns all fields to be indexed. It isn't possible to index
|
|
1877
|
+
/// columns across different tables, so the fields provided must all be from
|
|
1878
|
+
/// this same `Model`.
|
|
1879
|
+
/// indexFieldNames: Array<string>
|
|
1880
|
+
/// The field names that will be used to create the single or combo index. A
|
|
1881
|
+
/// single field name will generate an index name for a single column, whereas
|
|
1882
|
+
/// more than one field name will generate an index name for a combo-index that
|
|
1883
|
+
/// indexes all columns requested. These can be fully qualified field names, but
|
|
1884
|
+
/// they don't have to be, since the owning `Model` is already known. If fully qualified
|
|
1885
|
+
/// field names are used, then the model name for each field must match the `Model`
|
|
1886
|
+
/// provided (making it pointless to use fully qualified field names).
|
|
1887
|
+
/// options?: object
|
|
1888
|
+
/// Options for the operation. These are not used by this method, and instead are
|
|
1889
|
+
/// just provided for the user--should they overload this method and need the options.
|
|
1890
|
+
///
|
|
1891
|
+
/// Return: string
|
|
1892
|
+
/// Return an index name, in the format `'idx_tableName_column1_column2_column3_...'`. If
|
|
1893
|
+
/// the `indexFieldNames` provided is empty--or result in an empty set of field names after
|
|
1894
|
+
/// filtering out invalid field names--then an empty string will be returned instead.
|
|
1064
1895
|
// eslint-disable-next-line no-unused-vars
|
|
1065
1896
|
generateIndexName(Model, _indexFieldNames, options) {
|
|
1066
1897
|
let indexFieldNames = Nife.toArray(_indexFieldNames).filter((index) => {
|
|
@@ -1082,6 +1913,40 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1082
1913
|
return this.escapeID(`idx_${tableName}_${columnNames.sort().join('_')}`);
|
|
1083
1914
|
}
|
|
1084
1915
|
|
|
1916
|
+
/// Generate a `CREATE INDEX` statement.
|
|
1917
|
+
///
|
|
1918
|
+
/// This will generate a `CREATE INDEX` statement, indexing
|
|
1919
|
+
/// all fields (columns) provided. If a single field name is
|
|
1920
|
+
/// provided, then a `CREATE INDEX` statement for a single column
|
|
1921
|
+
/// will be generated. If more than one field name is provided, then
|
|
1922
|
+
/// a `CREATE INDEX` statement for a combo-index (indexing across more
|
|
1923
|
+
/// than one column at once) will be generated instead.
|
|
1924
|
+
///
|
|
1925
|
+
/// Arguments:
|
|
1926
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1927
|
+
/// The model to use for the table to index on. This model should also be
|
|
1928
|
+
/// the model that owns all fields to be indexed. It isn't possible to index
|
|
1929
|
+
/// columns across different tables, so the fields provided must all be from
|
|
1930
|
+
/// this same `Model`.
|
|
1931
|
+
/// indexFieldNames: Array<string>
|
|
1932
|
+
/// The field names that will be used to create the single or combo index. A
|
|
1933
|
+
/// single field name will generate a statement for a single column, whereas
|
|
1934
|
+
/// more than one field name will generate a statement for a combo-index that
|
|
1935
|
+
/// indexes all columns requested. These can be fully qualified field names, but
|
|
1936
|
+
/// they don't have to be, since the owning `Model` is already known. If fully qualified
|
|
1937
|
+
/// field names are used, then the model name for each field must match the `Model`
|
|
1938
|
+
/// provided (making it pointless to use fully qualified field names).
|
|
1939
|
+
/// options?: object
|
|
1940
|
+
/// Options for the operation.
|
|
1941
|
+
/// | Option | Type | Default Value | Description |
|
|
1942
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
1943
|
+
/// | `concurrently` | `boolean` | `false` | If `true`, then add a `CONCURRENTLY` clause to the `CREATE INDEX` statement (if the database supports it). |
|
|
1944
|
+
/// | `ifNotExists` | `boolean` | `false` | If `true`, then add an `IF NOT EXISTS` clause to the `CREATE INDEX` statement. |
|
|
1945
|
+
///
|
|
1946
|
+
/// Return: string
|
|
1947
|
+
/// Return a fully formatted `CREATE INDEX` statement for the fields (columns)
|
|
1948
|
+
/// requested. An empty string will be returned if `indexFieldNames` is empty,
|
|
1949
|
+
/// or contains no valid field names.
|
|
1085
1950
|
generateCreateIndexStatement(Model, _indexFieldNames, _options) {
|
|
1086
1951
|
let indexFieldNames = Nife.toArray(_indexFieldNames).filter((fieldName) => {
|
|
1087
1952
|
if (Nife.isEmpty(fieldName))
|
|
@@ -1117,6 +1982,43 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1117
1982
|
return `CREATE INDEX${(flags) ? ` ${flags}` : ''} ${indexName} ON ${escapedTableName} (${escapedColumnNames.join(',')})`;
|
|
1118
1983
|
}
|
|
1119
1984
|
|
|
1985
|
+
/// Generate a `DROP INDEX` statement.
|
|
1986
|
+
///
|
|
1987
|
+
/// This will generate a `DROP INDEX` statement, using the provided
|
|
1988
|
+
/// `indexFieldNames` to generate the name of the index to be dropped.
|
|
1989
|
+
/// The provided `indexFieldNames` are passed off to <see>SQLQueryGeneratorBase.generateIndexName</see>
|
|
1990
|
+
/// to get the name of the index to drop.
|
|
1991
|
+
///
|
|
1992
|
+
/// Arguments:
|
|
1993
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
1994
|
+
/// The model to use for the table to index on. This model should also be
|
|
1995
|
+
/// the model that owns all fields to be indexed. It isn't possible to index
|
|
1996
|
+
/// columns across different tables, so the fields provided must all be from
|
|
1997
|
+
/// this same `Model`.
|
|
1998
|
+
/// indexFieldNames: Array<string>
|
|
1999
|
+
/// The field names that will be used to create the single or combo index. A
|
|
2000
|
+
/// single field name will generate a statement for a single column, whereas
|
|
2001
|
+
/// more than one field name will generate a statement for a combo-index that
|
|
2002
|
+
/// indexes all columns requested. These can be fully qualified field names, but
|
|
2003
|
+
/// they don't have to be, since the owning `Model` is already known. If fully qualified
|
|
2004
|
+
/// field names are used, then the model name for each field must match the `Model`
|
|
2005
|
+
/// provided (making it pointless to use fully qualified field names).
|
|
2006
|
+
/// options?: object
|
|
2007
|
+
/// Options for the operation.
|
|
2008
|
+
/// | Option | Type | Default Value | Description |
|
|
2009
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2010
|
+
/// | `concurrently` | `boolean` | `false` | If `true`, then add a `CONCURRENTLY` clause to the `DROP INDEX` statement (if the database supports it). |
|
|
2011
|
+
/// | `ifExists` | `boolean` | `false` | If `true`, then add an `IF EXISTS` clause to the `DROP INDEX` statement. |
|
|
2012
|
+
/// | `cascade` | `boolean` | `true` | If `true`, then add a `CASCADE` clause to the `DROP INDEX` statement (if the database supports it). |
|
|
2013
|
+
///
|
|
2014
|
+
/// Return: string
|
|
2015
|
+
/// Return a fully formatted `DROP INDEX` statement for the fields (columns)
|
|
2016
|
+
/// requested. An empty string will be returned if `indexFieldNames` is empty,
|
|
2017
|
+
/// or contains no valid field names. <see>SQLQueryGeneratorBase.generateIndexName</see> is called
|
|
2018
|
+
/// with the provided `indexFieldNames` to generate the name of the index that should
|
|
2019
|
+
/// be dropped.
|
|
2020
|
+
///
|
|
2021
|
+
/// See: SQLQueryGeneratorBase.generateIndexName
|
|
1120
2022
|
generateDropIndexStatement(Model, _indexFieldNames, _options) {
|
|
1121
2023
|
let indexFieldNames = Nife.toArray(_indexFieldNames).filter((fieldName) => {
|
|
1122
2024
|
if (Nife.isEmpty(fieldName))
|
|
@@ -1150,6 +2052,31 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1150
2052
|
return `DROP INDEX${(flags) ? ` ${flags}` : ''} ${indexName}${(postFlags) ? ` ${postFlags}` : ''}`;
|
|
1151
2053
|
}
|
|
1152
2054
|
|
|
2055
|
+
/// Generate zero or more `CREATE INDEX` statements,
|
|
2056
|
+
/// using `field.index` to generate the statements.
|
|
2057
|
+
///
|
|
2058
|
+
/// A [Field](https://github.com/th317erd/mythix-orm/wiki/Field) in Mythix ORM
|
|
2059
|
+
/// can have an `index` property (see [Field.index](https://github.com/th317erd/mythix-orm/wiki/Field#property-index))
|
|
2060
|
+
/// that defines the indexes to be created for the field. A `true` value is short for
|
|
2061
|
+
/// "index this field". Other field names in the `index` array mean
|
|
2062
|
+
/// "index this field combined with the fields specified, creating a combined index".
|
|
2063
|
+
///
|
|
2064
|
+
/// This method will turn the `index` property on the provided `field` into one or more `CREATE INDEX`
|
|
2065
|
+
/// statements. If the `index` property on the `field` is falsy, or empty, then an empty array
|
|
2066
|
+
/// will be returned instead.
|
|
2067
|
+
///
|
|
2068
|
+
/// Arguments:
|
|
2069
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2070
|
+
/// The model that owns the `field` provided.
|
|
2071
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2072
|
+
/// The field to generate indexes for, using the `index` property of this field.
|
|
2073
|
+
/// options?: object
|
|
2074
|
+
/// Options for the operation. These options are passed off to <see>SQLQueryGeneratorBase.generateCreateIndexStatement</see>
|
|
2075
|
+
/// to generate each `CREATE INDEX` statement.
|
|
2076
|
+
///
|
|
2077
|
+
/// Return: Array<string>
|
|
2078
|
+
/// Return an array of `CREATE INDEX` statements. If the `index` property on the provided
|
|
2079
|
+
/// `field` is falsy or empty, then an empty array will be returned instead.
|
|
1153
2080
|
generateColumnIndexes(Model, field, _options) {
|
|
1154
2081
|
let indexes = Nife.toArray(field.index).filter((index) => {
|
|
1155
2082
|
if (index === true)
|
|
@@ -1171,6 +2098,20 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1171
2098
|
});
|
|
1172
2099
|
}
|
|
1173
2100
|
|
|
2101
|
+
/// Generate a `DROP TABLE` statement.
|
|
2102
|
+
///
|
|
2103
|
+
/// Arguments:
|
|
2104
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2105
|
+
/// The model that defines the table to be dropped.
|
|
2106
|
+
/// options?: object
|
|
2107
|
+
/// Options for the operation.
|
|
2108
|
+
/// | Option | Type | Default Value | Description |
|
|
2109
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2110
|
+
/// | `ifExists` | `boolean` | `false` | If `true`, then add an `IF EXISTS` clause to the `DROP TABLE` statement. |
|
|
2111
|
+
///
|
|
2112
|
+
/// Return: string
|
|
2113
|
+
/// Return a fully formatted `DROP TABLE` statement, using the `Model` provided
|
|
2114
|
+
/// to define which table should be dropped.
|
|
1174
2115
|
generateDropTableStatement(Model, _options) {
|
|
1175
2116
|
let options = _options || {};
|
|
1176
2117
|
let escapedTableName = this.getEscapedTableName(Model, options);
|
|
@@ -1184,6 +2125,30 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1184
2125
|
return `DROP TABLE ${flags} ${escapedTableName}${(options.cascade !== false) ? ' CASCADE' : ''}`;
|
|
1185
2126
|
}
|
|
1186
2127
|
|
|
2128
|
+
/// Generate foreign key constraints for a column
|
|
2129
|
+
/// in a `CREATE TABLE` statement.
|
|
2130
|
+
///
|
|
2131
|
+
/// This method will generate database specific syntax
|
|
2132
|
+
/// for foreign key constraints to apply to a column
|
|
2133
|
+
/// in a `CREATE TABLE` statement.
|
|
2134
|
+
///
|
|
2135
|
+
/// Arguments:
|
|
2136
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2137
|
+
/// The field to generate foreign key constraints for. This field should
|
|
2138
|
+
/// have a [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType)
|
|
2139
|
+
/// `type`.
|
|
2140
|
+
/// type: [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType)
|
|
2141
|
+
/// The `type` of the `field` provided, which should always be a [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType).
|
|
2142
|
+
/// options?: object
|
|
2143
|
+
/// Options for the operation. These options are simply passed through to any
|
|
2144
|
+
/// <see>SQLQueryGeneratorBase.getEscapedColumnName</see>, or <see>SQLQueryGeneratorBase.getEscapedTableName</see>
|
|
2145
|
+
/// calls that are made internally by this method.
|
|
2146
|
+
///
|
|
2147
|
+
/// Return: string
|
|
2148
|
+
/// A database specific string for defining foreign key constraints for a column.
|
|
2149
|
+
/// Any `ON DELETE` or `ON UPDATE` clauses will be generated from the `onDelete`
|
|
2150
|
+
/// and `onUpdate` properties set on the [ForeignKeyType](https://github.com/th317erd/mythix-orm/wiki/ForeignKeyType)
|
|
2151
|
+
/// `type` for the field.
|
|
1187
2152
|
generateForeignKeyConstraint(field, type, options) {
|
|
1188
2153
|
let typeOptions = type.getOptions();
|
|
1189
2154
|
let targetModel = type.getTargetModel(this.connection);
|
|
@@ -1217,6 +2182,39 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1217
2182
|
return sqlParts.join('');
|
|
1218
2183
|
}
|
|
1219
2184
|
|
|
2185
|
+
/// Generate an "inner tail" for a `CREATE TABLE`
|
|
2186
|
+
/// statement.
|
|
2187
|
+
///
|
|
2188
|
+
/// An "inner tail" is the trailing part of the `CREATE TABLE`
|
|
2189
|
+
/// statement that is still inside the parenthesis of the statement,
|
|
2190
|
+
/// after any columns have been defined. For example:
|
|
2191
|
+
/// ```sql
|
|
2192
|
+
/// CREATE TABLE table_name (
|
|
2193
|
+
/// column1 datatype(length) column_contraint,
|
|
2194
|
+
/// column2 datatype(length) column_contraint,
|
|
2195
|
+
/// ... // <---- this is the "inner tail"
|
|
2196
|
+
/// );
|
|
2197
|
+
///
|
|
2198
|
+
/// ... // <---- this is the "outer tail"
|
|
2199
|
+
/// ```
|
|
2200
|
+
///
|
|
2201
|
+
/// This is often database specific, and by default will be
|
|
2202
|
+
/// used to generate any foreign key constraints used by columns
|
|
2203
|
+
/// in the table.
|
|
2204
|
+
///
|
|
2205
|
+
/// Arguments:
|
|
2206
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2207
|
+
/// The model that defines the table being created.
|
|
2208
|
+
/// options?: object
|
|
2209
|
+
/// Any options for the `CREATE TABLE` operation being carried out.
|
|
2210
|
+
///
|
|
2211
|
+
/// Return: Array<string>
|
|
2212
|
+
/// Return an "inner tail" for the `CREATE TABLE` statement, or an empty
|
|
2213
|
+
/// array if there should be no "inner tail". An array of SQL statements
|
|
2214
|
+
/// is returned by this method, which will be added to the `CREATE TABLE`
|
|
2215
|
+
/// statement (inside its parenthesis).
|
|
2216
|
+
///
|
|
2217
|
+
/// See: SQLQueryGeneratorBase.generateForeignKeyConstraint
|
|
1220
2218
|
// eslint-disable-next-line no-unused-vars
|
|
1221
2219
|
generateCreateTableStatementInnerTail(Model, options) {
|
|
1222
2220
|
let fieldParts = [];
|
|
@@ -1237,6 +2235,40 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1237
2235
|
return fieldParts;
|
|
1238
2236
|
}
|
|
1239
2237
|
|
|
2238
|
+
/// Generate an "outer tail" for a `CREATE TABLE`
|
|
2239
|
+
/// statement.
|
|
2240
|
+
///
|
|
2241
|
+
/// An "outer tail" is the trailing part of the `CREATE TABLE`
|
|
2242
|
+
/// statement that is outside the parenthesis of the statement,
|
|
2243
|
+
/// after the column list. For example:
|
|
2244
|
+
/// ```sql
|
|
2245
|
+
/// CREATE TABLE table_name (
|
|
2246
|
+
/// column1 datatype(length) column_contraint,
|
|
2247
|
+
/// column2 datatype(length) column_contraint,
|
|
2248
|
+
/// ... // <---- this is the "inner tail"
|
|
2249
|
+
/// );
|
|
2250
|
+
///
|
|
2251
|
+
/// ... // <---- this is the "outer tail"
|
|
2252
|
+
/// ```
|
|
2253
|
+
///
|
|
2254
|
+
/// This is often database specific, and by default will be
|
|
2255
|
+
/// used to generate any `CREATE INDEX` statements for columns
|
|
2256
|
+
/// that have indexes.
|
|
2257
|
+
///
|
|
2258
|
+
/// Arguments:
|
|
2259
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2260
|
+
/// The model that defines the table being created.
|
|
2261
|
+
/// options?: object
|
|
2262
|
+
/// Any options for the `CREATE TABLE` operation being carried out.
|
|
2263
|
+
///
|
|
2264
|
+
/// Return: Array<string>
|
|
2265
|
+
/// Return an "outer tail" for the `CREATE TABLE` statement, or an empty
|
|
2266
|
+
/// array if there should be no "outer tail". An array of SQL statements
|
|
2267
|
+
/// is returned by this method, which will either be added to the `CREATE TABLE`
|
|
2268
|
+
/// statement, or executed separately after the `CREATE TABLE` statement is
|
|
2269
|
+
/// executed--depending on the underlying database.
|
|
2270
|
+
///
|
|
2271
|
+
/// See: SQLQueryGeneratorBase.generateColumnIndexes
|
|
1240
2272
|
// eslint-disable-next-line no-unused-vars
|
|
1241
2273
|
generateCreateTableStatementOuterTail(Model, options) {
|
|
1242
2274
|
let fieldParts = [];
|
|
@@ -1258,6 +2290,27 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1258
2290
|
return Nife.uniq(fieldParts);
|
|
1259
2291
|
}
|
|
1260
2292
|
|
|
2293
|
+
/// Generate a column definition for use inside a `CREATE TABLE`
|
|
2294
|
+
/// statement, or an `ALTER TABLE` statement. The generated
|
|
2295
|
+
/// column definition will include any `DEFAULT` defined, as well
|
|
2296
|
+
/// as any constraints that should be applied to the column, and
|
|
2297
|
+
/// will define at least the column's name and type.
|
|
2298
|
+
///
|
|
2299
|
+
/// Arguments:
|
|
2300
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2301
|
+
/// The model that defines the table the column definition is for.
|
|
2302
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2303
|
+
/// The field that defines the column whose definition is being generated.
|
|
2304
|
+
/// options?: object
|
|
2305
|
+
/// Options for the operation. These are simply passed off to other generate
|
|
2306
|
+
/// methods that are used internally, such as <see>SQLQueryGeneratorBase.getEscapedColumnName</see>,
|
|
2307
|
+
/// and [Type.toConnectionType](https://github.com/th317erd/mythix-orm/wiki/Type#method-toConnectionType)
|
|
2308
|
+
/// for stringifying the column's type. There may be connection-specific options that
|
|
2309
|
+
/// can be supplied as well.
|
|
2310
|
+
///
|
|
2311
|
+
/// Return: string
|
|
2312
|
+
/// A fully formatted "column definition" statement, for use in
|
|
2313
|
+
/// a `CREATE TABLE` or `ALTER TABLE` statement. i.e. `"id" BIGINT PRIMARY KEY AUTOINCREMENT`.
|
|
1261
2314
|
generateColumnDeclarationStatement(Model, field, _options) {
|
|
1262
2315
|
let options = _options || {};
|
|
1263
2316
|
let constraintParts = [];
|
|
@@ -1293,6 +2346,26 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1293
2346
|
return `${this.getEscapedColumnName(Model, field, { ...options, columnNameOnly: true })} ${field.type.toConnectionType(this.connection, { ...options, createTable: true, defaultValue })}${constraintParts}`;
|
|
1294
2347
|
}
|
|
1295
2348
|
|
|
2349
|
+
/// Generate a full `CREATE TABLE` statement using
|
|
2350
|
+
/// the provided `Model` and its fields.
|
|
2351
|
+
///
|
|
2352
|
+
/// Arguments:
|
|
2353
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2354
|
+
/// The model that defines the table being created.
|
|
2355
|
+
/// options?: object
|
|
2356
|
+
/// Options for the operation. Though these might contain connection-specific
|
|
2357
|
+
/// options, the following options are common across all connections:
|
|
2358
|
+
/// | Option | Type | Default Value | Description |
|
|
2359
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2360
|
+
/// | `ifNotExists` | `boolean` | `false` | If `true`, then add an `IF NOT EXISTS` clause to the `CREATE TABLE` statement. |
|
|
2361
|
+
///
|
|
2362
|
+
/// Return: string
|
|
2363
|
+
/// Return a fully formatted `CREATE TABLE` statement, to create
|
|
2364
|
+
/// the table defined by the provided `Model`.
|
|
2365
|
+
///
|
|
2366
|
+
/// See: SQLQueryGeneratorBase.generateColumnDeclarationStatement
|
|
2367
|
+
///
|
|
2368
|
+
/// See: SQLQueryGeneratorBase.generateCreateTableStatementInnerTail
|
|
1296
2369
|
generateCreateTableStatement(Model, _options) {
|
|
1297
2370
|
let options = _options || {};
|
|
1298
2371
|
let fieldParts = [];
|
|
@@ -1316,6 +2389,42 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1316
2389
|
return finalStatement;
|
|
1317
2390
|
}
|
|
1318
2391
|
|
|
2392
|
+
/// Generate a comma-separated list of values for
|
|
2393
|
+
/// use in an `INSERT` statement.
|
|
2394
|
+
///
|
|
2395
|
+
/// Only "dirty" fields are inserted into the table, which might seem
|
|
2396
|
+
/// odd at first. However, Mythix ORM model instances have all (or most) their
|
|
2397
|
+
/// fields set to dirty when they are first instantiated, except fields
|
|
2398
|
+
/// such as auto-incrementing ids. This makes sense, because we would want
|
|
2399
|
+
/// to insert all columns for a given model instance, but not columns such
|
|
2400
|
+
/// as an auto-incrementing "id" that we would want the database to provide
|
|
2401
|
+
/// a value for. Any field on a model that should be inserted should already
|
|
2402
|
+
/// be marked "dirty", and any field that isn't dirty should instead be provided
|
|
2403
|
+
/// the "default value" that is already defined for the column.
|
|
2404
|
+
///
|
|
2405
|
+
/// The `dirtyFields` option that can be provided is to provide the fields that
|
|
2406
|
+
/// are marked as dirty across **all** model instances being inserted (for bulk-inserts).
|
|
2407
|
+
/// If provide, this option will override the "dirty" fields reported by each model
|
|
2408
|
+
/// instance, since the values for insertion must be aligned across all rows.
|
|
2409
|
+
///
|
|
2410
|
+
/// Arguments:
|
|
2411
|
+
/// model: [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2412
|
+
/// The model instance to pull field values from. Only "dirty" values
|
|
2413
|
+
/// will be pulled from the model and compiled into output.
|
|
2414
|
+
/// options?: object
|
|
2415
|
+
/// Options for the operation. Though these might contain connection-specific
|
|
2416
|
+
/// options, the following options are common across all connections:
|
|
2417
|
+
/// | Option | Type | Default Value | Description |
|
|
2418
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
2419
|
+
/// | `dirtyFields` | `Array<Field>` | `undefined` | If more than one row is being inserted, then define all columns being inserted for the operation. |
|
|
2420
|
+
///
|
|
2421
|
+
/// Return: undefined | { modelChanges: object; rowValues: string; }
|
|
2422
|
+
/// Return `undefined` if no model instance is provided, or if the model
|
|
2423
|
+
/// instance is marked as "clean" (meaning no insert needs to happen).
|
|
2424
|
+
/// Otherwise, return an object with the shape: `{ modelChanges: object; rowValues: string; }`,
|
|
2425
|
+
/// where `modelChanges` is an object, where each key is a field name, and each value is the
|
|
2426
|
+
/// value that will be inserted into the database. `rowValues` is a string, that is a
|
|
2427
|
+
/// comma-separated list of all values to be inserted for this row.
|
|
1319
2428
|
generateInsertFieldValuesFromModel(model, _options) {
|
|
1320
2429
|
if (!model)
|
|
1321
2430
|
return;
|
|
@@ -1360,6 +2469,29 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1360
2469
|
return { modelChanges, rowValues: sqlParts.join(',') };
|
|
1361
2470
|
}
|
|
1362
2471
|
|
|
2472
|
+
/// Generate multiple rows of comma-separated values for
|
|
2473
|
+
/// a bulk `INSERT` operation.
|
|
2474
|
+
///
|
|
2475
|
+
/// Arguments:
|
|
2476
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2477
|
+
/// The model class of all `models` being inserted.
|
|
2478
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2479
|
+
/// An array of model instances, or a single model instance to generate insertion
|
|
2480
|
+
/// values for. Each model (if dirty) will have a single row created for it in the
|
|
2481
|
+
/// underlying database table defined by the provided `Model`.
|
|
2482
|
+
/// options?: object
|
|
2483
|
+
/// Options for the operation. The only option that is really useful here is the
|
|
2484
|
+
/// `newlines` option. If `false`, then newlines won't be used to separate the rows
|
|
2485
|
+
/// of values. By default, newlines will be used to separate each row of values.
|
|
2486
|
+
///
|
|
2487
|
+
/// Return: undefined | { modelChanges: Array<object>; values: string; }
|
|
2488
|
+
/// Return `undefined` if the provided `models` is empty. Otherwise,
|
|
2489
|
+
/// return an object with the shape `{ modelChanges: Array<object>; values: string; }`,
|
|
2490
|
+
/// where `modelChanges` are the fields being inserted for each model (key = field name, value = field value),
|
|
2491
|
+
/// and where `values` is the list of row-values to insert into the table, i.e.
|
|
2492
|
+
/// `(value1,value2,value3),(value1,value2,value3),...`.
|
|
2493
|
+
///
|
|
2494
|
+
/// See: SQLQueryGeneratorBase.generateInsertFieldValuesFromModel
|
|
1363
2495
|
generateInsertValuesFromModels(Model, _models, _options) {
|
|
1364
2496
|
let options = _options || {};
|
|
1365
2497
|
let preparedModels = this.connection.prepareAllModelsForOperation(Model, _models, options);
|
|
@@ -1389,10 +2521,55 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1389
2521
|
};
|
|
1390
2522
|
}
|
|
1391
2523
|
|
|
2524
|
+
/// Generate a "tail" for an `INSERT` statement.
|
|
2525
|
+
///
|
|
2526
|
+
/// This method is provided to allow the connection
|
|
2527
|
+
/// itself for any given database to "tack on extra" to
|
|
2528
|
+
/// an `INSERT` statement. This is commonly used by databases
|
|
2529
|
+
/// to add on a `RETURNING` clause to the `INSERT` statement.
|
|
2530
|
+
/// However, its primary purpose is just to allow the engine
|
|
2531
|
+
/// (or the user via overloading) to add on any "extra" to
|
|
2532
|
+
/// an `INSERT` statement.
|
|
2533
|
+
///
|
|
2534
|
+
/// Arguments:
|
|
2535
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2536
|
+
/// The model class of all `models` being inserted.
|
|
2537
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2538
|
+
/// An array of model instances, or a single model instance. These are the models
|
|
2539
|
+
/// that are being inserted into the database.
|
|
2540
|
+
/// options: object
|
|
2541
|
+
/// Options for the operation.
|
|
2542
|
+
/// context: object
|
|
2543
|
+
/// Useful information about the insert operation taking place. This is an
|
|
2544
|
+
/// object with the shape: `{ escapedTableName: string; modelChanges: Array<object>; dirtyFields: Array<Field>; }`.
|
|
2545
|
+
///
|
|
2546
|
+
/// Return: string
|
|
2547
|
+
/// Any "extra" SQL to add onto the end of the `INSERT` statement.
|
|
2548
|
+
/// Most connection drivers will usually use this for a `RETURNING` clause.
|
|
1392
2549
|
// eslint-disable-next-line no-unused-vars
|
|
1393
|
-
generateInsertStatementTail(Model,
|
|
1394
|
-
}
|
|
1395
|
-
|
|
2550
|
+
generateInsertStatementTail(Model, models, options, context) {
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
/// Generate an `INSERT` statement, for inserting
|
|
2554
|
+
/// one or more model instances into the database.
|
|
2555
|
+
///
|
|
2556
|
+
/// Note:
|
|
2557
|
+
/// "clean" models will be skipped, and won't result
|
|
2558
|
+
/// in any output.
|
|
2559
|
+
///
|
|
2560
|
+
/// Arguments:
|
|
2561
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2562
|
+
/// The model class of all `models` being inserted.
|
|
2563
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2564
|
+
/// An array of model instances, or a single model instance. These are the models
|
|
2565
|
+
/// that are being inserted into the database.
|
|
2566
|
+
/// options: object
|
|
2567
|
+
/// Options for the operation.
|
|
2568
|
+
///
|
|
2569
|
+
/// Return: string
|
|
2570
|
+
/// If all models are clean, or no model instances are provided,
|
|
2571
|
+
/// then an empty string will be returned. Otherwise, a fully
|
|
2572
|
+
/// formatted `INSERT` statement will be returned.
|
|
1396
2573
|
generateInsertStatement(Model, _models, _options) {
|
|
1397
2574
|
let options = _options || {};
|
|
1398
2575
|
let preparedModels = this.connection.prepareAllModelsForOperation(Model, _models, options);
|
|
@@ -1431,10 +2608,92 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1431
2608
|
return `INSERT INTO ${escapedTableName} (${escapedFieldNames}) VALUES ${values}`;
|
|
1432
2609
|
}
|
|
1433
2610
|
|
|
2611
|
+
/// Generate a "tail" for an `UPDATE` statement.
|
|
2612
|
+
///
|
|
2613
|
+
/// This method is provided to allow the connection
|
|
2614
|
+
/// itself for any given database to "tack on extra" to
|
|
2615
|
+
/// an `UPDATE` statement. This is commonly used by databases
|
|
2616
|
+
/// to add on a `RETURNING` clause to the `UPDATE` statement.
|
|
2617
|
+
/// However, its primary purpose is just to allow the engine
|
|
2618
|
+
/// (or the user via overloading) to add on any "extra" to
|
|
2619
|
+
/// an `UPDATE` statement.
|
|
2620
|
+
///
|
|
2621
|
+
/// Arguments:
|
|
2622
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2623
|
+
/// The model class of all `models` being updated.
|
|
2624
|
+
/// model: object | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2625
|
+
/// The model instance being updated. Bulk-updates aren't really supported
|
|
2626
|
+
/// well by any SQL database, so Mythix ORM takes the long route and
|
|
2627
|
+
/// updates model instances one-by-one. If `queryEngine` is a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance,
|
|
2628
|
+
/// then this should be a raw object listing the attributes (field names and values)
|
|
2629
|
+
/// that should be applied across all matching rows.
|
|
2630
|
+
/// queryEngine: null | [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2631
|
+
/// The query engine used for the update statement--if any. Updates have
|
|
2632
|
+
/// two primary paths: 1) update a single model instance, or 2) update across
|
|
2633
|
+
/// multiple rows at once. For the latter, a query engine will be used to
|
|
2634
|
+
/// select which rows to update. In this case, the `queryEngine` argument
|
|
2635
|
+
/// here will be a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance.
|
|
2636
|
+
/// In the case that we are updating a single model instance, then this
|
|
2637
|
+
/// `queryEngine` will be `null`.
|
|
2638
|
+
/// options: object
|
|
2639
|
+
/// Options for the operation.
|
|
2640
|
+
/// context: object
|
|
2641
|
+
/// Useful information about the update operation taking place. This is an
|
|
2642
|
+
/// object with the shape:
|
|
2643
|
+
/// ```javascript
|
|
2644
|
+
/// {
|
|
2645
|
+
/// queryEngine: QueryEngine | null;
|
|
2646
|
+
/// escapedTableName: string;
|
|
2647
|
+
/// modelChanges: Array<object>;
|
|
2648
|
+
/// dirtyFields: Array<Field>;
|
|
2649
|
+
/// where: string | null;
|
|
2650
|
+
/// }
|
|
2651
|
+
/// ```
|
|
2652
|
+
///
|
|
2653
|
+
/// Return: string
|
|
2654
|
+
/// Any "extra" SQL to add onto the end of the `UPDATE` statement.
|
|
2655
|
+
/// Most connection drivers will usually use this for a `RETURNING` clause.
|
|
1434
2656
|
// eslint-disable-next-line no-unused-vars
|
|
1435
2657
|
generateUpdateStatementTail(Model, model, queryEngine, options, context) {
|
|
1436
2658
|
}
|
|
1437
2659
|
|
|
2660
|
+
/// Generate an `UPDATE` statement.
|
|
2661
|
+
///
|
|
2662
|
+
/// Update statements in Mythix ORM generally take one of
|
|
2663
|
+
/// two forms: 1) Update a single model instance, or 2) Update
|
|
2664
|
+
/// one or more columns across multiple rows at once.
|
|
2665
|
+
///
|
|
2666
|
+
/// When updating a single model instance, the provided `model`
|
|
2667
|
+
/// argument should the model instance to update, and is expected
|
|
2668
|
+
/// to have dirty fields. If on the other hand the `queryEngine`
|
|
2669
|
+
/// argument is provided, and is a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance,
|
|
2670
|
+
/// then the provided `model` argument should be a raw object
|
|
2671
|
+
/// of attributes (field names) to update across all matching rows.
|
|
2672
|
+
///
|
|
2673
|
+
/// Arguments:
|
|
2674
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2675
|
+
/// The model class of the model being updated.
|
|
2676
|
+
/// model: object | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2677
|
+
/// The model instance being updated. Bulk-updates aren't really supported
|
|
2678
|
+
/// well by any SQL database, so Mythix ORM takes the long route and
|
|
2679
|
+
/// updates model instances one-by-one. If `queryEngine` is a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance,
|
|
2680
|
+
/// then this should be a raw object listing the attributes (field names and values)
|
|
2681
|
+
/// that should be applied across all matching rows.
|
|
2682
|
+
/// queryEngine: null | [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2683
|
+
/// The query engine used for the update statement--if any. Updates have
|
|
2684
|
+
/// two primary paths: 1) update a single model instance, or 2) update across
|
|
2685
|
+
/// multiple rows at once. For the latter, a query engine will be used to
|
|
2686
|
+
/// select which rows to update. In this case, the `queryEngine` argument
|
|
2687
|
+
/// here will be a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance.
|
|
2688
|
+
/// In the case that we are updating a single model instance, then this
|
|
2689
|
+
/// `queryEngine` will be `null`.
|
|
2690
|
+
/// options: object
|
|
2691
|
+
/// Options for the operation.
|
|
2692
|
+
///
|
|
2693
|
+
/// Return: string
|
|
2694
|
+
/// Return a fully formatted `UPDATE` statement, either for
|
|
2695
|
+
/// updating a single model instance, or for updating multiple
|
|
2696
|
+
/// rows at once using the provided attributes.
|
|
1438
2697
|
generateUpdateStatement(Model, _model, _queryEngine, _options) {
|
|
1439
2698
|
if (!_model)
|
|
1440
2699
|
return '';
|
|
@@ -1519,6 +2778,30 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1519
2778
|
return sqlParts.join('');
|
|
1520
2779
|
}
|
|
1521
2780
|
|
|
2781
|
+
/// Generate a `RETURNING` clause for a `DELETE` statement.
|
|
2782
|
+
///
|
|
2783
|
+
/// Arguments:
|
|
2784
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2785
|
+
/// The model class defining the table that is being deleted from.
|
|
2786
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2787
|
+
/// The query engine being used to specify which rows to delete.
|
|
2788
|
+
/// pkField: undefined | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
2789
|
+
/// The primary key field of the provided `Model`, if it has one. If the model has
|
|
2790
|
+
/// no primary key field, then this will be `undefined`.
|
|
2791
|
+
/// escapedColumnName: string
|
|
2792
|
+
/// The full column name (usually including the table name) of the column to use for the `RETURNING`
|
|
2793
|
+
/// clause. If the provided `Model` has a primary key field, then this should be that column name
|
|
2794
|
+
/// (though the name might be an alias of that column name, depending on how the `DELETE` statement
|
|
2795
|
+
/// is generated). If the provided `Model` has no primary key field, then this will be `*`.
|
|
2796
|
+
/// This column name might differ from the field's column name, because the `DELETE` statement
|
|
2797
|
+
/// might be constructed such that an alias name is needed for the column name.
|
|
2798
|
+
/// options?: object
|
|
2799
|
+
/// Options for the operation.
|
|
2800
|
+
///
|
|
2801
|
+
/// Return: string
|
|
2802
|
+
/// Return a `RETURNING` clause to apply to the end of a `DELETE` statement. If
|
|
2803
|
+
/// `escapedColumnName` is empty, then an empty string will be returned.
|
|
2804
|
+
// eslint-disable-next-line no-unused-vars
|
|
1522
2805
|
generateDeleteStatementReturningClause(Model, queryEngine, pkField, escapedColumnName, options) {
|
|
1523
2806
|
if (!escapedColumnName)
|
|
1524
2807
|
return '';
|
|
@@ -1526,8 +2809,43 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1526
2809
|
return `RETURNING ${escapedColumnName}`;
|
|
1527
2810
|
}
|
|
1528
2811
|
|
|
1529
|
-
|
|
1530
|
-
|
|
2812
|
+
/// Generate a `DELETE` statement to delete rows from
|
|
2813
|
+
/// the table defined by `Model`, either by using a
|
|
2814
|
+
/// query provided by the user, or by generating a query
|
|
2815
|
+
/// based on the provided model instances. If no query
|
|
2816
|
+
/// or model instances are provided, then generate a
|
|
2817
|
+
/// `DELETE` statement that will delete every row from
|
|
2818
|
+
/// the table, truncating the table.
|
|
2819
|
+
///
|
|
2820
|
+
/// Arguments:
|
|
2821
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2822
|
+
/// The model class defining the table that is being deleted from.
|
|
2823
|
+
/// 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)
|
|
2824
|
+
/// Model instance(s) to delete, or a query engine specifying which rows to delete.
|
|
2825
|
+
/// If model instances are provided, then their primary key field will be used to
|
|
2826
|
+
/// create a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2827
|
+
/// used to delete those specific primary keys from the database. If the `Model` provided
|
|
2828
|
+
/// has no primary key field, then an exception will be thrown, as deleting model instances
|
|
2829
|
+
/// this way requires the model have a primary key field. If your model has no primary key
|
|
2830
|
+
/// field, then it is required that the user generate their own query to select which rows
|
|
2831
|
+
/// to delete from the underlying table. Instead of provided model instances, the user
|
|
2832
|
+
/// can provide a raw [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine) instance
|
|
2833
|
+
/// that will be used to select which rows to delete instead. If neither is provided, then
|
|
2834
|
+
/// the entire table will be truncated.
|
|
2835
|
+
/// options?: object
|
|
2836
|
+
/// Options for the operation. These are simply passed through to any sub-calls
|
|
2837
|
+
/// this method makes internally.
|
|
2838
|
+
///
|
|
2839
|
+
/// Return: string
|
|
2840
|
+
/// Return a fully formatted `DELETE` statement to delete rows from the
|
|
2841
|
+
/// table defined by the provided `Model`. If no model instances or [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2842
|
+
/// are provided, then a simple `DELETE FROM "table_name";` statement will be
|
|
2843
|
+
/// generated, truncating the entire table. If model instances or a [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
2844
|
+
/// are provided, then a `DELETE` statement in the form of
|
|
2845
|
+
/// `DELETE FROM "table_name" WHERE EXISTS(SELECT ...)` will be returned,
|
|
2846
|
+
/// selecting which rows to delete with the provided query.
|
|
2847
|
+
generateDeleteStatement(Model, _modelsOrQueryEngine, _options) {
|
|
2848
|
+
let queryEngine = _modelsOrQueryEngine;
|
|
1531
2849
|
let options = _options;
|
|
1532
2850
|
|
|
1533
2851
|
if (queryEngine) {
|
|
@@ -1589,7 +2907,34 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1589
2907
|
}
|
|
1590
2908
|
}
|
|
1591
2909
|
|
|
1592
|
-
|
|
2910
|
+
/// Iterate all fields of the provided `Model`, and
|
|
2911
|
+
/// collect and return all fields that have a `defaultValue`
|
|
2912
|
+
/// with the `remote` flag set. The `remote` flag on
|
|
2913
|
+
/// the `defaultValue` of a field tells Mythix ORM that the
|
|
2914
|
+
/// default value is provided by the database itself. This
|
|
2915
|
+
/// would be the case for example for `AUTOINCREMENT` ids,
|
|
2916
|
+
/// and for `NOW()` date columns--among others.
|
|
2917
|
+
///
|
|
2918
|
+
/// Any field that is marked with a `remote` default (a value
|
|
2919
|
+
/// provided by the database itself) should always be part of any
|
|
2920
|
+
/// `RETURNING` clause in-play, so this method is used to ensure
|
|
2921
|
+
/// all `remote` fields are part of the `RETURNING` clause.
|
|
2922
|
+
/// See [Helpers](https://github.com/th317erd/mythix-orm/wiki/Helpers) in
|
|
2923
|
+
/// the Mythix ORM documentation for a better explanation of "remote" fields
|
|
2924
|
+
/// and flags.
|
|
2925
|
+
///
|
|
2926
|
+
/// Arguments:
|
|
2927
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2928
|
+
/// The model whose "remote" fields should be collected.
|
|
2929
|
+
/// options?: object
|
|
2930
|
+
/// Options for the operation.
|
|
2931
|
+
///
|
|
2932
|
+
/// Return: Array<string>
|
|
2933
|
+
/// Return an array of escaped column names for direct use on
|
|
2934
|
+
/// a `RETURNING` clause. If the provided `Model` has no "remote"
|
|
2935
|
+
/// fields, then an empty array will be returned.
|
|
2936
|
+
// eslint-disable-next-line no-unused-vars
|
|
2937
|
+
_collectRemoteReturningFields(Model, options) {
|
|
1593
2938
|
let remoteFieldNames = [];
|
|
1594
2939
|
|
|
1595
2940
|
Model.iterateFields(({ field }) => {
|
|
@@ -1608,7 +2953,40 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1608
2953
|
return remoteFieldNames;
|
|
1609
2954
|
}
|
|
1610
2955
|
|
|
1611
|
-
|
|
2956
|
+
/// Generate a `RETURNING` clause for `UPDATE`
|
|
2957
|
+
/// and `INSERT` statements.
|
|
2958
|
+
///
|
|
2959
|
+
/// This will generate a `RETURNING` clause that
|
|
2960
|
+
/// will always includes all "remote" fields for the `Model`
|
|
2961
|
+
/// provided, will always include the primary key of the
|
|
2962
|
+
/// model (if the model has one), and will include all
|
|
2963
|
+
/// fields marked as "dirty" across all models being inserted
|
|
2964
|
+
/// or updated.
|
|
2965
|
+
///
|
|
2966
|
+
/// Arguments:
|
|
2967
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2968
|
+
/// The model that defines the table for the insert or update operation.
|
|
2969
|
+
/// models: Array<[Model](https://github.com/th317erd/mythix-orm/wiki/Model)> | [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
2970
|
+
/// An array of model instances, or a single model instance. These are the models
|
|
2971
|
+
/// that are being inserted or updated.
|
|
2972
|
+
/// options: object
|
|
2973
|
+
/// Options for the operation.
|
|
2974
|
+
/// context: object
|
|
2975
|
+
/// The same `context` that is provided to <see>SQLQueryGeneratorBase.generateInsertStatementTail</see> or
|
|
2976
|
+
/// <see>SQLQueryGeneratorBase.generateUpdateStatementTail</see>, depending on if this is an
|
|
2977
|
+
/// insert or update operation.
|
|
2978
|
+
///
|
|
2979
|
+
/// Return: string
|
|
2980
|
+
/// Return a `RETURNING` clause to apply to the end of an `UPDATE`
|
|
2981
|
+
/// or `INSERT` statement. If no fields are found for this clause,
|
|
2982
|
+
/// then an empty string will be returned.
|
|
2983
|
+
///
|
|
2984
|
+
/// See: SQLQueryGeneratorBase.generateInsertStatementTail
|
|
2985
|
+
///
|
|
2986
|
+
/// See: SQLQueryGeneratorBase.generateUpdateStatementTail
|
|
2987
|
+
///
|
|
2988
|
+
/// See: SQLQueryGeneratorBase._collectRemoteReturningFields
|
|
2989
|
+
generateReturningClause(Model, models, options, context) {
|
|
1612
2990
|
let {
|
|
1613
2991
|
modelChanges,
|
|
1614
2992
|
dirtyFields,
|
|
@@ -1632,7 +3010,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1632
3010
|
if (!fieldValue.options.remote)
|
|
1633
3011
|
continue;
|
|
1634
3012
|
|
|
1635
|
-
let escapedColumnName = this.getEscapedColumnName(dirtyField.Model, dirtyField);
|
|
3013
|
+
let escapedColumnName = this.getEscapedColumnName(dirtyField.Model, dirtyField, options);
|
|
1636
3014
|
returnFieldsMap[escapedColumnName] = true;
|
|
1637
3015
|
|
|
1638
3016
|
break;
|
|
@@ -1652,17 +3030,41 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1652
3030
|
|
|
1653
3031
|
let returnFields = Object.keys(returnFieldsMap);
|
|
1654
3032
|
if (!returnFields.length)
|
|
1655
|
-
return;
|
|
3033
|
+
return '';
|
|
1656
3034
|
|
|
1657
3035
|
return `RETURNING ${returnFields.join(',')}`;
|
|
1658
3036
|
}
|
|
1659
3037
|
|
|
3038
|
+
/// Generate a `TRUNCATE TABLE` statement.
|
|
3039
|
+
///
|
|
3040
|
+
/// Arguments:
|
|
3041
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
3042
|
+
/// The model that defines the table being truncated.
|
|
3043
|
+
/// options?: object
|
|
3044
|
+
/// Options for the operation.
|
|
3045
|
+
///
|
|
3046
|
+
/// Return: string
|
|
3047
|
+
/// Return a fully formatted `TRUNCATE TABLE` statement.
|
|
1660
3048
|
// eslint-disable-next-line no-unused-vars
|
|
1661
3049
|
generateTruncateTableStatement(Model, _options) {
|
|
1662
3050
|
let escapedTableName = this.escapeID(Model.getTableName(this.connection));
|
|
1663
3051
|
return `TRUNCATE TABLE ${escapedTableName}`;
|
|
1664
3052
|
}
|
|
1665
3053
|
|
|
3054
|
+
/// Generate an `ALTER TABLE` statement
|
|
3055
|
+
/// to rename the table.
|
|
3056
|
+
///
|
|
3057
|
+
/// Arguments:
|
|
3058
|
+
/// Model: class [Model](https://github.com/th317erd/mythix-orm/wiki/Model)
|
|
3059
|
+
/// The model that defines the table being altered.
|
|
3060
|
+
/// newModelAttributes: object
|
|
3061
|
+
/// An object that contains a `tableName` key for the new table name
|
|
3062
|
+
/// options?: object
|
|
3063
|
+
/// Options for the operation.
|
|
3064
|
+
///
|
|
3065
|
+
/// Return: Array<string>
|
|
3066
|
+
/// An array of `ALTER TABLE` statements to change the table's name. For
|
|
3067
|
+
/// most databases this will probably only be a single statement.
|
|
1666
3068
|
generateAlterTableStatement(Model, newModelAttributes, options) {
|
|
1667
3069
|
if (Nife.isEmpty(newModelAttributes))
|
|
1668
3070
|
return [];
|
|
@@ -1678,6 +3080,23 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1678
3080
|
return statements;
|
|
1679
3081
|
}
|
|
1680
3082
|
|
|
3083
|
+
/// Generate an `ALTER TABLE ... DROP COLUMN` statement.
|
|
3084
|
+
///
|
|
3085
|
+
/// Arguments:
|
|
3086
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3087
|
+
/// The field to drop from the database.
|
|
3088
|
+
/// options?:
|
|
3089
|
+
/// Options for the operation. Though these might contain
|
|
3090
|
+
/// database specific options, generic options that should
|
|
3091
|
+
/// work for most databases are:
|
|
3092
|
+
/// | Option | Type | Default Value | Description |
|
|
3093
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
3094
|
+
/// | `ifExists` | `boolean` | `false` | If `true`, then add an `IF EXISTS` clause to the `ALTER TABLE` statement. |
|
|
3095
|
+
/// | `cascade` | `boolean` | `true` | If `true`, then add a `CASCADE` clause to the `ALTER TABLE` statement. |
|
|
3096
|
+
///
|
|
3097
|
+
/// Return: string
|
|
3098
|
+
/// An `ALTER TABLE` statement to drop the column specified
|
|
3099
|
+
/// by the provided `field`.
|
|
1681
3100
|
generateDropColumnStatement(field, _options) {
|
|
1682
3101
|
let Model = field.Model;
|
|
1683
3102
|
let options = _options || {};
|
|
@@ -1685,15 +3104,46 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1685
3104
|
return `ALTER TABLE ${this.getEscapedTableName(Model, options)} DROP COLUMN${(options.ifExists) ? ' IF EXISTS' : ''} ${this.getEscapedColumnName(Model, field, { ...options, columnNameOnly: true })} ${(options.cascade !== false) ? 'CASCADE' : 'RESTRICT'}`;
|
|
1686
3105
|
}
|
|
1687
3106
|
|
|
3107
|
+
/// Generate an `ALTER TABLE ... RENAME COLUMN` statement.
|
|
3108
|
+
///
|
|
3109
|
+
/// Arguments:
|
|
3110
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3111
|
+
/// The field to rename in the database.
|
|
3112
|
+
/// newField: object | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3113
|
+
/// A raw object containing a `columnName` or `fieldName` properties, or a `Field` instance
|
|
3114
|
+
/// containing a `columnName` or `fieldName`. This will be used as the new name
|
|
3115
|
+
/// of the column.
|
|
3116
|
+
/// options?:
|
|
3117
|
+
/// Options for the operation.
|
|
3118
|
+
///
|
|
3119
|
+
/// Return: string
|
|
3120
|
+
/// An `ALTER TABLE` statement to rename the column specified
|
|
3121
|
+
/// by the provided `field`.
|
|
1688
3122
|
generateAlterColumnRenameStatement(field, newField, _options) {
|
|
1689
3123
|
let Model = field.Model;
|
|
1690
3124
|
let options = _options || {};
|
|
1691
3125
|
let prefix = `ALTER TABLE ${this.getEscapedTableName(Model, options)}`;
|
|
1692
3126
|
let escapedColumnName = this.getEscapedColumnName(Model, field, { ...options, columnNameOnly: true });
|
|
1693
3127
|
|
|
1694
|
-
return `${prefix} RENAME COLUMN ${escapedColumnName} TO ${this.escapeID(newField.columnName)}`;
|
|
1695
|
-
}
|
|
1696
|
-
|
|
3128
|
+
return `${prefix} RENAME COLUMN ${escapedColumnName} TO ${this.escapeID(newField.columnName || newField.fieldName)}`;
|
|
3129
|
+
}
|
|
3130
|
+
|
|
3131
|
+
/// Generate an `ALTER TABLE` statement to add or remove
|
|
3132
|
+
/// a `NOT NULL` constraint on the specified `field`.
|
|
3133
|
+
///
|
|
3134
|
+
/// Arguments:
|
|
3135
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3136
|
+
/// The field to add or remove the constraint from in the database.
|
|
3137
|
+
/// newField: object | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3138
|
+
/// A raw object containing an `allowNull` property, or a `Field` instance
|
|
3139
|
+
/// containing a `allowNull` property. If `true`, then a `NOT NULL` constraint
|
|
3140
|
+
/// will be added. If `false`, then any `NOT NULL` constraint will be dropped.
|
|
3141
|
+
/// options?:
|
|
3142
|
+
/// Options for the operation.
|
|
3143
|
+
///
|
|
3144
|
+
/// Return: string
|
|
3145
|
+
/// An `ALTER TABLE` statement to add or remove the `NOT NULL` constraint
|
|
3146
|
+
/// of the specified `field`.
|
|
1697
3147
|
generateAlterColumnSetOrDropNullConstraintStatement(field, newField, _options) {
|
|
1698
3148
|
let Model = field.Model;
|
|
1699
3149
|
let options = _options || {};
|
|
@@ -1703,6 +3153,26 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1703
3153
|
return `${prefix} ALTER COLUMN ${escapedColumnName} ${(newField.allowNull) ? 'DROP' : 'SET'} NOT NULL`;
|
|
1704
3154
|
}
|
|
1705
3155
|
|
|
3156
|
+
/// Generate an `ALTER TABLE` statement to add or remove
|
|
3157
|
+
/// a `DEFAULT` value for the specified `field`.
|
|
3158
|
+
///
|
|
3159
|
+
/// Arguments:
|
|
3160
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3161
|
+
/// The field to add or remove the `DEFAULT` value from in the database.
|
|
3162
|
+
/// newField: object | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3163
|
+
/// A raw object or a `Field` instance defining how the field is being altered.
|
|
3164
|
+
/// This argument is not used by this method, but is passed through when calling
|
|
3165
|
+
/// other alter table generators.
|
|
3166
|
+
/// newDefaultValue: any
|
|
3167
|
+
/// The new `DEFAULT` value to apply to the column. If this argument is `undefined`,
|
|
3168
|
+
/// then any `DEFAULT` value applied to the column will be dropped. This value must
|
|
3169
|
+
/// already be escaped and ready for the underlying database to consume.
|
|
3170
|
+
/// options?:
|
|
3171
|
+
/// Options for the operation.
|
|
3172
|
+
///
|
|
3173
|
+
/// Return: string
|
|
3174
|
+
/// An `ALTER TABLE ... ALTER COLUMN ... DROP | SET DEFAULT` statement to add or set
|
|
3175
|
+
/// a `DEFAULT` value for this column.
|
|
1706
3176
|
generateAlterColumnSetDefaultStatement(field, newField, newDefaultValue, _options) {
|
|
1707
3177
|
let Model = field.Model;
|
|
1708
3178
|
let options = _options || {};
|
|
@@ -1715,6 +3185,25 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1715
3185
|
return `${prefix} ALTER COLUMN ${escapedColumnName} SET DEFAULT ${newDefaultValue}`;
|
|
1716
3186
|
}
|
|
1717
3187
|
|
|
3188
|
+
/// Generate an `ALTER TABLE` statement to change the
|
|
3189
|
+
/// type of the `field` specified.
|
|
3190
|
+
///
|
|
3191
|
+
/// Arguments:
|
|
3192
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3193
|
+
/// The field to change the type on in the database.
|
|
3194
|
+
/// newField: object | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3195
|
+
/// A raw object or a `Field` instance defining how the field is being altered.
|
|
3196
|
+
/// This argument is not used by this method, but is passed through when calling
|
|
3197
|
+
/// other alter table generators.
|
|
3198
|
+
/// newFieldType: string
|
|
3199
|
+
/// The new type to change the field/column to. This must be a raw type that
|
|
3200
|
+
/// the underlying database supports, in database format.
|
|
3201
|
+
/// options?:
|
|
3202
|
+
/// Options for the operation.
|
|
3203
|
+
///
|
|
3204
|
+
/// Return: string
|
|
3205
|
+
/// An `ALTER TABLE ... ALTER COLUMN ... SET DATA TYPE` statement to alter
|
|
3206
|
+
/// the column's data type.
|
|
1718
3207
|
generateAlterColumnChangeTypeStatement(field, newField, newFieldType, _options) {
|
|
1719
3208
|
let Model = field.Model;
|
|
1720
3209
|
let options = _options || {};
|
|
@@ -1724,6 +3213,22 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1724
3213
|
return `${prefix} ALTER COLUMN ${escapedColumnName} SET DATA TYPE ${newFieldType}`;
|
|
1725
3214
|
}
|
|
1726
3215
|
|
|
3216
|
+
/// Generate an `ALTER TABLE` statement to add or remove
|
|
3217
|
+
/// a `PRIMARY KEY` constraint on the specified `field`.
|
|
3218
|
+
///
|
|
3219
|
+
/// Arguments:
|
|
3220
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3221
|
+
/// The field to add or remove the constraint from in the database.
|
|
3222
|
+
/// newField: object | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3223
|
+
/// A raw object containing an `primaryKey` property, or a `Field` instance
|
|
3224
|
+
/// containing a `primaryKey` property. If `true`, then a `PRIMARY KEY` constraint
|
|
3225
|
+
/// will be added. If `false`, then any `PRIMARY KEY` constraint will be dropped.
|
|
3226
|
+
/// options?:
|
|
3227
|
+
/// Options for the operation.
|
|
3228
|
+
///
|
|
3229
|
+
/// Return: string
|
|
3230
|
+
/// An `ALTER TABLE` statement to add or remove the `PRIMARY KEY` constraint
|
|
3231
|
+
/// of the specified `field`.
|
|
1727
3232
|
generateAlterColumnChangePrimaryKeyConstraintStatement(field, newField, _options) {
|
|
1728
3233
|
let Model = field.Model;
|
|
1729
3234
|
let options = _options || {};
|
|
@@ -1736,6 +3241,22 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1736
3241
|
return `${prefix} ALTER COLUMN ${escapedColumnName} DROP CONSTRAINT PRIMARY KEY`;
|
|
1737
3242
|
}
|
|
1738
3243
|
|
|
3244
|
+
/// Generate an `ALTER TABLE` statement to add or remove
|
|
3245
|
+
/// a `UNIQUE` constraint on the specified `field`.
|
|
3246
|
+
///
|
|
3247
|
+
/// Arguments:
|
|
3248
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3249
|
+
/// The field to add or remove the constraint from in the database.
|
|
3250
|
+
/// newField: object | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3251
|
+
/// A raw object containing an `unique` property, or a `Field` instance
|
|
3252
|
+
/// containing a `unique` property. If `true`, then a `UNIQUE` constraint
|
|
3253
|
+
/// will be added. If `false`, then any `UNIQUE` constraint will be dropped.
|
|
3254
|
+
/// options?:
|
|
3255
|
+
/// Options for the operation.
|
|
3256
|
+
///
|
|
3257
|
+
/// Return: string
|
|
3258
|
+
/// An `ALTER TABLE` statement to add or remove a `UNIQUE` constraint
|
|
3259
|
+
/// of the specified `field`.
|
|
1739
3260
|
generateAlterColumnChangeUniqueConstraintStatement(field, newField, _options) {
|
|
1740
3261
|
let Model = field.Model;
|
|
1741
3262
|
let options = _options || {};
|
|
@@ -1748,6 +3269,28 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1748
3269
|
return `${prefix} ALTER COLUMN ${escapedColumnName} DROP CONSTRAINT UNIQUE`;
|
|
1749
3270
|
}
|
|
1750
3271
|
|
|
3272
|
+
/// Generate multiple `ALTER TABLE` statements to change the
|
|
3273
|
+
/// `field` provided to match the `newFieldAttributes` provided.
|
|
3274
|
+
///
|
|
3275
|
+
/// Arguments:
|
|
3276
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3277
|
+
/// The field to alter in the database.
|
|
3278
|
+
/// newFieldAttributes: object | [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3279
|
+
/// A raw object containing field properties, or a `Field` instance. Any differing
|
|
3280
|
+
/// properties between these two "fields" will generate an `ALTER TABLE` statement
|
|
3281
|
+
/// for that difference. For example, if the `columnName` between both "fields" is
|
|
3282
|
+
/// different, then an `ALTER TABLE` statement will be generated to change the column's
|
|
3283
|
+
/// name. Properties that are checked for differences are: `primaryKey`, `unique`, `index`,
|
|
3284
|
+
/// `columnName` & `fieldName`, `allowNull`, `type`, and `defaultValue`. If any of these
|
|
3285
|
+
/// differ between the two provided "fields", then an `ALTER TABLE` statement will be generated
|
|
3286
|
+
/// to update the column to match the new properties of `newFieldAttributes`.
|
|
3287
|
+
/// options?:
|
|
3288
|
+
/// Options for the operation.
|
|
3289
|
+
///
|
|
3290
|
+
/// Return: Array<string>
|
|
3291
|
+
/// Multiple `ALTER TABLE` statements to alter the specified `field`
|
|
3292
|
+
/// to match the new properties defined by `newFieldAttributes`. If
|
|
3293
|
+
/// no changes are detected, then an empty array will be returned instead.
|
|
1751
3294
|
generateAlterColumnStatements(field, _newFieldAttributes, _options) {
|
|
1752
3295
|
if (Nife.isEmpty(_newFieldAttributes))
|
|
1753
3296
|
return [];
|
|
@@ -1843,6 +3386,22 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1843
3386
|
return statements.filter(Boolean);
|
|
1844
3387
|
}
|
|
1845
3388
|
|
|
3389
|
+
/// Generate an `ALTER TABLE ... ADD COLUMN` statement.
|
|
3390
|
+
///
|
|
3391
|
+
/// Arguments:
|
|
3392
|
+
/// field: [Field](https://github.com/th317erd/mythix-orm/wiki/Field)
|
|
3393
|
+
/// The field to add to the database.
|
|
3394
|
+
/// options?:
|
|
3395
|
+
/// Options for the operation. Though these might contain
|
|
3396
|
+
/// database specific options, generic options that should
|
|
3397
|
+
/// work for most databases are:
|
|
3398
|
+
/// | Option | Type | Default Value | Description |
|
|
3399
|
+
/// | ------ | ---- | ------------- | ----------- |
|
|
3400
|
+
/// | `ifNotExists` | `boolean` | `false` | If `true`, then add an `IF NOT EXISTS` clause to the `ALTER TABLE` statement. |
|
|
3401
|
+
///
|
|
3402
|
+
/// Return: string
|
|
3403
|
+
/// An `ALTER TABLE ... ADD COLUMN` statement to add the column specified
|
|
3404
|
+
/// by the provided `field`.
|
|
1846
3405
|
generateAddColumnStatement(field, _options) {
|
|
1847
3406
|
let Model = field.Model;
|
|
1848
3407
|
let options = _options || {};
|
|
@@ -1851,6 +3410,22 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
|
|
|
1851
3410
|
return `${prefix} ADD COLUMN${(options.ifNotExists) ? ' IF NOT EXISTS' : ''} ${this.generateColumnDeclarationStatement(Model, field, options)}`;
|
|
1852
3411
|
}
|
|
1853
3412
|
|
|
3413
|
+
/// Convert the provided `queryEngine` into
|
|
3414
|
+
/// a `SELECT` statement.
|
|
3415
|
+
///
|
|
3416
|
+
/// This is similar to a `toSQL` method in other ORMs.
|
|
3417
|
+
/// It is usually called directly from the `queryEngine` itself,
|
|
3418
|
+
/// i.e. `queryEngine.toString()` will call this method.
|
|
3419
|
+
///
|
|
3420
|
+
/// Arguments:
|
|
3421
|
+
/// queryEngine: [QueryEngine](https://github.com/th317erd/mythix-orm/wiki/QueryEngine)
|
|
3422
|
+
/// The query engine to use to generate a `SELECT` statement.
|
|
3423
|
+
/// options?: object
|
|
3424
|
+
/// Options for the operation. These are simply passed off to <see>SQLQueryGeneratorBase.generateSelectStatement</see>.
|
|
3425
|
+
///
|
|
3426
|
+
/// Return: string
|
|
3427
|
+
/// A fully formatted `SELECT` statement, that was generated from
|
|
3428
|
+
/// the provided `queryEngine`.
|
|
1854
3429
|
toConnectionString(queryEngine, options) {
|
|
1855
3430
|
return this.generateSelectStatement(queryEngine, options);
|
|
1856
3431
|
}
|