@mikro-orm/sql 7.0.0-rc.2 → 7.0.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.
Files changed (66) hide show
  1. package/AbstractSqlConnection.d.ts +5 -4
  2. package/AbstractSqlConnection.js +20 -6
  3. package/AbstractSqlDriver.d.ts +19 -13
  4. package/AbstractSqlDriver.js +225 -47
  5. package/AbstractSqlPlatform.d.ts +35 -0
  6. package/AbstractSqlPlatform.js +51 -5
  7. package/PivotCollectionPersister.d.ts +2 -11
  8. package/PivotCollectionPersister.js +59 -59
  9. package/README.md +5 -4
  10. package/SqlEntityManager.d.ts +2 -2
  11. package/SqlEntityManager.js +5 -5
  12. package/dialects/index.d.ts +1 -0
  13. package/dialects/index.js +1 -0
  14. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +2 -0
  15. package/dialects/mssql/MsSqlNativeQueryBuilder.js +8 -4
  16. package/dialects/mysql/BaseMySqlPlatform.d.ts +6 -0
  17. package/dialects/mysql/BaseMySqlPlatform.js +18 -2
  18. package/dialects/mysql/MySqlSchemaHelper.d.ts +1 -1
  19. package/dialects/mysql/MySqlSchemaHelper.js +25 -14
  20. package/dialects/oracledb/OracleDialect.d.ts +78 -0
  21. package/dialects/oracledb/OracleDialect.js +166 -0
  22. package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +19 -0
  23. package/dialects/oracledb/OracleNativeQueryBuilder.js +249 -0
  24. package/dialects/oracledb/index.d.ts +2 -0
  25. package/dialects/oracledb/index.js +2 -0
  26. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +6 -0
  27. package/dialects/postgresql/BasePostgreSqlPlatform.js +49 -37
  28. package/dialects/postgresql/PostgreSqlSchemaHelper.js +75 -59
  29. package/dialects/sqlite/BaseSqliteConnection.js +2 -2
  30. package/dialects/sqlite/NodeSqliteDialect.js +3 -1
  31. package/dialects/sqlite/SqlitePlatform.d.ts +1 -0
  32. package/dialects/sqlite/SqlitePlatform.js +7 -1
  33. package/dialects/sqlite/SqliteSchemaHelper.js +23 -17
  34. package/index.d.ts +1 -1
  35. package/index.js +0 -1
  36. package/package.json +30 -30
  37. package/plugin/index.d.ts +1 -14
  38. package/plugin/index.js +13 -13
  39. package/plugin/transformer.d.ts +6 -22
  40. package/plugin/transformer.js +91 -82
  41. package/query/ArrayCriteriaNode.d.ts +1 -1
  42. package/query/CriteriaNode.js +28 -10
  43. package/query/CriteriaNodeFactory.js +20 -4
  44. package/query/NativeQueryBuilder.d.ts +28 -3
  45. package/query/NativeQueryBuilder.js +65 -3
  46. package/query/ObjectCriteriaNode.js +75 -31
  47. package/query/QueryBuilder.d.ts +199 -100
  48. package/query/QueryBuilder.js +544 -358
  49. package/query/QueryBuilderHelper.d.ts +18 -14
  50. package/query/QueryBuilderHelper.js +364 -147
  51. package/query/ScalarCriteriaNode.js +17 -8
  52. package/query/enums.d.ts +2 -0
  53. package/query/enums.js +2 -0
  54. package/query/raw.js +1 -1
  55. package/schema/DatabaseSchema.d.ts +7 -5
  56. package/schema/DatabaseSchema.js +68 -45
  57. package/schema/DatabaseTable.d.ts +8 -6
  58. package/schema/DatabaseTable.js +191 -107
  59. package/schema/SchemaComparator.d.ts +1 -3
  60. package/schema/SchemaComparator.js +76 -50
  61. package/schema/SchemaHelper.d.ts +2 -13
  62. package/schema/SchemaHelper.js +30 -9
  63. package/schema/SqlSchemaGenerator.d.ts +4 -14
  64. package/schema/SqlSchemaGenerator.js +26 -12
  65. package/typings.d.ts +10 -5
  66. package/tsconfig.build.tsbuildinfo +0 -1
@@ -3,13 +3,13 @@ import { ArrayType, BooleanType, DateTimeType, inspect, JsonType, parseJsonSafe,
3
3
  * Compares two Schemas and return an instance of SchemaDifference.
4
4
  */
5
5
  export class SchemaComparator {
6
- platform;
7
- helper;
8
- logger;
6
+ #helper;
7
+ #logger;
8
+ #platform;
9
9
  constructor(platform) {
10
- this.platform = platform;
11
- this.helper = this.platform.getSchemaHelper();
12
- this.logger = this.platform.getConfig().getLogger();
10
+ this.#platform = platform;
11
+ this.#helper = this.#platform.getSchemaHelper();
12
+ this.#logger = this.#platform.getConfig().getLogger();
13
13
  }
14
14
  /**
15
15
  * Returns a SchemaDifference object containing the differences between the schemas fromSchema and toSchema.
@@ -35,13 +35,13 @@ export class SchemaComparator {
35
35
  };
36
36
  const foreignKeysToTable = {};
37
37
  for (const namespace of toSchema.getNamespaces()) {
38
- if (fromSchema.hasNamespace(namespace) || namespace === this.platform.getDefaultSchemaName()) {
38
+ if (fromSchema.hasNamespace(namespace) || namespace === this.#platform.getDefaultSchemaName()) {
39
39
  continue;
40
40
  }
41
41
  diff.newNamespaces.add(namespace);
42
42
  }
43
43
  for (const namespace of fromSchema.getNamespaces()) {
44
- if (toSchema.hasNamespace(namespace) || namespace === this.platform.getDefaultSchemaName()) {
44
+ if (toSchema.hasNamespace(namespace) || namespace === this.#platform.getDefaultSchemaName()) {
45
45
  continue;
46
46
  }
47
47
  diff.removedNamespaces.add(namespace);
@@ -59,7 +59,9 @@ export class SchemaComparator {
59
59
  if (toSchema.hasNativeEnum(key)) {
60
60
  continue;
61
61
  }
62
- if (key.startsWith(`${fromSchema.name}.`) && (fromSchema.name !== toSchema.name || toSchema.getNativeEnum(key.substring(fromSchema.name.length + 1))?.schema === '*')) {
62
+ if (key.startsWith(`${fromSchema.name}.`) &&
63
+ (fromSchema.name !== toSchema.name ||
64
+ toSchema.getNativeEnum(key.substring(fromSchema.name.length + 1))?.schema === '*')) {
63
65
  continue;
64
66
  }
65
67
  diff.removedNativeEnums.push(nativeEnum);
@@ -164,7 +166,10 @@ export class SchemaComparator {
164
166
  };
165
167
  if (this.diffComment(fromTable.comment, toTable.comment)) {
166
168
  tableDifferences.changedComment = toTable.comment;
167
- this.log(`table comment changed for ${tableDifferences.name}`, { fromTableComment: fromTable.comment, toTableComment: toTable.comment });
169
+ this.log(`table comment changed for ${tableDifferences.name}`, {
170
+ fromTableComment: fromTable.comment,
171
+ toTableComment: toTable.comment,
172
+ });
168
173
  changes++;
169
174
  }
170
175
  const fromTableColumns = fromTable.getColumns();
@@ -222,7 +227,7 @@ export class SchemaComparator {
222
227
  // See if there are any removed indexes in "to" table
223
228
  for (const index of fromTableIndexes) {
224
229
  // See if index is removed in "to" table.
225
- if ((index.primary && !toTable.hasPrimaryKey()) || !index.primary && !toTable.hasIndex(index.keyName)) {
230
+ if ((index.primary && !toTable.hasPrimaryKey()) || (!index.primary && !toTable.hasIndex(index.keyName))) {
226
231
  tableDifferences.removedIndexes[index.keyName] = index;
227
232
  this.log(`index ${index.keyName} removed from table ${tableDifferences.name}`);
228
233
  changes++;
@@ -234,7 +239,10 @@ export class SchemaComparator {
234
239
  continue;
235
240
  }
236
241
  tableDifferences.changedIndexes[index.keyName] = toTableIndex;
237
- this.log(`index ${index.keyName} changed in table ${tableDifferences.name}`, { fromTableIndex: index, toTableIndex });
242
+ this.log(`index ${index.keyName} changed in table ${tableDifferences.name}`, {
243
+ fromTableIndex: index,
244
+ toTableIndex,
245
+ });
238
246
  changes++;
239
247
  }
240
248
  this.detectIndexRenamings(tableDifferences);
@@ -264,10 +272,15 @@ export class SchemaComparator {
264
272
  if (!this.diffExpression(check.expression, toTableCheck.expression)) {
265
273
  continue;
266
274
  }
267
- if (fromColumn?.enumItems && toColumn?.enumItems && !this.diffEnumItems(fromColumn.enumItems, toColumn.enumItems)) {
275
+ if (fromColumn?.enumItems &&
276
+ toColumn?.enumItems &&
277
+ !this.diffEnumItems(fromColumn.enumItems, toColumn.enumItems)) {
268
278
  continue;
269
279
  }
270
- this.log(`check constraint ${check.name} changed in table ${tableDifferences.name}`, { fromTableCheck: check, toTableCheck });
280
+ this.log(`check constraint ${check.name} changed in table ${tableDifferences.name}`, {
281
+ fromTableCheck: check,
282
+ toTableCheck,
283
+ });
271
284
  tableDifferences.changedChecks[check.name] = toTableCheck;
272
285
  changes++;
273
286
  }
@@ -280,7 +293,10 @@ export class SchemaComparator {
280
293
  delete toForeignKeys[toConstraint.constraintName];
281
294
  }
282
295
  else if (fromConstraint.constraintName.toLowerCase() === toConstraint.constraintName.toLowerCase()) {
283
- this.log(`FK constraint ${fromConstraint.constraintName} changed in table ${tableDifferences.name}`, { fromConstraint, toConstraint });
296
+ this.log(`FK constraint ${fromConstraint.constraintName} changed in table ${tableDifferences.name}`, {
297
+ fromConstraint,
298
+ toConstraint,
299
+ });
284
300
  tableDifferences.changedForeignKeys[toConstraint.constraintName] = toConstraint;
285
301
  changes++;
286
302
  delete fromForeignKeys[fromConstraint.constraintName];
@@ -295,7 +311,9 @@ export class SchemaComparator {
295
311
  }
296
312
  for (const toConstraint of Object.values(toForeignKeys)) {
297
313
  tableDifferences.addedForeignKeys[toConstraint.constraintName] = toConstraint;
298
- this.log(`FK constraint ${toConstraint.constraintName} added to table ${tableDifferences.name}`, { constraint: toConstraint });
314
+ this.log(`FK constraint ${toConstraint.constraintName} added to table ${tableDifferences.name}`, {
315
+ constraint: toConstraint,
316
+ });
299
317
  changes++;
300
318
  }
301
319
  return changes ? tableDifferences : false;
@@ -341,7 +359,10 @@ export class SchemaComparator {
341
359
  tableDifferences.renamedColumns[removedColumnName] = addedColumn;
342
360
  delete tableDifferences.addedColumns[addedColumnName];
343
361
  delete tableDifferences.removedColumns[removedColumnName];
344
- this.log(`renamed column detected in table ${tableDifferences.name}`, { old: removedColumnName, new: addedColumnName });
362
+ this.log(`renamed column detected in table ${tableDifferences.name}`, {
363
+ old: removedColumnName,
364
+ new: addedColumnName,
365
+ });
345
366
  }
346
367
  }
347
368
  /**
@@ -375,7 +396,10 @@ export class SchemaComparator {
375
396
  tableDifferences.renamedIndexes[removedIndexName] = addedIndex;
376
397
  delete tableDifferences.addedIndexes[addedIndexName];
377
398
  delete tableDifferences.removedIndexes[removedIndexName];
378
- this.log(`renamed index detected in table ${tableDifferences.name}`, { old: removedIndexName, new: addedIndexName });
399
+ this.log(`renamed index detected in table ${tableDifferences.name}`, {
400
+ old: removedIndexName,
401
+ new: addedIndexName,
402
+ });
379
403
  }
380
404
  }
381
405
  diffForeignKey(key1, key2, tableDifferences) {
@@ -394,7 +418,7 @@ export class SchemaComparator {
394
418
  if (key1.deferMode !== key2.deferMode) {
395
419
  return true;
396
420
  }
397
- if (key1.localTableName === key1.referencedTableName && !this.platform.supportsMultipleCascadePaths()) {
421
+ if (key1.localTableName === key1.referencedTableName && !this.#platform.supportsMultipleCascadePaths()) {
398
422
  return false;
399
423
  }
400
424
  if (key1.columnNames.some(col => tableDifferences.changedColumns[col]?.changedProperties.has('type'))) {
@@ -402,13 +426,12 @@ export class SchemaComparator {
402
426
  }
403
427
  const defaultRule = ['restrict', 'no action'];
404
428
  const rule = (key, method) => {
405
- return (key[method] ?? defaultRule[0])
406
- .toLowerCase()
407
- .replace(defaultRule[1], defaultRule[0])
408
- .replace(/"/g, '');
429
+ return (key[method] ?? defaultRule[0]).toLowerCase().replace(defaultRule[1], defaultRule[0]).replace(/"/g, '');
409
430
  };
410
431
  const compare = (method) => rule(key1, method) === rule(key2, method);
411
- return !compare('updateRule') || !compare('deleteRule');
432
+ // Skip updateRule comparison for platforms that don't support ON UPDATE (e.g., Oracle)
433
+ const updateRuleDiffers = this.#platform.supportsOnUpdate() && !compare('updateRule');
434
+ return updateRuleDiffers || !compare('deleteRule');
412
435
  }
413
436
  /**
414
437
  * Returns the difference between the columns
@@ -417,9 +440,10 @@ export class SchemaComparator {
417
440
  const changedProperties = new Set();
418
441
  const fromProp = this.mapColumnToProperty({ ...fromColumn, autoincrement: false });
419
442
  const toProp = this.mapColumnToProperty({ ...toColumn, autoincrement: false });
420
- const fromColumnType = this.platform.normalizeColumnType(fromColumn.mappedType.getColumnType(fromProp, this.platform).toLowerCase(), fromProp);
421
- const fromNativeEnum = fromTable.nativeEnums[fromColumnType] ?? Object.values(fromTable.nativeEnums).find(e => e.name === fromColumnType && e.schema !== '*');
422
- let toColumnType = this.platform.normalizeColumnType(toColumn.mappedType.getColumnType(toProp, this.platform).toLowerCase(), toProp);
443
+ const fromColumnType = this.#platform.normalizeColumnType(fromColumn.mappedType.getColumnType(fromProp, this.#platform).toLowerCase(), fromProp);
444
+ const fromNativeEnum = fromTable.nativeEnums[fromColumnType] ??
445
+ Object.values(fromTable.nativeEnums).find(e => e.name === fromColumnType && e.schema !== '*');
446
+ let toColumnType = this.#platform.normalizeColumnType(toColumn.mappedType.getColumnType(toProp, this.#platform).toLowerCase(), toProp);
423
447
  const log = (msg, params) => {
424
448
  if (logging) {
425
449
  const copy = Utils.copy(params);
@@ -430,8 +454,11 @@ export class SchemaComparator {
430
454
  if (fromColumnType !== toColumnType &&
431
455
  (!fromNativeEnum || `${fromNativeEnum.schema}.${fromNativeEnum.name}` !== toColumnType) &&
432
456
  !(fromColumn.ignoreSchemaChanges?.includes('type') || toColumn.ignoreSchemaChanges?.includes('type')) &&
433
- !fromColumn.generated && !toColumn.generated) {
434
- if (!toColumnType.includes('.') && fromTable.schema && fromTable.schema !== this.platform.getDefaultSchemaName()) {
457
+ !fromColumn.generated &&
458
+ !toColumn.generated) {
459
+ if (!toColumnType.includes('.') &&
460
+ fromTable.schema &&
461
+ fromTable.schema !== this.#platform.getDefaultSchemaName()) {
435
462
  toColumnType = `${fromTable.schema}.${toColumnType}`;
436
463
  }
437
464
  if (fromColumnType !== toColumnType) {
@@ -439,7 +466,7 @@ export class SchemaComparator {
439
466
  changedProperties.add('type');
440
467
  }
441
468
  }
442
- if (fromColumn.nullable !== toColumn.nullable && !fromColumn.generated && !toColumn.generated) {
469
+ if (!!fromColumn.nullable !== !!toColumn.nullable && !fromColumn.generated && !toColumn.generated) {
443
470
  log(`'nullable' changed for column ${fromTable.name}.${fromColumn.name}`, { fromColumn, toColumn });
444
471
  changedProperties.add('nullable');
445
472
  }
@@ -451,12 +478,12 @@ export class SchemaComparator {
451
478
  log(`'autoincrement' changed for column ${fromTable.name}.${fromColumn.name}`, { fromColumn, toColumn });
452
479
  changedProperties.add('autoincrement');
453
480
  }
454
- if (fromColumn.unsigned !== toColumn.unsigned && this.platform.supportsUnsigned()) {
481
+ if (!!fromColumn.unsigned !== !!toColumn.unsigned && this.#platform.supportsUnsigned()) {
455
482
  log(`'unsigned' changed for column ${fromTable.name}.${fromColumn.name}`, { fromColumn, toColumn });
456
483
  changedProperties.add('unsigned');
457
484
  }
458
- if (!(fromColumn.ignoreSchemaChanges?.includes('default') ||
459
- toColumn.ignoreSchemaChanges?.includes('default')) && !this.hasSameDefaultValue(fromColumn, toColumn)) {
485
+ if (!(fromColumn.ignoreSchemaChanges?.includes('default') || toColumn.ignoreSchemaChanges?.includes('default')) &&
486
+ !this.hasSameDefaultValue(fromColumn, toColumn)) {
460
487
  log(`'default' changed for column ${fromTable.name}.${fromColumn.name}`, { fromColumn, toColumn });
461
488
  changedProperties.add('default');
462
489
  }
@@ -471,8 +498,7 @@ export class SchemaComparator {
471
498
  changedProperties.add('enumItems');
472
499
  }
473
500
  if ((fromColumn.extra || '').toLowerCase() !== (toColumn.extra || '').toLowerCase() &&
474
- !(fromColumn.ignoreSchemaChanges?.includes('extra') ||
475
- toColumn.ignoreSchemaChanges?.includes('extra'))) {
501
+ !(fromColumn.ignoreSchemaChanges?.includes('extra') || toColumn.ignoreSchemaChanges?.includes('extra'))) {
476
502
  log(`'extra' changed for column ${fromTable.name}.${fromColumn.name}`, { fromColumn, toColumn });
477
503
  changedProperties.add('extra');
478
504
  }
@@ -549,7 +575,7 @@ export class SchemaComparator {
549
575
  // index that has no constraints.
550
576
  return true;
551
577
  }
552
- if (this.platform.supportsDeferredUniqueConstraints() && index1.deferMode !== index2.deferMode) {
578
+ if (this.#platform.supportsDeferredUniqueConstraints() && index1.deferMode !== index2.deferMode) {
553
579
  return false;
554
580
  }
555
581
  return index1.primary === index2.primary && index1.unique === index2.unique;
@@ -579,7 +605,7 @@ export class SchemaComparator {
579
605
  if (sort1 !== sort2) {
580
606
  return false;
581
607
  }
582
- const defaultNulls = (s) => s === 'DESC' ? 'FIRST' : 'LAST';
608
+ const defaultNulls = (s) => (s === 'DESC' ? 'FIRST' : 'LAST');
583
609
  const nulls1 = c1.nulls?.toUpperCase() ?? defaultNulls(sort1);
584
610
  const nulls2 = c2.nulls?.toUpperCase() ?? defaultNulls(sort2);
585
611
  if (nulls1 !== nulls2) {
@@ -610,9 +636,9 @@ export class SchemaComparator {
610
636
  // expressions like check constraints might be normalized by the driver,
611
637
  // e.g. quotes might be added (https://github.com/mikro-orm/mikro-orm/issues/3827)
612
638
  const simplify = (str) => {
613
- return str
639
+ return (str
614
640
  ?.replace(/_\w+'(.*?)'/g, '$1')
615
- .replace(/in\s*\((.*?)\)/ig, '= any (array[$1])')
641
+ .replace(/in\s*\((.*?)\)/gi, '= any (array[$1])')
616
642
  // MySQL normalizes count(*) to count(0)
617
643
  .replace(/\bcount\s*\(\s*0\s*\)/gi, 'count(*)')
618
644
  // Remove quotes first so we can process identifiers
@@ -628,7 +654,7 @@ export class SchemaComparator {
628
654
  .replace(/\bas\b/gi, '')
629
655
  // Remove remaining special chars, parentheses, type casts, asterisks, and normalize whitespace
630
656
  .replace(/[()\n[\]*]|::\w+| +/g, '')
631
- .replace(/anyarray\[(.*)]/ig, '$1')
657
+ .replace(/anyarray\[(.*)]/gi, '$1')
632
658
  .toLowerCase()
633
659
  // PostgreSQL adds default aliases to aggregate functions (e.g., count(*) AS count)
634
660
  // After removing AS and whitespace, this results in duplicate adjacent words
@@ -636,7 +662,7 @@ export class SchemaComparator {
636
662
  // Use lookahead to match repeated patterns of 3+ chars (avoid false positives on short sequences)
637
663
  .replace(/(\w{3,})\1/g, '$1')
638
664
  // Remove trailing semicolon (PostgreSQL adds it to view definitions)
639
- .replace(/;$/, '');
665
+ .replace(/;$/, ''));
640
666
  };
641
667
  return simplify(expr1) !== simplify(expr2);
642
668
  }
@@ -645,13 +671,13 @@ export class SchemaComparator {
645
671
  if (!defaultValue) {
646
672
  return null;
647
673
  }
648
- const val = defaultValue
649
- .replace(/^(_\w+\\)?'(.*?)\\?'$/, '$2')
650
- .replace(/^\(?'(.*?)'\)?$/, '$1');
674
+ const val = defaultValue.replace(/^(_\w+\\)?'(.*?)\\?'$/, '$2').replace(/^\(?'(.*?)'\)?$/, '$1');
651
675
  return parseJsonSafe(val);
652
676
  }
653
677
  hasSameDefaultValue(from, to) {
654
- if (from.default == null || from.default.toString().toLowerCase() === 'null' || from.default.toString().startsWith('nextval(')) {
678
+ if (from.default == null ||
679
+ from.default.toString().toLowerCase() === 'null' ||
680
+ from.default.toString().startsWith('nextval(')) {
655
681
  return to.default == null || to.default.toLowerCase() === 'null';
656
682
  }
657
683
  if (to.mappedType instanceof BooleanType) {
@@ -673,15 +699,15 @@ export class SchemaComparator {
673
699
  if (from.default && to.default) {
674
700
  return from.default.toString().toLowerCase() === to.default.toString().toLowerCase();
675
701
  }
676
- if (['', this.helper.getDefaultEmptyString()].includes(to.default) && from.default != null) {
677
- return ['', this.helper.getDefaultEmptyString()].includes(from.default.toString());
702
+ if (['', this.#helper.getDefaultEmptyString()].includes(to.default) && from.default != null) {
703
+ return ['', this.#helper.getDefaultEmptyString()].includes(from.default.toString());
678
704
  }
679
705
  // eslint-disable-next-line eqeqeq
680
706
  return from.default == to.default; // == intentionally
681
707
  }
682
708
  mapColumnToProperty(column) {
683
- const length = column.type.match(/\w+\((\d+)\)/);
684
- const match = column.type.match(/\w+\((\d+), ?(\d+)\)/);
709
+ const length = /\w+\((\d+)\)/.exec(column.type);
710
+ const match = /\w+\((\d+), ?(\d+)\)/.exec(column.type);
685
711
  return {
686
712
  fieldNames: [column.name],
687
713
  columnTypes: [column.type],
@@ -696,6 +722,6 @@ export class SchemaComparator {
696
722
  if (params) {
697
723
  message += ' ' + inspect(params);
698
724
  }
699
- this.logger.log('schema', message);
725
+ this.#logger.log('schema', message);
700
726
  }
701
727
  }
@@ -1,4 +1,4 @@
1
- import { type Connection, type Dictionary, RawQueryFragment } from '@mikro-orm/core';
1
+ import { type Connection, type Dictionary, type Options, RawQueryFragment } from '@mikro-orm/core';
2
2
  import type { AbstractSqlConnection } from '../AbstractSqlConnection.js';
3
3
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';
4
4
  import type { CheckDef, Column, ForeignKey, IndexDef, Table, TableDifference } from '../typings.js';
@@ -71,18 +71,7 @@ export declare abstract class SchemaHelper {
71
71
  createCheck(table: DatabaseTable, check: CheckDef): string;
72
72
  protected getTableName(table: string, schema?: string): string;
73
73
  getTablesGroupedBySchemas(tables: Table[]): Map<string | undefined, Table[]>;
74
- get options(): {
75
- disableForeignKeys?: boolean;
76
- disableForeignKeysForClear?: boolean;
77
- createForeignKeyConstraints?: boolean;
78
- ignoreSchema?: string[];
79
- skipTables?: (string | RegExp)[];
80
- skipViews?: (string | RegExp)[];
81
- skipColumns?: Dictionary<(string | RegExp)[]>;
82
- managementDbName?: string;
83
- defaultUpdateRule?: "cascade" | "no action" | "set null" | "set default" | "restrict";
84
- defaultDeleteRule?: "cascade" | "no action" | "set null" | "set default" | "restrict";
85
- };
74
+ get options(): NonNullable<Options['schemaGenerator']>;
86
75
  protected processComment(comment: string): string;
87
76
  protected quote(...keys: (string | undefined)[]): string;
88
77
  dropForeignKey(tableName: string, constraintName: string): string;
@@ -36,7 +36,7 @@ export class SchemaHelper {
36
36
  return Utils.flatten(pks);
37
37
  }
38
38
  inferLengthFromColumnType(type) {
39
- const match = type.match(/^\w+\s*(?:\(\s*(\d+)\s*\)|$)/);
39
+ const match = /^\w+\s*(?:\(\s*(\d+)\s*\)|$)/.exec(type);
40
40
  if (!match) {
41
41
  return;
42
42
  }
@@ -78,7 +78,7 @@ export class SchemaHelper {
78
78
  tableName = this.quote(tableName);
79
79
  oldColumnName = this.quote(oldColumnName);
80
80
  const columnName = this.quote(to.name);
81
- const schemaReference = (schemaName !== undefined && schemaName !== 'public') ? ('"' + schemaName + '".') : '';
81
+ const schemaReference = schemaName !== undefined && schemaName !== 'public' ? '"' + schemaName + '".' : '';
82
82
  const tableReference = schemaReference + tableName;
83
83
  return `alter table ${tableReference} rename column ${oldColumnName} to ${columnName}`;
84
84
  }
@@ -124,7 +124,8 @@ export class SchemaHelper {
124
124
  */
125
125
  getIndexColumns(index) {
126
126
  if (index.columns?.length) {
127
- return index.columns.map(col => {
127
+ return index.columns
128
+ .map(col => {
128
129
  let colDef = this.quote(col.name);
129
130
  // Collation comes after column name (SQLite syntax: column COLLATE name)
130
131
  if (col.collation) {
@@ -139,7 +140,8 @@ export class SchemaHelper {
139
140
  colDef += ` nulls ${col.nulls}`;
140
141
  }
141
142
  return colDef;
142
- }).join(', ');
143
+ })
144
+ .join(', ');
143
145
  }
144
146
  return index.columnNames.map(c => this.quote(c)).join(', ');
145
147
  }
@@ -256,9 +258,11 @@ export class SchemaHelper {
256
258
  return ret;
257
259
  }
258
260
  getAddColumnsSQL(table, columns) {
259
- const adds = columns.map(column => {
261
+ const adds = columns
262
+ .map(column => {
260
263
  return `add ${this.createTableColumn(column, table)}`;
261
- }).join(', ');
264
+ })
265
+ .join(', ');
262
266
  return [`alter table ${table.getQuotedName()} ${adds}`];
263
267
  }
264
268
  getDropColumnsSQL(tableName, columns, schemaName) {
@@ -310,12 +314,26 @@ export class SchemaHelper {
310
314
  Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable && !column.generated);
311
315
  Utils.runIfNotEmpty(() => col.push('auto_increment'), column.autoincrement);
312
316
  Utils.runIfNotEmpty(() => col.push('unique'), column.autoincrement && !column.primary);
313
- if (column.autoincrement && !column.generated && !compositePK && (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
317
+ if (column.autoincrement &&
318
+ !column.generated &&
319
+ !compositePK &&
320
+ (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
314
321
  Utils.runIfNotEmpty(() => col.push('primary key'), primaryKey && column.primary);
315
322
  }
316
323
  if (useDefault) {
317
324
  // https://dev.mysql.com/doc/refman/9.0/en/data-type-defaults.html
318
- const needsExpression = ['blob', 'text', 'json', 'point', 'linestring', 'polygon', 'multipoint', 'multilinestring', 'multipolygon', 'geometrycollection'].some(type => column.type.toLowerCase().startsWith(type));
325
+ const needsExpression = [
326
+ 'blob',
327
+ 'text',
328
+ 'json',
329
+ 'point',
330
+ 'linestring',
331
+ 'polygon',
332
+ 'multipoint',
333
+ 'multilinestring',
334
+ 'multipolygon',
335
+ 'geometrycollection',
336
+ ].some(type => column.type.toLowerCase().startsWith(type));
319
337
  const defaultSql = needsExpression && !column.default.startsWith('(') ? `(${column.default})` : column.default;
320
338
  col.push(`default ${defaultSql}`);
321
339
  }
@@ -371,7 +389,9 @@ export class SchemaHelper {
371
389
  columnNames: [fk.column_name],
372
390
  constraintName: fk.constraint_name,
373
391
  localTableName: schemaName ? `${schemaName}.${tableName}` : tableName,
374
- referencedTableName: fk.referenced_schema_name ? `${fk.referenced_schema_name}.${fk.referenced_table_name}` : fk.referenced_table_name,
392
+ referencedTableName: fk.referenced_schema_name
393
+ ? `${fk.referenced_schema_name}.${fk.referenced_table_name}`
394
+ : fk.referenced_table_name,
375
395
  referencedColumnNames: [fk.referenced_column_name],
376
396
  updateRule: fk.update_rule.toLowerCase(),
377
397
  deleteRule: fk.delete_rule.toLowerCase(),
@@ -396,6 +416,7 @@ export class SchemaHelper {
396
416
  return norm[0].replace('(?)', length != null ? `(${length})` : '');
397
417
  }
398
418
  getCreateDatabaseSQL(name) {
419
+ name = this.quote(name);
399
420
  // two line breaks to force separate execution
400
421
  return `create database ${name};\n\nuse ${name}`;
401
422
  }
@@ -1,22 +1,12 @@
1
- import { type ClearDatabaseOptions, type CreateSchemaOptions, type Dictionary, type DropSchemaOptions, type EnsureDatabaseOptions, type EntityMetadata, type ISchemaGenerator, type MikroORM, type Transaction, type UpdateSchemaOptions } from '@mikro-orm/core';
1
+ import { type ClearDatabaseOptions, type CreateSchemaOptions, type DropSchemaOptions, type EnsureDatabaseOptions, type EntityMetadata, type ISchemaGenerator, type MikroORM, type Options, type Transaction, type UpdateSchemaOptions } from '@mikro-orm/core';
2
2
  import { AbstractSchemaGenerator } from '@mikro-orm/core/schema';
3
3
  import type { SchemaDifference } from '../typings.js';
4
4
  import { DatabaseSchema } from './DatabaseSchema.js';
5
5
  import type { AbstractSqlDriver } from '../AbstractSqlDriver.js';
6
+ import type { SchemaHelper } from './SchemaHelper.js';
6
7
  export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDriver> implements ISchemaGenerator {
7
- protected readonly helper: import("./SchemaHelper.js").SchemaHelper;
8
- protected readonly options: {
9
- disableForeignKeys?: boolean;
10
- disableForeignKeysForClear?: boolean;
11
- createForeignKeyConstraints?: boolean;
12
- ignoreSchema?: string[];
13
- skipTables?: (string | RegExp)[];
14
- skipViews?: (string | RegExp)[];
15
- skipColumns?: Dictionary<(string | RegExp)[]>;
16
- managementDbName?: string;
17
- defaultUpdateRule?: "cascade" | "no action" | "set null" | "set default" | "restrict";
18
- defaultDeleteRule?: "cascade" | "no action" | "set null" | "set default" | "restrict";
19
- };
8
+ protected readonly helper: SchemaHelper;
9
+ protected readonly options: NonNullable<Options['schemaGenerator']>;
20
10
  protected lastEnsuredDatabase?: string;
21
11
  static register(orm: MikroORM): void;
22
12
  create(options?: CreateSchemaOptions): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { CommitOrderCalculator, Utils, } from '@mikro-orm/core';
1
+ import { CommitOrderCalculator, TableNotFoundException, Utils, } from '@mikro-orm/core';
2
2
  import { AbstractSchemaGenerator } from '@mikro-orm/core/schema';
3
3
  import { DatabaseSchema } from './DatabaseSchema.js';
4
4
  import { SchemaComparator } from './SchemaComparator.js';
@@ -128,10 +128,19 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
128
128
  }
129
129
  const schema = options?.schema ?? this.config.get('schema', this.platform.getDefaultSchemaName());
130
130
  for (const meta of this.getOrderedMetadata(schema).reverse()) {
131
- await this.driver.createQueryBuilder(meta.class, this.em?.getTransactionContext(), 'write', false)
132
- .withSchema(schema)
133
- .truncate()
134
- .execute();
131
+ try {
132
+ await this.driver
133
+ .createQueryBuilder(meta.class, this.em?.getTransactionContext(), 'write', false)
134
+ .withSchema(schema)
135
+ .truncate()
136
+ .execute();
137
+ }
138
+ catch (e) {
139
+ if (this.platform.getExceptionConverter().convertException(e) instanceof TableNotFoundException) {
140
+ continue;
141
+ }
142
+ throw e;
143
+ }
135
144
  }
136
145
  if (this.options.disableForeignKeysForClear) {
137
146
  await this.execute(this.helper.enableForeignKeysSQL());
@@ -224,8 +233,11 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
224
233
  options.dropTables ??= true;
225
234
  const toSchema = this.getTargetSchema(options.schema);
226
235
  const schemas = toSchema.getNamespaces();
227
- const fromSchema = options.fromSchema ?? (await DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas, undefined, this.options.skipTables, this.options.skipViews));
228
- const wildcardSchemaTables = [...this.metadata.getAll().values()].filter(meta => meta.schema === '*').map(meta => meta.tableName);
236
+ const fromSchema = options.fromSchema ??
237
+ (await DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas, undefined, this.options.skipTables, this.options.skipViews));
238
+ const wildcardSchemaTables = [...this.metadata.getAll().values()]
239
+ .filter(meta => meta.schema === '*')
240
+ .map(meta => meta.tableName);
229
241
  fromSchema.prune(options.schema, wildcardSchemaTables);
230
242
  toSchema.prune(options.schema, wildcardSchemaTables);
231
243
  return { fromSchema, toSchema };
@@ -368,7 +380,7 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
368
380
  */
369
381
  async createDatabase(name, options) {
370
382
  name ??= this.config.get('dbName');
371
- const sql = this.helper.getCreateDatabaseSQL('' + this.platform.quoteIdentifier(name));
383
+ const sql = this.helper.getCreateDatabaseSQL(name);
372
384
  if (sql) {
373
385
  await this.execute(sql);
374
386
  }
@@ -408,7 +420,11 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
408
420
  return;
409
421
  }
410
422
  const statements = groups.flatMap(group => {
411
- return group.join('\n').split(';\n').map(s => s.trim()).filter(s => s);
423
+ return group
424
+ .join('\n')
425
+ .split(';\n')
426
+ .map(s => s.trim())
427
+ .filter(s => s);
412
428
  });
413
429
  await Utils.runSerial(statements, stmt => this.driver.execute(stmt));
414
430
  }
@@ -476,9 +492,7 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
476
492
  }
477
493
  // Check if the definition references the other view's name
478
494
  // Use word boundary matching to avoid false positives
479
- const patterns = [
480
- new RegExp(`\\b${this.escapeRegExp(otherView.name.toLowerCase())}\\b`),
481
- ];
495
+ const patterns = [new RegExp(`\\b${this.escapeRegExp(otherView.name.toLowerCase())}\\b`)];
482
496
  if (otherView.schema) {
483
497
  patterns.push(new RegExp(`\\b${this.escapeRegExp(`${otherView.schema}.${otherView.name}`.toLowerCase())}\\b`));
484
498
  }
package/typings.d.ts CHANGED
@@ -3,8 +3,8 @@ import type { CheckCallback, DeferMode, Dictionary, EntityName, EntityProperty,
3
3
  import type { JoinType, QueryType } from './query/enums.js';
4
4
  import type { DatabaseSchema } from './schema/DatabaseSchema.js';
5
5
  import type { DatabaseTable } from './schema/DatabaseTable.js';
6
- import type { QueryBuilder } from './query/QueryBuilder.js';
7
- import type { NativeQueryBuilder } from './query/NativeQueryBuilder.js';
6
+ import type { AnyQueryBuilder } from './query/QueryBuilder.js';
7
+ import type { CteOptions, NativeQueryBuilder } from './query/NativeQueryBuilder.js';
8
8
  import type { MikroKyselyPluginOptions } from './plugin/index.js';
9
9
  export interface Table {
10
10
  table_name: string;
@@ -12,7 +12,7 @@ export interface Table {
12
12
  table_comment?: string;
13
13
  }
14
14
  /** @internal */
15
- export type InternalField<T> = string | RawQueryFragment | QueryBuilder | NativeQueryBuilder;
15
+ export type InternalField<T> = string | RawQueryFragment | AnyQueryBuilder | NativeQueryBuilder;
16
16
  export interface JoinOptions {
17
17
  table: string;
18
18
  schema?: string;
@@ -171,7 +171,10 @@ export interface IQueryBuilder<T> {
171
171
  readonly alias: string;
172
172
  readonly type: QueryType;
173
173
  /** @internal */
174
- _fields?: InternalField<T>[];
174
+ state: {
175
+ fields?: InternalField<T>[];
176
+ [key: string]: any;
177
+ };
175
178
  /** @internal */
176
179
  helper: any;
177
180
  select(fields: string | RawQueryFragment | (string | RawQueryFragment)[], distinct?: boolean): this;
@@ -202,6 +205,8 @@ export interface IQueryBuilder<T> {
202
205
  setFlag(flag: QueryFlag): this;
203
206
  unsetFlag(flag: QueryFlag): this;
204
207
  hasFlag(flag: QueryFlag): boolean;
208
+ with(name: string, query: AnyQueryBuilder | NativeQueryBuilder | RawQueryFragment, options?: CteOptions): this;
209
+ withRecursive(name: string, query: AnyQueryBuilder | NativeQueryBuilder | RawQueryFragment, options?: CteOptions): this;
205
210
  scheduleFilterCheck(path: string): void;
206
211
  withSchema(schema: string): this;
207
212
  }
@@ -309,7 +314,7 @@ type MaybeNever<TValue, TOptions> = TOptions extends {
309
314
  type ExcludeNever<TMap extends Record<string, any>> = {
310
315
  [K in keyof TMap as TMap[K] extends never ? never : K]: TMap[K];
311
316
  };
312
- export type InferClassEntityDB<TEntities, TOptions extends MikroKyselyPluginOptions = {}> = ClassEntityDBMap<TEntities, TOptions> extends infer R ? [keyof R] extends [never] ? unknown : R : never;
317
+ export type InferClassEntityDB<TEntities, TOptions extends MikroKyselyPluginOptions = {}> = ClassEntityDBMap<TEntities, TOptions> extends infer R ? ([keyof R] extends [never] ? unknown : R) : never;
313
318
  type ClassEntityDBMap<TEntities, TOptions extends MikroKyselyPluginOptions = {}> = {
314
319
  [T in TEntities as ClassEntityTableName<T, TOptions>]: ClassEntityColumns<T>;
315
320
  };