@mikro-orm/knex 6.0.0-dev.9 → 6.0.0-dev.90
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 +5 -2
- package/AbstractSqlConnection.js +25 -17
- package/AbstractSqlDriver.d.ts +19 -18
- package/AbstractSqlDriver.js +171 -70
- package/AbstractSqlPlatform.d.ts +1 -0
- package/AbstractSqlPlatform.js +26 -5
- package/MonkeyPatchable.d.ts +1 -0
- package/MonkeyPatchable.js +3 -0
- package/README.md +64 -107
- package/SqlEntityManager.d.ts +2 -5
- package/SqlEntityManager.js +5 -9
- package/SqlEntityRepository.d.ts +6 -4
- package/SqlEntityRepository.js +10 -8
- package/index.mjs +20 -6
- package/package.json +7 -7
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +9 -9
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +10 -13
- package/query/ObjectCriteriaNode.d.ts +3 -3
- package/query/ObjectCriteriaNode.js +12 -8
- package/query/QueryBuilder.d.ts +27 -16
- package/query/QueryBuilder.js +250 -91
- package/query/QueryBuilderHelper.d.ts +6 -9
- package/query/QueryBuilderHelper.js +112 -96
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/query/enums.js +1 -1
- package/schema/DatabaseSchema.d.ts +4 -1
- package/schema/DatabaseSchema.js +22 -6
- package/schema/DatabaseTable.d.ts +2 -1
- package/schema/DatabaseTable.js +25 -24
- package/schema/SchemaComparator.js +9 -2
- package/schema/SchemaHelper.d.ts +5 -3
- package/schema/SchemaHelper.js +10 -4
- package/schema/SqlSchemaGenerator.d.ts +3 -5
- package/schema/SqlSchemaGenerator.js +41 -20
- package/typings.d.ts +10 -7
package/schema/DatabaseTable.js
CHANGED
|
@@ -14,6 +14,7 @@ class DatabaseTable {
|
|
|
14
14
|
this.indexes = [];
|
|
15
15
|
this.checks = [];
|
|
16
16
|
this.foreignKeys = {};
|
|
17
|
+
this.nativeEnums = {}; // for postgres
|
|
17
18
|
Object.defineProperties(this, {
|
|
18
19
|
platform: { enumerable: false, writable: true },
|
|
19
20
|
});
|
|
@@ -41,7 +42,7 @@ class DatabaseTable {
|
|
|
41
42
|
const type = v.name in enums ? 'enum' : v.type;
|
|
42
43
|
v.mappedType = this.platform.getMappedType(type);
|
|
43
44
|
v.default = v.default?.toString().startsWith('nextval(') ? null : v.default;
|
|
44
|
-
v.enumItems
|
|
45
|
+
v.enumItems ??= enums[v.name] || [];
|
|
45
46
|
o[v.name] = v;
|
|
46
47
|
return o;
|
|
47
48
|
}, {});
|
|
@@ -51,7 +52,6 @@ class DatabaseTable {
|
|
|
51
52
|
}
|
|
52
53
|
addColumnFromProperty(prop, meta) {
|
|
53
54
|
prop.fieldNames.forEach((field, idx) => {
|
|
54
|
-
var _a;
|
|
55
55
|
const type = prop.enum ? 'enum' : prop.columnTypes[idx];
|
|
56
56
|
const mappedType = this.platform.getMappedType(type);
|
|
57
57
|
if (mappedType instanceof core_1.DecimalType) {
|
|
@@ -64,9 +64,9 @@ class DatabaseTable {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
if (mappedType instanceof core_1.DateTimeType) {
|
|
67
|
-
prop.length
|
|
67
|
+
prop.length ??= this.platform.getDefaultDateTimeLength();
|
|
68
68
|
}
|
|
69
|
-
const primary = !meta.compositePK && !!prop.primary && prop.
|
|
69
|
+
const primary = !meta.compositePK && !!prop.primary && prop.kind === core_1.ReferenceKind.SCALAR && this.platform.isNumericColumn(mappedType);
|
|
70
70
|
this.columns[field] = {
|
|
71
71
|
name: prop.fieldNames[idx],
|
|
72
72
|
type: prop.columnTypes[idx],
|
|
@@ -74,21 +74,22 @@ class DatabaseTable {
|
|
|
74
74
|
unsigned: prop.unsigned && this.platform.isNumericColumn(mappedType),
|
|
75
75
|
autoincrement: prop.autoincrement ?? primary,
|
|
76
76
|
primary,
|
|
77
|
+
nativeEnumName: prop.nativeEnumName,
|
|
77
78
|
nullable: !!prop.nullable,
|
|
78
79
|
length: prop.length,
|
|
79
80
|
precision: prop.precision,
|
|
80
81
|
scale: prop.scale,
|
|
81
82
|
default: prop.defaultRaw,
|
|
82
|
-
enumItems: prop.items?.every(core_1.Utils.isString) ? prop.items : undefined,
|
|
83
|
+
enumItems: prop.nativeEnumName || prop.items?.every(core_1.Utils.isString) ? prop.items : undefined,
|
|
83
84
|
comment: prop.comment,
|
|
84
85
|
extra: prop.extra,
|
|
85
86
|
ignoreSchemaChanges: prop.ignoreSchemaChanges,
|
|
86
87
|
};
|
|
87
|
-
|
|
88
|
+
this.columns[field].unsigned ||= this.columns[field].autoincrement;
|
|
88
89
|
const defaultValue = this.platform.getSchemaHelper().normalizeDefaultValue(prop.defaultRaw, prop.length);
|
|
89
90
|
this.columns[field].default = defaultValue;
|
|
90
91
|
});
|
|
91
|
-
if ([core_1.
|
|
92
|
+
if ([core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
92
93
|
const constraintName = this.getIndexName(true, prop.fieldNames, 'foreign');
|
|
93
94
|
let schema = prop.targetMeta.schema === '*' ? this.schema : prop.targetMeta.schema ?? this.schema;
|
|
94
95
|
if (prop.referencedTableName.includes('.')) {
|
|
@@ -102,11 +103,11 @@ class DatabaseTable {
|
|
|
102
103
|
referencedTableName: schema ? `${schema}.${prop.referencedTableName}` : prop.referencedTableName,
|
|
103
104
|
};
|
|
104
105
|
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.
|
|
106
|
+
if (prop.deleteRule || cascade || prop.nullable) {
|
|
107
|
+
this.foreignKeys[constraintName].deleteRule = prop.deleteRule || (cascade ? 'cascade' : 'set null');
|
|
107
108
|
}
|
|
108
|
-
if (prop.
|
|
109
|
-
this.foreignKeys[constraintName].updateRule = prop.
|
|
109
|
+
if (prop.updateRule || prop.cascade.includes(core_1.Cascade.PERSIST) || prop.cascade.includes(core_1.Cascade.ALL)) {
|
|
110
|
+
this.foreignKeys[constraintName].updateRule = prop.updateRule || 'cascade';
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
if (prop.index) {
|
|
@@ -164,8 +165,8 @@ class DatabaseTable {
|
|
|
164
165
|
}
|
|
165
166
|
const meta = schema.init().meta;
|
|
166
167
|
meta.relations
|
|
167
|
-
.filter(prop => prop.primary && prop.
|
|
168
|
-
.forEach(prop => prop.
|
|
168
|
+
.filter(prop => prop.primary && prop.kind === core_1.ReferenceKind.MANY_TO_ONE && !meta.compositePK)
|
|
169
|
+
.forEach(prop => prop.kind = core_1.ReferenceKind.ONE_TO_ONE);
|
|
169
170
|
return meta;
|
|
170
171
|
}
|
|
171
172
|
/**
|
|
@@ -206,20 +207,20 @@ class DatabaseTable {
|
|
|
206
207
|
const prop = this.getPropertyName(namingStrategy, column);
|
|
207
208
|
const index = compositeFkIndexes[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && !idx.unique && !idx.primary);
|
|
208
209
|
const unique = compositeFkUniques[prop] || this.indexes.find(idx => idx.columnNames[0] === column.name && !idx.composite && idx.unique && !idx.primary);
|
|
209
|
-
const
|
|
210
|
+
const kind = this.getReferenceKind(fk, unique);
|
|
210
211
|
const type = this.getPropertyType(namingStrategy, column, fk);
|
|
211
212
|
const fkOptions = {};
|
|
212
213
|
if (fk) {
|
|
213
214
|
fkOptions.fieldNames = fk.columnNames;
|
|
214
215
|
fkOptions.referencedTableName = fk.referencedTableName;
|
|
215
216
|
fkOptions.referencedColumnNames = fk.referencedColumnNames;
|
|
216
|
-
fkOptions.
|
|
217
|
-
fkOptions.
|
|
217
|
+
fkOptions.updateRule = fk.updateRule?.toLowerCase();
|
|
218
|
+
fkOptions.deleteRule = fk.deleteRule?.toLowerCase();
|
|
218
219
|
}
|
|
219
220
|
return {
|
|
220
221
|
name: prop,
|
|
221
222
|
type,
|
|
222
|
-
|
|
223
|
+
kind,
|
|
223
224
|
columnType: column.type,
|
|
224
225
|
default: this.getPropertyDefaultValue(schemaHelper, column, type),
|
|
225
226
|
defaultRaw: this.getPropertyDefaultValue(schemaHelper, column, type, true),
|
|
@@ -234,14 +235,14 @@ class DatabaseTable {
|
|
|
234
235
|
...fkOptions,
|
|
235
236
|
};
|
|
236
237
|
}
|
|
237
|
-
|
|
238
|
+
getReferenceKind(fk, unique) {
|
|
238
239
|
if (fk && unique) {
|
|
239
|
-
return core_1.
|
|
240
|
+
return core_1.ReferenceKind.ONE_TO_ONE;
|
|
240
241
|
}
|
|
241
242
|
if (fk) {
|
|
242
|
-
return core_1.
|
|
243
|
+
return core_1.ReferenceKind.MANY_TO_ONE;
|
|
243
244
|
}
|
|
244
|
-
return core_1.
|
|
245
|
+
return core_1.ReferenceKind.SCALAR;
|
|
245
246
|
}
|
|
246
247
|
getPropertyName(namingStrategy, column) {
|
|
247
248
|
const fk = Object.values(this.foreignKeys).find(fk => fk.columnNames.includes(column.name));
|
|
@@ -288,7 +289,7 @@ class DatabaseTable {
|
|
|
288
289
|
return '' + val;
|
|
289
290
|
}
|
|
290
291
|
addIndex(meta, index, type) {
|
|
291
|
-
const properties = core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames));
|
|
292
|
+
const properties = core_1.Utils.unique(core_1.Utils.flatten(core_1.Utils.asArray(index.properties).map(prop => meta.properties[prop].fieldNames)));
|
|
292
293
|
if (properties.length === 0 && !index.expression) {
|
|
293
294
|
return;
|
|
294
295
|
}
|
|
@@ -308,10 +309,10 @@ class DatabaseTable {
|
|
|
308
309
|
}
|
|
309
310
|
toJSON() {
|
|
310
311
|
const { platform, columns, ...rest } = this;
|
|
311
|
-
const columnsMapped =
|
|
312
|
+
const columnsMapped = core_1.Utils.keys(columns).reduce((o, col) => {
|
|
312
313
|
const { mappedType, ...restCol } = columns[col];
|
|
313
314
|
o[col] = restCol;
|
|
314
|
-
o[col].mappedType =
|
|
315
|
+
o[col].mappedType = core_1.Utils.keys(core_1.t).find(k => core_1.t[k] === mappedType.constructor);
|
|
315
316
|
return o;
|
|
316
317
|
}, {});
|
|
317
318
|
return { columns: columnsMapped, ...rest };
|
|
@@ -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(')) {
|
|
@@ -437,6 +439,11 @@ class SchemaComparator {
|
|
|
437
439
|
const defaultValueTo = !['0', 'false', 'f', 'n', 'no', 'off'].includes('' + to.default);
|
|
438
440
|
return defaultValueFrom === defaultValueTo;
|
|
439
441
|
}
|
|
442
|
+
if (to.mappedType instanceof core_1.JsonType) {
|
|
443
|
+
const defaultValueFrom = (0, core_1.parseJsonSafe)(from.default.replace(/^'(.*)'$/, '$1'));
|
|
444
|
+
const defaultValueTo = (0, core_1.parseJsonSafe)(to.default?.replace(/^'(.*)'$/, '$1'));
|
|
445
|
+
return core_1.Utils.equals(defaultValueFrom, defaultValueTo);
|
|
446
|
+
}
|
|
440
447
|
if (to.mappedType instanceof core_1.DateTimeType && from.default && to.default) {
|
|
441
448
|
// normalize now/current_timestamp defaults, also remove `()` from the end of default expression
|
|
442
449
|
const defaultValueFrom = from.default.toLowerCase().replace('current_timestamp', 'now').replace(/\(\)$/, '');
|
package/schema/SchemaHelper.d.ts
CHANGED
|
@@ -18,7 +18,9 @@ export declare abstract class SchemaHelper {
|
|
|
18
18
|
getForeignKeys(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Dictionary>;
|
|
19
19
|
protected getTableKey(t: Table): string;
|
|
20
20
|
getEnumDefinitions(connection: AbstractSqlConnection, checks: CheckDef[], tableName: string, schemaName?: string): Promise<Dictionary<string[]>>;
|
|
21
|
-
|
|
21
|
+
getDropNativeEnumSQL(name: string, schema?: string): string;
|
|
22
|
+
getAlterNativeEnumSQL(name: string, schema?: string, value?: string): string;
|
|
23
|
+
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[]): Promise<void>;
|
|
22
24
|
getListTablesSQL(schemaName?: string): string;
|
|
23
25
|
getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column, schemaName?: string): string;
|
|
24
26
|
getCreateIndexSQL(tableName: string, index: IndexDef): string;
|
|
@@ -29,8 +31,8 @@ export declare abstract class SchemaHelper {
|
|
|
29
31
|
configureColumn(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
|
|
30
32
|
configureColumnDefault(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
|
|
31
33
|
getPreAlterTable(tableDiff: TableDifference, safe: boolean): string;
|
|
32
|
-
getAlterColumnAutoincrement(tableName: string, column: Column): string;
|
|
33
|
-
getChangeColumnCommentSQL(tableName: string, to: Column): string;
|
|
34
|
+
getAlterColumnAutoincrement(tableName: string, column: Column, schemaName?: string): string;
|
|
35
|
+
getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
|
|
34
36
|
getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
|
|
35
37
|
getColumns(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Column[]>;
|
|
36
38
|
getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<IndexDef[]>;
|
package/schema/SchemaHelper.js
CHANGED
|
@@ -46,7 +46,13 @@ class SchemaHelper {
|
|
|
46
46
|
async getEnumDefinitions(connection, checks, tableName, schemaName) {
|
|
47
47
|
return {};
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
getDropNativeEnumSQL(name, schema) {
|
|
50
|
+
throw new Error('Not supported by given driver');
|
|
51
|
+
}
|
|
52
|
+
getAlterNativeEnumSQL(name, schema, value) {
|
|
53
|
+
throw new Error('Not supported by given driver');
|
|
54
|
+
}
|
|
55
|
+
async loadInformationSchema(schema, connection, tables, schemas) {
|
|
50
56
|
for (const t of tables) {
|
|
51
57
|
const table = schema.addTable(t.table_name, t.schema_name);
|
|
52
58
|
table.comment = t.table_comment;
|
|
@@ -122,17 +128,17 @@ class SchemaHelper {
|
|
|
122
128
|
core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), guard('default'));
|
|
123
129
|
}
|
|
124
130
|
else {
|
|
125
|
-
core_1.Utils.runIfNotEmpty(() => col.defaultTo(
|
|
131
|
+
core_1.Utils.runIfNotEmpty(() => col.defaultTo(knex.raw(column.default)), column.default != null && column.default !== 'null');
|
|
126
132
|
}
|
|
127
133
|
return col;
|
|
128
134
|
}
|
|
129
135
|
getPreAlterTable(tableDiff, safe) {
|
|
130
136
|
return '';
|
|
131
137
|
}
|
|
132
|
-
getAlterColumnAutoincrement(tableName, column) {
|
|
138
|
+
getAlterColumnAutoincrement(tableName, column, schemaName) {
|
|
133
139
|
return '';
|
|
134
140
|
}
|
|
135
|
-
getChangeColumnCommentSQL(tableName, to) {
|
|
141
|
+
getChangeColumnCommentSQL(tableName, to, schemaName) {
|
|
136
142
|
return '';
|
|
137
143
|
}
|
|
138
144
|
async getNamespaces(connection) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ISchemaGenerator, MikroORM } from '@mikro-orm/core';
|
|
2
2
|
import { AbstractSchemaGenerator } from '@mikro-orm/core';
|
|
3
3
|
import type { SchemaDifference } from '../typings';
|
|
4
4
|
import { DatabaseSchema } from './DatabaseSchema';
|
|
@@ -8,8 +8,6 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
|
|
|
8
8
|
private readonly options;
|
|
9
9
|
protected lastEnsuredDatabase?: string;
|
|
10
10
|
static register(orm: MikroORM): void;
|
|
11
|
-
/** @deprecated use `dropSchema` and `createSchema` commands respectively */
|
|
12
|
-
generate(): Promise<string>;
|
|
13
11
|
createSchema(options?: {
|
|
14
12
|
wrap?: boolean;
|
|
15
13
|
schema?: string;
|
|
@@ -82,10 +80,10 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
|
|
|
82
80
|
* creates new database and connects to it
|
|
83
81
|
*/
|
|
84
82
|
createDatabase(name: string): Promise<void>;
|
|
85
|
-
dropDatabase(name
|
|
83
|
+
dropDatabase(name?: string): Promise<void>;
|
|
86
84
|
execute(sql: string, options?: {
|
|
87
85
|
wrap?: boolean;
|
|
88
|
-
}): Promise<
|
|
86
|
+
}): Promise<void>;
|
|
89
87
|
private wrapSchema;
|
|
90
88
|
private createSchemaBuilder;
|
|
91
89
|
private createTable;
|
|
@@ -13,14 +13,6 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
13
13
|
static register(orm) {
|
|
14
14
|
orm.config.registerExtension('@mikro-orm/schema-generator', () => new SqlSchemaGenerator(orm.em));
|
|
15
15
|
}
|
|
16
|
-
/** @deprecated use `dropSchema` and `createSchema` commands respectively */
|
|
17
|
-
async generate() {
|
|
18
|
-
const [dropSchema, createSchema] = await Promise.all([
|
|
19
|
-
this.getDropSchemaSQL({ wrap: false }),
|
|
20
|
-
this.getCreateSchemaSQL({ wrap: false }),
|
|
21
|
-
]);
|
|
22
|
-
return this.wrapSchema(dropSchema + createSchema);
|
|
23
|
-
}
|
|
24
16
|
async createSchema(options) {
|
|
25
17
|
await this.ensureDatabase();
|
|
26
18
|
const sql = await this.getCreateSchemaSQL(options);
|
|
@@ -101,7 +93,8 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
101
93
|
await this.ensureDatabase();
|
|
102
94
|
const wrap = options.wrap ?? this.options.disableForeignKeys;
|
|
103
95
|
const metadata = this.getOrderedMetadata(options.schema).reverse();
|
|
104
|
-
const
|
|
96
|
+
const schemas = this.getTargetSchema(options.schema).getNamespaces();
|
|
97
|
+
const schema = await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas);
|
|
105
98
|
let ret = '';
|
|
106
99
|
// remove FKs explicitly if we can't use cascading statement and we don't disable FK checks (we need this for circular relations)
|
|
107
100
|
for (const meta of metadata) {
|
|
@@ -118,6 +111,12 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
118
111
|
for (const meta of metadata) {
|
|
119
112
|
ret += await this.dump(this.dropTable(meta.collection, this.getSchemaName(meta, options)), '\n');
|
|
120
113
|
}
|
|
114
|
+
if (this.platform.supportsNativeEnums()) {
|
|
115
|
+
for (const columnName of Object.keys(schema.getNativeEnums())) {
|
|
116
|
+
const sql = this.helper.getDropNativeEnumSQL(columnName, options.schema ?? this.config.get('schema'));
|
|
117
|
+
ret += await this.dump(this.knex.schema.raw(sql), '\n');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
121
120
|
if (options.dropMigrationsTable) {
|
|
122
121
|
ret += await this.dump(this.dropTable(this.config.get('migrations').tableName, this.config.get('schema')), '\n');
|
|
123
122
|
}
|
|
@@ -140,7 +139,9 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
140
139
|
return this.diffToSQL(diffUp, options);
|
|
141
140
|
}
|
|
142
141
|
async getUpdateSchemaMigrationSQL(options = {}) {
|
|
143
|
-
|
|
142
|
+
if (!options.fromSchema) {
|
|
143
|
+
await this.ensureDatabase();
|
|
144
|
+
}
|
|
144
145
|
const { fromSchema, toSchema } = await this.prepareSchemaForComparison(options);
|
|
145
146
|
const comparator = new SchemaComparator_1.SchemaComparator(this.platform);
|
|
146
147
|
const diffUp = comparator.compare(fromSchema, toSchema);
|
|
@@ -151,14 +152,16 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
151
152
|
};
|
|
152
153
|
}
|
|
153
154
|
async prepareSchemaForComparison(options) {
|
|
154
|
-
options.wrap
|
|
155
|
-
options.safe
|
|
156
|
-
options.dropTables
|
|
155
|
+
options.wrap ??= this.options.disableForeignKeys;
|
|
156
|
+
options.safe ??= false;
|
|
157
|
+
options.dropTables ??= true;
|
|
157
158
|
const toSchema = this.getTargetSchema(options.schema);
|
|
158
|
-
const
|
|
159
|
+
const schemas = toSchema.getNamespaces();
|
|
160
|
+
const fromSchema = options.fromSchema ?? await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas);
|
|
159
161
|
const wildcardSchemaTables = Object.values(this.metadata.getAll()).filter(meta => meta.schema === '*').map(meta => meta.tableName);
|
|
160
162
|
fromSchema.prune(options.schema, wildcardSchemaTables);
|
|
161
163
|
toSchema.prune(options.schema, wildcardSchemaTables);
|
|
164
|
+
toSchema.setNativeEnums(fromSchema.getNativeEnums());
|
|
162
165
|
return { fromSchema, toSchema };
|
|
163
166
|
}
|
|
164
167
|
async diffToSQL(schemaDiff, options) {
|
|
@@ -262,6 +265,12 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
262
265
|
alterTable(diff, safe) {
|
|
263
266
|
const ret = [];
|
|
264
267
|
const [schemaName, tableName] = this.splitTableName(diff.name);
|
|
268
|
+
const changedNativeEnums = [];
|
|
269
|
+
for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
|
|
270
|
+
if (column.nativeEnumName && changedProperties.has('enumItems') && column.nativeEnumName in diff.fromTable.nativeEnums) {
|
|
271
|
+
changedNativeEnums.push([column.nativeEnumName, column.enumItems, diff.fromTable.getColumn(column.name).enumItems]);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
265
274
|
ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
|
|
266
275
|
for (const index of Object.values(diff.removedIndexes)) {
|
|
267
276
|
this.dropIndex(table, index);
|
|
@@ -298,17 +307,20 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
298
307
|
if (changedProperties.size === 1 && changedProperties.has('comment')) {
|
|
299
308
|
continue;
|
|
300
309
|
}
|
|
310
|
+
if (changedProperties.size === 1 && changedProperties.has('enumItems') && column.nativeEnumName) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
301
313
|
const col = this.helper.createTableColumn(table, column, diff.fromTable, changedProperties).alter();
|
|
302
314
|
this.helper.configureColumn(column, col, this.knex, changedProperties);
|
|
303
315
|
}
|
|
304
316
|
for (const { column } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
|
|
305
|
-
this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column));
|
|
317
|
+
this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column, schemaName));
|
|
306
318
|
}
|
|
307
319
|
for (const { column, changedProperties } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('comment'))) {
|
|
308
320
|
if (['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems'].some(t => changedProperties.has(t))) {
|
|
309
321
|
continue; // will be handled via knex
|
|
310
322
|
}
|
|
311
|
-
this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column));
|
|
323
|
+
this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column, schemaName));
|
|
312
324
|
}
|
|
313
325
|
for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
|
|
314
326
|
this.helper.pushTableQuery(table, this.helper.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
|
|
@@ -345,6 +357,13 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
345
357
|
table.comment(comment);
|
|
346
358
|
}
|
|
347
359
|
}));
|
|
360
|
+
if (this.platform.supportsNativeEnums()) {
|
|
361
|
+
changedNativeEnums.forEach(([enumName, itemsNew, itemsOld]) => {
|
|
362
|
+
// postgres allows only adding new items
|
|
363
|
+
const newItems = itemsNew.filter(val => !itemsOld.includes(val));
|
|
364
|
+
ret.push(...newItems.map(val => this.knex.schema.raw(this.helper.getAlterNativeEnumSQL(enumName, schemaName, val))));
|
|
365
|
+
});
|
|
366
|
+
}
|
|
348
367
|
return ret;
|
|
349
368
|
}
|
|
350
369
|
/**
|
|
@@ -356,24 +375,26 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
356
375
|
await this.driver.reconnect();
|
|
357
376
|
}
|
|
358
377
|
async dropDatabase(name) {
|
|
378
|
+
name ??= this.config.get('dbName');
|
|
359
379
|
this.config.set('dbName', this.helper.getManagementDbName());
|
|
360
380
|
await this.driver.reconnect();
|
|
361
381
|
await this.driver.execute(this.helper.getDropDatabaseSQL('' + this.knex.ref(name)));
|
|
362
382
|
}
|
|
363
383
|
async execute(sql, options = {}) {
|
|
364
|
-
options.wrap
|
|
384
|
+
options.wrap ??= false;
|
|
365
385
|
const lines = this.wrapSchema(sql, options).split('\n').filter(i => i.trim());
|
|
366
386
|
if (lines.length === 0) {
|
|
367
387
|
return;
|
|
368
388
|
}
|
|
369
389
|
if (this.platform.supportsMultipleStatements()) {
|
|
370
390
|
const query = lines.join('\n');
|
|
371
|
-
|
|
391
|
+
await this.driver.execute(query);
|
|
392
|
+
return;
|
|
372
393
|
}
|
|
373
394
|
await core_1.Utils.runSerial(lines, line => this.driver.execute(line));
|
|
374
395
|
}
|
|
375
|
-
wrapSchema(sql, options
|
|
376
|
-
options.wrap
|
|
396
|
+
wrapSchema(sql, options) {
|
|
397
|
+
options.wrap ??= this.options.disableForeignKeys;
|
|
377
398
|
if (!options.wrap || sql.trim() === '') {
|
|
378
399
|
return sql;
|
|
379
400
|
}
|
package/typings.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
|
-
import type { CheckCallback, Dictionary, EntityProperty, GroupOperator, QBFilterQuery, QueryOrderMap, Type } from '@mikro-orm/core';
|
|
2
|
+
import type { CheckCallback, Dictionary, EntityProperty, GroupOperator, RawQueryFragment, QBFilterQuery, QueryOrderMap, Type } from '@mikro-orm/core';
|
|
3
3
|
import type { QueryType } from './query/enums';
|
|
4
4
|
import type { DatabaseSchema, DatabaseTable } from './schema';
|
|
5
5
|
export interface Table {
|
|
@@ -11,7 +11,7 @@ export type KnexStringRef = Knex.Ref<string, {
|
|
|
11
11
|
[alias: string]: string;
|
|
12
12
|
}>;
|
|
13
13
|
type AnyString = string & {};
|
|
14
|
-
export type Field<T> = AnyString | keyof T | KnexStringRef | Knex.QueryBuilder;
|
|
14
|
+
export type Field<T> = AnyString | keyof T | RawQueryFragment | KnexStringRef | Knex.QueryBuilder;
|
|
15
15
|
export interface JoinOptions {
|
|
16
16
|
table: string;
|
|
17
17
|
schema?: string;
|
|
@@ -25,6 +25,7 @@ export interface JoinOptions {
|
|
|
25
25
|
path?: string;
|
|
26
26
|
prop: EntityProperty;
|
|
27
27
|
cond: Dictionary;
|
|
28
|
+
cond_?: Dictionary;
|
|
28
29
|
}
|
|
29
30
|
export interface Column {
|
|
30
31
|
name: string;
|
|
@@ -38,6 +39,7 @@ export interface Column {
|
|
|
38
39
|
scale?: number;
|
|
39
40
|
default?: string | null;
|
|
40
41
|
comment?: string;
|
|
42
|
+
nativeEnumName?: string;
|
|
41
43
|
enumItems?: string[];
|
|
42
44
|
primary?: boolean;
|
|
43
45
|
unique?: boolean;
|
|
@@ -122,7 +124,8 @@ export interface IQueryBuilder<T> {
|
|
|
122
124
|
join(field: string, alias: string, cond?: QBFilterQuery, type?: 'leftJoin' | 'innerJoin' | 'pivotJoin', path?: string): this;
|
|
123
125
|
leftJoin(field: string, alias: string, cond?: QBFilterQuery): this;
|
|
124
126
|
joinAndSelect(field: string, alias: string, cond?: QBFilterQuery): this;
|
|
125
|
-
leftJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery): this;
|
|
127
|
+
leftJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery, fields?: string[]): this;
|
|
128
|
+
innerJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery, fields?: string[]): this;
|
|
126
129
|
withSubQuery(subQuery: Knex.QueryBuilder, alias: string): this;
|
|
127
130
|
where(cond: QBFilterQuery<T>, operator?: keyof typeof GroupOperator): this;
|
|
128
131
|
where(cond: string, params?: any[], operator?: keyof typeof GroupOperator): this;
|
|
@@ -136,16 +139,16 @@ export interface IQueryBuilder<T> {
|
|
|
136
139
|
getAliasForJoinPath(path: string): string | undefined;
|
|
137
140
|
getNextAlias(entityName?: string): string;
|
|
138
141
|
}
|
|
139
|
-
export interface ICriteriaNode {
|
|
142
|
+
export interface ICriteriaNode<T extends object> {
|
|
140
143
|
readonly entityName: string;
|
|
141
|
-
readonly parent?: ICriteriaNode | undefined;
|
|
144
|
+
readonly parent?: ICriteriaNode<T> | undefined;
|
|
142
145
|
readonly key?: string | undefined;
|
|
143
146
|
payload: any;
|
|
144
147
|
prop?: EntityProperty;
|
|
145
148
|
index?: number;
|
|
146
|
-
process
|
|
149
|
+
process(qb: IQueryBuilder<T>, alias?: string): any;
|
|
147
150
|
shouldInline(payload: any): boolean;
|
|
148
|
-
willAutoJoin
|
|
151
|
+
willAutoJoin(qb: IQueryBuilder<T>, alias?: string): boolean;
|
|
149
152
|
shouldRename(payload: any): boolean;
|
|
150
153
|
renameFieldToPK<T>(qb: IQueryBuilder<T>): string;
|
|
151
154
|
getPath(addIndex?: boolean): string;
|