mythix-orm-sql-base 1.4.3 → 1.4.6

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.
@@ -84,17 +84,6 @@ class SQLConnectionBase extends ConnectionBase {
84
84
  return Nife.uniq(array);
85
85
  }
86
86
 
87
- getDefaultOrder(Model, options) {
88
- let order = Nife.toArray(Model.getDefaultOrder(options));
89
-
90
- order = Nife.arrayFlatten(order).filter(Boolean);
91
-
92
- if (Nife.isEmpty(order))
93
- return;
94
-
95
- return order;
96
- }
97
-
98
87
  generateSavePointName() {
99
88
  let id = UUID.v4();
100
89
 
@@ -872,6 +861,7 @@ class SQLConnectionBase extends ConnectionBase {
872
861
  return (count > 0);
873
862
  }
874
863
 
864
+ // eslint-disable-next-line no-unused-vars
875
865
  async enableForeignKeyConstraints(enable) {
876
866
  throw new Error(`${this.constructor.name}::enableForeignKeyConstraints: This operation is not supported for this connection type.`);
877
867
  }
@@ -222,12 +222,11 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
222
222
  value = arrayValues;
223
223
  }
224
224
 
225
- let escapedTableName = this.escapeID(this.getTableNameFromQueryPart(queryPart));
226
- let escapedColumnName = this.escapeID(field.columnName);
225
+ let escapedColumnName = this.getEscapedColumnName(field.Model, field, options);
227
226
  let sqlOperator = this.generateSelectQueryOperatorFromQueryEngineOperator(queryPart, operator, value, false, options);
228
227
 
229
228
  if (QueryEngine.isQuery(value)) {
230
- if (!this.queryHasConditions(value._getRawQuery()))
229
+ if (!value._queryHasConditions())
231
230
  return '';
232
231
 
233
232
  if (sqlOperator === '=')
@@ -235,7 +234,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
235
234
  else if (sqlOperator === '!=')
236
235
  sqlOperator = 'NOT IN';
237
236
 
238
- return `${escapedTableName}.${escapedColumnName} ${sqlOperator} (${this.generateSelectStatement(value, this.stackAssign(options, { isSubQuery: true }))})`;
237
+ return `${escapedColumnName} ${sqlOperator} (${this.generateSelectStatement(value, this.stackAssign(options, { isSubQuery: true, subQueryOperator: sqlOperator }))})`;
239
238
  }
240
239
 
241
240
  let context = { queryPart, field, sqlOperator, operator, value };
@@ -244,7 +243,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
244
243
 
245
244
  let conditionPostfix = this.generateConditionPostfix(context);
246
245
 
247
- return `${escapedTableName}.${escapedColumnName} ${sqlOperator} ${this.escape(field, value)}${(conditionPostfix) ? ` ${conditionPostfix}` : ''}`;
246
+ return `${escapedColumnName} ${sqlOperator} ${this.escape(field, value)}${(conditionPostfix) ? ` ${conditionPostfix}` : ''}`;
248
247
  }
249
248
 
250
249
  // eslint-disable-next-line no-unused-vars
@@ -252,18 +251,16 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
252
251
  if (!Model)
253
252
  throw new Error(`${this.constructor.name}::generateFromTableOrTableJoin: No valid model provided.`);
254
253
 
255
- let escapedTableName = this.escapeID(Model.getTableName(this.connection));
254
+ let escapedTableName = this.getEscapedTableName(Model, options);
256
255
  return (joinType) ? `${joinType} ${escapedTableName}` : `FROM ${escapedTableName}`;
257
256
  }
258
257
 
259
258
  generateSelectJoinOnTableQueryCondition(leftQueryPart, rightQueryPart, leftField, rightField, operator, options) {
260
- let leftSideEscapedTableName = this.escapeID(this.getTableNameFromQueryPart(leftQueryPart));
261
- let leftSideEscapedColumnName = this.escapeID(leftField.columnName);
262
- let rightSideEscapedTableName = this.escapeID(this.getTableNameFromQueryPart(rightQueryPart));
263
- let rightSideEscapedColumnName = this.escapeID(rightField.columnName);
259
+ let leftSideEscapedColumnName = this.getEscapedColumnName(leftField.Model, leftField, options);
260
+ let rightSideEscapedColumnName = this.getEscapedColumnName(rightField.Model, rightField, options);
264
261
  let sqlOperator = this.generateSelectQueryOperatorFromQueryEngineOperator(leftQueryPart, operator, undefined, true, options);
265
262
 
266
- return `${leftSideEscapedTableName}.${leftSideEscapedColumnName} ${sqlOperator} ${rightSideEscapedTableName}.${rightSideEscapedColumnName}`;
263
+ return `${leftSideEscapedColumnName} ${sqlOperator} ${rightSideEscapedColumnName}`;
267
264
  }
268
265
 
269
266
  generateJoinOnTableQueryConditions(joinInfos, options) {
@@ -450,11 +447,6 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
450
447
  return sqlParts.join(' ');
451
448
  }
452
449
 
453
- // eslint-disable-next-line no-unused-vars
454
- allowOrderFieldWhenNotProjected(orderField, options) {
455
- return true;
456
- }
457
-
458
450
  // eslint-disable-next-line no-unused-vars
459
451
  generateOrderClause(_orders, _options) {
460
452
  if (LiteralBase.isLiteral(_orders))
@@ -464,13 +456,21 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
464
456
  if (Nife.isEmpty(orders))
465
457
  return '';
466
458
 
467
- let options = _options || {};
459
+ let options = _options || {};
460
+ let contextOrderSupport = this.connection.isOrderSupportedInContext(options);
461
+ if (contextOrderSupport === false)
462
+ return '';
463
+
468
464
  let orderByParts = [];
469
465
  for (let i = 0, il = orders.length; i < il; i++) {
470
466
  let orderField = orders[i];
471
467
 
472
468
  if (LiteralBase.isLiteral(orderField)) {
473
- orderByParts.push(orderField.toString(this.connection));
469
+ let fieldStr = orderField.toString(this.connection);
470
+ if (!options.projectionFields.has(fieldStr) && contextOrderSupport === 'PROJECTION_ONLY')
471
+ continue;
472
+
473
+ orderByParts.push(fieldStr);
474
474
  continue;
475
475
  }
476
476
 
@@ -480,12 +480,11 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
480
480
  let fieldName = orderField.Field.fieldName;
481
481
  let fqFieldName = `${modelName}:${fieldName}`;
482
482
 
483
- if (!options.projectionFields.has(fqFieldName) && !this.allowOrderFieldWhenNotProjected(orderField, options))
483
+ if (!options.projectionFields.has(fqFieldName) && contextOrderSupport === 'PROJECTION_ONLY')
484
484
  continue;
485
485
  }
486
486
 
487
- let escapedTableName = this.escapeID(orderField.Model.getTableName(this.connection));
488
- let escapedColumnName = this.escapeID(orderField.Field.columnName);
487
+ let escapedColumnName = this.getEscapedColumnName(orderField.Model, orderField.Field.columnName, options);
489
488
  let orderStr;
490
489
 
491
490
  if (options.reverseOrder !== true)
@@ -493,7 +492,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
493
492
  else
494
493
  orderStr = (orderField.direction === '-') ? 'ASC' : 'DESC';
495
494
 
496
- orderByParts.push(`${escapedTableName}.${escapedColumnName} ${orderStr}`);
495
+ orderByParts.push(`${escapedColumnName} ${orderStr}`);
497
496
  }
498
497
 
499
498
  if (Nife.isEmpty(orderByParts))
@@ -518,30 +517,45 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
518
517
  return `OFFSET ${offset}`;
519
518
  }
520
519
 
521
- generateSelectOrderLimitOffset(queryEngine, options) {
520
+ generateSelectOrderLimitOffset(queryEngine, _options) {
521
+ let options = _options || {};
522
522
  let {
523
523
  order,
524
524
  limit,
525
525
  offset,
526
526
  } = this.getOrderLimitOffset(queryEngine, options);
527
527
  let sqlParts = [];
528
+ let hasOrder = false;
528
529
 
529
530
  if (Nife.isNotEmpty(order)) {
530
- let result = this.generateOrderClause(order, options);
531
- if (result)
532
- sqlParts.push(result);
531
+ if (this.connection.isOrderSupportedInContext(options)) {
532
+ let result = this.generateOrderClause(order, options);
533
+ if (result) {
534
+ hasOrder = true;
535
+ sqlParts.push(result);
536
+ }
537
+
538
+ if (hasOrder && !(Nife.instanceOf(limit, 'number') && isFinite(limit)) && options && options.forceLimit) {
539
+ limit = options.forceLimit;
540
+ offset = 0;
541
+ }
542
+ }
533
543
  }
534
544
 
535
545
  if (!Object.is(limit, Infinity) && Nife.isNotEmpty(limit)) {
536
- let result = this.generateLimitClause(limit, options);
537
- if (result)
538
- sqlParts.push(result);
546
+ if (this.connection.isLimitSupportedInContext(options)) {
547
+ let result = this.generateLimitClause(limit, options);
548
+ if (result)
549
+ sqlParts.push(result);
550
+ }
539
551
  }
540
552
 
541
553
  if (Nife.isNotEmpty(offset)) {
542
- let result = this.generateOffsetClause(offset, options);
543
- if (result)
544
- sqlParts.push(result);
554
+ if (this.connection.isLimitSupportedInContext(options)) {
555
+ let result = this.generateOffsetClause(offset, options);
556
+ if (result)
557
+ sqlParts.push(result);
558
+ }
545
559
  }
546
560
 
547
561
  return sqlParts.join(' ');
@@ -647,8 +661,10 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
647
661
 
648
662
  // eslint-disable-next-line no-unused-vars
649
663
  generateIndexName(Model, field, index, options) {
650
- let tableName = Model.getTableName(this.connection);
664
+ if (!index)
665
+ return '';
651
666
 
667
+ let tableName = Model.getTableName(this.connection);
652
668
  if (index === true)
653
669
  return this.escapeID(`idx_${tableName}_${field.columnName}`.replace(/\W+/g, '_'));
654
670
 
@@ -662,13 +678,16 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
662
678
  fieldNames.push(indexField.columnName);
663
679
  }
664
680
 
665
- return this.escapeID(`idx_${tableName}_${fieldNames.join('_')}`);
681
+ return this.escapeID(`idx_${tableName}_${fieldNames.sort().join('_')}`);
666
682
  }
667
683
 
668
- generateColumnIndex(Model, field, index, _options) {
684
+ generateColumnIndexes(Model, field, _indexes, _options) {
685
+ let indexes = Nife.toArray(_indexes).filter(Boolean);
686
+ if (Nife.isEmpty(indexes))
687
+ return [];
688
+
669
689
  let options = _options || {};
670
- let escapedTableName = this.escapeID(Model.getTableName(this.connection));
671
- let indexName = this.generateIndexName(Model, field, index, options);
690
+ let escapedTableName = this.getEscapedTableName(Model, options);
672
691
  let flags = [];
673
692
 
674
693
  if (options.concurrently)
@@ -679,25 +698,26 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
679
698
 
680
699
  flags = flags.join(' ');
681
700
 
682
- if (index === true)
683
- return `CREATE INDEX ${flags} ${indexName} ON ${escapedTableName} (${this.escapeID(field.columnName)});`;
701
+ return indexes.map((indexNames) => {
702
+ let indexName = this.generateIndexName(Model, field, indexNames, options);
703
+ if (indexNames === true)
704
+ return `CREATE INDEX ${flags} ${indexName} ON ${escapedTableName} (${this.escapeID(field.columnName)});`;
684
705
 
685
- let fieldNames = [];
686
- for (let i = 0, il = index.length; i < il; i++) {
687
- let indexFieldName = index[i];
688
- let indexField = Model.getField(indexFieldName);
689
- if (!indexField)
690
- throw new Error(`${this.constructor.name}::generateColumnIndex: Unable to find field named "${indexFieldName}".`);
706
+ let escapedColumnNames = [field.fieldName].concat(indexNames).filter(Boolean).map((fieldName) => {
707
+ let thisField = Model.getField(fieldName);
708
+ if (!thisField)
709
+ throw new Error(`${this.constructor.name}::generateColumnIndexes: Unable to find field named "${fieldName}".`);
691
710
 
692
- fieldNames.push(this.escapeID(indexField.columnName));
693
- }
711
+ return this.getEscapedColumnName(Model, thisField, options);
712
+ });
694
713
 
695
- return `CREATE INDEX ${indexName} ON ${escapedTableName} (${fieldNames.join(',')});`;
714
+ return `CREATE INDEX ${indexName} ON ${escapedTableName} (${escapedColumnNames.join(',')});`;
715
+ });
696
716
  }
697
717
 
698
718
  generateDropTableStatement(Model, _options) {
699
719
  let options = _options || {};
700
- let escapedTableName = this.escapeID(Model.getTableName(this.connection));
720
+ let escapedTableName = this.getEscapedTableName(Model, options);
701
721
  let flags = [];
702
722
 
703
723
  if (options.ifExists)
@@ -708,34 +728,34 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
708
728
  return `DROP TABLE ${flags} ${escapedTableName}${(options.cascade === true) ? ' CASCADE' : ''}`;
709
729
  }
710
730
 
711
- generateForeignKeyConstraint(field, type) {
712
- let options = type.getOptions();
731
+ generateForeignKeyConstraint(field, type, options) {
732
+ let typeOptions = type.getOptions();
713
733
  let targetModel = type.getTargetModel(this.connection);
714
734
  let targetField = type.getTargetField(this.connection);
715
735
 
716
736
  let sqlParts = [
717
737
  'FOREIGN KEY(',
718
- this.escapeID(field.columnName),
738
+ this.getEscapedColumnName(field.Model, field, { ...(options || {}), columnNameOnly: true }),
719
739
  ') REFERENCES ',
720
- this.escapeID(targetModel.getTableName(this.connection)),
740
+ this.getEscapedTableName(targetModel, options),
721
741
  '(',
722
- this.escapeID(targetField.columnName),
742
+ this.getEscapedColumnName(targetModel, targetField, { ...(options || {}), columnNameOnly: true }),
723
743
  ')',
724
744
  ];
725
745
 
726
- if (options.deferred === true) {
746
+ if (typeOptions.deferred === true) {
727
747
  sqlParts.push(' ');
728
748
  sqlParts.push('DEFERRABLE INITIALLY DEFERRED');
729
749
  }
730
750
 
731
- if (options.onDelete) {
751
+ if (typeOptions.onDelete) {
732
752
  sqlParts.push(' ');
733
- sqlParts.push(`ON DELETE ${options.onDelete.toUpperCase()}`);
753
+ sqlParts.push(`ON DELETE ${typeOptions.onDelete.toUpperCase()}`);
734
754
  }
735
755
 
736
- if (options.onUpdate) {
756
+ if (typeOptions.onUpdate) {
737
757
  sqlParts.push(' ');
738
- sqlParts.push(`ON UPDATE ${options.onUpdate.toUpperCase()}`);
758
+ sqlParts.push(`ON UPDATE ${typeOptions.onUpdate.toUpperCase()}`);
739
759
  }
740
760
 
741
761
  return sqlParts.join('');
@@ -779,9 +799,9 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
779
799
  let indexes = Nife.toArray(field.index).filter(Boolean);
780
800
  for (let i = 0, il = indexes.length; i < il; i++) {
781
801
  let index = indexes[i];
782
- let result = this.generateColumnIndex(Model, field, index, options);
783
- if (result)
784
- fieldParts.push(result);
802
+ let result = this.generateColumnIndexes(Model, field, index, options);
803
+ if (Nife.isNotEmpty(result))
804
+ fieldParts.push(result.join('\n\n'));
785
805
  }
786
806
  });
787
807
 
@@ -796,10 +816,8 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
796
816
  if (field.type.isVirtual())
797
817
  return;
798
818
 
799
- let columnName = field.columnName || fieldName;
800
819
  let constraintParts = [];
801
-
802
- let defaultValue = this.getFieldDefaultValue(field, fieldName, { remoteOnly: true });
820
+ let defaultValue = this.getFieldDefaultValue(field, fieldName, { remoteOnly: true });
803
821
 
804
822
  if (field.primaryKey) {
805
823
  if (LiteralBase.isLiteral(field.primaryKey))
@@ -828,7 +846,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
828
846
  if (Nife.isNotEmpty(constraintParts))
829
847
  constraintParts = ` ${constraintParts}`;
830
848
 
831
- fieldParts.push(` ${this.escapeID(columnName)} ${field.type.toConnectionType(this.connection, { createTable: true, defaultValue })}${constraintParts}`);
849
+ fieldParts.push(` ${this.getEscapedColumnName(Model, field, { columnNameOnly: true })} ${field.type.toConnectionType(this.connection, { createTable: true, defaultValue })}${constraintParts}`);
832
850
  });
833
851
 
834
852
  let ifNotExists = '';
@@ -839,7 +857,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
839
857
  if (Nife.isNotEmpty(trailingParts))
840
858
  fieldParts = fieldParts.concat(trailingParts.map((part) => ` ${part.trim()}`));
841
859
 
842
- let finalStatement = `CREATE TABLE ${ifNotExists}${this.escapeID(Model.getTableName(this.connection))} (${fieldParts.join(',\n')}\n);`;
860
+ let finalStatement = `CREATE TABLE ${ifNotExists}${this.getEscapedTableName(Model)} (${fieldParts.join(',\n')}\n);`;
843
861
  return finalStatement;
844
862
  }
845
863
 
@@ -938,7 +956,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
938
956
  if (!values)
939
957
  return '';
940
958
 
941
- let escapedTableName = this.escapeID(Model.getTableName(this.connection));
959
+ let escapedTableName = this.getEscapedTableName(Model, subOptions);
942
960
  let escapedFieldNames = Array.from(Object.values(this.getEscapedModelFields(Model, subOptions)));
943
961
 
944
962
  let insertStatementTail = this.generateInsertStatementTail(
@@ -988,7 +1006,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
988
1006
  if (Nife.isEmpty(dirtyFields))
989
1007
  return '';
990
1008
 
991
- let escapedTableName = this.escapeID(Model.getTableName(this.connection));
1009
+ let escapedTableName = this.getEscapedTableName(Model, options);
992
1010
  let sqlParts = [ 'UPDATE ', escapedTableName, ' SET ' ];
993
1011
  let setParts = [];
994
1012
  let tabs = '';
@@ -1001,7 +1019,7 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
1001
1019
  for (let i = 0, il = dirtyFields.length; i < il; i++) {
1002
1020
  let dirtyField = dirtyFields[i];
1003
1021
  let fieldValue = modelChanges[dirtyField.fieldName].current;
1004
- let escapedColumnName = this.escapeID(dirtyField.columnName);
1022
+ let escapedColumnName = this.getEscapedColumnName(dirtyField.Model, dirtyField.columnName, { columnNameOnly: true });
1005
1023
  let escapedValue = (LiteralBase.isLiteral(fieldValue)) ? fieldValue.toString(this.connection) : this.escape(dirtyField, fieldValue);
1006
1024
  if (!escapedValue)
1007
1025
  continue;
@@ -1061,20 +1079,19 @@ class SQLQueryGeneratorBase extends QueryGeneratorBase {
1061
1079
  }
1062
1080
  }
1063
1081
 
1064
- let escapedTableName = this.escapeID(Model.getTableName(this.connection));
1065
- if (queryEngine) {
1066
- let pkField = Model.getPrimaryKeyField();
1067
- let where = this.generateWhereAndOrderLimitOffset(queryEngine, options);
1068
-
1069
- if (where && pkField) {
1070
- if (pkField)
1071
- queryEngine = queryEngine.PROJECT(`${Model.getModelName()}:${pkField.fieldName}`);
1072
-
1073
- let innerSelect = this.generateSelectStatement(queryEngine, this.stackAssign(options, { isSubQuery: true, noProjectionAliases: true }));
1074
- let escapedColumnName = this.getEscapedColumnName(Model, pkField, options);
1075
-
1076
- return `DELETE FROM ${escapedTableName} WHERE ${escapedColumnName} IN (${innerSelect})`;
1082
+ let escapedTableName = this.getEscapedTableName(Model, options);
1083
+ if (queryEngine && queryEngine._queryHasConditions()) {
1084
+ if (queryEngine._queryHasJoins()) {
1085
+ let pkField = Model.getPrimaryKeyField();
1086
+ if (!pkField)
1087
+ throw new Error(`${this.constructor.name}::generateDeleteStatement: Can not delete using table joins on a table with no primary key field.`);
1088
+
1089
+ let escapedTableNameAlias = this.getEscapedTableName(Model, { tableNamePrefix: '_' });
1090
+ let escapedFieldAlias = this.getEscapedColumnName(Model, pkField, { columnNameOnly: true });
1091
+ let innerSelect = this.generateSelectStatement(queryEngine.AND[pkField.fieldName].EQ(new Literals.Literal(`${escapedTableNameAlias}.${escapedFieldAlias}`)).PROJECT(new Literals.Literal('1')), this.stackAssign(options, { isSubQuery: true, subQueryOperator: 'EXISTS', noProjectionAliases: true }));
1092
+ return `DELETE FROM ${escapedTableName} AS ${escapedTableNameAlias} WHERE EXISTS (${innerSelect})`;
1077
1093
  } else {
1094
+ let where = this.generateWhereAndOrderLimitOffset(queryEngine, options);
1078
1095
  return `DELETE FROM ${escapedTableName}${(where) ? ` ${where}` : ''}`;
1079
1096
  }
1080
1097
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mythix-orm-sql-base",
3
- "version": "1.4.3",
3
+ "version": "1.4.6",
4
4
  "description": "SQL base support for Mythix ORM",
5
5
  "main": "lib/index.js",
6
6
  "type": "commonjs",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "homepage": "https://github.com/th317erd/mythix-orm-sql-base#readme",
35
35
  "peerDependencies": {
36
- "mythix-orm": "^1.5.2"
36
+ "mythix-orm": "^1.5.6"
37
37
  },
38
38
  "dependencies": {
39
39
  "nife": "^1.11.3",