@mikro-orm/knex 6.0.0-dev.16 → 6.0.0-dev.160

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 (44) hide show
  1. package/AbstractSqlConnection.d.ts +8 -4
  2. package/AbstractSqlConnection.js +30 -18
  3. package/AbstractSqlDriver.d.ts +21 -23
  4. package/AbstractSqlDriver.js +394 -225
  5. package/AbstractSqlPlatform.d.ts +5 -4
  6. package/AbstractSqlPlatform.js +34 -5
  7. package/MonkeyPatchable.d.ts +1 -0
  8. package/MonkeyPatchable.js +3 -0
  9. package/PivotCollectionPersister.d.ts +17 -0
  10. package/PivotCollectionPersister.js +128 -0
  11. package/README.md +64 -107
  12. package/SqlEntityManager.d.ts +2 -6
  13. package/SqlEntityManager.js +5 -9
  14. package/SqlEntityRepository.d.ts +7 -6
  15. package/SqlEntityRepository.js +11 -8
  16. package/index.mjs +24 -5
  17. package/package.json +8 -8
  18. package/query/ArrayCriteriaNode.d.ts +4 -3
  19. package/query/ArrayCriteriaNode.js +5 -0
  20. package/query/CriteriaNode.d.ts +10 -8
  21. package/query/CriteriaNode.js +23 -10
  22. package/query/CriteriaNodeFactory.d.ts +6 -6
  23. package/query/CriteriaNodeFactory.js +17 -13
  24. package/query/ObjectCriteriaNode.d.ts +4 -3
  25. package/query/ObjectCriteriaNode.js +48 -17
  26. package/query/QueryBuilder.d.ts +53 -24
  27. package/query/QueryBuilder.js +393 -133
  28. package/query/QueryBuilderHelper.d.ts +11 -16
  29. package/query/QueryBuilderHelper.js +194 -155
  30. package/query/ScalarCriteriaNode.d.ts +3 -2
  31. package/query/ScalarCriteriaNode.js +10 -6
  32. package/query/enums.d.ts +7 -0
  33. package/query/enums.js +10 -2
  34. package/schema/DatabaseSchema.d.ts +5 -2
  35. package/schema/DatabaseSchema.js +27 -9
  36. package/schema/DatabaseTable.d.ts +4 -2
  37. package/schema/DatabaseTable.js +67 -32
  38. package/schema/SchemaComparator.d.ts +3 -3
  39. package/schema/SchemaComparator.js +50 -30
  40. package/schema/SchemaHelper.d.ts +6 -4
  41. package/schema/SchemaHelper.js +18 -7
  42. package/schema/SqlSchemaGenerator.d.ts +3 -6
  43. package/schema/SqlSchemaGenerator.js +69 -34
  44. package/typings.d.ts +19 -10
package/query/enums.d.ts CHANGED
@@ -6,3 +6,10 @@ export declare enum QueryType {
6
6
  UPDATE = "UPDATE",
7
7
  DELETE = "DELETE"
8
8
  }
9
+ export declare enum JoinType {
10
+ leftJoin = "left join",
11
+ innerJoin = "inner join",
12
+ pivotJoin = "pivot join",
13
+ innerJoinLateral = "inner join lateral",
14
+ leftJoinLateral = "left join lateral"
15
+ }
package/query/enums.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueryType = void 0;
3
+ exports.JoinType = exports.QueryType = void 0;
4
4
  var QueryType;
5
5
  (function (QueryType) {
6
6
  QueryType["TRUNCATE"] = "TRUNCATE";
@@ -9,4 +9,12 @@ var QueryType;
9
9
  QueryType["INSERT"] = "INSERT";
10
10
  QueryType["UPDATE"] = "UPDATE";
11
11
  QueryType["DELETE"] = "DELETE";
12
- })(QueryType = exports.QueryType || (exports.QueryType = {}));
12
+ })(QueryType || (exports.QueryType = QueryType = {}));
13
+ var JoinType;
14
+ (function (JoinType) {
15
+ JoinType["leftJoin"] = "left join";
16
+ JoinType["innerJoin"] = "inner join";
17
+ JoinType["pivotJoin"] = "pivot join";
18
+ JoinType["innerJoinLateral"] = "inner join lateral";
19
+ JoinType["leftJoinLateral"] = "left join lateral";
20
+ })(JoinType || (exports.JoinType = JoinType = {}));
@@ -1,4 +1,4 @@
1
- import type { Configuration, Dictionary, EntityMetadata } from '@mikro-orm/core';
1
+ import { type Configuration, type Dictionary, type EntityMetadata } from '@mikro-orm/core';
2
2
  import { DatabaseTable } from './DatabaseTable';
3
3
  import type { AbstractSqlConnection } from '../AbstractSqlConnection';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
@@ -10,14 +10,17 @@ export declare class DatabaseSchema {
10
10
  readonly name: string;
11
11
  private tables;
12
12
  private namespaces;
13
+ private nativeEnums;
13
14
  constructor(platform: AbstractSqlPlatform, name: string);
14
15
  addTable(name: string, schema: string | undefined | null, comment?: string): DatabaseTable;
15
16
  getTables(): DatabaseTable[];
16
17
  getTable(name: string): DatabaseTable | undefined;
17
18
  hasTable(name: string): boolean;
19
+ setNativeEnums(nativeEnums: Dictionary<unknown[]>): void;
20
+ getNativeEnums(): Dictionary<unknown[]>;
18
21
  hasNamespace(namespace: string): boolean;
19
22
  getNamespaces(): string[];
20
- static create(connection: AbstractSqlConnection, platform: AbstractSqlPlatform, config: Configuration, schemaName?: string): Promise<DatabaseSchema>;
23
+ static create(connection: AbstractSqlConnection, platform: AbstractSqlPlatform, config: Configuration, schemaName?: string, schemas?: string[]): Promise<DatabaseSchema>;
21
24
  static fromMetadata(metadata: EntityMetadata[], platform: AbstractSqlPlatform, config: Configuration, schemaName?: string): DatabaseSchema;
22
25
  private static getSchemaName;
23
26
  private static shouldHaveColumn;
@@ -7,15 +7,19 @@ const DatabaseTable_1 = require("./DatabaseTable");
7
7
  * @internal
8
8
  */
9
9
  class DatabaseSchema {
10
+ platform;
11
+ name;
12
+ tables = [];
13
+ namespaces = new Set();
14
+ nativeEnums = {}; // for postgres
10
15
  constructor(platform, name) {
11
16
  this.platform = platform;
12
17
  this.name = name;
13
- this.tables = [];
14
- this.namespaces = new Set();
15
18
  }
16
19
  addTable(name, schema, comment) {
17
20
  const namespaceName = schema ?? this.name;
18
21
  const table = new DatabaseTable_1.DatabaseTable(this.platform, name, namespaceName);
22
+ table.nativeEnums = this.nativeEnums;
19
23
  table.comment = comment;
20
24
  this.tables.push(table);
21
25
  if (namespaceName != null) {
@@ -32,24 +36,38 @@ class DatabaseSchema {
32
36
  hasTable(name) {
33
37
  return !!this.getTable(name);
34
38
  }
39
+ setNativeEnums(nativeEnums) {
40
+ this.nativeEnums = nativeEnums;
41
+ this.tables.forEach(t => t.nativeEnums = nativeEnums);
42
+ }
43
+ getNativeEnums() {
44
+ return this.nativeEnums;
45
+ }
35
46
  hasNamespace(namespace) {
36
47
  return this.namespaces.has(namespace);
37
48
  }
38
49
  getNamespaces() {
39
50
  return [...this.namespaces];
40
51
  }
41
- static async create(connection, platform, config, schemaName) {
42
- const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema'));
52
+ static async create(connection, platform, config, schemaName, schemas) {
53
+ const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema') ?? platform.getDefaultSchemaName());
43
54
  const allTables = await connection.execute(platform.getSchemaHelper().getListTablesSQL());
44
55
  const parts = config.get('migrations').tableName.split('.');
45
56
  const migrationsTableName = parts[1] ?? parts[0];
46
57
  const migrationsSchemaName = parts.length > 1 ? parts[0] : config.get('schema', platform.getDefaultSchemaName());
47
58
  const tables = allTables.filter(t => t.table_name !== migrationsTableName || (t.schema_name && t.schema_name !== migrationsSchemaName));
48
- await platform.getSchemaHelper().loadInformationSchema(schema, connection, tables);
59
+ await platform.getSchemaHelper().loadInformationSchema(schema, connection, tables, schemas && schemas.length > 0 ? schemas : undefined);
49
60
  return schema;
50
61
  }
51
62
  static fromMetadata(metadata, platform, config, schemaName) {
52
63
  const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema'));
64
+ const nativeEnums = {};
65
+ for (const meta of metadata) {
66
+ meta.props
67
+ .filter(prop => prop.nativeEnumName)
68
+ .forEach(prop => nativeEnums[prop.nativeEnumName] = prop.items?.map(val => '' + val) ?? []);
69
+ }
70
+ schema.setNativeEnums(nativeEnums);
53
71
  for (const meta of metadata) {
54
72
  const table = schema.addTable(meta.collection, this.getSchemaName(meta, config, schemaName));
55
73
  table.comment = meta.comment;
@@ -75,18 +93,18 @@ class DatabaseSchema {
75
93
  return (meta.schema === '*' ? schema : meta.schema) ?? config.get('schema');
76
94
  }
77
95
  static shouldHaveColumn(meta, prop) {
78
- if (prop.persist === false || !prop.fieldNames) {
96
+ if (prop.persist === false || (prop.columnTypes?.length ?? 0) === 0) {
79
97
  return false;
80
98
  }
81
- if (meta.pivotTable || (core_1.ReferenceType.EMBEDDED && prop.object)) {
99
+ if (meta.pivotTable || (prop.kind === core_1.ReferenceKind.EMBEDDED && prop.object)) {
82
100
  return true;
83
101
  }
84
102
  const getRootProperty = (prop) => prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop;
85
103
  const rootProp = getRootProperty(prop);
86
- if (rootProp.reference === core_1.ReferenceType.EMBEDDED) {
104
+ if (rootProp.kind === core_1.ReferenceKind.EMBEDDED) {
87
105
  return prop === rootProp || !rootProp.object;
88
106
  }
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);
107
+ 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
108
  }
91
109
  toJSON() {
92
110
  const { platform, namespaces, ...rest } = this;
@@ -1,4 +1,4 @@
1
- import type { Dictionary, EntityMetadata, EntityProperty, NamingStrategy } from '@mikro-orm/core';
1
+ import { type Dictionary, type EntityMetadata, type EntityProperty, type NamingStrategy } from '@mikro-orm/core';
2
2
  import type { SchemaHelper } from './SchemaHelper';
3
3
  import type { CheckDef, Column, ForeignKey, IndexDef } from '../typings';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
@@ -13,10 +13,12 @@ export declare class DatabaseTable {
13
13
  private indexes;
14
14
  private checks;
15
15
  private foreignKeys;
16
+ nativeEnums: Dictionary<unknown[]>;
16
17
  comment?: string;
17
18
  constructor(platform: AbstractSqlPlatform, name: string, schema?: string | undefined);
18
19
  getColumns(): Column[];
19
20
  getColumn(name: string): Column | undefined;
21
+ removeColumn(name: string): void;
20
22
  getIndexes(): IndexDef[];
21
23
  getChecks(): CheckDef[];
22
24
  init(cols: Column[], indexes: IndexDef[] | undefined, checks: CheckDef<unknown>[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
@@ -37,7 +39,7 @@ export declare class DatabaseTable {
37
39
  getPrimaryKey(): IndexDef | undefined;
38
40
  hasPrimaryKey(): boolean;
39
41
  private getPropertyDeclaration;
40
- private getReferenceType;
42
+ private getReferenceKind;
41
43
  private getPropertyName;
42
44
  private getPropertyType;
43
45
  private getPropertyDefaultValue;
@@ -6,14 +6,19 @@ const core_1 = require("@mikro-orm/core");
6
6
  * @internal
7
7
  */
8
8
  class DatabaseTable {
9
+ platform;
10
+ name;
11
+ schema;
12
+ columns = {};
13
+ indexes = [];
14
+ checks = [];
15
+ foreignKeys = {};
16
+ nativeEnums = {}; // for postgres
17
+ comment;
9
18
  constructor(platform, name, schema) {
10
19
  this.platform = platform;
11
20
  this.name = name;
12
21
  this.schema = schema;
13
- this.columns = {};
14
- this.indexes = [];
15
- this.checks = [];
16
- this.foreignKeys = {};
17
22
  Object.defineProperties(this, {
18
23
  platform: { enumerable: false, writable: true },
19
24
  });
@@ -24,8 +29,11 @@ class DatabaseTable {
24
29
  getColumn(name) {
25
30
  return this.columns[name];
26
31
  }
32
+ removeColumn(name) {
33
+ delete this.columns[name];
34
+ }
27
35
  getIndexes() {
28
- return this.indexes;
36
+ return core_1.Utils.removeDuplicates(this.indexes);
29
37
  }
30
38
  getChecks() {
31
39
  return this.checks;
@@ -41,7 +49,7 @@ class DatabaseTable {
41
49
  const type = v.name in enums ? 'enum' : v.type;
42
50
  v.mappedType = this.platform.getMappedType(type);
43
51
  v.default = v.default?.toString().startsWith('nextval(') ? null : v.default;
44
- v.enumItems = enums[v.name] || [];
52
+ v.enumItems ??= enums[v.name] || [];
45
53
  o[v.name] = v;
46
54
  return o;
47
55
  }, {});
@@ -51,44 +59,51 @@ class DatabaseTable {
51
59
  }
52
60
  addColumnFromProperty(prop, meta) {
53
61
  prop.fieldNames.forEach((field, idx) => {
54
- var _a;
55
62
  const type = prop.enum ? 'enum' : prop.columnTypes[idx];
56
63
  const mappedType = this.platform.getMappedType(type);
57
64
  if (mappedType instanceof core_1.DecimalType) {
58
65
  const match = prop.columnTypes[idx].match(/\w+\((\d+), ?(\d+)\)/);
59
66
  /* istanbul ignore else */
60
67
  if (match) {
61
- prop.precision = +match[1];
62
- prop.scale = +match[2];
68
+ prop.precision ??= +match[1];
69
+ prop.scale ??= +match[2];
63
70
  prop.length = undefined;
64
71
  }
65
72
  }
66
73
  if (mappedType instanceof core_1.DateTimeType) {
67
- prop.length ?? (prop.length = this.platform.getDefaultDateTimeLength());
74
+ const match = prop.columnTypes[idx].match(/\w+\((\d+)\)/);
75
+ if (match) {
76
+ prop.length ??= +match[1];
77
+ }
78
+ else {
79
+ prop.length ??= this.platform.getDefaultDateTimeLength();
80
+ }
68
81
  }
69
- const primary = !meta.compositePK && !!prop.primary && prop.reference === core_1.ReferenceType.SCALAR && this.platform.isNumericColumn(mappedType);
82
+ const primary = !meta.compositePK && !!prop.primary && prop.kind === core_1.ReferenceKind.SCALAR && this.platform.isNumericColumn(mappedType);
70
83
  this.columns[field] = {
71
84
  name: prop.fieldNames[idx],
72
85
  type: prop.columnTypes[idx],
86
+ generated: prop.generated,
73
87
  mappedType,
74
88
  unsigned: prop.unsigned && this.platform.isNumericColumn(mappedType),
75
89
  autoincrement: prop.autoincrement ?? primary,
76
90
  primary,
77
- nullable: !!prop.nullable,
91
+ nullable: this.columns[field]?.nullable ?? !!prop.nullable,
92
+ nativeEnumName: prop.nativeEnumName,
78
93
  length: prop.length,
79
94
  precision: prop.precision,
80
95
  scale: prop.scale,
81
96
  default: prop.defaultRaw,
82
- enumItems: prop.items?.every(core_1.Utils.isString) ? prop.items : undefined,
97
+ enumItems: prop.nativeEnumName || prop.items?.every(core_1.Utils.isString) ? prop.items : undefined,
83
98
  comment: prop.comment,
84
99
  extra: prop.extra,
85
100
  ignoreSchemaChanges: prop.ignoreSchemaChanges,
86
101
  };
87
- (_a = this.columns[field]).unsigned || (_a.unsigned = this.columns[field].autoincrement);
102
+ this.columns[field].unsigned ||= this.columns[field].autoincrement;
88
103
  const defaultValue = this.platform.getSchemaHelper().normalizeDefaultValue(prop.defaultRaw, prop.length);
89
104
  this.columns[field].default = defaultValue;
90
105
  });
91
- if ([core_1.ReferenceType.MANY_TO_ONE, core_1.ReferenceType.ONE_TO_ONE].includes(prop.reference)) {
106
+ if ([core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
92
107
  const constraintName = this.getIndexName(true, prop.fieldNames, 'foreign');
93
108
  let schema = prop.targetMeta.schema === '*' ? this.schema : prop.targetMeta.schema ?? this.schema;
94
109
  if (prop.referencedTableName.includes('.')) {
@@ -102,11 +117,11 @@ class DatabaseTable {
102
117
  referencedTableName: schema ? `${schema}.${prop.referencedTableName}` : prop.referencedTableName,
103
118
  };
104
119
  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');
120
+ if (prop.deleteRule || cascade || prop.nullable) {
121
+ this.foreignKeys[constraintName].deleteRule = prop.deleteRule || (cascade ? 'cascade' : 'set null');
107
122
  }
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';
123
+ if (prop.updateRule || prop.cascade.includes(core_1.Cascade.PERSIST) || prop.cascade.includes(core_1.Cascade.ALL)) {
124
+ this.foreignKeys[constraintName].updateRule = prop.updateRule || 'cascade';
110
125
  }
111
126
  }
112
127
  if (prop.index) {
@@ -114,6 +129,7 @@ class DatabaseTable {
114
129
  columnNames: prop.fieldNames,
115
130
  composite: prop.fieldNames.length > 1,
116
131
  keyName: this.getIndexName(prop.index, prop.fieldNames, 'index'),
132
+ constraint: false,
117
133
  primary: false,
118
134
  unique: false,
119
135
  });
@@ -123,6 +139,7 @@ class DatabaseTable {
123
139
  columnNames: prop.fieldNames,
124
140
  composite: prop.fieldNames.length > 1,
125
141
  keyName: this.getIndexName(prop.unique, prop.fieldNames, 'unique'),
142
+ constraint: !prop.fieldNames.some((d) => d.includes('.')),
126
143
  primary: false,
127
144
  unique: true,
128
145
  });
@@ -164,8 +181,8 @@ class DatabaseTable {
164
181
  }
165
182
  const meta = schema.init().meta;
166
183
  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);
184
+ .filter(prop => prop.primary && prop.kind === core_1.ReferenceKind.MANY_TO_ONE && !meta.compositePK)
185
+ .forEach(prop => prop.kind = core_1.ReferenceKind.ONE_TO_ONE);
169
186
  return meta;
170
187
  }
171
188
  /**
@@ -206,20 +223,20 @@ class DatabaseTable {
206
223
  const prop = this.getPropertyName(namingStrategy, column);
207
224
  const index = compositeFkIndexes[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && !idx.unique && !idx.primary);
208
225
  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);
226
+ const kind = this.getReferenceKind(fk, unique);
210
227
  const type = this.getPropertyType(namingStrategy, column, fk);
211
228
  const fkOptions = {};
212
229
  if (fk) {
213
230
  fkOptions.fieldNames = fk.columnNames;
214
231
  fkOptions.referencedTableName = fk.referencedTableName;
215
232
  fkOptions.referencedColumnNames = fk.referencedColumnNames;
216
- fkOptions.onUpdateIntegrity = fk.updateRule?.toLowerCase();
217
- fkOptions.onDelete = fk.deleteRule?.toLowerCase();
233
+ fkOptions.updateRule = fk.updateRule?.toLowerCase();
234
+ fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
218
235
  }
219
236
  return {
220
237
  name: prop,
221
238
  type,
222
- reference,
239
+ kind,
223
240
  columnType: column.type,
224
241
  default: this.getPropertyDefaultValue(schemaHelper, column, type),
225
242
  defaultRaw: this.getPropertyDefaultValue(schemaHelper, column, type, true),
@@ -227,6 +244,8 @@ class DatabaseTable {
227
244
  primary: column.primary,
228
245
  fieldName: column.name,
229
246
  length: column.length,
247
+ precision: column.precision,
248
+ scale: column.scale,
230
249
  index: index ? index.keyName : undefined,
231
250
  unique: unique ? unique.keyName : undefined,
232
251
  enum: !!column.enumItems?.length,
@@ -234,14 +253,14 @@ class DatabaseTable {
234
253
  ...fkOptions,
235
254
  };
236
255
  }
237
- getReferenceType(fk, unique) {
256
+ getReferenceKind(fk, unique) {
238
257
  if (fk && unique) {
239
- return core_1.ReferenceType.ONE_TO_ONE;
258
+ return core_1.ReferenceKind.ONE_TO_ONE;
240
259
  }
241
260
  if (fk) {
242
- return core_1.ReferenceType.MANY_TO_ONE;
261
+ return core_1.ReferenceKind.MANY_TO_ONE;
243
262
  }
244
- return core_1.ReferenceType.SCALAR;
263
+ return core_1.ReferenceKind.SCALAR;
245
264
  }
246
265
  getPropertyName(namingStrategy, column) {
247
266
  const fk = Object.values(this.foreignKeys).find(fk => fk.columnNames.includes(column.name));
@@ -288,7 +307,20 @@ class DatabaseTable {
288
307
  return '' + val;
289
308
  }
290
309
  addIndex(meta, index, type) {
291
- const properties = core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames));
310
+ const properties = core_1.Utils.unique(core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => {
311
+ const root = prop.replace(/\..+$/, '');
312
+ if (meta.properties[prop]) {
313
+ if (meta.properties[prop].embeddedPath) {
314
+ return [meta.properties[prop].embeddedPath.join('.')];
315
+ }
316
+ return meta.properties[prop].fieldNames;
317
+ }
318
+ // json index, we need to rename the column only
319
+ if (meta.properties[root]) {
320
+ return [prop.replace(root, meta.properties[root].fieldNames[0])];
321
+ }
322
+ return [prop];
323
+ })));
292
324
  if (properties.length === 0 && !index.expression) {
293
325
  return;
294
326
  }
@@ -297,10 +329,13 @@ class DatabaseTable {
297
329
  keyName: name,
298
330
  columnNames: properties,
299
331
  composite: properties.length > 1,
332
+ // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
333
+ constraint: type !== 'index' && !properties.some((d) => d.includes('.')),
300
334
  primary: type === 'primary',
301
335
  unique: type !== 'index',
302
336
  type: index.type,
303
337
  expression: index.expression,
338
+ options: index.options,
304
339
  });
305
340
  }
306
341
  addCheck(check) {
@@ -308,10 +343,10 @@ class DatabaseTable {
308
343
  }
309
344
  toJSON() {
310
345
  const { platform, columns, ...rest } = this;
311
- const columnsMapped = Object.keys(columns).reduce((o, col) => {
346
+ const columnsMapped = core_1.Utils.keys(columns).reduce((o, col) => {
312
347
  const { mappedType, ...restCol } = columns[col];
313
348
  o[col] = restCol;
314
- o[col].mappedType = Object.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
349
+ o[col].mappedType = core_1.Utils.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
315
350
  return o;
316
351
  }, {});
317
352
  return { columns: columnsMapped, ...rest };
@@ -1,4 +1,4 @@
1
- import type { CheckDef, Column, ForeignKey, IndexDef, SchemaDifference, TableDifference } from '../typings';
1
+ import type { 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';
@@ -38,7 +38,7 @@ export declare class SchemaComparator {
38
38
  * Returns the difference between the columns
39
39
  * If there are differences this method returns field2, otherwise the boolean false.
40
40
  */
41
- diffColumn(column1: Column, column2: Column, tableName?: string): Set<string>;
41
+ diffColumn(fromColumn: Column, toColumn: Column, tableName?: string): Set<string>;
42
42
  diffEnumItems(items1?: string[], items2?: string[]): boolean;
43
43
  diffComment(comment1?: string, comment2?: string): boolean;
44
44
  /**
@@ -50,7 +50,7 @@ export declare class SchemaComparator {
50
50
  * Checks if the other index already fulfills all the indexing and constraint needs of the current one.
51
51
  */
52
52
  isIndexFulfilledBy(index1: IndexDef, index2: IndexDef): boolean;
53
- diffCheck(check1: CheckDef, check2: CheckDef): boolean;
53
+ diffExpression(expr1: string, expr2: string): boolean;
54
54
  hasSameDefaultValue(from: Column, to: Column): boolean;
55
55
  private mapColumnToProperty;
56
56
  private log;
@@ -7,6 +7,9 @@ const core_1 = require("@mikro-orm/core");
7
7
  * Compares two Schemas and return an instance of SchemaDifference.
8
8
  */
9
9
  class SchemaComparator {
10
+ platform;
11
+ helper;
12
+ logger;
10
13
  constructor(platform) {
11
14
  this.platform = platform;
12
15
  this.helper = this.platform.getSchemaHelper();
@@ -139,6 +142,12 @@ class SchemaComparator {
139
142
  if (changedProperties.size === 0) {
140
143
  continue;
141
144
  }
145
+ if (changedProperties.size === 1 && changedProperties.has('generated')) {
146
+ tableDifferences.addedColumns[column.name] = toTable.getColumn(column.name);
147
+ tableDifferences.removedColumns[column.name] = column;
148
+ changes++;
149
+ continue;
150
+ }
142
151
  tableDifferences.changedColumns[column.name] = {
143
152
  oldColumnName: column.name,
144
153
  fromColumn: column,
@@ -200,7 +209,7 @@ class SchemaComparator {
200
209
  }
201
210
  // See if index has changed in "to" table
202
211
  const toTableCheck = toTable.getCheck(check.name);
203
- if (!this.diffCheck(check, toTableCheck)) {
212
+ if (!this.diffExpression(check.expression, toTableCheck.expression)) {
204
213
  continue;
205
214
  }
206
215
  this.log(`check constraint ${check.name} changed in table ${tableDifferences.name}`, { fromTableCheck: check, toTableCheck });
@@ -324,12 +333,12 @@ class SchemaComparator {
324
333
  * Returns the difference between the columns
325
334
  * If there are differences this method returns field2, otherwise the boolean false.
326
335
  */
327
- diffColumn(column1, column2, tableName) {
336
+ diffColumn(fromColumn, toColumn, tableName) {
328
337
  const changedProperties = new Set();
329
- const prop1 = this.mapColumnToProperty({ ...column1, autoincrement: false });
330
- const prop2 = this.mapColumnToProperty({ ...column2, autoincrement: false });
331
- const columnType1 = column1.mappedType.getColumnType(prop1, this.platform).toLowerCase();
332
- const columnType2 = column2.mappedType.getColumnType(prop2, this.platform).toLowerCase();
338
+ const fromProp = this.mapColumnToProperty({ ...fromColumn, autoincrement: false });
339
+ const toProp = this.mapColumnToProperty({ ...toColumn, autoincrement: false });
340
+ const fromColumnType = fromColumn.mappedType.getColumnType(fromProp, this.platform).toLowerCase();
341
+ const toColumnType = toColumn.mappedType.getColumnType(toProp, this.platform).toLowerCase();
333
342
  const log = (msg, params) => {
334
343
  if (tableName) {
335
344
  const copy = core_1.Utils.copy(params);
@@ -337,40 +346,46 @@ class SchemaComparator {
337
346
  this.log(msg, copy);
338
347
  }
339
348
  };
340
- if (columnType1 !== columnType2 &&
341
- !(column1.ignoreSchemaChanges?.includes('type') ||
342
- column2.ignoreSchemaChanges?.includes('type'))) {
343
- log(`'type' changed for column ${tableName}.${column1.name}`, { columnType1, columnType2 });
349
+ if (fromColumnType !== toColumnType &&
350
+ !(fromColumn.ignoreSchemaChanges?.includes('type') ||
351
+ toColumn.ignoreSchemaChanges?.includes('type'))) {
352
+ log(`'type' changed for column ${tableName}.${fromColumn.name}`, { fromColumnType, toColumnType });
344
353
  changedProperties.add('type');
345
354
  }
346
- if (column1.nullable !== column2.nullable) {
347
- log(`'nullable' changed for column ${tableName}.${column1.name}`, { column1, column2 });
355
+ if (fromColumn.nullable !== toColumn.nullable && !fromColumn.generated && !toColumn.generated) {
356
+ log(`'nullable' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
348
357
  changedProperties.add('nullable');
349
358
  }
350
- if (!!column1.autoincrement !== !!column2.autoincrement) {
351
- log(`'autoincrement' changed for column ${tableName}.${column1.name}`, { column1, column2 });
359
+ if (this.diffExpression(fromColumn.generated, toColumn.generated)) {
360
+ log(`'generated' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
361
+ changedProperties.add('generated');
362
+ }
363
+ if (!!fromColumn.autoincrement !== !!toColumn.autoincrement) {
364
+ log(`'autoincrement' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
352
365
  changedProperties.add('autoincrement');
353
366
  }
354
- if (column1.unsigned !== column2.unsigned && this.platform.supportsUnsigned()) {
355
- log(`'unsigned' changed for column ${tableName}.${column1.name}`, { column1, column2 });
367
+ if (fromColumn.unsigned !== toColumn.unsigned && this.platform.supportsUnsigned()) {
368
+ log(`'unsigned' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
356
369
  changedProperties.add('unsigned');
357
370
  }
358
- if (!this.hasSameDefaultValue(column1, column2)) {
359
- log(`'default' changed for column ${tableName}.${column1.name}`, { column1, column2 });
371
+ if (!this.hasSameDefaultValue(fromColumn, toColumn)) {
372
+ log(`'default' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
360
373
  changedProperties.add('default');
361
374
  }
362
- if (this.diffComment(column1.comment, column2.comment)) {
363
- log(`'comment' changed for column ${tableName}.${column1.name}`, { column1, column2 });
375
+ if (this.diffComment(fromColumn.comment, toColumn.comment)) {
376
+ log(`'comment' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
364
377
  changedProperties.add('comment');
365
378
  }
366
- if (this.diffEnumItems(column1.enumItems, column2.enumItems)) {
367
- log(`'enumItems' changed for column ${tableName}.${column1.name}`, { column1, column2 });
379
+ if (!(fromColumn.mappedType instanceof core_1.ArrayType) &&
380
+ !(toColumn.mappedType instanceof core_1.ArrayType) &&
381
+ this.diffEnumItems(fromColumn.enumItems, toColumn.enumItems)) {
382
+ log(`'enumItems' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
368
383
  changedProperties.add('enumItems');
369
384
  }
370
- if ((column1.extra || '').toLowerCase() !== (column2.extra || '').toLowerCase() &&
371
- !(column1.ignoreSchemaChanges?.includes('extra') ||
372
- column2.ignoreSchemaChanges?.includes('extra'))) {
373
- log(`'extra' changed for column ${tableName}.${column1.name}`, { column1, column2 });
385
+ if ((fromColumn.extra || '').toLowerCase() !== (toColumn.extra || '').toLowerCase() &&
386
+ !(fromColumn.ignoreSchemaChanges?.includes('extra') ||
387
+ toColumn.ignoreSchemaChanges?.includes('extra'))) {
388
+ log(`'extra' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
374
389
  changedProperties.add('extra');
375
390
  }
376
391
  return changedProperties;
@@ -424,11 +439,11 @@ class SchemaComparator {
424
439
  }
425
440
  return index1.primary === index2.primary && index1.unique === index2.unique;
426
441
  }
427
- diffCheck(check1, check2) {
428
- // check constraint definition might be normalized by the driver,
442
+ diffExpression(expr1, expr2) {
443
+ // expressions like check constraints might be normalized by the driver,
429
444
  // 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);
445
+ const simplify = (str) => str?.replace(/_\w+\\'(.*?)\\'/g, '$1').replace(/['"`()]|::\w+| +/g, '').toLowerCase();
446
+ return simplify(expr1) !== simplify(expr2);
432
447
  }
433
448
  hasSameDefaultValue(from, to) {
434
449
  if (from.default == null || from.default.toString().toLowerCase() === 'null' || from.default.toString().startsWith('nextval(')) {
@@ -439,6 +454,11 @@ class SchemaComparator {
439
454
  const defaultValueTo = !['0', 'false', 'f', 'n', 'no', 'off'].includes('' + to.default);
440
455
  return defaultValueFrom === defaultValueTo;
441
456
  }
457
+ if (to.mappedType instanceof core_1.JsonType) {
458
+ const defaultValueFrom = (0, core_1.parseJsonSafe)(from.default.replace(/^'(.*)'$/, '$1'));
459
+ const defaultValueTo = (0, core_1.parseJsonSafe)(to.default?.replace(/^'(.*)'$/, '$1'));
460
+ return core_1.Utils.equals(defaultValueFrom, defaultValueTo);
461
+ }
442
462
  if (to.mappedType instanceof core_1.DateTimeType && from.default && to.default) {
443
463
  // normalize now/current_timestamp defaults, also remove `()` from the end of default expression
444
464
  const defaultValueFrom = from.default.toLowerCase().replace('current_timestamp', 'now').replace(/\(\)$/, '');
@@ -1,5 +1,5 @@
1
1
  import type { Knex } from 'knex';
2
- import type { Connection, Dictionary } from '@mikro-orm/core';
2
+ import { type Connection, type Dictionary } from '@mikro-orm/core';
3
3
  import type { AbstractSqlConnection } from '../AbstractSqlConnection';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
5
5
  import type { CheckDef, Column, IndexDef, Table, TableDifference } from '../typings';
@@ -18,7 +18,9 @@ export declare abstract class SchemaHelper {
18
18
  getForeignKeys(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Dictionary>;
19
19
  protected getTableKey(t: Table): string;
20
20
  getEnumDefinitions(connection: AbstractSqlConnection, checks: CheckDef[], tableName: string, schemaName?: string): Promise<Dictionary<string[]>>;
21
- loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[]): Promise<void>;
21
+ getDropNativeEnumSQL(name: string, schema?: string): string;
22
+ getAlterNativeEnumSQL(name: string, schema?: string, value?: string): string;
23
+ loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[]): Promise<void>;
22
24
  getListTablesSQL(schemaName?: string): string;
23
25
  getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column, schemaName?: string): string;
24
26
  getCreateIndexSQL(tableName: string, index: IndexDef): string;
@@ -29,8 +31,8 @@ export declare abstract class SchemaHelper {
29
31
  configureColumn(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
30
32
  configureColumnDefault(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
31
33
  getPreAlterTable(tableDiff: TableDifference, safe: boolean): string;
32
- getAlterColumnAutoincrement(tableName: string, column: Column): string;
33
- getChangeColumnCommentSQL(tableName: string, to: Column): string;
34
+ getAlterColumnAutoincrement(tableName: string, column: Column, schemaName?: string): string;
35
+ getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
34
36
  getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
35
37
  getColumns(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Column[]>;
36
38
  getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<IndexDef[]>;