mythix-orm-sql-base 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -661,18 +661,18 @@ class SQLConnectionBase extends ConnectionBase {
661
661
  queryEngine = await this.finalizeQuery('read', queryEngine, options);
662
662
  queryEngine = queryEngine.clone();
663
663
 
664
- let queryContext = queryEngine.getOperationContext();
665
- let distinct = queryContext.distinct;
666
- if (distinct) {
667
- let fullyQualifiedFieldName = distinct.getFullyQualifiedFieldName();
668
-
669
- if (fullyQualifiedFieldName) {
670
- let LiteralConstructor = literal.constructor;
671
- literal = new LiteralConstructor(fullyQualifiedFieldName);
672
-
673
- queryEngine = queryEngine.DISTINCT(false).PROJECT(literal);
674
- }
675
- }
664
+ // let queryContext = queryEngine.getOperationContext();
665
+ // let distinct = queryContext.distinct;
666
+ // if (distinct) {
667
+ // let fullyQualifiedFieldName = distinct.getFullyQualifiedFieldName();
668
+
669
+ // if (fullyQualifiedFieldName) {
670
+ // let LiteralConstructor = literal.constructor;
671
+ // literal = new LiteralConstructor(fullyQualifiedFieldName);
672
+
673
+ // queryEngine = queryEngine.DISTINCT(false).PROJECT(literal);
674
+ // }
675
+ // }
676
676
 
677
677
  let literalStr = literal.toString(this);
678
678
  let queryGenerator = this.getQueryGenerator();
@@ -1,4 +1,4 @@
1
- import { Field, FieldOrderInfo, JoinTableInfo, Model, ModelClass, PreparedModels, QueryEngine, QueryGeneratorBase } from 'mythix-orm';
1
+ import { Field, Model, ModelClass, PreparedModels, QueryEngine, QueryGeneratorBase } from 'mythix-orm';
2
2
  import { LiteralBase } from 'mythix-orm/lib/connection/literals';
3
3
  import { GenericObject } from 'mythix-orm/lib/interfaces/common';
4
4
  import { Type } from 'mythix-orm/lib/types';
@@ -11,7 +11,61 @@ export declare interface QueryConditionContext {
11
11
  value: any;
12
12
  }
13
13
 
14
+ export declare interface GetEscapedFieldNameOptions {
15
+ fieldNameOnly?: boolean;
16
+ }
17
+
18
+ export declare interface GetEscapedTableNameNameOptions {
19
+ tableNamePrefix?: string;
20
+ }
21
+
22
+ export declare interface GetEscapedColumnNameOptions extends GetEscapedTableNameNameOptions {
23
+ columnNamePrefix?: string
24
+ columnNameOnly?: boolean;
25
+ }
26
+
27
+ export declare interface GetEscapedProjectionNameOptions extends GetEscapedColumnNameOptions, GetEscapedFieldNameOptions {
28
+ noProjectionAliases?: boolean;
29
+ }
30
+
31
+ export declare interface GetEscapedModelFieldsOptions extends GetEscapedProjectionNameOptions {
32
+ asProjection?: boolean;
33
+ asColumn?: boolean;
34
+ }
35
+
36
+ export declare interface JoinTableInfo {
37
+ operator: string;
38
+ joinType: string | LiteralBase;
39
+ rootModelName: string;
40
+ joinModel: ModelClass;
41
+ joinModelName: string;
42
+ leftSideModel: ModelClass;
43
+ leftSideModelName: string;
44
+ leftQueryContext: GenericObject;
45
+ leftSideField: Field;
46
+ rightSideModel: ModelClass;
47
+ rightSideModelName: string;
48
+ rightQueryContext: GenericObject;
49
+ rightSideField: Field;
50
+ }
51
+
14
52
  declare class SQLQueryGeneratorBase extends QueryGeneratorBase {
53
+ public getEscapedFieldName(Model: ModelClass | null | undefined, field: Field, options?: GetEscapedFieldNameOptions): string;
54
+ public getEscapedColumnName(Model: ModelClass | null | undefined, field: Field, options?: GetEscapedColumnNameOptions): string;
55
+ public getEscapedTableName(modelOrField: ModelClass | Field, options?: GetEscapedTableNameNameOptions): string;
56
+ public getEscapedProjectionName(Model: ModelClass | null | undefined, field: Field, options?: GetEscapedProjectionNameOptions): string;
57
+ public getEscapedModelFields(Model: ModelClass, options?: GetEscapedModelFieldsOptions): { [key: string]: string };
58
+ public isFieldIdentifier(value: string): boolean;
59
+ public getProjectedFields(queryEngine: QueryEngine, options?: GenericObject, asMap?: false | undefined): Array<string>;
60
+ public getProjectedFields(queryEngine: QueryEngine, options?: GenericObject, asMap?: true): Map<string, string>;
61
+
62
+ public getJoinTableInfoFromQueryContexts(
63
+ leftQueryContext: GenericObject,
64
+ rightQueryContext: GenericObject,
65
+ joinType: string | LiteralBase,
66
+ options?: GenericObject
67
+ ): JoinTableInfo;
68
+
15
69
  public prepareArrayValuesForSQL(array: Array<any>): Array<any>;
16
70
  public parseFieldProjection(value: string, getRawField: boolean): string | Field | undefined;
17
71
  public parseFieldProjectionToFieldMap(selectStatement: string): Map<string, Field | string>;
@@ -15,6 +15,296 @@ const DefaultHelpers = Types.DefaultHelpers;
15
15
  const LiteralBase = Literals.LiteralBase;
16
16
 
17
17
  class SQLQueryGeneratorBase extends QueryGeneratorBase {
18
+ getEscapedFieldName(_Model, field, options) {
19
+ let isString = Nife.instanceOf(field, 'string');
20
+ let fieldName = (isString) ? field : field.fieldName;
21
+ let Model = _Model;
22
+
23
+ if (!Model && field && !isString)
24
+ Model = field.Model;
25
+
26
+ if (!Model || (options && options.fieldNameOnly === true))
27
+ return this.escapeID(fieldName);
28
+ else
29
+ return `"${field.Model.getModelName()}:${fieldName}"`;
30
+ }
31
+
32
+ getEscapedColumnName(_Model, field, options) {
33
+ let isString = Nife.instanceOf(field, 'string');
34
+ let columnName = (isString) ? field : (field.columnName || field.fieldName);
35
+ let Model = _Model;
36
+
37
+ if (!Model && field && !isString)
38
+ Model = field.Model;
39
+
40
+ if (options && options.columnNamePrefix)
41
+ columnName = `${options.columnNamePrefix}${columnName}`;
42
+
43
+ if (!Model || (options && options.columnNameOnly === true))
44
+ return this.escapeID(columnName);
45
+ else
46
+ return `${this.getEscapedTableName(Model)}.${this.escapeID(columnName)}`;
47
+ }
48
+
49
+ getEscapedTableName(_modelOrField, options) {
50
+ let Model = (_modelOrField.Model) ? _modelOrField.Model : _modelOrField;
51
+ let tableName = Model.getTableName(this.connection);
52
+
53
+ if (options && options.tableNamePrefix)
54
+ tableName = `${options.tableNamePrefix}${tableName}`;
55
+
56
+ return this.escapeID(tableName);
57
+ }
58
+
59
+ // eslint-disable-next-line no-unused-vars
60
+ getEscapedProjectionName(Model, field, options) {
61
+ if (options && options.noProjectionAliases)
62
+ return this.getEscapedColumnName(Model, field, options);
63
+ else
64
+ return `${this.getEscapedColumnName(Model, field, options)} AS ${(options && options.as) ? this.escapeID(options.as) : this.getEscapedFieldName(Model, field, options)}`;
65
+ }
66
+
67
+ // eslint-disable-next-line no-unused-vars
68
+ getEscapedModelFields(Model, options) {
69
+ let fields = {};
70
+ let modelName = Model.getModelName();
71
+
72
+ Model.iterateFields(({ field, fieldName }) => {
73
+ if (field.type.isVirtual())
74
+ return;
75
+
76
+ let result;
77
+
78
+ if (options && options.asProjection)
79
+ result = this.getEscapedProjectionName(Model, field, options);
80
+ else if (options && options.asColumn)
81
+ result = this.getEscapedColumnName(Model, field, options);
82
+ else
83
+ result = this.getEscapedFieldName(Model, field, options);
84
+
85
+ fields[`${modelName}:${fieldName}`] = result;
86
+ }, (options && options.fields));
87
+
88
+ return fields;
89
+ }
90
+
91
+ isFieldIdentifier(str) {
92
+ return (/^"[^"]+"."[^"]+"|"\w+:[\w.]+"/i).test(str);
93
+ }
94
+
95
+ getQueryEngineOrder(queryEngine, _options) {
96
+ let options = _options || {};
97
+ let context = queryEngine.getOperationContext();
98
+ let order = context.order;
99
+
100
+ return (order && order.size) ? order : this.connection.getDefaultOrder(context.rootModel, options);
101
+ }
102
+
103
+ getProjectedFields(queryEngine, _options, asMap) {
104
+ let options = this.stackAssign(_options || {}, { isProjection: true });
105
+ let context = queryEngine.getOperationContext();
106
+ let queryProjection = new Map(context.projection);
107
+ let order = this.getQueryEngineOrder(queryEngine, options);
108
+ let allProjectionFields = new Map();
109
+ let allModelsUsedInQuery = queryEngine.getAllModelsUsedInQuery();
110
+
111
+ if (!options.isSubQuery && order && order.size) {
112
+ let contextOrderSupport = this.connection.isOrderSupportedInContext(options);
113
+ if (contextOrderSupport) {
114
+ for (let [ fullyQualifiedFieldName, orderScope ] of order) {
115
+ if (!queryProjection.has(fullyQualifiedFieldName))
116
+ queryProjection.set(fullyQualifiedFieldName, orderScope);
117
+ }
118
+ }
119
+ }
120
+
121
+ for (let [ fullyQualifiedName, projectedScope ] of queryProjection) {
122
+ let { value } = projectedScope;
123
+
124
+ if (Nife.instanceOf(value, 'string')) {
125
+ // Raw string is treated as a literal
126
+ allProjectionFields.set(fullyQualifiedName, value);
127
+ continue;
128
+ } else if (LiteralBase.isLiteral(value)) {
129
+ let result = value.toString(this.connection, options);
130
+ allProjectionFields.set(result || fullyQualifiedName, result || fullyQualifiedName);
131
+
132
+ continue;
133
+ }
134
+
135
+ if (allModelsUsedInQuery.indexOf(value.Model) < 0)
136
+ continue;
137
+
138
+ let escapedFieldName = this.getEscapedProjectionName(value.Model, value, options);
139
+ allProjectionFields.set(`${value.Model.getModelName()}:${value.fieldName}`, escapedFieldName);
140
+ }
141
+
142
+ if (asMap === true)
143
+ return allProjectionFields;
144
+ else
145
+ return Array.from(allProjectionFields.values());
146
+ }
147
+
148
+ // eslint-disable-next-line no-unused-vars
149
+ getJoinTableInfoFromQueryContexts(leftQueryContext, rightQueryContext, joinType, options) {
150
+ let rootModel = leftQueryContext.rootModel;
151
+ let rootModelName = rootModel.getModelName();
152
+ let leftSideModel = leftQueryContext.Model;
153
+ let leftSideModelName = leftQueryContext.modelName;
154
+ if (!leftSideModel)
155
+ throw new Error(`${this.constructor.name}::getJoinTableInfoFromQueryEngine: Invalid operation: No model found for left-side of join statement.`);
156
+
157
+ let leftSideField = leftQueryContext.Field;
158
+ if (!leftSideField)
159
+ throw new Error(`${this.constructor.name}::getJoinTableInfoFromQueryEngine: Invalid operation: No left-side field found to match on for table join statement.`);
160
+
161
+ let isNot = leftQueryContext.not;
162
+ let operator = (isNot) ? leftQueryContext.inverseOperator : leftQueryContext.operator;
163
+ let rightSideModel = rightQueryContext.Model;
164
+ let rightSideModelName = rightQueryContext.modelName;
165
+ if (!rightSideModel)
166
+ throw new Error(`${this.constructor.name}::getJoinTableInfoFromQueryEngine: Invalid operation: No model found for right-side of join statement.`);
167
+
168
+ let rightSideField = rightQueryContext.Field;
169
+ if (!rightSideField)
170
+ throw new Error(`${this.constructor.name}::getJoinTableInfoFromQueryEngine: Invalid operation: No right-side field found to match on for table join statement.`);
171
+
172
+ let swapJoinRelation = (rightSideModelName === rootModelName);
173
+ let joinModel = (swapJoinRelation) ? leftSideModel : rightSideModel;
174
+ let joinModelName = (swapJoinRelation) ? leftSideModelName : rightSideModelName;
175
+
176
+ return {
177
+ operator,
178
+ joinType,
179
+ rootModelName,
180
+
181
+ joinModel,
182
+ joinModelName,
183
+
184
+ leftSideModel,
185
+ leftSideModelName,
186
+ leftQueryContext,
187
+ leftSideField,
188
+
189
+ rightSideModel,
190
+ rightSideModelName,
191
+ rightQueryContext,
192
+ rightSideField,
193
+ };
194
+ }
195
+
196
+ _getLiteralAlias(literal, options) {
197
+ let as = (literal.options && literal.options.as) || (options && options.as);
198
+ if (Nife.isEmpty(as))
199
+ return '';
200
+
201
+ return ` AS ${this.escapeID(as)}`;
202
+ }
203
+
204
+ _averageLiteralToString(literal, options) {
205
+ if (!literal || !LiteralBase.isLiteral(literal))
206
+ return;
207
+
208
+ let field = literal.getField(this.connection);
209
+ let escapedFieldName;
210
+
211
+ if (LiteralBase.isLiteral(field))
212
+ escapedFieldName = field.toString(this.connection, options);
213
+ else
214
+ escapedFieldName = this.getEscapedColumnName(field.Model, field, this.stackAssign(options, literal.options));
215
+
216
+ return `AVG(${escapedFieldName})${this._getLiteralAlias(literal, options)}`;
217
+ }
218
+
219
+ _countLiteralToString(literal, options) {
220
+ if (!literal || !LiteralBase.isLiteral(literal))
221
+ return;
222
+
223
+ let field = literal.getField(this.connection);
224
+ let escapedFieldName;
225
+
226
+ if (field) {
227
+ if (LiteralBase.isLiteral(field))
228
+ escapedFieldName = field.toString(this.connection, options);
229
+ else
230
+ escapedFieldName = this.getEscapedColumnName(field.Model, field, this.stackAssign(options, literal.options));
231
+ } else {
232
+ escapedFieldName = '*';
233
+ }
234
+
235
+ return `COUNT(${escapedFieldName})${this._getLiteralAlias(literal, options)}`;
236
+ }
237
+
238
+ _distinctLiteralToString(literal, options) {
239
+ if (!literal || !LiteralBase.isLiteral(literal))
240
+ return;
241
+
242
+ let field = literal.getField(this.connection);
243
+ if (!field)
244
+ return 'DISTINCT';
245
+
246
+ if (LiteralBase.isLiteral(field))
247
+ return `DISTINCT ON(${field.toString(this.connection, this.stackAssign(options, { noProjectionAliases: true }))})`;
248
+
249
+ return `DISTINCT ON(${this.getEscapedColumnName(field.Model, field, this.stackAssign(options, literal.options, { noProjectionAliases: true }))})`;
250
+ }
251
+
252
+ _fieldLiteralToString(literal, options) {
253
+ if (!literal || !LiteralBase.isLiteral(literal))
254
+ return;
255
+
256
+ let field = literal.getField(this.connection);
257
+ if (LiteralBase.isLiteral(field))
258
+ return field.toString(this.connection, options);
259
+
260
+ return this.getEscapedProjectionName(field.Model, field, this.stackAssign(options, { noProjectionAliases: (options && !options.isProjection) }, literal.options));
261
+ }
262
+
263
+ _maxLiteralToString(literal, options) {
264
+ if (!literal || !LiteralBase.isLiteral(literal))
265
+ return;
266
+
267
+ let field = literal.getField(this.connection);
268
+ let escapedFieldName;
269
+
270
+ if (LiteralBase.isLiteral(field))
271
+ escapedFieldName = field.toString(this.connection, options);
272
+ else
273
+ escapedFieldName = this.getEscapedColumnName(field.Model, field, this.stackAssign(options, literal.options));
274
+
275
+ return `MAX(${escapedFieldName})${this._getLiteralAlias(literal, options)}`;
276
+ }
277
+
278
+ _minLiteralToString(literal, options) {
279
+ if (!literal || !LiteralBase.isLiteral(literal))
280
+ return;
281
+
282
+ let field = literal.getField(this.connection);
283
+ let escapedFieldName;
284
+
285
+ if (LiteralBase.isLiteral(field))
286
+ escapedFieldName = field.toString(this.connection, options);
287
+ else
288
+ escapedFieldName = this.getEscapedColumnName(field.Model, field, this.stackAssign(options, literal.options));
289
+
290
+ return `MIN(${escapedFieldName})${this._getLiteralAlias(literal, options)}`;
291
+ }
292
+
293
+ _sumLiteralToString(literal, options) {
294
+ if (!literal || !LiteralBase.isLiteral(literal))
295
+ return;
296
+
297
+ let field = literal.getField(this.connection);
298
+ let escapedFieldName;
299
+
300
+ if (LiteralBase.isLiteral(field))
301
+ escapedFieldName = field.toString(this.connection, options);
302
+ else
303
+ escapedFieldName = this.getEscapedColumnName(field.Model, field, this.stackAssign(options, literal.options));
304
+
305
+ return `SUM(${escapedFieldName})${this._getLiteralAlias(literal, options)}`;
306
+ }
307
+
18
308
  prepareArrayValuesForSQL(array) {
19
309
  return this.connection.prepareArrayValuesForSQL(array);
20
310
  }
@@ -459,20 +749,17 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
459
749
  }
460
750
 
461
751
  generateOrderClause(queryEngine, _options) {
462
- if (!queryEngine)
463
- return '';
464
-
465
- if (typeof queryEngine.getOperationContext !== 'function')
466
- return '';
752
+ if (!queryEngine || typeof queryEngine.getOperationContext !== 'function')
753
+ return (_options && _options.rawOrder) ? [] : '';
467
754
 
468
- let order = this.getQueryEngineOrder(queryEngine, _options);
755
+ let options = _options || {};
756
+ let order = this.getQueryEngineOrder(queryEngine, _options);
469
757
  if (!order || !order.size)
470
- return '';
758
+ return (options.rawOrder) ? [] : '';
471
759
 
472
- let options = _options || {};
473
760
  let contextOrderSupport = this.connection.isOrderSupportedInContext(options);
474
761
  if (contextOrderSupport === false)
475
- return '';
762
+ return (options.rawOrder) ? [] : '';
476
763
 
477
764
  let allModelsUsedInQuery = queryEngine.getAllModelsUsedInQuery();
478
765
  let orderByParts = [];
@@ -515,23 +802,20 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
515
802
  }
516
803
 
517
804
  if (Nife.isEmpty(orderByParts))
518
- return '';
805
+ return (options.rawOrder) ? [] : '';
519
806
 
520
- return `ORDER BY ${orderByParts.join(',')}`;
807
+ return (options.rawOrder) ? orderByParts : `ORDER BY ${orderByParts.join(',')}`;
521
808
  }
522
809
 
523
810
  generateGroupByClause(queryEngine, _options) {
524
- if (!queryEngine)
525
- return '';
526
-
527
- if (typeof queryEngine.getOperationContext !== 'function')
528
- return '';
811
+ if (!queryEngine || typeof queryEngine.getOperationContext !== 'function')
812
+ return (_options && _options.rawGroupBy) ? [] : '';
529
813
 
814
+ let options = _options || {};
530
815
  let groupBy = queryEngine.getOperationContext().groupBy;
531
816
  if (!groupBy || !groupBy.size)
532
- return '';
817
+ return (options.rawGroupBy) ? [] : '';
533
818
 
534
- let options = _options || {};
535
819
 
536
820
  let groupByParts = [];
537
821
  for (let groupByScope of groupBy.values()) {
@@ -551,9 +835,9 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
551
835
  }
552
836
 
553
837
  if (Nife.isEmpty(groupByParts))
554
- return '';
838
+ return (options.rawGroupBy) ? [] : '';
555
839
 
556
- return `GROUP BY ${groupByParts.join(',')}`;
840
+ return (options.rawGroupBy) ? groupByParts : `GROUP BY ${groupByParts.join(',')}`;
557
841
  }
558
842
 
559
843
  generateHavingClause(queryEngine, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mythix-orm-sql-base",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
4
4
  "description": "SQL base support for Mythix ORM",
5
5
  "main": "lib/index",
6
6
  "type": "commonjs",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "homepage": "https://github.com/th317erd/mythix-orm-sql-base#readme",
36
36
  "peerDependencies": {
37
- "mythix-orm": "^1.11.1"
37
+ "mythix-orm": "^1.11.4"
38
38
  },
39
39
  "dependencies": {
40
40
  "luxon": "^3.1.0",
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@spothero/eslint-plugin-spothero": "github:spothero/eslint-plugin-spothero",
46
- "better-sqlite3": "^7.6.2",
47
- "eslint": "^8.27.0",
46
+ "better-sqlite3": "^8.0.0",
47
+ "eslint": "^8.28.0",
48
48
  "jasmine": "^4.5.0",
49
49
  "nyc": "^15.1.0"
50
50
  },