@mikro-orm/knex 6.0.0-dev.6 → 6.0.0-dev.60

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 (42) hide show
  1. package/AbstractSqlConnection.d.ts +3 -0
  2. package/AbstractSqlConnection.js +16 -8
  3. package/AbstractSqlDriver.d.ts +16 -16
  4. package/AbstractSqlDriver.js +107 -44
  5. package/AbstractSqlPlatform.d.ts +2 -2
  6. package/AbstractSqlPlatform.js +14 -7
  7. package/MonkeyPatchable.d.ts +1 -0
  8. package/MonkeyPatchable.js +3 -0
  9. package/README.md +64 -107
  10. package/SqlEntityManager.d.ts +0 -4
  11. package/SqlEntityManager.js +1 -9
  12. package/SqlEntityRepository.d.ts +0 -1
  13. package/SqlEntityRepository.js +0 -1
  14. package/index.d.ts +1 -0
  15. package/index.js +1 -0
  16. package/index.mjs +176 -0
  17. package/package.json +5 -5
  18. package/query/ArrayCriteriaNode.d.ts +3 -3
  19. package/query/CriteriaNode.d.ts +8 -8
  20. package/query/CriteriaNode.js +8 -8
  21. package/query/CriteriaNodeFactory.d.ts +6 -6
  22. package/query/CriteriaNodeFactory.js +11 -11
  23. package/query/ObjectCriteriaNode.d.ts +3 -3
  24. package/query/ObjectCriteriaNode.js +12 -8
  25. package/query/QueryBuilder.d.ts +17 -4
  26. package/query/QueryBuilder.js +188 -45
  27. package/query/QueryBuilderHelper.d.ts +3 -5
  28. package/query/QueryBuilderHelper.js +85 -71
  29. package/query/ScalarCriteriaNode.d.ts +3 -2
  30. package/query/ScalarCriteriaNode.js +9 -6
  31. package/schema/DatabaseSchema.js +3 -3
  32. package/schema/DatabaseTable.d.ts +9 -9
  33. package/schema/DatabaseTable.js +21 -22
  34. package/schema/SchemaComparator.d.ts +4 -4
  35. package/schema/SchemaComparator.js +4 -2
  36. package/schema/SchemaHelper.d.ts +11 -11
  37. package/schema/SchemaHelper.js +3 -3
  38. package/schema/{SchemaGenerator.d.ts → SqlSchemaGenerator.d.ts} +3 -7
  39. package/schema/{SchemaGenerator.js → SqlSchemaGenerator.js} +17 -24
  40. package/schema/index.d.ts +1 -1
  41. package/schema/index.js +1 -1
  42. package/typings.d.ts +14 -13
@@ -19,6 +19,9 @@ class QueryBuilderHelper {
19
19
  this.metadata = this.driver.getMetadata();
20
20
  }
21
21
  mapper(field, type = enums_1.QueryType.SELECT, value, alias) {
22
+ if (core_1.Utils.isRawSql(field)) {
23
+ return this.knex.raw(field.sql, field.params);
24
+ }
22
25
  if (typeof field !== 'string') {
23
26
  return field;
24
27
  }
@@ -36,12 +39,26 @@ class QueryBuilderHelper {
36
39
  parts.push(this.mapper(a !== this.alias ? `${a}.${f}` : f, type, value, alias));
37
40
  }
38
41
  }
42
+ // flatten the value if we see we are expanding nested composite key
43
+ // hackish, but cleaner solution would require quite a lot of refactoring
44
+ if (fields.length !== parts.length && Array.isArray(value)) {
45
+ value.forEach(row => {
46
+ if (Array.isArray(row)) {
47
+ const tmp = core_1.Utils.flatten(row);
48
+ row.length = 0;
49
+ row.push(...tmp);
50
+ }
51
+ });
52
+ }
39
53
  return this.knex.raw('(' + parts.map(part => this.knex.ref(part)).join(', ') + ')');
40
54
  }
41
- let ret = field;
42
- const customExpression = QueryBuilderHelper.isCustomExpression(field, !!alias);
55
+ const rawField = core_1.RawQueryFragment.getKnownFragment(field);
56
+ if (rawField) {
57
+ return this.knex.raw(rawField.sql, rawField.params);
58
+ }
43
59
  const [a, f] = this.splitField(field);
44
60
  const prop = this.getProperty(f, a);
61
+ let ret = field;
45
62
  // embeddable nested path instead of a regular property with table alias, reset alias
46
63
  if (prop?.name === a && prop.embeddedProps[f]) {
47
64
  return this.alias + '.' + prop.fieldNames[0];
@@ -65,15 +82,12 @@ class QueryBuilderHelper {
65
82
  return this.knex.raw(`${valueSQL} as ${this.platform.quoteIdentifier(alias ?? prop.fieldNames[0])}`);
66
83
  }
67
84
  // do not wrap custom expressions
68
- if (!customExpression) {
85
+ if (!rawField) {
69
86
  ret = this.prefix(field);
70
87
  }
71
88
  if (alias) {
72
89
  ret += ' as ' + alias;
73
90
  }
74
- if (customExpression) {
75
- return this.knex.raw(ret, value);
76
- }
77
91
  if (!isTableNameAliasRequired || this.isPrefixed(ret) || noPrefix) {
78
92
  return ret;
79
93
  }
@@ -212,20 +226,14 @@ class QueryBuilderHelper {
212
226
  if (operator === '$exists') {
213
227
  value = null;
214
228
  }
215
- if (QueryBuilderHelper.isCustomExpression(key)) {
216
- // unwind parameters when ? found in field name
217
- const count = key.concat('?').match(/\?/g).length - 1;
218
- const values = core_1.Utils.asArray(value);
219
- const params1 = values.slice(0, count).map((c) => core_1.Utils.isObject(c) ? JSON.stringify(c) : c);
220
- const params2 = values.slice(count);
221
- const k = this.mapper(key, enums_1.QueryType.SELECT, params1);
222
- const { sql, bindings } = k.toSQL().toNative();
223
- if (params2.length > 0) {
224
- params.push(...bindings);
225
- params.push(...params2);
226
- return sql + ' = ?';
229
+ const rawField = core_1.RawQueryFragment.getKnownFragment(key);
230
+ if (rawField) {
231
+ let sql = rawField.sql;
232
+ params.push(...rawField.params);
233
+ params.push(...core_1.Utils.asArray(value));
234
+ if (core_1.Utils.asArray(value).length > 0) {
235
+ sql += ' = ?';
227
236
  }
228
- params.push(...bindings);
229
237
  return sql;
230
238
  }
231
239
  const sql = this.mapper(key);
@@ -241,7 +249,7 @@ class QueryBuilderHelper {
241
249
  return `(${parts.join(` ${core_1.GroupOperator[operator]} `)})`;
242
250
  }
243
251
  mapJoinColumns(type, join) {
244
- if (join.prop && join.prop.reference === core_1.ReferenceType.ONE_TO_ONE && !join.prop.owner) {
252
+ if (join.prop && join.prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !join.prop.owner) {
245
253
  return join.prop.fieldNames.map((fieldName, idx) => {
246
254
  return this.mapper(`${join.alias}.${join.inverseJoinColumns[idx]}`, type, undefined, fieldName);
247
255
  });
@@ -254,7 +262,7 @@ class QueryBuilderHelper {
254
262
  isOneToOneInverse(field) {
255
263
  const meta = this.metadata.find(this.entityName);
256
264
  const prop = meta.properties[field];
257
- return prop && prop.reference === core_1.ReferenceType.ONE_TO_ONE && !prop.owner;
265
+ return prop && prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner;
258
266
  }
259
267
  getTableName(entityName) {
260
268
  const meta = this.metadata.find(entityName);
@@ -299,7 +307,7 @@ class QueryBuilderHelper {
299
307
  let mergeParam = item.merge;
300
308
  if (core_1.Utils.isObject(item.merge)) {
301
309
  mergeParam = {};
302
- Object.keys(item.merge).forEach(key => {
310
+ core_1.Utils.keys(item.merge).forEach(key => {
303
311
  const k = this.mapper(key, type);
304
312
  mergeParam[k] = item.merge[key];
305
313
  });
@@ -336,28 +344,20 @@ class QueryBuilderHelper {
336
344
  if (core_1.Utils.isPlainObject(cond[key]) || cond[key] instanceof RegExp) {
337
345
  return this.processObjectSubCondition(cond, key, qb, method, m, type);
338
346
  }
339
- if (QueryBuilderHelper.isCustomExpression(key)) {
340
- return this.processCustomExpression(qb, m, key, cond, type);
341
- }
342
347
  const op = cond[key] === null ? 'is' : '=';
348
+ const raw = core_1.RawQueryFragment.getKnownFragment(key);
349
+ if (raw) {
350
+ const value = core_1.Utils.asArray(cond[key]);
351
+ if (value.length > 0) {
352
+ return void qb[m](this.knex.raw(raw.sql, raw.params), op, value[0]);
353
+ }
354
+ return void qb[m](this.knex.raw(raw.sql, raw.params));
355
+ }
343
356
  if (this.subQueries[key]) {
344
357
  return void qb[m](this.knex.raw(`(${this.subQueries[key]})`), op, cond[key]);
345
358
  }
346
359
  qb[m](this.mapper(key, type, cond[key], null), op, cond[key]);
347
360
  }
348
- processCustomExpression(clause, m, key, cond, type) {
349
- // unwind parameters when ? found in field name
350
- const count = key.concat('?').match(/\?/g).length - 1;
351
- const value = core_1.Utils.asArray(cond[key]);
352
- const params1 = value.slice(0, count).map((c) => core_1.Utils.isObject(c) ? JSON.stringify(c) : c);
353
- const params2 = value.slice(count);
354
- const k = this.mapper(key, type, params1);
355
- if (params2.length > 0) {
356
- const val = params2.length === 1 && params2[0] === null ? null : this.knex.raw('?', params2);
357
- return void clause[m](k, val);
358
- }
359
- clause[m](k);
360
- }
361
361
  processObjectSubCondition(cond, key, qb, method, m, type) {
362
362
  // grouped condition for one field
363
363
  let value = cond[key];
@@ -394,7 +394,8 @@ class QueryBuilderHelper {
394
394
  }));
395
395
  }
396
396
  else {
397
- qb[m](this.mapper(key, type, undefined, null), replacement, value[op]);
397
+ const mappedKey = this.mapper(key, type, value[op], null);
398
+ qb[m](mappedKey, replacement, value[op]);
398
399
  }
399
400
  }
400
401
  getOperatorReplacement(op, value) {
@@ -422,20 +423,21 @@ class QueryBuilderHelper {
422
423
  }
423
424
  getQueryOrderFromObject(type, orderBy, populate) {
424
425
  const ret = [];
425
- Object.keys(orderBy).forEach(k => {
426
- const direction = orderBy[k];
426
+ Object.keys(orderBy).forEach(key => {
427
+ const direction = orderBy[key];
427
428
  const order = core_1.Utils.isNumber(direction) ? core_1.QueryOrderNumeric[direction] : direction;
428
- if (QueryBuilderHelper.isCustomExpression(k)) {
429
- ret.push(`${k} ${order.toLowerCase()}`);
429
+ const raw = core_1.RawQueryFragment.getKnownFragment(key);
430
+ if (raw) {
431
+ ret.push(`${this.platform.formatQuery(raw.sql, raw.params)} ${order.toLowerCase()}`);
430
432
  return;
431
433
  }
432
- // eslint-disable-next-line prefer-const
433
- let [alias, field] = this.splitField(k, true);
434
- alias = populate[alias] || alias;
435
- core_1.Utils.splitPrimaryKeys(field).forEach(f => {
436
- const prop = this.getProperty(f, alias);
437
- const noPrefix = (prop && prop.persist === false && !prop.formula) || QueryBuilderHelper.isCustomExpression(f);
438
- const column = this.mapper(noPrefix ? f : `${alias}.${f}`, type, undefined, null);
434
+ core_1.Utils.splitPrimaryKeys(key).forEach(f => {
435
+ // eslint-disable-next-line prefer-const
436
+ let [alias, field] = this.splitField(f, true);
437
+ alias = populate[alias] || alias;
438
+ const prop = this.getProperty(field, alias);
439
+ const noPrefix = (prop && prop.persist === false && !prop.formula) || core_1.RawQueryFragment.isKnownFragment(f);
440
+ const column = this.mapper(noPrefix ? field : `${alias}.${field}`, type, undefined, null);
439
441
  /* istanbul ignore next */
440
442
  const rawColumn = core_1.Utils.isString(column) ? column.split('.').map(e => this.knex.ref(e)).join('.') : column;
441
443
  const customOrder = prop?.customOrder;
@@ -447,11 +449,23 @@ class QueryBuilderHelper {
447
449
  });
448
450
  return ret.join(', ');
449
451
  }
450
- finalize(type, qb, meta) {
451
- const useReturningStatement = type === enums_1.QueryType.INSERT && this.platform.usesReturningStatement() && meta && !meta.compositePK;
452
- if (useReturningStatement) {
453
- const returningProps = meta.hydrateProps.filter(prop => prop.persist !== false && (prop.primary || prop.defaultRaw));
454
- qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
452
+ finalize(type, qb, meta, data) {
453
+ if (!meta || !data || !this.platform.usesReturningStatement()) {
454
+ return;
455
+ }
456
+ if (type === enums_1.QueryType.INSERT) {
457
+ const returningProps = meta.hydrateProps
458
+ .filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw))
459
+ .filter(prop => !(prop.name in data) || core_1.Utils.isRawSql(data[prop.name]));
460
+ if (returningProps.length > 0) {
461
+ qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
462
+ }
463
+ }
464
+ if (type === enums_1.QueryType.UPDATE) {
465
+ const returningProps = meta.hydrateProps.filter(prop => core_1.Utils.isRawSql(data[prop.name]));
466
+ if (returningProps.length > 0) {
467
+ qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
468
+ }
455
469
  }
456
470
  }
457
471
  splitField(field, greedyAlias = false) {
@@ -494,20 +508,20 @@ class QueryBuilderHelper {
494
508
  }
495
509
  qb.update(versionProperty.fieldNames[0], this.knex.raw(sql));
496
510
  }
497
- static isCustomExpression(field, hasAlias = false) {
498
- // if we do not have alias, we don't consider spaces as custom expressions
499
- const re = hasAlias ? /[ ?<>=()'"`:]|^\d/ : /[?<>=()'"`:]|^\d/;
500
- return !!field.match(re);
501
- }
502
511
  prefix(field, always = false, quote = false) {
503
512
  let ret;
504
513
  if (!this.isPrefixed(field)) {
505
514
  const alias = always ? (quote ? this.alias : this.platform.quoteIdentifier(this.alias)) + '.' : '';
506
515
  const fieldName = this.fieldName(field, this.alias, always);
507
- if (QueryBuilderHelper.isCustomExpression(fieldName)) {
508
- return fieldName;
516
+ if (fieldName instanceof core_1.RawQueryFragment) {
517
+ return fieldName.sql;
518
+ }
519
+ if (this.isPrefixed(fieldName)) {
520
+ ret = fieldName;
521
+ }
522
+ else {
523
+ ret = alias + fieldName;
509
524
  }
510
- ret = alias + fieldName;
511
525
  }
512
526
  else {
513
527
  const [a, ...rest] = field.split('.');
@@ -545,15 +559,15 @@ class QueryBuilderHelper {
545
559
  }
546
560
  if (prop.fieldNameRaw) {
547
561
  if (!always) {
548
- return prop.fieldNameRaw
549
- .replace(/\[::alias::]\.?/g, '')
550
- .replace(this.platform.quoteIdentifier('') + '.', '');
562
+ return (0, core_1.raw)(prop.fieldNameRaw
563
+ .replace(new RegExp(core_1.ALIAS_REPLACEMENT_RE + '\\.?', 'g'), '')
564
+ .replace(this.platform.quoteIdentifier('') + '.', ''));
551
565
  }
552
566
  if (alias) {
553
- return prop.fieldNameRaw.replace(/\[::alias::]/g, alias);
567
+ return (0, core_1.raw)(prop.fieldNameRaw.replace(new RegExp(core_1.ALIAS_REPLACEMENT_RE, 'g'), alias));
554
568
  }
555
569
  /* istanbul ignore next */
556
- return prop.fieldNameRaw;
570
+ return (0, core_1.raw)(prop.fieldNameRaw);
557
571
  }
558
572
  /* istanbul ignore next */
559
573
  return prop.fieldNames?.[0] ?? field;
@@ -564,7 +578,7 @@ class QueryBuilderHelper {
564
578
  // check if `alias` is not matching an embedded property name instead of alias, e.g. `address.city`
565
579
  if (alias && meta) {
566
580
  const prop = meta.properties[alias];
567
- if (prop?.reference === core_1.ReferenceType.EMBEDDED) {
581
+ if (prop?.kind === core_1.ReferenceKind.EMBEDDED) {
568
582
  // we want to select the full object property so hydration works as expected
569
583
  if (prop.object) {
570
584
  return prop;
@@ -596,13 +610,13 @@ class QueryBuilderHelper {
596
610
  return;
597
611
  }
598
612
  if (prop.joinColumns && Array.isArray(data[k])) {
599
- const copy = data[k];
613
+ const copy = core_1.Utils.flatten(data[k]);
600
614
  delete data[k];
601
615
  prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
602
616
  return;
603
617
  }
604
618
  if (prop.customType && convertCustomTypes && !this.platform.isRaw(data[k])) {
605
- data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, { fromQuery: true, key: k, mode: 'query' });
619
+ data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, { fromQuery: true, key: k, mode: 'query-data' });
606
620
  }
607
621
  if (prop.customType && 'convertToDatabaseValueSQL' in prop.customType && !this.platform.isRaw(data[k])) {
608
622
  const quoted = this.platform.quoteValue(data[k]);
@@ -3,7 +3,8 @@ import type { IQueryBuilder } from '../typings';
3
3
  /**
4
4
  * @internal
5
5
  */
6
- export declare class ScalarCriteriaNode extends CriteriaNode {
7
- process<T>(qb: IQueryBuilder<T>, alias?: string): any;
6
+ export declare class ScalarCriteriaNode<T extends object> extends CriteriaNode<T> {
7
+ process(qb: IQueryBuilder<T>, alias?: string): any;
8
+ willAutoJoin<T>(qb: IQueryBuilder<T>, alias?: string): boolean;
8
9
  shouldJoin(): boolean;
9
10
  }
@@ -13,23 +13,26 @@ class ScalarCriteriaNode extends CriteriaNode_1.CriteriaNode {
13
13
  const parentPath = this.parent.getPath(); // the parent is always there, otherwise `shouldJoin` would return `false`
14
14
  const nestedAlias = qb.getAliasForJoinPath(path) || qb.getNextAlias(this.prop?.pivotTable ?? this.entityName);
15
15
  const field = `${alias}.${this.prop.name}`;
16
- const type = this.prop.reference === core_1.ReferenceType.MANY_TO_MANY ? 'pivotJoin' : 'leftJoin';
16
+ const type = this.prop.kind === core_1.ReferenceKind.MANY_TO_MANY ? 'pivotJoin' : 'leftJoin';
17
17
  qb.join(field, nestedAlias, undefined, type, path);
18
18
  // select the owner as virtual property when joining from 1:1 inverse side, but only if the parent is root entity
19
- if (this.prop.reference === core_1.ReferenceType.ONE_TO_ONE && !parentPath.includes('.')) {
19
+ if (this.prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !parentPath.includes('.')) {
20
20
  qb.addSelect(field);
21
21
  }
22
22
  }
23
23
  return this.payload;
24
24
  }
25
+ willAutoJoin(qb, alias) {
26
+ return this.shouldJoin();
27
+ }
25
28
  shouldJoin() {
26
29
  if (!this.parent || !this.prop) {
27
30
  return false;
28
31
  }
29
- switch (this.prop.reference) {
30
- case core_1.ReferenceType.ONE_TO_MANY: return true;
31
- case core_1.ReferenceType.MANY_TO_MANY: return true;
32
- case core_1.ReferenceType.ONE_TO_ONE: return !this.prop.owner;
32
+ switch (this.prop.kind) {
33
+ case core_1.ReferenceKind.ONE_TO_MANY: return true;
34
+ case core_1.ReferenceKind.MANY_TO_MANY: return true;
35
+ case core_1.ReferenceKind.ONE_TO_ONE: return !this.prop.owner;
33
36
  default: return false; // SCALAR, MANY_TO_ONE
34
37
  }
35
38
  }
@@ -78,15 +78,15 @@ class DatabaseSchema {
78
78
  if (prop.persist === false || !prop.fieldNames) {
79
79
  return false;
80
80
  }
81
- if (meta.pivotTable || (core_1.ReferenceType.EMBEDDED && prop.object)) {
81
+ if (meta.pivotTable || (core_1.ReferenceKind.EMBEDDED && prop.object)) {
82
82
  return true;
83
83
  }
84
84
  const getRootProperty = (prop) => prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop;
85
85
  const rootProp = getRootProperty(prop);
86
- if (rootProp.reference === core_1.ReferenceType.EMBEDDED) {
86
+ if (rootProp.kind === core_1.ReferenceKind.EMBEDDED) {
87
87
  return prop === rootProp || !rootProp.object;
88
88
  }
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);
89
+ 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
90
  }
91
91
  toJSON() {
92
92
  const { platform, namespaces, ...rest } = this;
@@ -1,6 +1,6 @@
1
1
  import type { Dictionary, EntityMetadata, EntityProperty, NamingStrategy } from '@mikro-orm/core';
2
2
  import type { SchemaHelper } from './SchemaHelper';
3
- import type { Check, Column, ForeignKey, Index } from '../typings';
3
+ import type { CheckDef, Column, ForeignKey, IndexDef } from '../typings';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
5
5
  /**
6
6
  * @internal
@@ -17,9 +17,9 @@ export declare class DatabaseTable {
17
17
  constructor(platform: AbstractSqlPlatform, name: string, schema?: string | undefined);
18
18
  getColumns(): Column[];
19
19
  getColumn(name: string): Column | undefined;
20
- getIndexes(): Index[];
21
- getChecks(): Check[];
22
- init(cols: Column[], indexes: Index[] | undefined, checks: Check<unknown>[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
20
+ getIndexes(): IndexDef[];
21
+ getChecks(): CheckDef[];
22
+ init(cols: Column[], indexes: IndexDef[] | undefined, checks: CheckDef<unknown>[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
23
23
  addColumn(column: Column): void;
24
24
  addColumnFromProperty(prop: EntityProperty, meta: EntityMetadata): void;
25
25
  private getIndexName;
@@ -30,14 +30,14 @@ export declare class DatabaseTable {
30
30
  getShortestName(): string;
31
31
  getForeignKeys(): Dictionary<ForeignKey>;
32
32
  hasColumn(columnName: string): boolean;
33
- getIndex(indexName: string): Index | undefined;
33
+ getIndex(indexName: string): IndexDef | undefined;
34
34
  hasIndex(indexName: string): boolean;
35
- getCheck(checkName: string): Check<unknown> | undefined;
35
+ getCheck(checkName: string): CheckDef<unknown> | undefined;
36
36
  hasCheck(checkName: string): boolean;
37
- getPrimaryKey(): Index | undefined;
37
+ getPrimaryKey(): IndexDef | undefined;
38
38
  hasPrimaryKey(): boolean;
39
39
  private getPropertyDeclaration;
40
- private getReferenceType;
40
+ private getReferenceKind;
41
41
  private getPropertyName;
42
42
  private getPropertyType;
43
43
  private getPropertyDefaultValue;
@@ -48,6 +48,6 @@ export declare class DatabaseTable {
48
48
  expression?: string;
49
49
  options?: Dictionary;
50
50
  }, type: 'index' | 'unique' | 'primary'): void;
51
- addCheck(check: Check): void;
51
+ addCheck(check: CheckDef): void;
52
52
  toJSON(): Dictionary;
53
53
  }
@@ -51,7 +51,6 @@ class DatabaseTable {
51
51
  }
52
52
  addColumnFromProperty(prop, meta) {
53
53
  prop.fieldNames.forEach((field, idx) => {
54
- var _a;
55
54
  const type = prop.enum ? 'enum' : prop.columnTypes[idx];
56
55
  const mappedType = this.platform.getMappedType(type);
57
56
  if (mappedType instanceof core_1.DecimalType) {
@@ -64,9 +63,9 @@ class DatabaseTable {
64
63
  }
65
64
  }
66
65
  if (mappedType instanceof core_1.DateTimeType) {
67
- prop.length ?? (prop.length = this.platform.getDefaultDateTimeLength());
66
+ prop.length ??= this.platform.getDefaultDateTimeLength();
68
67
  }
69
- const primary = !meta.compositePK && !!prop.primary && prop.reference === core_1.ReferenceType.SCALAR && this.platform.isNumericColumn(mappedType);
68
+ const primary = !meta.compositePK && !!prop.primary && prop.kind === core_1.ReferenceKind.SCALAR && this.platform.isNumericColumn(mappedType);
70
69
  this.columns[field] = {
71
70
  name: prop.fieldNames[idx],
72
71
  type: prop.columnTypes[idx],
@@ -84,11 +83,11 @@ class DatabaseTable {
84
83
  extra: prop.extra,
85
84
  ignoreSchemaChanges: prop.ignoreSchemaChanges,
86
85
  };
87
- (_a = this.columns[field]).unsigned || (_a.unsigned = this.columns[field].autoincrement);
86
+ this.columns[field].unsigned ||= this.columns[field].autoincrement;
88
87
  const defaultValue = this.platform.getSchemaHelper().normalizeDefaultValue(prop.defaultRaw, prop.length);
89
88
  this.columns[field].default = defaultValue;
90
89
  });
91
- if ([core_1.ReferenceType.MANY_TO_ONE, core_1.ReferenceType.ONE_TO_ONE].includes(prop.reference)) {
90
+ if ([core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
92
91
  const constraintName = this.getIndexName(true, prop.fieldNames, 'foreign');
93
92
  let schema = prop.targetMeta.schema === '*' ? this.schema : prop.targetMeta.schema ?? this.schema;
94
93
  if (prop.referencedTableName.includes('.')) {
@@ -102,11 +101,11 @@ class DatabaseTable {
102
101
  referencedTableName: schema ? `${schema}.${prop.referencedTableName}` : prop.referencedTableName,
103
102
  };
104
103
  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');
104
+ if (prop.deleteRule || cascade || prop.nullable) {
105
+ this.foreignKeys[constraintName].deleteRule = prop.deleteRule || (cascade ? 'cascade' : 'set null');
107
106
  }
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';
107
+ if (prop.updateRule || prop.cascade.includes(core_1.Cascade.PERSIST) || prop.cascade.includes(core_1.Cascade.ALL)) {
108
+ this.foreignKeys[constraintName].updateRule = prop.updateRule || 'cascade';
110
109
  }
111
110
  }
112
111
  if (prop.index) {
@@ -164,8 +163,8 @@ class DatabaseTable {
164
163
  }
165
164
  const meta = schema.init().meta;
166
165
  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);
166
+ .filter(prop => prop.primary && prop.kind === core_1.ReferenceKind.MANY_TO_ONE && !meta.compositePK)
167
+ .forEach(prop => prop.kind = core_1.ReferenceKind.ONE_TO_ONE);
169
168
  return meta;
170
169
  }
171
170
  /**
@@ -206,20 +205,20 @@ class DatabaseTable {
206
205
  const prop = this.getPropertyName(namingStrategy, column);
207
206
  const index = compositeFkIndexes[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && !idx.unique && !idx.primary);
208
207
  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);
208
+ const kind = this.getReferenceKind(fk, unique);
210
209
  const type = this.getPropertyType(namingStrategy, column, fk);
211
210
  const fkOptions = {};
212
211
  if (fk) {
213
212
  fkOptions.fieldNames = fk.columnNames;
214
213
  fkOptions.referencedTableName = fk.referencedTableName;
215
214
  fkOptions.referencedColumnNames = fk.referencedColumnNames;
216
- fkOptions.onUpdateIntegrity = fk.updateRule?.toLowerCase();
217
- fkOptions.onDelete = fk.deleteRule?.toLowerCase();
215
+ fkOptions.updateRule = fk.updateRule?.toLowerCase();
216
+ fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
218
217
  }
219
218
  return {
220
219
  name: prop,
221
220
  type,
222
- reference,
221
+ kind,
223
222
  columnType: column.type,
224
223
  default: this.getPropertyDefaultValue(schemaHelper, column, type),
225
224
  defaultRaw: this.getPropertyDefaultValue(schemaHelper, column, type, true),
@@ -234,14 +233,14 @@ class DatabaseTable {
234
233
  ...fkOptions,
235
234
  };
236
235
  }
237
- getReferenceType(fk, unique) {
236
+ getReferenceKind(fk, unique) {
238
237
  if (fk && unique) {
239
- return core_1.ReferenceType.ONE_TO_ONE;
238
+ return core_1.ReferenceKind.ONE_TO_ONE;
240
239
  }
241
240
  if (fk) {
242
- return core_1.ReferenceType.MANY_TO_ONE;
241
+ return core_1.ReferenceKind.MANY_TO_ONE;
243
242
  }
244
- return core_1.ReferenceType.SCALAR;
243
+ return core_1.ReferenceKind.SCALAR;
245
244
  }
246
245
  getPropertyName(namingStrategy, column) {
247
246
  const fk = Object.values(this.foreignKeys).find(fk => fk.columnNames.includes(column.name));
@@ -288,7 +287,7 @@ class DatabaseTable {
288
287
  return '' + val;
289
288
  }
290
289
  addIndex(meta, index, type) {
291
- const properties = core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames));
290
+ const properties = core_1.Utils.unique(core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames)));
292
291
  if (properties.length === 0 && !index.expression) {
293
292
  return;
294
293
  }
@@ -308,10 +307,10 @@ class DatabaseTable {
308
307
  }
309
308
  toJSON() {
310
309
  const { platform, columns, ...rest } = this;
311
- const columnsMapped = Object.keys(columns).reduce((o, col) => {
310
+ const columnsMapped = core_1.Utils.keys(columns).reduce((o, col) => {
312
311
  const { mappedType, ...restCol } = columns[col];
313
312
  o[col] = restCol;
314
- o[col].mappedType = Object.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
313
+ o[col].mappedType = core_1.Utils.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
315
314
  return o;
316
315
  }, {});
317
316
  return { columns: columnsMapped, ...rest };
@@ -1,4 +1,4 @@
1
- import type { Check, Column, ForeignKey, Index, SchemaDifference, TableDifference } from '../typings';
1
+ import type { CheckDef, 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';
@@ -45,12 +45,12 @@ export declare class SchemaComparator {
45
45
  * Finds the difference between the indexes index1 and index2.
46
46
  * Compares index1 with index2 and returns index2 if there are any differences or false in case there are no differences.
47
47
  */
48
- diffIndex(index1: Index, index2: Index): boolean;
48
+ diffIndex(index1: IndexDef, index2: IndexDef): boolean;
49
49
  /**
50
50
  * Checks if the other index already fulfills all the indexing and constraint needs of the current one.
51
51
  */
52
- isIndexFulfilledBy(index1: Index, index2: Index): boolean;
53
- diffCheck(check1: Check, check2: Check): boolean;
52
+ isIndexFulfilledBy(index1: IndexDef, index2: IndexDef): boolean;
53
+ diffCheck(check1: CheckDef, check2: CheckDef): boolean;
54
54
  hasSameDefaultValue(from: Column, to: Column): boolean;
55
55
  private mapColumnToProperty;
56
56
  private log;
@@ -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(')) {
@@ -2,7 +2,7 @@ import type { Knex } from 'knex';
2
2
  import type { Connection, Dictionary } from '@mikro-orm/core';
3
3
  import type { AbstractSqlConnection } from '../AbstractSqlConnection';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
5
- import type { Check, Column, Index, Table, TableDifference } from '../typings';
5
+ import type { CheckDef, Column, IndexDef, Table, TableDifference } from '../typings';
6
6
  import type { DatabaseTable } from './DatabaseTable';
7
7
  import type { DatabaseSchema } from './DatabaseSchema';
8
8
  export declare abstract class SchemaHelper {
@@ -14,28 +14,28 @@ export declare abstract class SchemaHelper {
14
14
  getSchemaEnd(): string;
15
15
  finalizeTable(table: Knex.TableBuilder, charset: string, collate?: string): void;
16
16
  supportsSchemaConstraints(): boolean;
17
- getPrimaryKeys(connection: AbstractSqlConnection, indexes: Index[] | undefined, tableName: string, schemaName?: string): Promise<string[]>;
17
+ getPrimaryKeys(connection: AbstractSqlConnection, indexes: IndexDef[] | undefined, tableName: string, schemaName?: string): Promise<string[]>;
18
18
  getForeignKeys(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Dictionary>;
19
19
  protected getTableKey(t: Table): string;
20
- getEnumDefinitions(connection: AbstractSqlConnection, checks: Check[], tableName: string, schemaName?: string): Promise<Dictionary<string[]>>;
20
+ getEnumDefinitions(connection: AbstractSqlConnection, checks: CheckDef[], tableName: string, schemaName?: string): Promise<Dictionary<string[]>>;
21
21
  loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[]): Promise<void>;
22
22
  getListTablesSQL(schemaName?: string): string;
23
23
  getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column, schemaName?: string): string;
24
- getCreateIndexSQL(tableName: string, index: Index): string;
25
- getDropIndexSQL(tableName: string, index: Index): string;
26
- getRenameIndexSQL(tableName: string, index: Index, oldIndexName: string): string;
24
+ getCreateIndexSQL(tableName: string, index: IndexDef): string;
25
+ getDropIndexSQL(tableName: string, index: IndexDef): string;
26
+ getRenameIndexSQL(tableName: string, index: IndexDef, oldIndexName: string): string;
27
27
  hasNonDefaultPrimaryKeyName(table: DatabaseTable): boolean;
28
28
  createTableColumn(table: Knex.TableBuilder, column: Column, fromTable: DatabaseTable, changedProperties?: Set<string>): Knex.ColumnBuilder;
29
29
  configureColumn(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
30
30
  configureColumnDefault(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
31
31
  getPreAlterTable(tableDiff: TableDifference, safe: boolean): string;
32
- getAlterColumnAutoincrement(tableName: string, column: Column): string;
33
- getChangeColumnCommentSQL(tableName: string, to: Column): string;
32
+ getAlterColumnAutoincrement(tableName: string, column: Column, schemaName?: string): string;
33
+ getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
34
34
  getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
35
35
  getColumns(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Column[]>;
36
- getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Index[]>;
37
- getChecks(connection: AbstractSqlConnection, tableName: string, schemaName?: string, columns?: Column[]): Promise<Check[]>;
38
- protected mapIndexes(indexes: Index[]): Promise<Index[]>;
36
+ getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<IndexDef[]>;
37
+ getChecks(connection: AbstractSqlConnection, tableName: string, schemaName?: string, columns?: Column[]): Promise<CheckDef[]>;
38
+ protected mapIndexes(indexes: IndexDef[]): Promise<IndexDef[]>;
39
39
  getForeignKeysSQL(tableName: string, schemaName?: string): string;
40
40
  mapForeignKeys(fks: any[], tableName: string, schemaName?: string): Dictionary;
41
41
  normalizeDefaultValue(defaultValue: string, length?: number, defaultValues?: Dictionary<string[]>): string | number;
@@ -122,17 +122,17 @@ class SchemaHelper {
122
122
  core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), guard('default'));
123
123
  }
124
124
  else {
125
- core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), column.default !== undefined);
125
+ core_1.Utils.runIfNotEmpty(() => col.defaultTo(knex.raw(column.default)), column.default != null && column.default !== 'null');
126
126
  }
127
127
  return col;
128
128
  }
129
129
  getPreAlterTable(tableDiff, safe) {
130
130
  return '';
131
131
  }
132
- getAlterColumnAutoincrement(tableName, column) {
132
+ getAlterColumnAutoincrement(tableName, column, schemaName) {
133
133
  return '';
134
134
  }
135
- getChangeColumnCommentSQL(tableName, to) {
135
+ getChangeColumnCommentSQL(tableName, to, schemaName) {
136
136
  return '';
137
137
  }
138
138
  async getNamespaces(connection) {