@mikro-orm/knex 6.1.13-dev.2 → 6.1.13-dev.20

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.
@@ -125,7 +125,13 @@ class AbstractSqlConnection extends core_1.Connection {
125
125
  */
126
126
  async loadFile(path) {
127
127
  const buf = await (0, fs_extra_1.readFile)(path);
128
- await this.getKnex().raw(buf.toString());
128
+ try {
129
+ await this.getKnex().raw(buf.toString());
130
+ }
131
+ catch (e) {
132
+ /* istanbul ignore next */
133
+ throw this.platform.getExceptionConverter().convertException(e);
134
+ }
129
135
  }
130
136
  createKnexClient(type) {
131
137
  const driverOptions = this.config.get('driverOptions');
@@ -943,9 +943,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
943
943
  }
944
944
  if (tableAlias) {
945
945
  return prop.fieldNames.map(fieldName => {
946
- const name = this.platform.quoteIdentifier(`${tableAlias}.${fieldName}`);
947
- const alias = this.platform.quoteIdentifier(`${tableAlias}__${fieldName}`);
948
- return (0, core_1.raw)(`${name} as ${alias}`);
946
+ return `${tableAlias}.${fieldName} as ${tableAlias}__${fieldName}`;
949
947
  });
950
948
  }
951
949
  return prop.fieldNames;
@@ -963,10 +961,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
963
961
  if (args.ctx) {
964
962
  return 'write';
965
963
  }
966
- else if (args.connectionType) {
964
+ if (args.connectionType) {
967
965
  return args.connectionType;
968
966
  }
969
- else if (this.config.get('preferReadReplicas') === true) {
967
+ if (this.config.get('preferReadReplicas')) {
970
968
  return 'read';
971
969
  }
972
970
  return 'write';
package/index.mjs CHANGED
@@ -56,6 +56,7 @@ export const DateType = mod.DateType;
56
56
  export const DeadlockException = mod.DeadlockException;
57
57
  export const DecimalType = mod.DecimalType;
58
58
  export const DefaultLogger = mod.DefaultLogger;
59
+ export const DeferMode = mod.DeferMode;
59
60
  export const DoubleType = mod.DoubleType;
60
61
  export const DriverException = mod.DriverException;
61
62
  export const EagerProps = mod.EagerProps;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.1.13-dev.2",
3
+ "version": "6.1.13-dev.20",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -66,6 +66,6 @@
66
66
  "@mikro-orm/core": "^6.1.12"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.1.13-dev.2"
69
+ "@mikro-orm/core": "6.1.13-dev.20"
70
70
  }
71
71
  }
@@ -598,14 +598,14 @@ class QueryBuilder {
598
598
  if (!this.connectionType && method !== 'run' && [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type ?? enums_1.QueryType.SELECT)) {
599
599
  this.connectionType = 'write';
600
600
  }
601
+ if (!this.finalized && method === 'get' && this.type === enums_1.QueryType.SELECT) {
602
+ this.limit(1);
603
+ }
601
604
  const query = this.toQuery()._sql;
602
605
  const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.bindings, method]);
603
606
  if (cached?.data) {
604
607
  return cached.data;
605
608
  }
606
- if (!this.finalized && method === 'get') {
607
- this.limit(1);
608
- }
609
609
  const write = method === 'run' || !this.platform.getConfig().get('preferReadReplicas');
610
610
  const type = this.connectionType || (write ? 'write' : 'read');
611
611
  const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context, this.loggerContext);
@@ -652,8 +652,8 @@ class QueryBuilder {
652
652
  (0, core_1.helper)(entity).__serializationContext.populate ??= hint;
653
653
  hint.forEach(hint => {
654
654
  const [propName] = hint.field.split(':', 2);
655
- const value = entity[propName];
656
- if (core_1.Utils.isEntity(value, true)) {
655
+ const value = core_1.Reference.unwrapReference(entity[propName]);
656
+ if (core_1.Utils.isEntity(value)) {
657
657
  (0, core_1.helper)(value).populated();
658
658
  propagatePopulateHint(value, hint.children ?? []);
659
659
  }
@@ -954,15 +954,19 @@ class QueryBuilder {
954
954
  /* istanbul ignore next */
955
955
  const requiresSQLConversion = meta?.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false) ?? [];
956
956
  if (this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
957
- requiresSQLConversion.forEach(p => ret.push(this.helper.mapper(p.name, this.type)));
957
+ for (const p of requiresSQLConversion) {
958
+ ret.push(this.helper.mapper(p.name, this.type));
959
+ }
958
960
  }
959
- Object.keys(this._populateMap).forEach(f => {
960
- if (!fields.includes(f.replace(/#\w+$/, '')) && type === 'where') {
961
+ for (const f of Object.keys(this._populateMap)) {
962
+ if (type === 'where') {
961
963
  const cols = this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[f]);
962
- ret.push(...cols);
964
+ for (const col of cols) {
965
+ ret.push(col);
966
+ }
963
967
  }
964
- });
965
- return ret;
968
+ }
969
+ return core_1.Utils.unique(ret);
966
970
  }
967
971
  init(type, data, cond) {
968
972
  this.ensureNotFinalized();
@@ -1204,8 +1208,7 @@ class QueryBuilder {
1204
1208
  // not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
1205
1209
  return field.sql.includes(prop);
1206
1210
  }
1207
- // not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
1208
- return field.toString().includes(prop);
1211
+ return false;
1209
1212
  });
1210
1213
  if (field instanceof core_1.RawQueryFragment) {
1211
1214
  knexQuery.select(this.platform.formatQuery(field.sql, field.params));
@@ -123,6 +123,9 @@ class DatabaseTable {
123
123
  if (prop.updateRule || prop.cascade.includes(core_1.Cascade.PERSIST) || prop.cascade.includes(core_1.Cascade.ALL)) {
124
124
  this.foreignKeys[constraintName].updateRule = prop.updateRule || 'cascade';
125
125
  }
126
+ if (prop.deferMode) {
127
+ this.foreignKeys[constraintName].deferMode = prop.deferMode;
128
+ }
126
129
  }
127
130
  if (prop.index) {
128
131
  this.indexes.push({
@@ -473,6 +476,7 @@ class DatabaseTable {
473
476
  fkOptions.referencedColumnNames = fk.referencedColumnNames;
474
477
  fkOptions.updateRule = fk.updateRule?.toLowerCase();
475
478
  fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
479
+ fkOptions.deferMode = fk.deferMode;
476
480
  fkOptions.columnTypes = fk.columnNames.map(c => this.getColumn(c).type);
477
481
  const columnOptions = {};
478
482
  if (fk.columnNames.length === 1) {
@@ -520,6 +524,7 @@ class DatabaseTable {
520
524
  fkOptions.referencedColumnNames = fk.referencedColumnNames;
521
525
  fkOptions.updateRule = fk.updateRule?.toLowerCase();
522
526
  fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
527
+ fkOptions.deferMode = fk.deferMode;
523
528
  }
524
529
  return {
525
530
  name: prop,
@@ -273,12 +273,19 @@ class SchemaComparator {
273
273
  */
274
274
  detectColumnRenamings(tableDifferences, inverseTableDiff) {
275
275
  const renameCandidates = {};
276
+ const oldFKs = Object.values(tableDifferences.fromTable.getForeignKeys());
277
+ const newFKs = Object.values(tableDifferences.toTable.getForeignKeys());
276
278
  for (const addedColumn of Object.values(tableDifferences.addedColumns)) {
277
279
  for (const removedColumn of Object.values(tableDifferences.removedColumns)) {
278
280
  const diff = this.diffColumn(addedColumn, removedColumn);
279
281
  if (diff.size !== 0) {
280
282
  continue;
281
283
  }
284
+ const wasFK = oldFKs.some(fk => fk.columnNames.includes(removedColumn.name));
285
+ const isFK = newFKs.some(fk => fk.columnNames.includes(addedColumn.name));
286
+ if (wasFK !== isFK) {
287
+ continue;
288
+ }
282
289
  const renamedColumn = inverseTableDiff?.renamedColumns[addedColumn.name];
283
290
  if (renamedColumn && renamedColumn?.name !== removedColumn.name) {
284
291
  continue;
@@ -348,6 +355,9 @@ class SchemaComparator {
348
355
  if (key1.referencedTableName !== key2.referencedTableName) {
349
356
  return true;
350
357
  }
358
+ if (key1.deferMode !== key2.deferMode) {
359
+ return true;
360
+ }
351
361
  const defaultRule = ['restrict', 'no action'];
352
362
  const rule = (key, method) => {
353
363
  return (key[method] ?? defaultRule[0]).toLowerCase().replace(defaultRule[1], defaultRule[0]);
@@ -27,8 +27,9 @@ export declare abstract class SchemaHelper {
27
27
  getCreateIndexSQL(tableName: string, index: IndexDef, partialExpression?: boolean): string;
28
28
  getDropIndexSQL(tableName: string, index: IndexDef): string;
29
29
  getRenameIndexSQL(tableName: string, index: IndexDef, oldIndexName: string): string;
30
+ getDropColumnsSQL(tableName: string, columns: Column[], schemaName?: string): string;
30
31
  hasNonDefaultPrimaryKeyName(table: DatabaseTable): boolean;
31
- createTableColumn(table: Knex.TableBuilder, column: Column, fromTable: DatabaseTable, changedProperties?: Set<string>, alter?: boolean): Knex.ColumnBuilder;
32
+ createTableColumn(table: Knex.TableBuilder, column: Column, fromTable: DatabaseTable, changedProperties?: Set<string>, alter?: boolean): Knex.ColumnBuilder | undefined;
32
33
  configureColumn(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
33
34
  configureColumnDefault(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
34
35
  getPreAlterTable(tableDiff: TableDifference, safe: boolean): string;
@@ -99,6 +99,11 @@ class SchemaHelper {
99
99
  getRenameIndexSQL(tableName, index, oldIndexName) {
100
100
  return [this.getDropIndexSQL(tableName, { ...index, keyName: oldIndexName }), this.getCreateIndexSQL(tableName, index)].join(';\n');
101
101
  }
102
+ getDropColumnsSQL(tableName, columns, schemaName) {
103
+ const name = this.platform.quoteIdentifier((schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName);
104
+ const drops = columns.map(column => `drop column ${this.platform.quoteIdentifier(column.name)}`).join(', ');
105
+ return `alter table ${name} ${drops}`;
106
+ }
102
107
  hasNonDefaultPrimaryKeyName(table) {
103
108
  const pkIndex = table.getPrimaryKey();
104
109
  if (!pkIndex || !this.platform.supportsCustomPrimaryKeyNames()) {
@@ -199,6 +204,7 @@ class SchemaHelper {
199
204
  referencedColumnNames: [fk.referenced_column_name],
200
205
  updateRule: fk.update_rule.toLowerCase(),
201
206
  deleteRule: fk.delete_rule.toLowerCase(),
207
+ deferMode: fk.defer_mode,
202
208
  };
203
209
  }
204
210
  return ret;
@@ -220,10 +226,11 @@ class SchemaHelper {
220
226
  return norm[0].replace('(?)', length != null ? `(${length})` : '');
221
227
  }
222
228
  getCreateDatabaseSQL(name) {
223
- return `create database ${name}`;
229
+ // two line breaks to force separate execution
230
+ return `create database ${name};\n\nuse ${name}`;
224
231
  }
225
232
  getDropDatabaseSQL(name) {
226
- return `drop database if exists ${name}`;
233
+ return `drop database if exists ${this.platform.quoteIdentifier(name)}`;
227
234
  }
228
235
  getDatabaseExistsSQL(name) {
229
236
  return `select 1 from information_schema.schemata where schema_name = '${name}'`;
@@ -1,4 +1,4 @@
1
- import { AbstractSchemaGenerator, type MikroORM, type ISchemaGenerator, type ClearDatabaseOptions, type CreateSchemaOptions, type EnsureDatabaseOptions, type DropSchemaOptions, type UpdateSchemaOptions } from '@mikro-orm/core';
1
+ import { AbstractSchemaGenerator, type ClearDatabaseOptions, type CreateSchemaOptions, type DropSchemaOptions, type EnsureDatabaseOptions, type ISchemaGenerator, type MikroORM, type Transaction, type UpdateSchemaOptions } from '@mikro-orm/core';
2
2
  import type { SchemaDifference } from '../typings';
3
3
  import { DatabaseSchema } from './DatabaseSchema';
4
4
  import type { AbstractSqlDriver } from '../AbstractSqlDriver';
@@ -43,10 +43,11 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
43
43
  /**
44
44
  * creates new database and connects to it
45
45
  */
46
- createDatabase(name: string): Promise<void>;
46
+ createDatabase(name?: string): Promise<void>;
47
47
  dropDatabase(name?: string): Promise<void>;
48
48
  execute(sql: string, options?: {
49
49
  wrap?: boolean;
50
+ ctx?: Transaction;
50
51
  }): Promise<void>;
51
52
  private wrapSchema;
52
53
  private createSchemaBuilder;
@@ -118,7 +118,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
118
118
  // remove FKs explicitly if we can't use cascading statement and we don't disable FK checks (we need this for circular relations)
119
119
  for (const meta of metadata) {
120
120
  const table = schema.getTable(meta.tableName);
121
- if (!this.platform.usesCascadeStatement() && table && !wrap) {
121
+ if (!this.platform.usesCascadeStatement() && table && (!wrap || options.dropForeignKeys)) {
122
122
  for (const fk of Object.values(table.getForeignKeys())) {
123
123
  const builder = this.createSchemaBuilder(table.schema).alterTable(table.name, tbl => {
124
124
  tbl.dropForeign(fk.columnNames, fk.constraintName);
@@ -272,6 +272,9 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
272
272
  if (foreignKey.deleteRule) {
273
273
  builder.onDelete(foreignKey.deleteRule);
274
274
  }
275
+ if (foreignKey.deferMode) {
276
+ builder.deferrable(foreignKey.deferMode);
277
+ }
275
278
  }
276
279
  /**
277
280
  * We need to drop foreign keys first for all tables to allow dropping PK constraints.
@@ -338,10 +341,8 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
338
341
  this.dropCheck(table, check);
339
342
  }
340
343
  /* istanbul ignore else */
341
- if (!safe) {
342
- for (const column of Object.values(diff.removedColumns)) {
343
- this.helper.pushTableQuery(table, `alter table ${this.platform.quoteIdentifier(tableName)} drop column ${this.platform.quoteIdentifier(column.name)}`);
344
- }
344
+ if (!safe && Object.values(diff.removedColumns).length > 0) {
345
+ this.helper.pushTableQuery(table, this.helper.getDropColumnsSQL(tableName, Object.values(diff.removedColumns), schemaName));
345
346
  }
346
347
  }));
347
348
  ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
@@ -365,8 +366,10 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
365
366
  if (changedProperties.size === 1 && changedProperties.has('enumItems') && column.nativeEnumName) {
366
367
  continue;
367
368
  }
368
- const col = this.helper.createTableColumn(table, column, diff.fromTable, changedProperties, true).alter();
369
- this.helper.configureColumn(column, col, this.knex, changedProperties);
369
+ const col = this.helper.createTableColumn(table, column, diff.fromTable, changedProperties, true)?.alter();
370
+ if (col) {
371
+ this.helper.configureColumn(column, col, this.knex, changedProperties);
372
+ }
370
373
  }
371
374
  for (const { column } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
372
375
  this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column, schemaName));
@@ -418,9 +421,10 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
418
421
  * creates new database and connects to it
419
422
  */
420
423
  async createDatabase(name) {
424
+ name ??= this.config.get('dbName');
421
425
  const sql = this.helper.getCreateDatabaseSQL('' + this.knex.ref(name));
422
426
  if (sql) {
423
- await this.driver.execute(sql);
427
+ await this.execute(sql);
424
428
  }
425
429
  this.config.set('dbName', name);
426
430
  await this.driver.reconnect();
@@ -429,20 +433,34 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
429
433
  name ??= this.config.get('dbName');
430
434
  this.config.set('dbName', this.helper.getManagementDbName());
431
435
  await this.driver.reconnect();
432
- await this.driver.execute(this.helper.getDropDatabaseSQL('' + this.knex.ref(name)));
436
+ await this.execute(this.helper.getDropDatabaseSQL(name));
433
437
  }
434
438
  async execute(sql, options = {}) {
435
439
  options.wrap ??= false;
436
- const lines = this.wrapSchema(sql, options).split('\n').filter(i => i.trim());
437
- if (lines.length === 0) {
440
+ const lines = this.wrapSchema(sql, options).split('\n');
441
+ const groups = [];
442
+ let i = 0;
443
+ for (const line of lines) {
444
+ if (line.trim() === '') {
445
+ if (groups[i]?.length > 0) {
446
+ i++;
447
+ }
448
+ continue;
449
+ }
450
+ groups[i] ??= [];
451
+ groups[i].push(line.trim());
452
+ }
453
+ if (groups.length === 0) {
438
454
  return;
439
455
  }
440
456
  if (this.platform.supportsMultipleStatements()) {
441
- const query = lines.join('\n');
442
- await this.driver.execute(query);
457
+ for (const group of groups) {
458
+ const query = group.join('\n');
459
+ await this.driver.execute(query);
460
+ }
443
461
  return;
444
462
  }
445
- await core_1.Utils.runSerial(lines, line => this.driver.execute(line));
463
+ await core_1.Utils.runSerial(groups.flat(), line => this.driver.execute(line));
446
464
  }
447
465
  wrapSchema(sql, options) {
448
466
  options.wrap ??= this.options.disableForeignKeys;
package/typings.d.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import type { DeferMode, CheckCallback, Dictionary, EntityProperty, GroupOperator, RawQueryFragment, QBFilterQuery, QueryOrderMap, Type, QueryFlag, AnyEntity, EntityName } from '@mikro-orm/core';
1
2
  import type { Knex } from 'knex';
2
- import type { CheckCallback, Dictionary, EntityProperty, GroupOperator, RawQueryFragment, QBFilterQuery, QueryOrderMap, Type, QueryFlag, AnyEntity, EntityName } from '@mikro-orm/core';
3
3
  import type { JoinType, QueryType } from './query/enums';
4
4
  import type { DatabaseSchema, DatabaseTable } from './schema';
5
5
  export interface Table {
@@ -57,6 +57,7 @@ export interface ForeignKey {
57
57
  referencedColumnNames: string[];
58
58
  updateRule?: string;
59
59
  deleteRule?: string;
60
+ deferMode?: DeferMode;
60
61
  }
61
62
  export interface IndexDef {
62
63
  columnNames: string[];