@mikro-orm/knex 6.0.0-dev.9 → 6.0.0-dev.90

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 (39) hide show
  1. package/AbstractSqlConnection.d.ts +5 -2
  2. package/AbstractSqlConnection.js +25 -17
  3. package/AbstractSqlDriver.d.ts +19 -18
  4. package/AbstractSqlDriver.js +171 -70
  5. package/AbstractSqlPlatform.d.ts +1 -0
  6. package/AbstractSqlPlatform.js +26 -5
  7. package/MonkeyPatchable.d.ts +1 -0
  8. package/MonkeyPatchable.js +3 -0
  9. package/README.md +64 -107
  10. package/SqlEntityManager.d.ts +2 -5
  11. package/SqlEntityManager.js +5 -9
  12. package/SqlEntityRepository.d.ts +6 -4
  13. package/SqlEntityRepository.js +10 -8
  14. package/index.mjs +20 -6
  15. package/package.json +7 -7
  16. package/query/ArrayCriteriaNode.d.ts +3 -3
  17. package/query/CriteriaNode.d.ts +8 -8
  18. package/query/CriteriaNode.js +9 -9
  19. package/query/CriteriaNodeFactory.d.ts +6 -6
  20. package/query/CriteriaNodeFactory.js +10 -13
  21. package/query/ObjectCriteriaNode.d.ts +3 -3
  22. package/query/ObjectCriteriaNode.js +12 -8
  23. package/query/QueryBuilder.d.ts +27 -16
  24. package/query/QueryBuilder.js +250 -91
  25. package/query/QueryBuilderHelper.d.ts +6 -9
  26. package/query/QueryBuilderHelper.js +112 -96
  27. package/query/ScalarCriteriaNode.d.ts +3 -2
  28. package/query/ScalarCriteriaNode.js +9 -6
  29. package/query/enums.js +1 -1
  30. package/schema/DatabaseSchema.d.ts +4 -1
  31. package/schema/DatabaseSchema.js +22 -6
  32. package/schema/DatabaseTable.d.ts +2 -1
  33. package/schema/DatabaseTable.js +25 -24
  34. package/schema/SchemaComparator.js +9 -2
  35. package/schema/SchemaHelper.d.ts +5 -3
  36. package/schema/SchemaHelper.js +10 -4
  37. package/schema/SqlSchemaGenerator.d.ts +3 -5
  38. package/schema/SqlSchemaGenerator.js +41 -20
  39. package/typings.d.ts +10 -7
@@ -14,6 +14,7 @@ class DatabaseTable {
14
14
  this.indexes = [];
15
15
  this.checks = [];
16
16
  this.foreignKeys = {};
17
+ this.nativeEnums = {}; // for postgres
17
18
  Object.defineProperties(this, {
18
19
  platform: { enumerable: false, writable: true },
19
20
  });
@@ -41,7 +42,7 @@ class DatabaseTable {
41
42
  const type = v.name in enums ? 'enum' : v.type;
42
43
  v.mappedType = this.platform.getMappedType(type);
43
44
  v.default = v.default?.toString().startsWith('nextval(') ? null : v.default;
44
- v.enumItems = enums[v.name] || [];
45
+ v.enumItems ??= enums[v.name] || [];
45
46
  o[v.name] = v;
46
47
  return o;
47
48
  }, {});
@@ -51,7 +52,6 @@ class DatabaseTable {
51
52
  }
52
53
  addColumnFromProperty(prop, meta) {
53
54
  prop.fieldNames.forEach((field, idx) => {
54
- var _a;
55
55
  const type = prop.enum ? 'enum' : prop.columnTypes[idx];
56
56
  const mappedType = this.platform.getMappedType(type);
57
57
  if (mappedType instanceof core_1.DecimalType) {
@@ -64,9 +64,9 @@ class DatabaseTable {
64
64
  }
65
65
  }
66
66
  if (mappedType instanceof core_1.DateTimeType) {
67
- prop.length ?? (prop.length = this.platform.getDefaultDateTimeLength());
67
+ prop.length ??= this.platform.getDefaultDateTimeLength();
68
68
  }
69
- const primary = !meta.compositePK && !!prop.primary && prop.reference === core_1.ReferenceType.SCALAR && this.platform.isNumericColumn(mappedType);
69
+ const primary = !meta.compositePK && !!prop.primary && prop.kind === core_1.ReferenceKind.SCALAR && this.platform.isNumericColumn(mappedType);
70
70
  this.columns[field] = {
71
71
  name: prop.fieldNames[idx],
72
72
  type: prop.columnTypes[idx],
@@ -74,21 +74,22 @@ class DatabaseTable {
74
74
  unsigned: prop.unsigned && this.platform.isNumericColumn(mappedType),
75
75
  autoincrement: prop.autoincrement ?? primary,
76
76
  primary,
77
+ nativeEnumName: prop.nativeEnumName,
77
78
  nullable: !!prop.nullable,
78
79
  length: prop.length,
79
80
  precision: prop.precision,
80
81
  scale: prop.scale,
81
82
  default: prop.defaultRaw,
82
- enumItems: prop.items?.every(core_1.Utils.isString) ? prop.items : undefined,
83
+ enumItems: prop.nativeEnumName || prop.items?.every(core_1.Utils.isString) ? prop.items : undefined,
83
84
  comment: prop.comment,
84
85
  extra: prop.extra,
85
86
  ignoreSchemaChanges: prop.ignoreSchemaChanges,
86
87
  };
87
- (_a = this.columns[field]).unsigned || (_a.unsigned = this.columns[field].autoincrement);
88
+ this.columns[field].unsigned ||= this.columns[field].autoincrement;
88
89
  const defaultValue = this.platform.getSchemaHelper().normalizeDefaultValue(prop.defaultRaw, prop.length);
89
90
  this.columns[field].default = defaultValue;
90
91
  });
91
- if ([core_1.ReferenceType.MANY_TO_ONE, core_1.ReferenceType.ONE_TO_ONE].includes(prop.reference)) {
92
+ if ([core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
92
93
  const constraintName = this.getIndexName(true, prop.fieldNames, 'foreign');
93
94
  let schema = prop.targetMeta.schema === '*' ? this.schema : prop.targetMeta.schema ?? this.schema;
94
95
  if (prop.referencedTableName.includes('.')) {
@@ -102,11 +103,11 @@ class DatabaseTable {
102
103
  referencedTableName: schema ? `${schema}.${prop.referencedTableName}` : prop.referencedTableName,
103
104
  };
104
105
  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');
106
+ if (prop.deleteRule || cascade || prop.nullable) {
107
+ this.foreignKeys[constraintName].deleteRule = prop.deleteRule || (cascade ? 'cascade' : 'set null');
107
108
  }
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';
109
+ if (prop.updateRule || prop.cascade.includes(core_1.Cascade.PERSIST) || prop.cascade.includes(core_1.Cascade.ALL)) {
110
+ this.foreignKeys[constraintName].updateRule = prop.updateRule || 'cascade';
110
111
  }
111
112
  }
112
113
  if (prop.index) {
@@ -164,8 +165,8 @@ class DatabaseTable {
164
165
  }
165
166
  const meta = schema.init().meta;
166
167
  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);
168
+ .filter(prop => prop.primary && prop.kind === core_1.ReferenceKind.MANY_TO_ONE && !meta.compositePK)
169
+ .forEach(prop => prop.kind = core_1.ReferenceKind.ONE_TO_ONE);
169
170
  return meta;
170
171
  }
171
172
  /**
@@ -206,20 +207,20 @@ class DatabaseTable {
206
207
  const prop = this.getPropertyName(namingStrategy, column);
207
208
  const index = compositeFkIndexes[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && !idx.unique && !idx.primary);
208
209
  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);
210
+ const kind = this.getReferenceKind(fk, unique);
210
211
  const type = this.getPropertyType(namingStrategy, column, fk);
211
212
  const fkOptions = {};
212
213
  if (fk) {
213
214
  fkOptions.fieldNames = fk.columnNames;
214
215
  fkOptions.referencedTableName = fk.referencedTableName;
215
216
  fkOptions.referencedColumnNames = fk.referencedColumnNames;
216
- fkOptions.onUpdateIntegrity = fk.updateRule?.toLowerCase();
217
- fkOptions.onDelete = fk.deleteRule?.toLowerCase();
217
+ fkOptions.updateRule = fk.updateRule?.toLowerCase();
218
+ fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
218
219
  }
219
220
  return {
220
221
  name: prop,
221
222
  type,
222
- reference,
223
+ kind,
223
224
  columnType: column.type,
224
225
  default: this.getPropertyDefaultValue(schemaHelper, column, type),
225
226
  defaultRaw: this.getPropertyDefaultValue(schemaHelper, column, type, true),
@@ -234,14 +235,14 @@ class DatabaseTable {
234
235
  ...fkOptions,
235
236
  };
236
237
  }
237
- getReferenceType(fk, unique) {
238
+ getReferenceKind(fk, unique) {
238
239
  if (fk && unique) {
239
- return core_1.ReferenceType.ONE_TO_ONE;
240
+ return core_1.ReferenceKind.ONE_TO_ONE;
240
241
  }
241
242
  if (fk) {
242
- return core_1.ReferenceType.MANY_TO_ONE;
243
+ return core_1.ReferenceKind.MANY_TO_ONE;
243
244
  }
244
- return core_1.ReferenceType.SCALAR;
245
+ return core_1.ReferenceKind.SCALAR;
245
246
  }
246
247
  getPropertyName(namingStrategy, column) {
247
248
  const fk = Object.values(this.foreignKeys).find(fk => fk.columnNames.includes(column.name));
@@ -288,7 +289,7 @@ class DatabaseTable {
288
289
  return '' + val;
289
290
  }
290
291
  addIndex(meta, index, type) {
291
- const properties = core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames));
292
+ const properties = core_1.Utils.unique(core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames)));
292
293
  if (properties.length === 0 && !index.expression) {
293
294
  return;
294
295
  }
@@ -308,10 +309,10 @@ class DatabaseTable {
308
309
  }
309
310
  toJSON() {
310
311
  const { platform, columns, ...rest } = this;
311
- const columnsMapped = Object.keys(columns).reduce((o, col) => {
312
+ const columnsMapped = core_1.Utils.keys(columns).reduce((o, col) => {
312
313
  const { mappedType, ...restCol } = columns[col];
313
314
  o[col] = restCol;
314
- o[col].mappedType = Object.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
315
+ o[col].mappedType = core_1.Utils.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
315
316
  return o;
316
317
  }, {});
317
318
  return { columns: columnsMapped, ...rest };
@@ -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(')) {
@@ -437,6 +439,11 @@ class SchemaComparator {
437
439
  const defaultValueTo = !['0', 'false', 'f', 'n', 'no', 'off'].includes('' + to.default);
438
440
  return defaultValueFrom === defaultValueTo;
439
441
  }
442
+ if (to.mappedType instanceof core_1.JsonType) {
443
+ const defaultValueFrom = (0, core_1.parseJsonSafe)(from.default.replace(/^'(.*)'$/, '$1'));
444
+ const defaultValueTo = (0, core_1.parseJsonSafe)(to.default?.replace(/^'(.*)'$/, '$1'));
445
+ return core_1.Utils.equals(defaultValueFrom, defaultValueTo);
446
+ }
440
447
  if (to.mappedType instanceof core_1.DateTimeType && from.default && to.default) {
441
448
  // normalize now/current_timestamp defaults, also remove `()` from the end of default expression
442
449
  const defaultValueFrom = from.default.toLowerCase().replace('current_timestamp', 'now').replace(/\(\)$/, '');
@@ -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[]>;
@@ -46,7 +46,13 @@ class SchemaHelper {
46
46
  async getEnumDefinitions(connection, checks, tableName, schemaName) {
47
47
  return {};
48
48
  }
49
- async loadInformationSchema(schema, connection, tables) {
49
+ getDropNativeEnumSQL(name, schema) {
50
+ throw new Error('Not supported by given driver');
51
+ }
52
+ getAlterNativeEnumSQL(name, schema, value) {
53
+ throw new Error('Not supported by given driver');
54
+ }
55
+ async loadInformationSchema(schema, connection, tables, schemas) {
50
56
  for (const t of tables) {
51
57
  const table = schema.addTable(t.table_name, t.schema_name);
52
58
  table.comment = t.table_comment;
@@ -122,17 +128,17 @@ class SchemaHelper {
122
128
  core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), guard('default'));
123
129
  }
124
130
  else {
125
- core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), column.default !== undefined);
131
+ core_1.Utils.runIfNotEmpty(() => col.defaultTo(knex.raw(column.default)), column.default != null && column.default !== 'null');
126
132
  }
127
133
  return col;
128
134
  }
129
135
  getPreAlterTable(tableDiff, safe) {
130
136
  return '';
131
137
  }
132
- getAlterColumnAutoincrement(tableName, column) {
138
+ getAlterColumnAutoincrement(tableName, column, schemaName) {
133
139
  return '';
134
140
  }
135
- getChangeColumnCommentSQL(tableName, to) {
141
+ getChangeColumnCommentSQL(tableName, to, schemaName) {
136
142
  return '';
137
143
  }
138
144
  async getNamespaces(connection) {
@@ -1,4 +1,4 @@
1
- import type { MikroORM, ISchemaGenerator } from '@mikro-orm/core';
1
+ import type { ISchemaGenerator, MikroORM } 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';
@@ -8,8 +8,6 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
8
8
  private readonly options;
9
9
  protected lastEnsuredDatabase?: string;
10
10
  static register(orm: MikroORM): void;
11
- /** @deprecated use `dropSchema` and `createSchema` commands respectively */
12
- generate(): Promise<string>;
13
11
  createSchema(options?: {
14
12
  wrap?: boolean;
15
13
  schema?: string;
@@ -82,10 +80,10 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
82
80
  * creates new database and connects to it
83
81
  */
84
82
  createDatabase(name: string): Promise<void>;
85
- dropDatabase(name: string): Promise<void>;
83
+ dropDatabase(name?: string): Promise<void>;
86
84
  execute(sql: string, options?: {
87
85
  wrap?: boolean;
88
- }): Promise<undefined>;
86
+ }): Promise<void>;
89
87
  private wrapSchema;
90
88
  private createSchemaBuilder;
91
89
  private createTable;
@@ -13,14 +13,6 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
13
13
  static register(orm) {
14
14
  orm.config.registerExtension('@mikro-orm/schema-generator', () => new SqlSchemaGenerator(orm.em));
15
15
  }
16
- /** @deprecated use `dropSchema` and `createSchema` commands respectively */
17
- async generate() {
18
- const [dropSchema, createSchema] = await Promise.all([
19
- this.getDropSchemaSQL({ wrap: false }),
20
- this.getCreateSchemaSQL({ wrap: false }),
21
- ]);
22
- return this.wrapSchema(dropSchema + createSchema);
23
- }
24
16
  async createSchema(options) {
25
17
  await this.ensureDatabase();
26
18
  const sql = await this.getCreateSchemaSQL(options);
@@ -101,7 +93,8 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
101
93
  await this.ensureDatabase();
102
94
  const wrap = options.wrap ?? this.options.disableForeignKeys;
103
95
  const metadata = this.getOrderedMetadata(options.schema).reverse();
104
- const schema = await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema);
96
+ const schemas = this.getTargetSchema(options.schema).getNamespaces();
97
+ const schema = await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas);
105
98
  let ret = '';
106
99
  // remove FKs explicitly if we can't use cascading statement and we don't disable FK checks (we need this for circular relations)
107
100
  for (const meta of metadata) {
@@ -118,6 +111,12 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
118
111
  for (const meta of metadata) {
119
112
  ret += await this.dump(this.dropTable(meta.collection, this.getSchemaName(meta, options)), '\n');
120
113
  }
114
+ if (this.platform.supportsNativeEnums()) {
115
+ for (const columnName of Object.keys(schema.getNativeEnums())) {
116
+ const sql = this.helper.getDropNativeEnumSQL(columnName, options.schema ?? this.config.get('schema'));
117
+ ret += await this.dump(this.knex.schema.raw(sql), '\n');
118
+ }
119
+ }
121
120
  if (options.dropMigrationsTable) {
122
121
  ret += await this.dump(this.dropTable(this.config.get('migrations').tableName, this.config.get('schema')), '\n');
123
122
  }
@@ -140,7 +139,9 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
140
139
  return this.diffToSQL(diffUp, options);
141
140
  }
142
141
  async getUpdateSchemaMigrationSQL(options = {}) {
143
- await this.ensureDatabase();
142
+ if (!options.fromSchema) {
143
+ await this.ensureDatabase();
144
+ }
144
145
  const { fromSchema, toSchema } = await this.prepareSchemaForComparison(options);
145
146
  const comparator = new SchemaComparator_1.SchemaComparator(this.platform);
146
147
  const diffUp = comparator.compare(fromSchema, toSchema);
@@ -151,14 +152,16 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
151
152
  };
152
153
  }
153
154
  async prepareSchemaForComparison(options) {
154
- options.wrap ?? (options.wrap = this.options.disableForeignKeys);
155
- options.safe ?? (options.safe = false);
156
- options.dropTables ?? (options.dropTables = true);
155
+ options.wrap ??= this.options.disableForeignKeys;
156
+ options.safe ??= false;
157
+ options.dropTables ??= true;
157
158
  const toSchema = this.getTargetSchema(options.schema);
158
- const fromSchema = options.fromSchema ?? await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema);
159
+ const schemas = toSchema.getNamespaces();
160
+ const fromSchema = options.fromSchema ?? await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas);
159
161
  const wildcardSchemaTables = Object.values(this.metadata.getAll()).filter(meta => meta.schema === '*').map(meta => meta.tableName);
160
162
  fromSchema.prune(options.schema, wildcardSchemaTables);
161
163
  toSchema.prune(options.schema, wildcardSchemaTables);
164
+ toSchema.setNativeEnums(fromSchema.getNativeEnums());
162
165
  return { fromSchema, toSchema };
163
166
  }
164
167
  async diffToSQL(schemaDiff, options) {
@@ -262,6 +265,12 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
262
265
  alterTable(diff, safe) {
263
266
  const ret = [];
264
267
  const [schemaName, tableName] = this.splitTableName(diff.name);
268
+ const changedNativeEnums = [];
269
+ for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
270
+ if (column.nativeEnumName && changedProperties.has('enumItems') && column.nativeEnumName in diff.fromTable.nativeEnums) {
271
+ changedNativeEnums.push([column.nativeEnumName, column.enumItems, diff.fromTable.getColumn(column.name).enumItems]);
272
+ }
273
+ }
265
274
  ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
266
275
  for (const index of Object.values(diff.removedIndexes)) {
267
276
  this.dropIndex(table, index);
@@ -298,17 +307,20 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
298
307
  if (changedProperties.size === 1 && changedProperties.has('comment')) {
299
308
  continue;
300
309
  }
310
+ if (changedProperties.size === 1 && changedProperties.has('enumItems') && column.nativeEnumName) {
311
+ continue;
312
+ }
301
313
  const col = this.helper.createTableColumn(table, column, diff.fromTable, changedProperties).alter();
302
314
  this.helper.configureColumn(column, col, this.knex, changedProperties);
303
315
  }
304
316
  for (const { column } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
305
- this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column));
317
+ this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column, schemaName));
306
318
  }
307
319
  for (const { column, changedProperties } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('comment'))) {
308
320
  if (['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems'].some(t => changedProperties.has(t))) {
309
321
  continue; // will be handled via knex
310
322
  }
311
- this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column));
323
+ this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column, schemaName));
312
324
  }
313
325
  for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
314
326
  this.helper.pushTableQuery(table, this.helper.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
@@ -345,6 +357,13 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
345
357
  table.comment(comment);
346
358
  }
347
359
  }));
360
+ if (this.platform.supportsNativeEnums()) {
361
+ changedNativeEnums.forEach(([enumName, itemsNew, itemsOld]) => {
362
+ // postgres allows only adding new items
363
+ const newItems = itemsNew.filter(val => !itemsOld.includes(val));
364
+ ret.push(...newItems.map(val => this.knex.schema.raw(this.helper.getAlterNativeEnumSQL(enumName, schemaName, val))));
365
+ });
366
+ }
348
367
  return ret;
349
368
  }
350
369
  /**
@@ -356,24 +375,26 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
356
375
  await this.driver.reconnect();
357
376
  }
358
377
  async dropDatabase(name) {
378
+ name ??= this.config.get('dbName');
359
379
  this.config.set('dbName', this.helper.getManagementDbName());
360
380
  await this.driver.reconnect();
361
381
  await this.driver.execute(this.helper.getDropDatabaseSQL('' + this.knex.ref(name)));
362
382
  }
363
383
  async execute(sql, options = {}) {
364
- options.wrap ?? (options.wrap = false);
384
+ options.wrap ??= false;
365
385
  const lines = this.wrapSchema(sql, options).split('\n').filter(i => i.trim());
366
386
  if (lines.length === 0) {
367
387
  return;
368
388
  }
369
389
  if (this.platform.supportsMultipleStatements()) {
370
390
  const query = lines.join('\n');
371
- return void await this.driver.execute(query);
391
+ await this.driver.execute(query);
392
+ return;
372
393
  }
373
394
  await core_1.Utils.runSerial(lines, line => this.driver.execute(line));
374
395
  }
375
- wrapSchema(sql, options = {}) {
376
- options.wrap ?? (options.wrap = this.options.disableForeignKeys);
396
+ wrapSchema(sql, options) {
397
+ options.wrap ??= this.options.disableForeignKeys;
377
398
  if (!options.wrap || sql.trim() === '') {
378
399
  return sql;
379
400
  }
package/typings.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Knex } from 'knex';
2
- import type { CheckCallback, Dictionary, EntityProperty, GroupOperator, QBFilterQuery, QueryOrderMap, Type } from '@mikro-orm/core';
2
+ import type { CheckCallback, Dictionary, EntityProperty, GroupOperator, RawQueryFragment, QBFilterQuery, QueryOrderMap, Type } from '@mikro-orm/core';
3
3
  import type { QueryType } from './query/enums';
4
4
  import type { DatabaseSchema, DatabaseTable } from './schema';
5
5
  export interface Table {
@@ -11,7 +11,7 @@ export type KnexStringRef = Knex.Ref<string, {
11
11
  [alias: string]: string;
12
12
  }>;
13
13
  type AnyString = string & {};
14
- export type Field<T> = AnyString | keyof T | KnexStringRef | Knex.QueryBuilder;
14
+ export type Field<T> = AnyString | keyof T | RawQueryFragment | KnexStringRef | Knex.QueryBuilder;
15
15
  export interface JoinOptions {
16
16
  table: string;
17
17
  schema?: string;
@@ -25,6 +25,7 @@ export interface JoinOptions {
25
25
  path?: string;
26
26
  prop: EntityProperty;
27
27
  cond: Dictionary;
28
+ cond_?: Dictionary;
28
29
  }
29
30
  export interface Column {
30
31
  name: string;
@@ -38,6 +39,7 @@ export interface Column {
38
39
  scale?: number;
39
40
  default?: string | null;
40
41
  comment?: string;
42
+ nativeEnumName?: string;
41
43
  enumItems?: string[];
42
44
  primary?: boolean;
43
45
  unique?: boolean;
@@ -122,7 +124,8 @@ export interface IQueryBuilder<T> {
122
124
  join(field: string, alias: string, cond?: QBFilterQuery, type?: 'leftJoin' | 'innerJoin' | 'pivotJoin', path?: string): this;
123
125
  leftJoin(field: string, alias: string, cond?: QBFilterQuery): this;
124
126
  joinAndSelect(field: string, alias: string, cond?: QBFilterQuery): this;
125
- leftJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery): this;
127
+ leftJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery, fields?: string[]): this;
128
+ innerJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery, fields?: string[]): this;
126
129
  withSubQuery(subQuery: Knex.QueryBuilder, alias: string): this;
127
130
  where(cond: QBFilterQuery<T>, operator?: keyof typeof GroupOperator): this;
128
131
  where(cond: string, params?: any[], operator?: keyof typeof GroupOperator): this;
@@ -136,16 +139,16 @@ export interface IQueryBuilder<T> {
136
139
  getAliasForJoinPath(path: string): string | undefined;
137
140
  getNextAlias(entityName?: string): string;
138
141
  }
139
- export interface ICriteriaNode {
142
+ export interface ICriteriaNode<T extends object> {
140
143
  readonly entityName: string;
141
- readonly parent?: ICriteriaNode | undefined;
144
+ readonly parent?: ICriteriaNode<T> | undefined;
142
145
  readonly key?: string | undefined;
143
146
  payload: any;
144
147
  prop?: EntityProperty;
145
148
  index?: number;
146
- process<T>(qb: IQueryBuilder<T>, alias?: string): any;
149
+ process(qb: IQueryBuilder<T>, alias?: string): any;
147
150
  shouldInline(payload: any): boolean;
148
- willAutoJoin<T>(qb: IQueryBuilder<T>, alias?: string): boolean;
151
+ willAutoJoin(qb: IQueryBuilder<T>, alias?: string): boolean;
149
152
  shouldRename(payload: any): boolean;
150
153
  renameFieldToPK<T>(qb: IQueryBuilder<T>): string;
151
154
  getPath(addIndex?: boolean): string;