@mikro-orm/knex 6.0.0-dev.122 → 6.0.0-dev.123

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.
@@ -333,7 +333,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
333
333
  }
334
334
  if (meta && this.platform.usesReturningStatement()) {
335
335
  const returningProps = meta.props
336
- .filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw || prop.autoincrement))
336
+ .filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
337
337
  .filter(prop => !(prop.name in data[0]) || core_1.Utils.isRawSql(data[0][prop.name]));
338
338
  const returningFields = core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames));
339
339
  /* istanbul ignore next */
@@ -386,6 +386,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
386
386
  }
387
387
  else {
388
388
  qb.update(data).where(where);
389
+ // reload generated columns
390
+ const returning = [];
391
+ meta?.props
392
+ .filter(prop => prop.generated && !prop.primary)
393
+ .forEach(prop => returning.push(prop.name));
394
+ qb.returning(returning);
389
395
  }
390
396
  res = await this.rethrow(qb.execute('run', false));
391
397
  }
@@ -425,6 +431,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
425
431
  }
426
432
  });
427
433
  });
434
+ // reload generated columns
435
+ meta?.props
436
+ .filter(prop => prop.generated && !prop.primary)
437
+ .forEach(prop => returning.add(prop.name));
428
438
  const pkCond = core_1.Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
429
439
  const params = [];
430
440
  let sql = `update ${this.getTableName(meta, options)} set `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.0.0-dev.122",
3
+ "version": "6.0.0-dev.123",
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": "^5.9.0"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.0.0-dev.122"
69
+ "@mikro-orm/core": "6.0.0-dev.123"
70
70
  }
71
71
  }
@@ -83,6 +83,7 @@ class DatabaseTable {
83
83
  this.columns[field] = {
84
84
  name: prop.fieldNames[idx],
85
85
  type: prop.columnTypes[idx],
86
+ generated: prop.generated,
86
87
  mappedType,
87
88
  unsigned: prop.unsigned && this.platform.isNumericColumn(mappedType),
88
89
  autoincrement: prop.autoincrement ?? primary,
@@ -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;
@@ -142,6 +142,12 @@ class SchemaComparator {
142
142
  if (changedProperties.size === 0) {
143
143
  continue;
144
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
+ }
145
151
  tableDifferences.changedColumns[column.name] = {
146
152
  oldColumnName: column.name,
147
153
  fromColumn: column,
@@ -203,7 +209,7 @@ class SchemaComparator {
203
209
  }
204
210
  // See if index has changed in "to" table
205
211
  const toTableCheck = toTable.getCheck(check.name);
206
- if (!this.diffCheck(check, toTableCheck)) {
212
+ if (!this.diffExpression(check.expression, toTableCheck.expression)) {
207
213
  continue;
208
214
  }
209
215
  this.log(`check constraint ${check.name} changed in table ${tableDifferences.name}`, { fromTableCheck: check, toTableCheck });
@@ -327,12 +333,12 @@ class SchemaComparator {
327
333
  * Returns the difference between the columns
328
334
  * If there are differences this method returns field2, otherwise the boolean false.
329
335
  */
330
- diffColumn(column1, column2, tableName) {
336
+ diffColumn(fromColumn, toColumn, tableName) {
331
337
  const changedProperties = new Set();
332
- const prop1 = this.mapColumnToProperty({ ...column1, autoincrement: false });
333
- const prop2 = this.mapColumnToProperty({ ...column2, autoincrement: false });
334
- const columnType1 = column1.mappedType.getColumnType(prop1, this.platform).toLowerCase();
335
- 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();
336
342
  const log = (msg, params) => {
337
343
  if (tableName) {
338
344
  const copy = core_1.Utils.copy(params);
@@ -340,42 +346,46 @@ class SchemaComparator {
340
346
  this.log(msg, copy);
341
347
  }
342
348
  };
343
- if (columnType1 !== columnType2 &&
344
- !(column1.ignoreSchemaChanges?.includes('type') ||
345
- column2.ignoreSchemaChanges?.includes('type'))) {
346
- 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 });
347
353
  changedProperties.add('type');
348
354
  }
349
- if (column1.nullable !== column2.nullable) {
350
- 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 });
351
357
  changedProperties.add('nullable');
352
358
  }
353
- if (!!column1.autoincrement !== !!column2.autoincrement) {
354
- 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 });
355
365
  changedProperties.add('autoincrement');
356
366
  }
357
- if (column1.unsigned !== column2.unsigned && this.platform.supportsUnsigned()) {
358
- 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 });
359
369
  changedProperties.add('unsigned');
360
370
  }
361
- if (!this.hasSameDefaultValue(column1, column2)) {
362
- 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 });
363
373
  changedProperties.add('default');
364
374
  }
365
- if (this.diffComment(column1.comment, column2.comment)) {
366
- 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 });
367
377
  changedProperties.add('comment');
368
378
  }
369
- if (!(column1.mappedType instanceof core_1.ArrayType) &&
370
- !(column2.mappedType instanceof core_1.ArrayType) &&
371
- this.diffEnumItems(column1.enumItems, column2.enumItems)) {
372
- 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 });
373
383
  changedProperties.add('enumItems');
374
384
  }
375
- if ((column1.extra || '').toLowerCase() !== (column2.extra || '').toLowerCase() &&
376
- !(column1.ignoreSchemaChanges?.includes('extra') ||
377
- column2.ignoreSchemaChanges?.includes('extra'))) {
378
- 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 });
379
389
  changedProperties.add('extra');
380
390
  }
381
391
  return changedProperties;
@@ -429,11 +439,11 @@ class SchemaComparator {
429
439
  }
430
440
  return index1.primary === index2.primary && index1.unique === index2.unique;
431
441
  }
432
- diffCheck(check1, check2) {
433
- // check constraint definition might be normalized by the driver,
442
+ diffExpression(expr1, expr2) {
443
+ // expressions like check constraints might be normalized by the driver,
434
444
  // e.g. quotes might be added (https://github.com/mikro-orm/mikro-orm/issues/3827)
435
- const simplify = (str) => str?.replace(/['"`()]/g, '').toLowerCase();
436
- 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);
437
447
  }
438
448
  hasSameDefaultValue(from, to) {
439
449
  if (from.default == null || from.default.toString().toLowerCase() === 'null' || from.default.toString().startsWith('nextval(')) {
@@ -102,7 +102,7 @@ class SchemaHelper {
102
102
  }
103
103
  createTableColumn(table, column, fromTable, changedProperties) {
104
104
  const compositePK = fromTable.getPrimaryKey()?.composite;
105
- if (column.autoincrement && !compositePK && (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
105
+ if (column.autoincrement && !column.generated && !compositePK && (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
106
106
  const primaryKey = !changedProperties && !this.hasNonDefaultPrimaryKeyName(fromTable);
107
107
  if (column.mappedType instanceof core_1.BigIntType) {
108
108
  return table.bigIncrements(column.name, { primaryKey });
@@ -112,12 +112,16 @@ class SchemaHelper {
112
112
  if (column.mappedType instanceof core_1.EnumType && column.enumItems?.every(item => core_1.Utils.isString(item))) {
113
113
  return table.enum(column.name, column.enumItems);
114
114
  }
115
- return table.specificType(column.name, column.type);
115
+ let columnType = column.type;
116
+ if (column.generated) {
117
+ columnType += ` generated always as ${column.generated}`;
118
+ }
119
+ return table.specificType(column.name, columnType);
116
120
  }
117
121
  configureColumn(column, col, knex, changedProperties) {
118
122
  const guard = (key) => !changedProperties || changedProperties.has(key);
119
123
  core_1.Utils.runIfNotEmpty(() => col.nullable(), column.nullable && guard('nullable'));
120
- core_1.Utils.runIfNotEmpty(() => col.notNullable(), !column.nullable);
124
+ core_1.Utils.runIfNotEmpty(() => col.notNullable(), !column.nullable && !column.generated);
121
125
  core_1.Utils.runIfNotEmpty(() => col.unsigned(), column.unsigned);
122
126
  core_1.Utils.runIfNotEmpty(() => col.comment(column.comment), column.comment);
123
127
  this.configureColumnDefault(column, col, knex, changedProperties);
@@ -282,6 +282,14 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
282
282
  for (const check of Object.values(diff.changedChecks)) {
283
283
  this.dropCheck(table, check);
284
284
  }
285
+ /* istanbul ignore else */
286
+ if (!safe) {
287
+ for (const column of Object.values(diff.removedColumns)) {
288
+ this.helper.pushTableQuery(table, `alter table ${this.platform.quoteIdentifier(tableName)} drop column ${this.platform.quoteIdentifier(column.name)}`);
289
+ }
290
+ }
291
+ }));
292
+ ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
285
293
  for (const column of Object.values(diff.addedColumns)) {
286
294
  const col = this.helper.createTableColumn(table, column, diff.fromTable);
287
295
  this.helper.configureColumn(column, col, this.knex);
@@ -295,12 +303,6 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
295
303
  .onDelete(foreignKey.deleteRule);
296
304
  }
297
305
  }
298
- /* istanbul ignore else */
299
- if (!safe) {
300
- for (const column of Object.values(diff.removedColumns)) {
301
- table.dropColumn(column.name);
302
- }
303
- }
304
306
  for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
305
307
  if (changedProperties.size === 1 && changedProperties.has('comment')) {
306
308
  continue;
package/typings.d.ts CHANGED
@@ -40,6 +40,7 @@ export interface Column {
40
40
  scale?: number;
41
41
  default?: string | null;
42
42
  comment?: string;
43
+ generated?: string;
43
44
  nativeEnumName?: string;
44
45
  enumItems?: string[];
45
46
  primary?: boolean;