@mikro-orm/knex 6.0.0-dev.8 → 6.0.0-dev.80

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 (38) hide show
  1. package/AbstractSqlConnection.d.ts +5 -2
  2. package/AbstractSqlConnection.js +25 -17
  3. package/AbstractSqlDriver.d.ts +18 -18
  4. package/AbstractSqlDriver.js +117 -48
  5. package/AbstractSqlPlatform.d.ts +1 -0
  6. package/AbstractSqlPlatform.js +20 -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 +19 -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 +25 -7
  24. package/query/QueryBuilder.js +237 -61
  25. package/query/QueryBuilderHelper.d.ts +3 -5
  26. package/query/QueryBuilderHelper.js +96 -74
  27. package/query/ScalarCriteriaNode.d.ts +3 -2
  28. package/query/ScalarCriteriaNode.js +9 -6
  29. package/schema/DatabaseSchema.d.ts +4 -1
  30. package/schema/DatabaseSchema.js +22 -6
  31. package/schema/DatabaseTable.d.ts +2 -1
  32. package/schema/DatabaseTable.js +25 -24
  33. package/schema/SchemaComparator.js +9 -2
  34. package/schema/SchemaHelper.d.ts +5 -3
  35. package/schema/SchemaHelper.js +10 -4
  36. package/schema/SqlSchemaGenerator.d.ts +3 -5
  37. package/schema/SqlSchemaGenerator.js +41 -20
  38. package/typings.d.ts +8 -5
@@ -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
@@ -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;