@mikro-orm/knex 6.0.0-dev.5 → 6.0.0-dev.50
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.
- package/AbstractSqlConnection.d.ts +3 -0
- package/AbstractSqlConnection.js +16 -8
- package/AbstractSqlDriver.d.ts +11 -11
- package/AbstractSqlDriver.js +100 -40
- package/AbstractSqlPlatform.d.ts +2 -4
- package/AbstractSqlPlatform.js +6 -16
- package/README.md +63 -106
- package/SqlEntityManager.d.ts +0 -4
- package/SqlEntityManager.js +1 -9
- package/SqlEntityRepository.d.ts +0 -1
- package/SqlEntityRepository.js +0 -1
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.mjs +173 -0
- package/package.json +5 -39
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +8 -8
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +11 -11
- package/query/ObjectCriteriaNode.d.ts +3 -3
- package/query/ObjectCriteriaNode.js +5 -5
- package/query/QueryBuilder.d.ts +11 -4
- package/query/QueryBuilder.js +141 -36
- package/query/QueryBuilderHelper.d.ts +3 -3
- package/query/QueryBuilderHelper.js +47 -19
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/schema/DatabaseSchema.js +3 -3
- package/schema/DatabaseTable.d.ts +9 -9
- package/schema/DatabaseTable.js +21 -22
- package/schema/SchemaComparator.d.ts +4 -4
- package/schema/SchemaComparator.js +4 -2
- package/schema/SchemaHelper.d.ts +11 -11
- package/schema/SchemaHelper.js +3 -3
- package/schema/{SchemaGenerator.d.ts → SqlSchemaGenerator.d.ts} +4 -8
- package/schema/{SchemaGenerator.js → SqlSchemaGenerator.js} +17 -24
- package/schema/index.d.ts +1 -1
- package/schema/index.js +1 -1
- 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.platform.formatQuery(field.sql, field.params ?? []);
|
|
24
|
+
}
|
|
22
25
|
if (typeof field !== 'string') {
|
|
23
26
|
return field;
|
|
24
27
|
}
|
|
@@ -36,6 +39,17 @@ 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
55
|
let ret = field;
|
|
@@ -72,7 +86,8 @@ class QueryBuilderHelper {
|
|
|
72
86
|
ret += ' as ' + alias;
|
|
73
87
|
}
|
|
74
88
|
if (customExpression) {
|
|
75
|
-
|
|
89
|
+
const bindings = core_1.Utils.asArray(value).slice(0, ret.match(/\?/g)?.length ?? 0);
|
|
90
|
+
return this.knex.raw(ret, bindings);
|
|
76
91
|
}
|
|
77
92
|
if (!isTableNameAliasRequired || this.isPrefixed(ret) || noPrefix) {
|
|
78
93
|
return ret;
|
|
@@ -241,7 +256,7 @@ class QueryBuilderHelper {
|
|
|
241
256
|
return `(${parts.join(` ${core_1.GroupOperator[operator]} `)})`;
|
|
242
257
|
}
|
|
243
258
|
mapJoinColumns(type, join) {
|
|
244
|
-
if (join.prop && join.prop.
|
|
259
|
+
if (join.prop && join.prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !join.prop.owner) {
|
|
245
260
|
return join.prop.fieldNames.map((fieldName, idx) => {
|
|
246
261
|
return this.mapper(`${join.alias}.${join.inverseJoinColumns[idx]}`, type, undefined, fieldName);
|
|
247
262
|
});
|
|
@@ -254,7 +269,7 @@ class QueryBuilderHelper {
|
|
|
254
269
|
isOneToOneInverse(field) {
|
|
255
270
|
const meta = this.metadata.find(this.entityName);
|
|
256
271
|
const prop = meta.properties[field];
|
|
257
|
-
return prop && prop.
|
|
272
|
+
return prop && prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner;
|
|
258
273
|
}
|
|
259
274
|
getTableName(entityName) {
|
|
260
275
|
const meta = this.metadata.find(entityName);
|
|
@@ -299,7 +314,7 @@ class QueryBuilderHelper {
|
|
|
299
314
|
let mergeParam = item.merge;
|
|
300
315
|
if (core_1.Utils.isObject(item.merge)) {
|
|
301
316
|
mergeParam = {};
|
|
302
|
-
|
|
317
|
+
core_1.Utils.keys(item.merge).forEach(key => {
|
|
303
318
|
const k = this.mapper(key, type);
|
|
304
319
|
mergeParam[k] = item.merge[key];
|
|
305
320
|
});
|
|
@@ -394,7 +409,8 @@ class QueryBuilderHelper {
|
|
|
394
409
|
}));
|
|
395
410
|
}
|
|
396
411
|
else {
|
|
397
|
-
|
|
412
|
+
const mappedKey = this.mapper(key, type, value[op], null);
|
|
413
|
+
qb[m](mappedKey, replacement, value[op]);
|
|
398
414
|
}
|
|
399
415
|
}
|
|
400
416
|
getOperatorReplacement(op, value) {
|
|
@@ -429,13 +445,13 @@ class QueryBuilderHelper {
|
|
|
429
445
|
ret.push(`${k} ${order.toLowerCase()}`);
|
|
430
446
|
return;
|
|
431
447
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const prop = this.getProperty(
|
|
448
|
+
core_1.Utils.splitPrimaryKeys(k).forEach(f => {
|
|
449
|
+
// eslint-disable-next-line prefer-const
|
|
450
|
+
let [alias, field] = this.splitField(f, true);
|
|
451
|
+
alias = populate[alias] || alias;
|
|
452
|
+
const prop = this.getProperty(field, alias);
|
|
437
453
|
const noPrefix = (prop && prop.persist === false && !prop.formula) || QueryBuilderHelper.isCustomExpression(f);
|
|
438
|
-
const column = this.mapper(noPrefix ?
|
|
454
|
+
const column = this.mapper(noPrefix ? field : `${alias}.${field}`, type, undefined, null);
|
|
439
455
|
/* istanbul ignore next */
|
|
440
456
|
const rawColumn = core_1.Utils.isString(column) ? column.split('.').map(e => this.knex.ref(e)).join('.') : column;
|
|
441
457
|
const customOrder = prop?.customOrder;
|
|
@@ -447,11 +463,23 @@ class QueryBuilderHelper {
|
|
|
447
463
|
});
|
|
448
464
|
return ret.join(', ');
|
|
449
465
|
}
|
|
450
|
-
finalize(type, qb, meta) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
466
|
+
finalize(type, qb, meta, data) {
|
|
467
|
+
if (!meta || !data || !this.platform.usesReturningStatement()) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
if (type === enums_1.QueryType.INSERT) {
|
|
471
|
+
const returningProps = meta.hydrateProps
|
|
472
|
+
.filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw))
|
|
473
|
+
.filter(prop => !(prop.name in data) || core_1.Utils.isRawSql(data[prop.name]));
|
|
474
|
+
if (returningProps.length > 0) {
|
|
475
|
+
qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (type === enums_1.QueryType.UPDATE) {
|
|
479
|
+
const returningProps = meta.hydrateProps.filter(prop => core_1.Utils.isRawSql(data[prop.name]));
|
|
480
|
+
if (returningProps.length > 0) {
|
|
481
|
+
qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
|
|
482
|
+
}
|
|
455
483
|
}
|
|
456
484
|
}
|
|
457
485
|
splitField(field, greedyAlias = false) {
|
|
@@ -564,7 +592,7 @@ class QueryBuilderHelper {
|
|
|
564
592
|
// check if `alias` is not matching an embedded property name instead of alias, e.g. `address.city`
|
|
565
593
|
if (alias && meta) {
|
|
566
594
|
const prop = meta.properties[alias];
|
|
567
|
-
if (prop?.
|
|
595
|
+
if (prop?.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
568
596
|
// we want to select the full object property so hydration works as expected
|
|
569
597
|
if (prop.object) {
|
|
570
598
|
return prop;
|
|
@@ -596,13 +624,13 @@ class QueryBuilderHelper {
|
|
|
596
624
|
return;
|
|
597
625
|
}
|
|
598
626
|
if (prop.joinColumns && Array.isArray(data[k])) {
|
|
599
|
-
const copy = data[k];
|
|
627
|
+
const copy = core_1.Utils.flatten(data[k]);
|
|
600
628
|
delete data[k];
|
|
601
629
|
prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
|
|
602
630
|
return;
|
|
603
631
|
}
|
|
604
632
|
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' });
|
|
633
|
+
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, { fromQuery: true, key: k, mode: 'query-data' });
|
|
606
634
|
}
|
|
607
635
|
if (prop.customType && 'convertToDatabaseValueSQL' in prop.customType && !this.platform.isRaw(data[k])) {
|
|
608
636
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
30
|
-
case core_1.
|
|
31
|
-
case core_1.
|
|
32
|
-
case core_1.
|
|
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
|
}
|
package/schema/DatabaseSchema.js
CHANGED
|
@@ -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.
|
|
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.
|
|
86
|
+
if (rootProp.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
87
87
|
return prop === rootProp || !rootProp.object;
|
|
88
88
|
}
|
|
89
|
-
return [core_1.
|
|
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 {
|
|
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():
|
|
21
|
-
getChecks():
|
|
22
|
-
init(cols: Column[], indexes:
|
|
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):
|
|
33
|
+
getIndex(indexName: string): IndexDef | undefined;
|
|
34
34
|
hasIndex(indexName: string): boolean;
|
|
35
|
-
getCheck(checkName: string):
|
|
35
|
+
getCheck(checkName: string): CheckDef<unknown> | undefined;
|
|
36
36
|
hasCheck(checkName: string): boolean;
|
|
37
|
-
getPrimaryKey():
|
|
37
|
+
getPrimaryKey(): IndexDef | undefined;
|
|
38
38
|
hasPrimaryKey(): boolean;
|
|
39
39
|
private getPropertyDeclaration;
|
|
40
|
-
private
|
|
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:
|
|
51
|
+
addCheck(check: CheckDef): void;
|
|
52
52
|
toJSON(): Dictionary;
|
|
53
53
|
}
|
package/schema/DatabaseTable.js
CHANGED
|
@@ -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
|
|
66
|
+
prop.length ??= this.platform.getDefaultDateTimeLength();
|
|
68
67
|
}
|
|
69
|
-
const primary = !meta.compositePK && !!prop.primary && prop.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
106
|
-
this.foreignKeys[constraintName].deleteRule = prop.
|
|
104
|
+
if (prop.deleteRule || cascade || prop.nullable) {
|
|
105
|
+
this.foreignKeys[constraintName].deleteRule = prop.deleteRule || (cascade ? 'cascade' : 'set null');
|
|
107
106
|
}
|
|
108
|
-
if (prop.
|
|
109
|
-
this.foreignKeys[constraintName].updateRule = prop.
|
|
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.
|
|
168
|
-
.forEach(prop => prop.
|
|
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
|
|
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.
|
|
217
|
-
fkOptions.
|
|
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
|
-
|
|
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
|
-
|
|
236
|
+
getReferenceKind(fk, unique) {
|
|
238
237
|
if (fk && unique) {
|
|
239
|
-
return core_1.
|
|
238
|
+
return core_1.ReferenceKind.ONE_TO_ONE;
|
|
240
239
|
}
|
|
241
240
|
if (fk) {
|
|
242
|
-
return core_1.
|
|
241
|
+
return core_1.ReferenceKind.MANY_TO_ONE;
|
|
243
242
|
}
|
|
244
|
-
return core_1.
|
|
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 =
|
|
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 =
|
|
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 {
|
|
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:
|
|
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:
|
|
53
|
-
diffCheck(check1:
|
|
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
|
-
|
|
429
|
-
|
|
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(')) {
|
package/schema/SchemaHelper.d.ts
CHANGED
|
@@ -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 {
|
|
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:
|
|
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:
|
|
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:
|
|
25
|
-
getDropIndexSQL(tableName: string, index:
|
|
26
|
-
getRenameIndexSQL(tableName: string, index:
|
|
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<
|
|
37
|
-
getChecks(connection: AbstractSqlConnection, tableName: string, schemaName?: string, columns?: Column[]): Promise<
|
|
38
|
-
protected mapIndexes(indexes:
|
|
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;
|
package/schema/SchemaHelper.js
CHANGED
|
@@ -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(
|
|
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) {
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
import type { MikroORM } from '@mikro-orm/core';
|
|
1
|
+
import type { MikroORM, ISchemaGenerator } 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';
|
|
5
5
|
import type { AbstractSqlDriver } from '../AbstractSqlDriver';
|
|
6
|
-
|
|
7
|
-
* Should be renamed to `SqlSchemaGenerator` in v6
|
|
8
|
-
*/
|
|
9
|
-
export declare class SchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDriver> {
|
|
6
|
+
export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDriver> implements ISchemaGenerator {
|
|
10
7
|
private readonly helper;
|
|
11
8
|
private readonly options;
|
|
12
9
|
protected lastEnsuredDatabase?: string;
|
|
13
10
|
static register(orm: MikroORM): void;
|
|
14
|
-
/** @deprecated use `dropSchema` and `createSchema` commands respectively */
|
|
15
|
-
generate(): Promise<string>;
|
|
16
11
|
createSchema(options?: {
|
|
17
12
|
wrap?: boolean;
|
|
18
13
|
schema?: string;
|
|
@@ -88,7 +83,7 @@ export declare class SchemaGenerator extends AbstractSchemaGenerator<AbstractSql
|
|
|
88
83
|
dropDatabase(name: string): Promise<void>;
|
|
89
84
|
execute(sql: string, options?: {
|
|
90
85
|
wrap?: boolean;
|
|
91
|
-
}): Promise<
|
|
86
|
+
}): Promise<void>;
|
|
92
87
|
private wrapSchema;
|
|
93
88
|
private createSchemaBuilder;
|
|
94
89
|
private createTable;
|
|
@@ -101,3 +96,4 @@ export declare class SchemaGenerator extends AbstractSchemaGenerator<AbstractSql
|
|
|
101
96
|
private dump;
|
|
102
97
|
private get knex();
|
|
103
98
|
}
|
|
99
|
+
export { SqlSchemaGenerator as SchemaGenerator };
|
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SchemaGenerator = void 0;
|
|
3
|
+
exports.SchemaGenerator = exports.SqlSchemaGenerator = void 0;
|
|
4
4
|
const core_1 = require("@mikro-orm/core");
|
|
5
5
|
const DatabaseSchema_1 = require("./DatabaseSchema");
|
|
6
6
|
const SchemaComparator_1 = require("./SchemaComparator");
|
|
7
|
-
|
|
8
|
-
* Should be renamed to `SqlSchemaGenerator` in v6
|
|
9
|
-
*/
|
|
10
|
-
class SchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
7
|
+
class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
11
8
|
constructor() {
|
|
12
9
|
super(...arguments);
|
|
13
10
|
this.helper = this.platform.getSchemaHelper();
|
|
14
11
|
this.options = this.config.get('schemaGenerator');
|
|
15
12
|
}
|
|
16
13
|
static register(orm) {
|
|
17
|
-
orm.config.registerExtension('@mikro-orm/schema-generator', new
|
|
18
|
-
}
|
|
19
|
-
/** @deprecated use `dropSchema` and `createSchema` commands respectively */
|
|
20
|
-
async generate() {
|
|
21
|
-
const [dropSchema, createSchema] = await Promise.all([
|
|
22
|
-
this.getDropSchemaSQL({ wrap: false }),
|
|
23
|
-
this.getCreateSchemaSQL({ wrap: false }),
|
|
24
|
-
]);
|
|
25
|
-
return this.wrapSchema(dropSchema + createSchema);
|
|
14
|
+
orm.config.registerExtension('@mikro-orm/schema-generator', () => new SqlSchemaGenerator(orm.em));
|
|
26
15
|
}
|
|
27
16
|
async createSchema(options) {
|
|
28
17
|
await this.ensureDatabase();
|
|
@@ -143,7 +132,9 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
143
132
|
return this.diffToSQL(diffUp, options);
|
|
144
133
|
}
|
|
145
134
|
async getUpdateSchemaMigrationSQL(options = {}) {
|
|
146
|
-
|
|
135
|
+
if (!options.fromSchema) {
|
|
136
|
+
await this.ensureDatabase();
|
|
137
|
+
}
|
|
147
138
|
const { fromSchema, toSchema } = await this.prepareSchemaForComparison(options);
|
|
148
139
|
const comparator = new SchemaComparator_1.SchemaComparator(this.platform);
|
|
149
140
|
const diffUp = comparator.compare(fromSchema, toSchema);
|
|
@@ -154,9 +145,9 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
154
145
|
};
|
|
155
146
|
}
|
|
156
147
|
async prepareSchemaForComparison(options) {
|
|
157
|
-
options.wrap
|
|
158
|
-
options.safe
|
|
159
|
-
options.dropTables
|
|
148
|
+
options.wrap ??= this.options.disableForeignKeys;
|
|
149
|
+
options.safe ??= false;
|
|
150
|
+
options.dropTables ??= true;
|
|
160
151
|
const toSchema = this.getTargetSchema(options.schema);
|
|
161
152
|
const fromSchema = options.fromSchema ?? await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema);
|
|
162
153
|
const wildcardSchemaTables = Object.values(this.metadata.getAll()).filter(meta => meta.schema === '*').map(meta => meta.tableName);
|
|
@@ -305,13 +296,13 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
305
296
|
this.helper.configureColumn(column, col, this.knex, changedProperties);
|
|
306
297
|
}
|
|
307
298
|
for (const { column } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
|
|
308
|
-
this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column));
|
|
299
|
+
this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column, schemaName));
|
|
309
300
|
}
|
|
310
301
|
for (const { column, changedProperties } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('comment'))) {
|
|
311
302
|
if (['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems'].some(t => changedProperties.has(t))) {
|
|
312
303
|
continue; // will be handled via knex
|
|
313
304
|
}
|
|
314
|
-
this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column));
|
|
305
|
+
this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column, schemaName));
|
|
315
306
|
}
|
|
316
307
|
for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
|
|
317
308
|
this.helper.pushTableQuery(table, this.helper.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
|
|
@@ -364,19 +355,20 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
364
355
|
await this.driver.execute(this.helper.getDropDatabaseSQL('' + this.knex.ref(name)));
|
|
365
356
|
}
|
|
366
357
|
async execute(sql, options = {}) {
|
|
367
|
-
options.wrap
|
|
358
|
+
options.wrap ??= false;
|
|
368
359
|
const lines = this.wrapSchema(sql, options).split('\n').filter(i => i.trim());
|
|
369
360
|
if (lines.length === 0) {
|
|
370
361
|
return;
|
|
371
362
|
}
|
|
372
363
|
if (this.platform.supportsMultipleStatements()) {
|
|
373
364
|
const query = lines.join('\n');
|
|
374
|
-
|
|
365
|
+
await this.driver.execute(query);
|
|
366
|
+
return;
|
|
375
367
|
}
|
|
376
368
|
await core_1.Utils.runSerial(lines, line => this.driver.execute(line));
|
|
377
369
|
}
|
|
378
370
|
wrapSchema(sql, options = {}) {
|
|
379
|
-
options.wrap
|
|
371
|
+
options.wrap ??= this.options.disableForeignKeys;
|
|
380
372
|
if (!options.wrap || sql.trim() === '') {
|
|
381
373
|
return sql;
|
|
382
374
|
}
|
|
@@ -487,4 +479,5 @@ class SchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
487
479
|
return this.connection.getKnex();
|
|
488
480
|
}
|
|
489
481
|
}
|
|
490
|
-
exports.
|
|
482
|
+
exports.SqlSchemaGenerator = SqlSchemaGenerator;
|
|
483
|
+
exports.SchemaGenerator = SqlSchemaGenerator;
|
package/schema/index.d.ts
CHANGED