@mikro-orm/knex 6.0.0-dev.5 → 6.0.0-dev.50

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 (40) hide show
  1. package/AbstractSqlConnection.d.ts +3 -0
  2. package/AbstractSqlConnection.js +16 -8
  3. package/AbstractSqlDriver.d.ts +11 -11
  4. package/AbstractSqlDriver.js +100 -40
  5. package/AbstractSqlPlatform.d.ts +2 -4
  6. package/AbstractSqlPlatform.js +6 -16
  7. package/README.md +63 -106
  8. package/SqlEntityManager.d.ts +0 -4
  9. package/SqlEntityManager.js +1 -9
  10. package/SqlEntityRepository.d.ts +0 -1
  11. package/SqlEntityRepository.js +0 -1
  12. package/index.d.ts +1 -0
  13. package/index.js +1 -0
  14. package/index.mjs +173 -0
  15. package/package.json +5 -39
  16. package/query/ArrayCriteriaNode.d.ts +3 -3
  17. package/query/CriteriaNode.d.ts +8 -8
  18. package/query/CriteriaNode.js +8 -8
  19. package/query/CriteriaNodeFactory.d.ts +6 -6
  20. package/query/CriteriaNodeFactory.js +11 -11
  21. package/query/ObjectCriteriaNode.d.ts +3 -3
  22. package/query/ObjectCriteriaNode.js +5 -5
  23. package/query/QueryBuilder.d.ts +11 -4
  24. package/query/QueryBuilder.js +141 -36
  25. package/query/QueryBuilderHelper.d.ts +3 -3
  26. package/query/QueryBuilderHelper.js +47 -19
  27. package/query/ScalarCriteriaNode.d.ts +3 -2
  28. package/query/ScalarCriteriaNode.js +9 -6
  29. package/schema/DatabaseSchema.js +3 -3
  30. package/schema/DatabaseTable.d.ts +9 -9
  31. package/schema/DatabaseTable.js +21 -22
  32. package/schema/SchemaComparator.d.ts +4 -4
  33. package/schema/SchemaComparator.js +4 -2
  34. package/schema/SchemaHelper.d.ts +11 -11
  35. package/schema/SchemaHelper.js +3 -3
  36. package/schema/{SchemaGenerator.d.ts → SqlSchemaGenerator.d.ts} +4 -8
  37. package/schema/{SchemaGenerator.js → SqlSchemaGenerator.js} +17 -24
  38. package/schema/index.d.ts +1 -1
  39. package/schema/index.js +1 -1
  40. package/typings.d.ts +14 -13
@@ -19,6 +19,9 @@ class QueryBuilderHelper {
19
19
  this.metadata = this.driver.getMetadata();
20
20
  }
21
21
  mapper(field, type = enums_1.QueryType.SELECT, value, alias) {
22
+ if (core_1.Utils.isRawSql(field)) {
23
+ return this.platform.formatQuery(field.sql, field.params ?? []);
24
+ }
22
25
  if (typeof field !== 'string') {
23
26
  return field;
24
27
  }
@@ -36,6 +39,17 @@ class QueryBuilderHelper {
36
39
  parts.push(this.mapper(a !== this.alias ? `${a}.${f}` : f, type, value, alias));
37
40
  }
38
41
  }
42
+ // flatten the value if we see we are expanding nested composite key
43
+ // hackish, but cleaner solution would require quite a lot of refactoring
44
+ if (fields.length !== parts.length && Array.isArray(value)) {
45
+ value.forEach(row => {
46
+ if (Array.isArray(row)) {
47
+ const tmp = core_1.Utils.flatten(row);
48
+ row.length = 0;
49
+ row.push(...tmp);
50
+ }
51
+ });
52
+ }
39
53
  return this.knex.raw('(' + parts.map(part => this.knex.ref(part)).join(', ') + ')');
40
54
  }
41
55
  let ret = field;
@@ -72,7 +86,8 @@ class QueryBuilderHelper {
72
86
  ret += ' as ' + alias;
73
87
  }
74
88
  if (customExpression) {
75
- return this.knex.raw(ret, value);
89
+ const bindings = core_1.Utils.asArray(value).slice(0, ret.match(/\?/g)?.length ?? 0);
90
+ return this.knex.raw(ret, bindings);
76
91
  }
77
92
  if (!isTableNameAliasRequired || this.isPrefixed(ret) || noPrefix) {
78
93
  return ret;
@@ -241,7 +256,7 @@ class QueryBuilderHelper {
241
256
  return `(${parts.join(` ${core_1.GroupOperator[operator]} `)})`;
242
257
  }
243
258
  mapJoinColumns(type, join) {
244
- if (join.prop && join.prop.reference === core_1.ReferenceType.ONE_TO_ONE && !join.prop.owner) {
259
+ if (join.prop && join.prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !join.prop.owner) {
245
260
  return join.prop.fieldNames.map((fieldName, idx) => {
246
261
  return this.mapper(`${join.alias}.${join.inverseJoinColumns[idx]}`, type, undefined, fieldName);
247
262
  });
@@ -254,7 +269,7 @@ class QueryBuilderHelper {
254
269
  isOneToOneInverse(field) {
255
270
  const meta = this.metadata.find(this.entityName);
256
271
  const prop = meta.properties[field];
257
- return prop && prop.reference === core_1.ReferenceType.ONE_TO_ONE && !prop.owner;
272
+ return prop && prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner;
258
273
  }
259
274
  getTableName(entityName) {
260
275
  const meta = this.metadata.find(entityName);
@@ -299,7 +314,7 @@ class QueryBuilderHelper {
299
314
  let mergeParam = item.merge;
300
315
  if (core_1.Utils.isObject(item.merge)) {
301
316
  mergeParam = {};
302
- Object.keys(item.merge).forEach(key => {
317
+ core_1.Utils.keys(item.merge).forEach(key => {
303
318
  const k = this.mapper(key, type);
304
319
  mergeParam[k] = item.merge[key];
305
320
  });
@@ -394,7 +409,8 @@ class QueryBuilderHelper {
394
409
  }));
395
410
  }
396
411
  else {
397
- qb[m](this.mapper(key, type, undefined, null), replacement, value[op]);
412
+ const mappedKey = this.mapper(key, type, value[op], null);
413
+ qb[m](mappedKey, replacement, value[op]);
398
414
  }
399
415
  }
400
416
  getOperatorReplacement(op, value) {
@@ -429,13 +445,13 @@ class QueryBuilderHelper {
429
445
  ret.push(`${k} ${order.toLowerCase()}`);
430
446
  return;
431
447
  }
432
- // eslint-disable-next-line prefer-const
433
- let [alias, field] = this.splitField(k, true);
434
- alias = populate[alias] || alias;
435
- core_1.Utils.splitPrimaryKeys(field).forEach(f => {
436
- const prop = this.getProperty(f, alias);
448
+ core_1.Utils.splitPrimaryKeys(k).forEach(f => {
449
+ // eslint-disable-next-line prefer-const
450
+ let [alias, field] = this.splitField(f, true);
451
+ alias = populate[alias] || alias;
452
+ const prop = this.getProperty(field, alias);
437
453
  const noPrefix = (prop && prop.persist === false && !prop.formula) || QueryBuilderHelper.isCustomExpression(f);
438
- const column = this.mapper(noPrefix ? f : `${alias}.${f}`, type, undefined, null);
454
+ const column = this.mapper(noPrefix ? field : `${alias}.${field}`, type, undefined, null);
439
455
  /* istanbul ignore next */
440
456
  const rawColumn = core_1.Utils.isString(column) ? column.split('.').map(e => this.knex.ref(e)).join('.') : column;
441
457
  const customOrder = prop?.customOrder;
@@ -447,11 +463,23 @@ class QueryBuilderHelper {
447
463
  });
448
464
  return ret.join(', ');
449
465
  }
450
- finalize(type, qb, meta) {
451
- const useReturningStatement = type === enums_1.QueryType.INSERT && this.platform.usesReturningStatement() && meta && !meta.compositePK;
452
- if (useReturningStatement) {
453
- const returningProps = meta.hydrateProps.filter(prop => prop.persist !== false && (prop.primary || prop.defaultRaw));
454
- qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
466
+ finalize(type, qb, meta, data) {
467
+ if (!meta || !data || !this.platform.usesReturningStatement()) {
468
+ return;
469
+ }
470
+ if (type === enums_1.QueryType.INSERT) {
471
+ const returningProps = meta.hydrateProps
472
+ .filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw))
473
+ .filter(prop => !(prop.name in data) || core_1.Utils.isRawSql(data[prop.name]));
474
+ if (returningProps.length > 0) {
475
+ qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
476
+ }
477
+ }
478
+ if (type === enums_1.QueryType.UPDATE) {
479
+ const returningProps = meta.hydrateProps.filter(prop => core_1.Utils.isRawSql(data[prop.name]));
480
+ if (returningProps.length > 0) {
481
+ qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
482
+ }
455
483
  }
456
484
  }
457
485
  splitField(field, greedyAlias = false) {
@@ -564,7 +592,7 @@ class QueryBuilderHelper {
564
592
  // check if `alias` is not matching an embedded property name instead of alias, e.g. `address.city`
565
593
  if (alias && meta) {
566
594
  const prop = meta.properties[alias];
567
- if (prop?.reference === core_1.ReferenceType.EMBEDDED) {
595
+ if (prop?.kind === core_1.ReferenceKind.EMBEDDED) {
568
596
  // we want to select the full object property so hydration works as expected
569
597
  if (prop.object) {
570
598
  return prop;
@@ -596,13 +624,13 @@ class QueryBuilderHelper {
596
624
  return;
597
625
  }
598
626
  if (prop.joinColumns && Array.isArray(data[k])) {
599
- const copy = data[k];
627
+ const copy = core_1.Utils.flatten(data[k]);
600
628
  delete data[k];
601
629
  prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
602
630
  return;
603
631
  }
604
632
  if (prop.customType && convertCustomTypes && !this.platform.isRaw(data[k])) {
605
- data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, { fromQuery: true, key: k, mode: 'query' });
633
+ data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, { fromQuery: true, key: k, mode: 'query-data' });
606
634
  }
607
635
  if (prop.customType && 'convertToDatabaseValueSQL' in prop.customType && !this.platform.isRaw(data[k])) {
608
636
  const quoted = this.platform.quoteValue(data[k]);
@@ -3,7 +3,8 @@ import type { IQueryBuilder } from '../typings';
3
3
  /**
4
4
  * @internal
5
5
  */
6
- export declare class ScalarCriteriaNode extends CriteriaNode {
7
- process<T>(qb: IQueryBuilder<T>, alias?: string): any;
6
+ export declare class ScalarCriteriaNode<T extends object> extends CriteriaNode<T> {
7
+ process(qb: IQueryBuilder<T>, alias?: string): any;
8
+ willAutoJoin<T>(qb: IQueryBuilder<T>, alias?: string): boolean;
8
9
  shouldJoin(): boolean;
9
10
  }
@@ -13,23 +13,26 @@ class ScalarCriteriaNode extends CriteriaNode_1.CriteriaNode {
13
13
  const parentPath = this.parent.getPath(); // the parent is always there, otherwise `shouldJoin` would return `false`
14
14
  const nestedAlias = qb.getAliasForJoinPath(path) || qb.getNextAlias(this.prop?.pivotTable ?? this.entityName);
15
15
  const field = `${alias}.${this.prop.name}`;
16
- const type = this.prop.reference === core_1.ReferenceType.MANY_TO_MANY ? 'pivotJoin' : 'leftJoin';
16
+ const type = this.prop.kind === core_1.ReferenceKind.MANY_TO_MANY ? 'pivotJoin' : 'leftJoin';
17
17
  qb.join(field, nestedAlias, undefined, type, path);
18
18
  // select the owner as virtual property when joining from 1:1 inverse side, but only if the parent is root entity
19
- if (this.prop.reference === core_1.ReferenceType.ONE_TO_ONE && !parentPath.includes('.')) {
19
+ if (this.prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !parentPath.includes('.')) {
20
20
  qb.addSelect(field);
21
21
  }
22
22
  }
23
23
  return this.payload;
24
24
  }
25
+ willAutoJoin(qb, alias) {
26
+ return this.shouldJoin();
27
+ }
25
28
  shouldJoin() {
26
29
  if (!this.parent || !this.prop) {
27
30
  return false;
28
31
  }
29
- switch (this.prop.reference) {
30
- case core_1.ReferenceType.ONE_TO_MANY: return true;
31
- case core_1.ReferenceType.MANY_TO_MANY: return true;
32
- case core_1.ReferenceType.ONE_TO_ONE: return !this.prop.owner;
32
+ switch (this.prop.kind) {
33
+ case core_1.ReferenceKind.ONE_TO_MANY: return true;
34
+ case core_1.ReferenceKind.MANY_TO_MANY: return true;
35
+ case core_1.ReferenceKind.ONE_TO_ONE: return !this.prop.owner;
33
36
  default: return false; // SCALAR, MANY_TO_ONE
34
37
  }
35
38
  }
@@ -78,15 +78,15 @@ class DatabaseSchema {
78
78
  if (prop.persist === false || !prop.fieldNames) {
79
79
  return false;
80
80
  }
81
- if (meta.pivotTable || (core_1.ReferenceType.EMBEDDED && prop.object)) {
81
+ if (meta.pivotTable || (core_1.ReferenceKind.EMBEDDED && prop.object)) {
82
82
  return true;
83
83
  }
84
84
  const getRootProperty = (prop) => prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop;
85
85
  const rootProp = getRootProperty(prop);
86
- if (rootProp.reference === core_1.ReferenceType.EMBEDDED) {
86
+ if (rootProp.kind === core_1.ReferenceKind.EMBEDDED) {
87
87
  return prop === rootProp || !rootProp.object;
88
88
  }
89
- return [core_1.ReferenceType.SCALAR, core_1.ReferenceType.MANY_TO_ONE].includes(prop.reference) || (prop.reference === core_1.ReferenceType.ONE_TO_ONE && prop.owner);
89
+ return [core_1.ReferenceKind.SCALAR, core_1.ReferenceKind.MANY_TO_ONE].includes(prop.kind) || (prop.kind === core_1.ReferenceKind.ONE_TO_ONE && prop.owner);
90
90
  }
91
91
  toJSON() {
92
92
  const { platform, namespaces, ...rest } = this;
@@ -1,6 +1,6 @@
1
1
  import type { Dictionary, EntityMetadata, EntityProperty, NamingStrategy } from '@mikro-orm/core';
2
2
  import type { SchemaHelper } from './SchemaHelper';
3
- import type { Check, Column, ForeignKey, Index } from '../typings';
3
+ import type { CheckDef, Column, ForeignKey, IndexDef } from '../typings';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
5
5
  /**
6
6
  * @internal
@@ -17,9 +17,9 @@ export declare class DatabaseTable {
17
17
  constructor(platform: AbstractSqlPlatform, name: string, schema?: string | undefined);
18
18
  getColumns(): Column[];
19
19
  getColumn(name: string): Column | undefined;
20
- getIndexes(): Index[];
21
- getChecks(): Check[];
22
- init(cols: Column[], indexes: Index[] | undefined, checks: Check<unknown>[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
20
+ getIndexes(): IndexDef[];
21
+ getChecks(): CheckDef[];
22
+ init(cols: Column[], indexes: IndexDef[] | undefined, checks: CheckDef<unknown>[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
23
23
  addColumn(column: Column): void;
24
24
  addColumnFromProperty(prop: EntityProperty, meta: EntityMetadata): void;
25
25
  private getIndexName;
@@ -30,14 +30,14 @@ export declare class DatabaseTable {
30
30
  getShortestName(): string;
31
31
  getForeignKeys(): Dictionary<ForeignKey>;
32
32
  hasColumn(columnName: string): boolean;
33
- getIndex(indexName: string): Index | undefined;
33
+ getIndex(indexName: string): IndexDef | undefined;
34
34
  hasIndex(indexName: string): boolean;
35
- getCheck(checkName: string): Check<unknown> | undefined;
35
+ getCheck(checkName: string): CheckDef<unknown> | undefined;
36
36
  hasCheck(checkName: string): boolean;
37
- getPrimaryKey(): Index | undefined;
37
+ getPrimaryKey(): IndexDef | undefined;
38
38
  hasPrimaryKey(): boolean;
39
39
  private getPropertyDeclaration;
40
- private getReferenceType;
40
+ private getReferenceKind;
41
41
  private getPropertyName;
42
42
  private getPropertyType;
43
43
  private getPropertyDefaultValue;
@@ -48,6 +48,6 @@ export declare class DatabaseTable {
48
48
  expression?: string;
49
49
  options?: Dictionary;
50
50
  }, type: 'index' | 'unique' | 'primary'): void;
51
- addCheck(check: Check): void;
51
+ addCheck(check: CheckDef): void;
52
52
  toJSON(): Dictionary;
53
53
  }
@@ -51,7 +51,6 @@ class DatabaseTable {
51
51
  }
52
52
  addColumnFromProperty(prop, meta) {
53
53
  prop.fieldNames.forEach((field, idx) => {
54
- var _a;
55
54
  const type = prop.enum ? 'enum' : prop.columnTypes[idx];
56
55
  const mappedType = this.platform.getMappedType(type);
57
56
  if (mappedType instanceof core_1.DecimalType) {
@@ -64,9 +63,9 @@ class DatabaseTable {
64
63
  }
65
64
  }
66
65
  if (mappedType instanceof core_1.DateTimeType) {
67
- prop.length ?? (prop.length = this.platform.getDefaultDateTimeLength());
66
+ prop.length ??= this.platform.getDefaultDateTimeLength();
68
67
  }
69
- const primary = !meta.compositePK && !!prop.primary && prop.reference === core_1.ReferenceType.SCALAR && this.platform.isNumericColumn(mappedType);
68
+ const primary = !meta.compositePK && !!prop.primary && prop.kind === core_1.ReferenceKind.SCALAR && this.platform.isNumericColumn(mappedType);
70
69
  this.columns[field] = {
71
70
  name: prop.fieldNames[idx],
72
71
  type: prop.columnTypes[idx],
@@ -84,11 +83,11 @@ class DatabaseTable {
84
83
  extra: prop.extra,
85
84
  ignoreSchemaChanges: prop.ignoreSchemaChanges,
86
85
  };
87
- (_a = this.columns[field]).unsigned || (_a.unsigned = this.columns[field].autoincrement);
86
+ this.columns[field].unsigned ||= this.columns[field].autoincrement;
88
87
  const defaultValue = this.platform.getSchemaHelper().normalizeDefaultValue(prop.defaultRaw, prop.length);
89
88
  this.columns[field].default = defaultValue;
90
89
  });
91
- if ([core_1.ReferenceType.MANY_TO_ONE, core_1.ReferenceType.ONE_TO_ONE].includes(prop.reference)) {
90
+ if ([core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
92
91
  const constraintName = this.getIndexName(true, prop.fieldNames, 'foreign');
93
92
  let schema = prop.targetMeta.schema === '*' ? this.schema : prop.targetMeta.schema ?? this.schema;
94
93
  if (prop.referencedTableName.includes('.')) {
@@ -102,11 +101,11 @@ class DatabaseTable {
102
101
  referencedTableName: schema ? `${schema}.${prop.referencedTableName}` : prop.referencedTableName,
103
102
  };
104
103
  const cascade = prop.cascade.includes(core_1.Cascade.REMOVE) || prop.cascade.includes(core_1.Cascade.ALL);
105
- if (prop.onDelete || cascade || prop.nullable) {
106
- this.foreignKeys[constraintName].deleteRule = prop.onDelete || (cascade ? 'cascade' : 'set null');
104
+ if (prop.deleteRule || cascade || prop.nullable) {
105
+ this.foreignKeys[constraintName].deleteRule = prop.deleteRule || (cascade ? 'cascade' : 'set null');
107
106
  }
108
- if (prop.onUpdateIntegrity || prop.cascade.includes(core_1.Cascade.PERSIST) || prop.cascade.includes(core_1.Cascade.ALL)) {
109
- this.foreignKeys[constraintName].updateRule = prop.onUpdateIntegrity || 'cascade';
107
+ if (prop.updateRule || prop.cascade.includes(core_1.Cascade.PERSIST) || prop.cascade.includes(core_1.Cascade.ALL)) {
108
+ this.foreignKeys[constraintName].updateRule = prop.updateRule || 'cascade';
110
109
  }
111
110
  }
112
111
  if (prop.index) {
@@ -164,8 +163,8 @@ class DatabaseTable {
164
163
  }
165
164
  const meta = schema.init().meta;
166
165
  meta.relations
167
- .filter(prop => prop.primary && prop.reference === core_1.ReferenceType.MANY_TO_ONE && !meta.compositePK)
168
- .forEach(prop => prop.reference = core_1.ReferenceType.ONE_TO_ONE);
166
+ .filter(prop => prop.primary && prop.kind === core_1.ReferenceKind.MANY_TO_ONE && !meta.compositePK)
167
+ .forEach(prop => prop.kind = core_1.ReferenceKind.ONE_TO_ONE);
169
168
  return meta;
170
169
  }
171
170
  /**
@@ -206,20 +205,20 @@ class DatabaseTable {
206
205
  const prop = this.getPropertyName(namingStrategy, column);
207
206
  const index = compositeFkIndexes[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && !idx.unique && !idx.primary);
208
207
  const unique = compositeFkUniques[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && idx.unique && !idx.primary);
209
- const reference = this.getReferenceType(fk, unique);
208
+ const kind = this.getReferenceKind(fk, unique);
210
209
  const type = this.getPropertyType(namingStrategy, column, fk);
211
210
  const fkOptions = {};
212
211
  if (fk) {
213
212
  fkOptions.fieldNames = fk.columnNames;
214
213
  fkOptions.referencedTableName = fk.referencedTableName;
215
214
  fkOptions.referencedColumnNames = fk.referencedColumnNames;
216
- fkOptions.onUpdateIntegrity = fk.updateRule?.toLowerCase();
217
- fkOptions.onDelete = fk.deleteRule?.toLowerCase();
215
+ fkOptions.updateRule = fk.updateRule?.toLowerCase();
216
+ fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
218
217
  }
219
218
  return {
220
219
  name: prop,
221
220
  type,
222
- reference,
221
+ kind,
223
222
  columnType: column.type,
224
223
  default: this.getPropertyDefaultValue(schemaHelper, column, type),
225
224
  defaultRaw: this.getPropertyDefaultValue(schemaHelper, column, type, true),
@@ -234,14 +233,14 @@ class DatabaseTable {
234
233
  ...fkOptions,
235
234
  };
236
235
  }
237
- getReferenceType(fk, unique) {
236
+ getReferenceKind(fk, unique) {
238
237
  if (fk && unique) {
239
- return core_1.ReferenceType.ONE_TO_ONE;
238
+ return core_1.ReferenceKind.ONE_TO_ONE;
240
239
  }
241
240
  if (fk) {
242
- return core_1.ReferenceType.MANY_TO_ONE;
241
+ return core_1.ReferenceKind.MANY_TO_ONE;
243
242
  }
244
- return core_1.ReferenceType.SCALAR;
243
+ return core_1.ReferenceKind.SCALAR;
245
244
  }
246
245
  getPropertyName(namingStrategy, column) {
247
246
  const fk = Object.values(this.foreignKeys).find(fk => fk.columnNames.includes(column.name));
@@ -288,7 +287,7 @@ class DatabaseTable {
288
287
  return '' + val;
289
288
  }
290
289
  addIndex(meta, index, type) {
291
- const properties = core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames));
290
+ const properties = core_1.Utils.unique(core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames)));
292
291
  if (properties.length === 0 && !index.expression) {
293
292
  return;
294
293
  }
@@ -308,10 +307,10 @@ class DatabaseTable {
308
307
  }
309
308
  toJSON() {
310
309
  const { platform, columns, ...rest } = this;
311
- const columnsMapped = Object.keys(columns).reduce((o, col) => {
310
+ const columnsMapped = core_1.Utils.keys(columns).reduce((o, col) => {
312
311
  const { mappedType, ...restCol } = columns[col];
313
312
  o[col] = restCol;
314
- o[col].mappedType = Object.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
313
+ o[col].mappedType = core_1.Utils.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
315
314
  return o;
316
315
  }, {});
317
316
  return { columns: columnsMapped, ...rest };
@@ -1,4 +1,4 @@
1
- import type { Check, Column, ForeignKey, Index, SchemaDifference, TableDifference } from '../typings';
1
+ import type { CheckDef, Column, ForeignKey, IndexDef, SchemaDifference, TableDifference } from '../typings';
2
2
  import type { DatabaseSchema } from './DatabaseSchema';
3
3
  import type { DatabaseTable } from './DatabaseTable';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
@@ -45,12 +45,12 @@ export declare class SchemaComparator {
45
45
  * Finds the difference between the indexes index1 and index2.
46
46
  * Compares index1 with index2 and returns index2 if there are any differences or false in case there are no differences.
47
47
  */
48
- diffIndex(index1: Index, index2: Index): boolean;
48
+ diffIndex(index1: IndexDef, index2: IndexDef): boolean;
49
49
  /**
50
50
  * Checks if the other index already fulfills all the indexing and constraint needs of the current one.
51
51
  */
52
- isIndexFulfilledBy(index1: Index, index2: Index): boolean;
53
- diffCheck(check1: Check, check2: Check): boolean;
52
+ isIndexFulfilledBy(index1: IndexDef, index2: IndexDef): boolean;
53
+ diffCheck(check1: CheckDef, check2: CheckDef): boolean;
54
54
  hasSameDefaultValue(from: Column, to: Column): boolean;
55
55
  private mapColumnToProperty;
56
56
  private log;
@@ -425,8 +425,10 @@ class SchemaComparator {
425
425
  return index1.primary === index2.primary && index1.unique === index2.unique;
426
426
  }
427
427
  diffCheck(check1, check2) {
428
- const unquote = (str) => str?.replace(/['"`]/g, '');
429
- return unquote(check1.expression) !== unquote(check2.expression);
428
+ // check constraint definition might be normalized by the driver,
429
+ // e.g. quotes might be added (https://github.com/mikro-orm/mikro-orm/issues/3827)
430
+ const simplify = (str) => str?.replace(/['"`()]/g, '').toLowerCase();
431
+ return simplify(check1.expression) !== simplify(check2.expression);
430
432
  }
431
433
  hasSameDefaultValue(from, to) {
432
434
  if (from.default == null || from.default.toString().toLowerCase() === 'null' || from.default.toString().startsWith('nextval(')) {
@@ -2,7 +2,7 @@ import type { Knex } from 'knex';
2
2
  import type { Connection, Dictionary } from '@mikro-orm/core';
3
3
  import type { AbstractSqlConnection } from '../AbstractSqlConnection';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
5
- import type { Check, Column, Index, Table, TableDifference } from '../typings';
5
+ import type { CheckDef, Column, IndexDef, Table, TableDifference } from '../typings';
6
6
  import type { DatabaseTable } from './DatabaseTable';
7
7
  import type { DatabaseSchema } from './DatabaseSchema';
8
8
  export declare abstract class SchemaHelper {
@@ -14,28 +14,28 @@ export declare abstract class SchemaHelper {
14
14
  getSchemaEnd(): string;
15
15
  finalizeTable(table: Knex.TableBuilder, charset: string, collate?: string): void;
16
16
  supportsSchemaConstraints(): boolean;
17
- getPrimaryKeys(connection: AbstractSqlConnection, indexes: Index[] | undefined, tableName: string, schemaName?: string): Promise<string[]>;
17
+ getPrimaryKeys(connection: AbstractSqlConnection, indexes: IndexDef[] | undefined, tableName: string, schemaName?: string): Promise<string[]>;
18
18
  getForeignKeys(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Dictionary>;
19
19
  protected getTableKey(t: Table): string;
20
- getEnumDefinitions(connection: AbstractSqlConnection, checks: Check[], tableName: string, schemaName?: string): Promise<Dictionary<string[]>>;
20
+ getEnumDefinitions(connection: AbstractSqlConnection, checks: CheckDef[], tableName: string, schemaName?: string): Promise<Dictionary<string[]>>;
21
21
  loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[]): Promise<void>;
22
22
  getListTablesSQL(schemaName?: string): string;
23
23
  getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column, schemaName?: string): string;
24
- getCreateIndexSQL(tableName: string, index: Index): string;
25
- getDropIndexSQL(tableName: string, index: Index): string;
26
- getRenameIndexSQL(tableName: string, index: Index, oldIndexName: string): string;
24
+ getCreateIndexSQL(tableName: string, index: IndexDef): string;
25
+ getDropIndexSQL(tableName: string, index: IndexDef): string;
26
+ getRenameIndexSQL(tableName: string, index: IndexDef, oldIndexName: string): string;
27
27
  hasNonDefaultPrimaryKeyName(table: DatabaseTable): boolean;
28
28
  createTableColumn(table: Knex.TableBuilder, column: Column, fromTable: DatabaseTable, changedProperties?: Set<string>): Knex.ColumnBuilder;
29
29
  configureColumn(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
30
30
  configureColumnDefault(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
31
31
  getPreAlterTable(tableDiff: TableDifference, safe: boolean): string;
32
- getAlterColumnAutoincrement(tableName: string, column: Column): string;
33
- getChangeColumnCommentSQL(tableName: string, to: Column): string;
32
+ getAlterColumnAutoincrement(tableName: string, column: Column, schemaName?: string): string;
33
+ getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
34
34
  getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
35
35
  getColumns(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Column[]>;
36
- getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Index[]>;
37
- getChecks(connection: AbstractSqlConnection, tableName: string, schemaName?: string, columns?: Column[]): Promise<Check[]>;
38
- protected mapIndexes(indexes: Index[]): Promise<Index[]>;
36
+ getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<IndexDef[]>;
37
+ getChecks(connection: AbstractSqlConnection, tableName: string, schemaName?: string, columns?: Column[]): Promise<CheckDef[]>;
38
+ protected mapIndexes(indexes: IndexDef[]): Promise<IndexDef[]>;
39
39
  getForeignKeysSQL(tableName: string, schemaName?: string): string;
40
40
  mapForeignKeys(fks: any[], tableName: string, schemaName?: string): Dictionary;
41
41
  normalizeDefaultValue(defaultValue: string, length?: number, defaultValues?: Dictionary<string[]>): string | number;
@@ -122,17 +122,17 @@ class SchemaHelper {
122
122
  core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), guard('default'));
123
123
  }
124
124
  else {
125
- core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), column.default !== undefined);
125
+ core_1.Utils.runIfNotEmpty(() => col.defaultTo(knex.raw(column.default)), column.default != null && column.default !== 'null');
126
126
  }
127
127
  return col;
128
128
  }
129
129
  getPreAlterTable(tableDiff, safe) {
130
130
  return '';
131
131
  }
132
- getAlterColumnAutoincrement(tableName, column) {
132
+ getAlterColumnAutoincrement(tableName, column, schemaName) {
133
133
  return '';
134
134
  }
135
- getChangeColumnCommentSQL(tableName, to) {
135
+ getChangeColumnCommentSQL(tableName, to, schemaName) {
136
136
  return '';
137
137
  }
138
138
  async getNamespaces(connection) {
@@ -1,18 +1,13 @@
1
- import type { MikroORM } from '@mikro-orm/core';
1
+ import type { MikroORM, ISchemaGenerator } from '@mikro-orm/core';
2
2
  import { AbstractSchemaGenerator } from '@mikro-orm/core';
3
3
  import type { SchemaDifference } from '../typings';
4
4
  import { DatabaseSchema } from './DatabaseSchema';
5
5
  import type { AbstractSqlDriver } from '../AbstractSqlDriver';
6
- /**
7
- * Should be renamed to `SqlSchemaGenerator` in v6
8
- */
9
- export declare class SchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDriver> {
6
+ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDriver> implements ISchemaGenerator {
10
7
  private readonly helper;
11
8
  private readonly options;
12
9
  protected lastEnsuredDatabase?: string;
13
10
  static register(orm: MikroORM): void;
14
- /** @deprecated use `dropSchema` and `createSchema` commands respectively */
15
- generate(): Promise<string>;
16
11
  createSchema(options?: {
17
12
  wrap?: boolean;
18
13
  schema?: string;
@@ -88,7 +83,7 @@ export declare class SchemaGenerator extends AbstractSchemaGenerator<AbstractSql
88
83
  dropDatabase(name: string): Promise<void>;
89
84
  execute(sql: string, options?: {
90
85
  wrap?: boolean;
91
- }): Promise<undefined>;
86
+ }): Promise<void>;
92
87
  private wrapSchema;
93
88
  private createSchemaBuilder;
94
89
  private createTable;
@@ -101,3 +96,4 @@ export declare class SchemaGenerator extends AbstractSchemaGenerator<AbstractSql
101
96
  private dump;
102
97
  private get knex();
103
98
  }
99
+ export { SqlSchemaGenerator as SchemaGenerator };
@@ -1,28 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SchemaGenerator = void 0;
3
+ exports.SchemaGenerator = exports.SqlSchemaGenerator = void 0;
4
4
  const core_1 = require("@mikro-orm/core");
5
5
  const DatabaseSchema_1 = require("./DatabaseSchema");
6
6
  const SchemaComparator_1 = require("./SchemaComparator");
7
- /**
8
- * Should be renamed to `SqlSchemaGenerator` in v6
9
- */
10
- class SchemaGenerator extends core_1.AbstractSchemaGenerator {
7
+ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
11
8
  constructor() {
12
9
  super(...arguments);
13
10
  this.helper = this.platform.getSchemaHelper();
14
11
  this.options = this.config.get('schemaGenerator');
15
12
  }
16
13
  static register(orm) {
17
- orm.config.registerExtension('@mikro-orm/schema-generator', new SchemaGenerator(orm.em));
18
- }
19
- /** @deprecated use `dropSchema` and `createSchema` commands respectively */
20
- async generate() {
21
- const [dropSchema, createSchema] = await Promise.all([
22
- this.getDropSchemaSQL({ wrap: false }),
23
- this.getCreateSchemaSQL({ wrap: false }),
24
- ]);
25
- return this.wrapSchema(dropSchema + createSchema);
14
+ orm.config.registerExtension('@mikro-orm/schema-generator', () => new SqlSchemaGenerator(orm.em));
26
15
  }
27
16
  async createSchema(options) {
28
17
  await this.ensureDatabase();
@@ -143,7 +132,9 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
143
132
  return this.diffToSQL(diffUp, options);
144
133
  }
145
134
  async getUpdateSchemaMigrationSQL(options = {}) {
146
- await this.ensureDatabase();
135
+ if (!options.fromSchema) {
136
+ await this.ensureDatabase();
137
+ }
147
138
  const { fromSchema, toSchema } = await this.prepareSchemaForComparison(options);
148
139
  const comparator = new SchemaComparator_1.SchemaComparator(this.platform);
149
140
  const diffUp = comparator.compare(fromSchema, toSchema);
@@ -154,9 +145,9 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
154
145
  };
155
146
  }
156
147
  async prepareSchemaForComparison(options) {
157
- options.wrap ?? (options.wrap = this.options.disableForeignKeys);
158
- options.safe ?? (options.safe = false);
159
- options.dropTables ?? (options.dropTables = true);
148
+ options.wrap ??= this.options.disableForeignKeys;
149
+ options.safe ??= false;
150
+ options.dropTables ??= true;
160
151
  const toSchema = this.getTargetSchema(options.schema);
161
152
  const fromSchema = options.fromSchema ?? await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema);
162
153
  const wildcardSchemaTables = Object.values(this.metadata.getAll()).filter(meta => meta.schema === '*').map(meta => meta.tableName);
@@ -305,13 +296,13 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
305
296
  this.helper.configureColumn(column, col, this.knex, changedProperties);
306
297
  }
307
298
  for (const { column } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
308
- this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column));
299
+ this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column, schemaName));
309
300
  }
310
301
  for (const { column, changedProperties } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('comment'))) {
311
302
  if (['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems'].some(t => changedProperties.has(t))) {
312
303
  continue; // will be handled via knex
313
304
  }
314
- this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column));
305
+ this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column, schemaName));
315
306
  }
316
307
  for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
317
308
  this.helper.pushTableQuery(table, this.helper.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
@@ -364,19 +355,20 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
364
355
  await this.driver.execute(this.helper.getDropDatabaseSQL('' + this.knex.ref(name)));
365
356
  }
366
357
  async execute(sql, options = {}) {
367
- options.wrap ?? (options.wrap = false);
358
+ options.wrap ??= false;
368
359
  const lines = this.wrapSchema(sql, options).split('\n').filter(i => i.trim());
369
360
  if (lines.length === 0) {
370
361
  return;
371
362
  }
372
363
  if (this.platform.supportsMultipleStatements()) {
373
364
  const query = lines.join('\n');
374
- return void await this.driver.execute(query);
365
+ await this.driver.execute(query);
366
+ return;
375
367
  }
376
368
  await core_1.Utils.runSerial(lines, line => this.driver.execute(line));
377
369
  }
378
370
  wrapSchema(sql, options = {}) {
379
- options.wrap ?? (options.wrap = this.options.disableForeignKeys);
371
+ options.wrap ??= this.options.disableForeignKeys;
380
372
  if (!options.wrap || sql.trim() === '') {
381
373
  return sql;
382
374
  }
@@ -487,4 +479,5 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
487
479
  return this.connection.getKnex();
488
480
  }
489
481
  }
490
- exports.SchemaGenerator = SchemaGenerator;
482
+ exports.SqlSchemaGenerator = SqlSchemaGenerator;
483
+ exports.SchemaGenerator = SqlSchemaGenerator;
package/schema/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './DatabaseSchema';
2
2
  export * from './DatabaseTable';
3
- export * from './SchemaGenerator';
3
+ export * from './SqlSchemaGenerator';
4
4
  export * from './SchemaHelper';
5
5
  export * from './SchemaComparator';