@mikro-orm/knex 6.0.0-dev.2 → 6.0.0-dev.200
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/{dist/AbstractSqlConnection.d.ts → AbstractSqlConnection.d.ts} +8 -4
- package/{dist/AbstractSqlConnection.js → AbstractSqlConnection.js} +35 -18
- package/AbstractSqlDriver.d.ts +73 -0
- package/AbstractSqlDriver.js +1085 -0
- package/AbstractSqlPlatform.d.ts +22 -0
- package/{dist/AbstractSqlPlatform.js → AbstractSqlPlatform.js} +46 -19
- package/{dist/MonkeyPatchable.d.ts → MonkeyPatchable.d.ts} +1 -0
- package/{dist/MonkeyPatchable.js → MonkeyPatchable.js} +3 -0
- package/PivotCollectionPersister.d.ts +17 -0
- package/PivotCollectionPersister.js +128 -0
- package/{dist/README.md → README.md} +66 -109
- package/{dist/SqlEntityManager.d.ts → SqlEntityManager.d.ts} +6 -10
- package/{dist/SqlEntityManager.js → SqlEntityManager.js} +5 -10
- package/SqlEntityRepository.d.ts +24 -0
- package/{dist/SqlEntityRepository.js → SqlEntityRepository.js} +11 -8
- package/{dist/index.d.ts → index.d.ts} +1 -0
- package/{dist/index.js → index.js} +6 -1
- package/index.mjs +211 -0
- package/package.json +20 -49
- package/query/ArrayCriteriaNode.d.ts +10 -0
- package/{dist/query → query}/ArrayCriteriaNode.js +7 -2
- package/{dist/query → query}/CriteriaNode.d.ts +11 -9
- package/{dist/query → query}/CriteriaNode.js +31 -15
- package/query/CriteriaNodeFactory.d.ts +12 -0
- package/{dist/query → query}/CriteriaNodeFactory.js +32 -15
- package/query/ObjectCriteriaNode.d.ts +15 -0
- package/{dist/query → query}/ObjectCriteriaNode.js +68 -21
- package/query/QueryBuilder.d.ts +284 -0
- package/query/QueryBuilder.js +1218 -0
- package/{dist/query → query}/QueryBuilderHelper.d.ts +26 -23
- package/query/QueryBuilderHelper.js +661 -0
- package/query/ScalarCriteriaNode.d.ts +10 -0
- package/{dist/query → query}/ScalarCriteriaNode.js +12 -8
- package/query/enums.d.ts +15 -0
- package/query/enums.js +20 -0
- package/{dist/query → query}/index.js +5 -1
- package/{dist/schema → schema}/DatabaseSchema.d.ts +6 -3
- package/{dist/schema → schema}/DatabaseSchema.js +35 -25
- package/{dist/schema → schema}/DatabaseTable.d.ts +21 -13
- package/schema/DatabaseTable.js +645 -0
- package/{dist/schema → schema}/SchemaComparator.d.ts +9 -7
- package/{dist/schema → schema}/SchemaComparator.js +99 -25
- package/{dist/schema → schema}/SchemaHelper.d.ts +20 -13
- package/{dist/schema → schema}/SchemaHelper.js +70 -18
- package/{dist/schema/SchemaGenerator.d.ts → schema/SqlSchemaGenerator.d.ts} +11 -14
- package/{dist/schema/SchemaGenerator.js → schema/SqlSchemaGenerator.js} +149 -63
- package/{dist/schema → schema}/index.d.ts +1 -1
- package/{dist/schema → schema}/index.js +6 -2
- package/{dist/typings.d.ts → typings.d.ts} +45 -22
- package/CHANGELOG.md +0 -661
- package/dist/AbstractSqlDriver.d.ts +0 -55
- package/dist/AbstractSqlDriver.js +0 -644
- package/dist/AbstractSqlPlatform.d.ts +0 -21
- package/dist/LICENSE +0 -21
- package/dist/SqlEntityRepository.d.ts +0 -23
- package/dist/index.mjs +0 -26
- package/dist/package.json +0 -99
- package/dist/query/ArrayCriteriaNode.d.ts +0 -9
- package/dist/query/CriteriaNodeFactory.d.ts +0 -12
- package/dist/query/ObjectCriteriaNode.d.ts +0 -14
- package/dist/query/QueryBuilder.d.ts +0 -211
- package/dist/query/QueryBuilder.js +0 -688
- package/dist/query/QueryBuilderHelper.js +0 -523
- package/dist/query/ScalarCriteriaNode.d.ts +0 -9
- package/dist/query/enums.d.ts +0 -8
- package/dist/query/enums.js +0 -12
- package/dist/schema/DatabaseTable.js +0 -319
- /package/{dist/query → query}/index.d.ts +0 -0
- /package/{dist/typings.js → typings.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Column, ForeignKey, IndexDef, SchemaDifference, TableDifference } from '../typings';
|
|
2
2
|
import type { DatabaseSchema } from './DatabaseSchema';
|
|
3
3
|
import type { DatabaseTable } from './DatabaseTable';
|
|
4
4
|
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
|
|
@@ -8,6 +8,7 @@ import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
|
|
|
8
8
|
export declare class SchemaComparator {
|
|
9
9
|
private readonly platform;
|
|
10
10
|
private readonly helper;
|
|
11
|
+
private readonly logger;
|
|
11
12
|
constructor(platform: AbstractSqlPlatform);
|
|
12
13
|
/**
|
|
13
14
|
* Returns a SchemaDifference object containing the differences between the schemas fromSchema and toSchema.
|
|
@@ -16,12 +17,12 @@ export declare class SchemaComparator {
|
|
|
16
17
|
* operations to change the schema stored in fromSchema to the schema that is
|
|
17
18
|
* stored in toSchema.
|
|
18
19
|
*/
|
|
19
|
-
compare(fromSchema: DatabaseSchema, toSchema: DatabaseSchema): SchemaDifference;
|
|
20
|
+
compare(fromSchema: DatabaseSchema, toSchema: DatabaseSchema, inverseDiff?: SchemaDifference): SchemaDifference;
|
|
20
21
|
/**
|
|
21
22
|
* Returns the difference between the tables fromTable and toTable.
|
|
22
23
|
* If there are no differences this method returns the boolean false.
|
|
23
24
|
*/
|
|
24
|
-
diffTable(fromTable: DatabaseTable, toTable: DatabaseTable): TableDifference | false;
|
|
25
|
+
diffTable(fromTable: DatabaseTable, toTable: DatabaseTable, inverseTableDiff?: TableDifference): TableDifference | false;
|
|
25
26
|
/**
|
|
26
27
|
* Try to find columns that only changed their name, rename operations maybe cheaper than add/drop
|
|
27
28
|
* however ambiguities between different possibilities should not lead to renaming at all.
|
|
@@ -37,19 +38,20 @@ export declare class SchemaComparator {
|
|
|
37
38
|
* Returns the difference between the columns
|
|
38
39
|
* If there are differences this method returns field2, otherwise the boolean false.
|
|
39
40
|
*/
|
|
40
|
-
diffColumn(
|
|
41
|
+
diffColumn(fromColumn: Column, toColumn: Column, tableName?: string): Set<string>;
|
|
41
42
|
diffEnumItems(items1?: string[], items2?: string[]): boolean;
|
|
42
43
|
diffComment(comment1?: string, comment2?: string): boolean;
|
|
43
44
|
/**
|
|
44
45
|
* Finds the difference between the indexes index1 and index2.
|
|
45
46
|
* Compares index1 with index2 and returns index2 if there are any differences or false in case there are no differences.
|
|
46
47
|
*/
|
|
47
|
-
diffIndex(index1:
|
|
48
|
+
diffIndex(index1: IndexDef, index2: IndexDef): boolean;
|
|
48
49
|
/**
|
|
49
50
|
* Checks if the other index already fulfills all the indexing and constraint needs of the current one.
|
|
50
51
|
*/
|
|
51
|
-
isIndexFulfilledBy(index1:
|
|
52
|
-
|
|
52
|
+
isIndexFulfilledBy(index1: IndexDef, index2: IndexDef): boolean;
|
|
53
|
+
diffExpression(expr1: string, expr2: string): boolean;
|
|
53
54
|
hasSameDefaultValue(from: Column, to: Column): boolean;
|
|
54
55
|
private mapColumnToProperty;
|
|
56
|
+
private log;
|
|
55
57
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SchemaComparator = void 0;
|
|
4
|
+
const util_1 = require("util");
|
|
4
5
|
const core_1 = require("@mikro-orm/core");
|
|
5
6
|
/**
|
|
6
7
|
* Compares two Schemas and return an instance of SchemaDifference.
|
|
7
8
|
*/
|
|
8
9
|
class SchemaComparator {
|
|
10
|
+
platform;
|
|
11
|
+
helper;
|
|
12
|
+
logger;
|
|
9
13
|
constructor(platform) {
|
|
10
14
|
this.platform = platform;
|
|
11
15
|
this.helper = this.platform.getSchemaHelper();
|
|
16
|
+
this.logger = this.platform.getConfig().getLogger();
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
19
|
* Returns a SchemaDifference object containing the differences between the schemas fromSchema and toSchema.
|
|
@@ -17,7 +22,7 @@ class SchemaComparator {
|
|
|
17
22
|
* operations to change the schema stored in fromSchema to the schema that is
|
|
18
23
|
* stored in toSchema.
|
|
19
24
|
*/
|
|
20
|
-
compare(fromSchema, toSchema) {
|
|
25
|
+
compare(fromSchema, toSchema, inverseDiff) {
|
|
21
26
|
const diff = { newTables: {}, removedTables: {}, changedTables: {}, orphanedForeignKeys: [], newNamespaces: new Set(), removedNamespaces: new Set(), fromSchema };
|
|
22
27
|
const foreignKeysToTable = {};
|
|
23
28
|
for (const namespace of toSchema.getNamespaces()) {
|
|
@@ -38,7 +43,7 @@ class SchemaComparator {
|
|
|
38
43
|
diff.newTables[tableName] = toSchema.getTable(tableName);
|
|
39
44
|
}
|
|
40
45
|
else {
|
|
41
|
-
const tableDifferences = this.diffTable(fromSchema.getTable(tableName), toSchema.getTable(tableName));
|
|
46
|
+
const tableDifferences = this.diffTable(fromSchema.getTable(tableName), toSchema.getTable(tableName), inverseDiff?.changedTables[tableName]);
|
|
42
47
|
if (tableDifferences !== false) {
|
|
43
48
|
diff.changedTables[tableName] = tableDifferences;
|
|
44
49
|
}
|
|
@@ -86,7 +91,7 @@ class SchemaComparator {
|
|
|
86
91
|
* Returns the difference between the tables fromTable and toTable.
|
|
87
92
|
* If there are no differences this method returns the boolean false.
|
|
88
93
|
*/
|
|
89
|
-
diffTable(fromTable, toTable) {
|
|
94
|
+
diffTable(fromTable, toTable, inverseTableDiff) {
|
|
90
95
|
let changes = 0;
|
|
91
96
|
const tableDifferences = {
|
|
92
97
|
name: fromTable.getShortestName(),
|
|
@@ -105,18 +110,22 @@ class SchemaComparator {
|
|
|
105
110
|
renamedColumns: {},
|
|
106
111
|
renamedIndexes: {},
|
|
107
112
|
fromTable,
|
|
113
|
+
toTable,
|
|
108
114
|
};
|
|
109
115
|
if (this.diffComment(fromTable.comment, toTable.comment)) {
|
|
110
116
|
tableDifferences.changedComment = toTable.comment;
|
|
117
|
+
this.log(`table comment changed for ${tableDifferences.name}`, { fromTableComment: fromTable.comment, toTableComment: toTable.comment });
|
|
111
118
|
}
|
|
112
119
|
const fromTableColumns = fromTable.getColumns();
|
|
113
120
|
const toTableColumns = toTable.getColumns();
|
|
121
|
+
const tableName = (toTable.schema ? toTable.schema + '.' : '') + toTable.name;
|
|
114
122
|
// See if all the columns in "from" table exist in "to" table
|
|
115
123
|
for (const column of toTableColumns) {
|
|
116
124
|
if (fromTable.hasColumn(column.name)) {
|
|
117
125
|
continue;
|
|
118
126
|
}
|
|
119
127
|
tableDifferences.addedColumns[column.name] = column;
|
|
128
|
+
this.log(`column ${tableDifferences.name}.${column.name} of type ${column.type} added`);
|
|
120
129
|
changes++;
|
|
121
130
|
}
|
|
122
131
|
/* See if there are any removed columns in "to" table */
|
|
@@ -124,23 +133,31 @@ class SchemaComparator {
|
|
|
124
133
|
// See if column is removed in "to" table.
|
|
125
134
|
if (!toTable.hasColumn(column.name)) {
|
|
126
135
|
tableDifferences.removedColumns[column.name] = column;
|
|
136
|
+
this.log(`column ${tableDifferences.name}.${column.name} removed`);
|
|
127
137
|
changes++;
|
|
128
138
|
continue;
|
|
129
139
|
}
|
|
130
140
|
// See if column has changed properties in "to" table.
|
|
131
|
-
const changedProperties = this.diffColumn(column, toTable.getColumn(column.name));
|
|
141
|
+
const changedProperties = this.diffColumn(column, toTable.getColumn(column.name), tableName);
|
|
132
142
|
if (changedProperties.size === 0) {
|
|
133
143
|
continue;
|
|
134
144
|
}
|
|
145
|
+
if (changedProperties.size === 1 && changedProperties.has('generated')) {
|
|
146
|
+
tableDifferences.addedColumns[column.name] = toTable.getColumn(column.name);
|
|
147
|
+
tableDifferences.removedColumns[column.name] = column;
|
|
148
|
+
changes++;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
135
151
|
tableDifferences.changedColumns[column.name] = {
|
|
136
152
|
oldColumnName: column.name,
|
|
137
153
|
fromColumn: column,
|
|
138
154
|
column: toTable.getColumn(column.name),
|
|
139
155
|
changedProperties,
|
|
140
156
|
};
|
|
157
|
+
this.log(`column ${tableDifferences.name}.${column.name} changed`, { changedProperties });
|
|
141
158
|
changes++;
|
|
142
159
|
}
|
|
143
|
-
this.detectColumnRenamings(tableDifferences);
|
|
160
|
+
this.detectColumnRenamings(tableDifferences, inverseTableDiff);
|
|
144
161
|
const fromTableIndexes = fromTable.getIndexes();
|
|
145
162
|
const toTableIndexes = toTable.getIndexes();
|
|
146
163
|
// See if all the indexes in "from" table exist in "to" table
|
|
@@ -149,6 +166,7 @@ class SchemaComparator {
|
|
|
149
166
|
continue;
|
|
150
167
|
}
|
|
151
168
|
tableDifferences.addedIndexes[index.keyName] = index;
|
|
169
|
+
this.log(`index ${index.keyName} added to table ${tableDifferences.name}`, { index });
|
|
152
170
|
changes++;
|
|
153
171
|
}
|
|
154
172
|
// See if there are any removed indexes in "to" table
|
|
@@ -156,6 +174,7 @@ class SchemaComparator {
|
|
|
156
174
|
// See if index is removed in "to" table.
|
|
157
175
|
if ((index.primary && !toTable.hasPrimaryKey()) || !index.primary && !toTable.hasIndex(index.keyName)) {
|
|
158
176
|
tableDifferences.removedIndexes[index.keyName] = index;
|
|
177
|
+
this.log(`index ${index.keyName} removed from table ${tableDifferences.name}`);
|
|
159
178
|
changes++;
|
|
160
179
|
continue;
|
|
161
180
|
}
|
|
@@ -165,6 +184,7 @@ class SchemaComparator {
|
|
|
165
184
|
continue;
|
|
166
185
|
}
|
|
167
186
|
tableDifferences.changedIndexes[index.keyName] = toTableIndex;
|
|
187
|
+
this.log(`index ${index.keyName} changed in table ${tableDifferences.name}`, { fromTableIndex: index, toTableIndex });
|
|
168
188
|
changes++;
|
|
169
189
|
}
|
|
170
190
|
this.detectIndexRenamings(tableDifferences);
|
|
@@ -176,20 +196,23 @@ class SchemaComparator {
|
|
|
176
196
|
continue;
|
|
177
197
|
}
|
|
178
198
|
tableDifferences.addedChecks[check.name] = check;
|
|
199
|
+
this.log(`check constraint ${check.name} added to table ${tableDifferences.name}`, { check });
|
|
179
200
|
changes++;
|
|
180
201
|
}
|
|
181
202
|
// See if there are any removed checks in "to" table
|
|
182
203
|
for (const check of fromTableChecks) {
|
|
183
204
|
if (!toTable.hasCheck(check.name)) {
|
|
184
205
|
tableDifferences.removedChecks[check.name] = check;
|
|
206
|
+
this.log(`check constraint ${check.name} removed from table ${tableDifferences.name}`);
|
|
185
207
|
changes++;
|
|
186
208
|
continue;
|
|
187
209
|
}
|
|
188
210
|
// See if index has changed in "to" table
|
|
189
211
|
const toTableCheck = toTable.getCheck(check.name);
|
|
190
|
-
if (!this.
|
|
212
|
+
if (!this.diffExpression(check.expression, toTableCheck.expression)) {
|
|
191
213
|
continue;
|
|
192
214
|
}
|
|
215
|
+
this.log(`check constraint ${check.name} changed in table ${tableDifferences.name}`, { fromTableCheck: check, toTableCheck });
|
|
193
216
|
tableDifferences.changedChecks[check.name] = toTableCheck;
|
|
194
217
|
changes++;
|
|
195
218
|
}
|
|
@@ -202,6 +225,7 @@ class SchemaComparator {
|
|
|
202
225
|
delete toForeignKeys[toConstraint.constraintName];
|
|
203
226
|
}
|
|
204
227
|
else if (fromConstraint.constraintName.toLowerCase() === toConstraint.constraintName.toLowerCase()) {
|
|
228
|
+
this.log(`FK constraint ${fromConstraint.constraintName} changed in table ${tableDifferences.name}`, { fromConstraint, toConstraint });
|
|
205
229
|
tableDifferences.changedForeignKeys[toConstraint.constraintName] = toConstraint;
|
|
206
230
|
changes++;
|
|
207
231
|
delete fromForeignKeys[fromConstraint.constraintName];
|
|
@@ -211,10 +235,12 @@ class SchemaComparator {
|
|
|
211
235
|
}
|
|
212
236
|
for (const fromConstraint of Object.values(fromForeignKeys)) {
|
|
213
237
|
tableDifferences.removedForeignKeys[fromConstraint.constraintName] = fromConstraint;
|
|
238
|
+
this.log(`FK constraint ${fromConstraint.constraintName} removed from table ${tableDifferences.name}`);
|
|
214
239
|
changes++;
|
|
215
240
|
}
|
|
216
241
|
for (const toConstraint of Object.values(toForeignKeys)) {
|
|
217
242
|
tableDifferences.addedForeignKeys[toConstraint.constraintName] = toConstraint;
|
|
243
|
+
this.log(`FK constraint ${toConstraint.constraintName} added from table ${tableDifferences.name}`, { constraint: toConstraint });
|
|
218
244
|
changes++;
|
|
219
245
|
}
|
|
220
246
|
return changes ? tableDifferences : false;
|
|
@@ -223,7 +249,7 @@ class SchemaComparator {
|
|
|
223
249
|
* Try to find columns that only changed their name, rename operations maybe cheaper than add/drop
|
|
224
250
|
* however ambiguities between different possibilities should not lead to renaming at all.
|
|
225
251
|
*/
|
|
226
|
-
detectColumnRenamings(tableDifferences) {
|
|
252
|
+
detectColumnRenamings(tableDifferences, inverseTableDiff) {
|
|
227
253
|
const renameCandidates = {};
|
|
228
254
|
for (const addedColumn of Object.values(tableDifferences.addedColumns)) {
|
|
229
255
|
for (const removedColumn of Object.values(tableDifferences.removedColumns)) {
|
|
@@ -231,6 +257,10 @@ class SchemaComparator {
|
|
|
231
257
|
if (diff.size !== 0) {
|
|
232
258
|
continue;
|
|
233
259
|
}
|
|
260
|
+
const renamedColumn = inverseTableDiff?.renamedColumns[addedColumn.name];
|
|
261
|
+
if (renamedColumn && renamedColumn?.name !== removedColumn.name) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
234
264
|
renameCandidates[addedColumn.name] = renameCandidates[addedColumn.name] ?? [];
|
|
235
265
|
renameCandidates[addedColumn.name].push([removedColumn, addedColumn]);
|
|
236
266
|
}
|
|
@@ -249,6 +279,7 @@ class SchemaComparator {
|
|
|
249
279
|
tableDifferences.renamedColumns[removedColumnName] = addedColumn;
|
|
250
280
|
delete tableDifferences.addedColumns[addedColumnName];
|
|
251
281
|
delete tableDifferences.removedColumns[removedColumnName];
|
|
282
|
+
this.log(`renamed column detected in table ${tableDifferences.name}`, { old: removedColumnName, new: addedColumnName });
|
|
252
283
|
}
|
|
253
284
|
}
|
|
254
285
|
/**
|
|
@@ -282,6 +313,7 @@ class SchemaComparator {
|
|
|
282
313
|
tableDifferences.renamedIndexes[removedIndexName] = addedIndex;
|
|
283
314
|
delete tableDifferences.addedIndexes[addedIndexName];
|
|
284
315
|
delete tableDifferences.removedIndexes[removedIndexName];
|
|
316
|
+
this.log(`renamed index detected in table ${tableDifferences.name}`, { old: removedIndexName, new: addedIndexName });
|
|
285
317
|
}
|
|
286
318
|
}
|
|
287
319
|
diffForeignKey(key1, key2) {
|
|
@@ -294,7 +326,10 @@ class SchemaComparator {
|
|
|
294
326
|
if (key1.referencedTableName !== key2.referencedTableName) {
|
|
295
327
|
return true;
|
|
296
328
|
}
|
|
297
|
-
const
|
|
329
|
+
const defaultRule = ['restrict', 'no action'];
|
|
330
|
+
const rule = (key, method) => {
|
|
331
|
+
return (key[method] ?? defaultRule[0]).toLowerCase().replace(defaultRule[1], defaultRule[0]);
|
|
332
|
+
};
|
|
298
333
|
const compare = (method) => rule(key1, method) === rule(key2, method);
|
|
299
334
|
return !compare('updateRule') || !compare('deleteRule');
|
|
300
335
|
}
|
|
@@ -302,34 +337,59 @@ class SchemaComparator {
|
|
|
302
337
|
* Returns the difference between the columns
|
|
303
338
|
* If there are differences this method returns field2, otherwise the boolean false.
|
|
304
339
|
*/
|
|
305
|
-
diffColumn(
|
|
340
|
+
diffColumn(fromColumn, toColumn, tableName) {
|
|
306
341
|
const changedProperties = new Set();
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
const
|
|
311
|
-
|
|
342
|
+
const fromProp = this.mapColumnToProperty({ ...fromColumn, autoincrement: false });
|
|
343
|
+
const toProp = this.mapColumnToProperty({ ...toColumn, autoincrement: false });
|
|
344
|
+
const fromColumnType = fromColumn.mappedType.getColumnType(fromProp, this.platform).toLowerCase();
|
|
345
|
+
const toColumnType = toColumn.mappedType.getColumnType(toProp, this.platform).toLowerCase();
|
|
346
|
+
const log = (msg, params) => {
|
|
347
|
+
if (tableName) {
|
|
348
|
+
const copy = core_1.Utils.copy(params);
|
|
349
|
+
core_1.Utils.dropUndefinedProperties(copy);
|
|
350
|
+
this.log(msg, copy);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
if (fromColumnType !== toColumnType &&
|
|
354
|
+
!(fromColumn.ignoreSchemaChanges?.includes('type') ||
|
|
355
|
+
toColumn.ignoreSchemaChanges?.includes('type'))) {
|
|
356
|
+
log(`'type' changed for column ${tableName}.${fromColumn.name}`, { fromColumnType, toColumnType });
|
|
312
357
|
changedProperties.add('type');
|
|
313
358
|
}
|
|
314
|
-
if (
|
|
359
|
+
if (fromColumn.nullable !== toColumn.nullable && !fromColumn.generated && !toColumn.generated) {
|
|
360
|
+
log(`'nullable' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
315
361
|
changedProperties.add('nullable');
|
|
316
362
|
}
|
|
317
|
-
if (
|
|
363
|
+
if (this.diffExpression(fromColumn.generated, toColumn.generated)) {
|
|
364
|
+
log(`'generated' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
365
|
+
changedProperties.add('generated');
|
|
366
|
+
}
|
|
367
|
+
if (!!fromColumn.autoincrement !== !!toColumn.autoincrement) {
|
|
368
|
+
log(`'autoincrement' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
318
369
|
changedProperties.add('autoincrement');
|
|
319
370
|
}
|
|
320
|
-
if (
|
|
371
|
+
if (fromColumn.unsigned !== toColumn.unsigned && this.platform.supportsUnsigned()) {
|
|
372
|
+
log(`'unsigned' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
321
373
|
changedProperties.add('unsigned');
|
|
322
374
|
}
|
|
323
|
-
if (!this.hasSameDefaultValue(
|
|
375
|
+
if (!this.hasSameDefaultValue(fromColumn, toColumn)) {
|
|
376
|
+
log(`'default' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
324
377
|
changedProperties.add('default');
|
|
325
378
|
}
|
|
326
|
-
if (this.diffComment(
|
|
379
|
+
if (this.diffComment(fromColumn.comment, toColumn.comment)) {
|
|
380
|
+
log(`'comment' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
327
381
|
changedProperties.add('comment');
|
|
328
382
|
}
|
|
329
|
-
if (
|
|
383
|
+
if (!(fromColumn.mappedType instanceof core_1.ArrayType) &&
|
|
384
|
+
!(toColumn.mappedType instanceof core_1.ArrayType) &&
|
|
385
|
+
this.diffEnumItems(fromColumn.enumItems, toColumn.enumItems)) {
|
|
386
|
+
log(`'enumItems' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
330
387
|
changedProperties.add('enumItems');
|
|
331
388
|
}
|
|
332
|
-
if ((
|
|
389
|
+
if ((fromColumn.extra || '').toLowerCase() !== (toColumn.extra || '').toLowerCase() &&
|
|
390
|
+
!(fromColumn.ignoreSchemaChanges?.includes('extra') ||
|
|
391
|
+
toColumn.ignoreSchemaChanges?.includes('extra'))) {
|
|
392
|
+
log(`'extra' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
333
393
|
changedProperties.add('extra');
|
|
334
394
|
}
|
|
335
395
|
return changedProperties;
|
|
@@ -347,8 +407,8 @@ class SchemaComparator {
|
|
|
347
407
|
* Compares index1 with index2 and returns index2 if there are any differences or false in case there are no differences.
|
|
348
408
|
*/
|
|
349
409
|
diffIndex(index1, index2) {
|
|
350
|
-
// if one of them is a custom expression, compare only by name
|
|
351
|
-
if (index1.expression || index2.expression) {
|
|
410
|
+
// if one of them is a custom expression or full text index, compare only by name
|
|
411
|
+
if (index1.expression || index2.expression || index1.type === 'fulltext' || index2.type === 'fulltext') {
|
|
352
412
|
return index1.keyName !== index2.keyName;
|
|
353
413
|
}
|
|
354
414
|
return !this.isIndexFulfilledBy(index1, index2) || !this.isIndexFulfilledBy(index2, index1);
|
|
@@ -383,8 +443,11 @@ class SchemaComparator {
|
|
|
383
443
|
}
|
|
384
444
|
return index1.primary === index2.primary && index1.unique === index2.unique;
|
|
385
445
|
}
|
|
386
|
-
|
|
387
|
-
|
|
446
|
+
diffExpression(expr1, expr2) {
|
|
447
|
+
// expressions like check constraints might be normalized by the driver,
|
|
448
|
+
// e.g. quotes might be added (https://github.com/mikro-orm/mikro-orm/issues/3827)
|
|
449
|
+
const simplify = (str) => str?.replace(/_\w+\\'(.*?)\\'/g, '$1').replace(/['"`()]|::\w+| +/g, '').toLowerCase();
|
|
450
|
+
return simplify(expr1) !== simplify(expr2);
|
|
388
451
|
}
|
|
389
452
|
hasSameDefaultValue(from, to) {
|
|
390
453
|
if (from.default == null || from.default.toString().toLowerCase() === 'null' || from.default.toString().startsWith('nextval(')) {
|
|
@@ -395,6 +458,11 @@ class SchemaComparator {
|
|
|
395
458
|
const defaultValueTo = !['0', 'false', 'f', 'n', 'no', 'off'].includes('' + to.default);
|
|
396
459
|
return defaultValueFrom === defaultValueTo;
|
|
397
460
|
}
|
|
461
|
+
if (to.mappedType instanceof core_1.JsonType) {
|
|
462
|
+
const defaultValueFrom = (0, core_1.parseJsonSafe)(from.default.replace(/^(_\w+\\)?'(.*?)\\?'$/, '$2'));
|
|
463
|
+
const defaultValueTo = (0, core_1.parseJsonSafe)(to.default?.replace(/^\(?'(.*?)'\)?$/, '$1'));
|
|
464
|
+
return core_1.Utils.equals(defaultValueFrom, defaultValueTo);
|
|
465
|
+
}
|
|
398
466
|
if (to.mappedType instanceof core_1.DateTimeType && from.default && to.default) {
|
|
399
467
|
// normalize now/current_timestamp defaults, also remove `()` from the end of default expression
|
|
400
468
|
const defaultValueFrom = from.default.toLowerCase().replace('current_timestamp', 'now').replace(/\(\)$/, '');
|
|
@@ -423,5 +491,11 @@ class SchemaComparator {
|
|
|
423
491
|
scale: match ? +match[2] : column.scale,
|
|
424
492
|
};
|
|
425
493
|
}
|
|
494
|
+
log(message, params) {
|
|
495
|
+
if (params) {
|
|
496
|
+
message += ' ' + (0, util_1.inspect)(params);
|
|
497
|
+
}
|
|
498
|
+
this.logger.log('schema', message);
|
|
499
|
+
}
|
|
426
500
|
}
|
|
427
501
|
exports.SchemaComparator = SchemaComparator;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
|
-
import type
|
|
2
|
+
import { type Connection, type 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
|
+
import type { DatabaseSchema } from './DatabaseSchema';
|
|
7
8
|
export declare abstract class SchemaHelper {
|
|
8
9
|
protected readonly platform: AbstractSqlPlatform;
|
|
9
10
|
constructor(platform: AbstractSqlPlatform);
|
|
@@ -13,24 +14,30 @@ export declare abstract class SchemaHelper {
|
|
|
13
14
|
getSchemaEnd(): string;
|
|
14
15
|
finalizeTable(table: Knex.TableBuilder, charset: string, collate?: string): void;
|
|
15
16
|
supportsSchemaConstraints(): boolean;
|
|
16
|
-
getPrimaryKeys(connection: AbstractSqlConnection, indexes:
|
|
17
|
+
getPrimaryKeys(connection: AbstractSqlConnection, indexes: IndexDef[] | undefined, tableName: string, schemaName?: string): Promise<string[]>;
|
|
17
18
|
getForeignKeys(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Dictionary>;
|
|
18
|
-
|
|
19
|
+
protected getTableKey(t: Table): string;
|
|
20
|
+
getEnumDefinitions(connection: AbstractSqlConnection, checks: CheckDef[], tableName: string, schemaName?: string): Promise<Dictionary<string[]>>;
|
|
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>;
|
|
19
24
|
getListTablesSQL(schemaName?: string): string;
|
|
20
|
-
getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column): string;
|
|
21
|
-
getCreateIndexSQL(tableName: string, index:
|
|
22
|
-
getDropIndexSQL(tableName: string, index:
|
|
23
|
-
getRenameIndexSQL(tableName: string, index:
|
|
25
|
+
getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column, schemaName?: string): string;
|
|
26
|
+
getCreateIndexSQL(tableName: string, index: IndexDef, partialExpression?: boolean): string;
|
|
27
|
+
getDropIndexSQL(tableName: string, index: IndexDef): string;
|
|
28
|
+
getRenameIndexSQL(tableName: string, index: IndexDef, oldIndexName: string): string;
|
|
29
|
+
hasNonDefaultPrimaryKeyName(table: DatabaseTable): boolean;
|
|
24
30
|
createTableColumn(table: Knex.TableBuilder, column: Column, fromTable: DatabaseTable, changedProperties?: Set<string>): Knex.ColumnBuilder;
|
|
25
31
|
configureColumn(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
|
|
26
32
|
configureColumnDefault(column: Column, col: Knex.ColumnBuilder, knex: Knex, changedProperties?: Set<string>): Knex.ColumnBuilder;
|
|
27
33
|
getPreAlterTable(tableDiff: TableDifference, safe: boolean): string;
|
|
28
|
-
getAlterColumnAutoincrement(tableName: string, column: Column): string;
|
|
29
|
-
getChangeColumnCommentSQL(tableName: string, to: Column): string;
|
|
34
|
+
getAlterColumnAutoincrement(tableName: string, column: Column, schemaName?: string): string;
|
|
35
|
+
getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
|
|
36
|
+
getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
|
|
30
37
|
getColumns(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<Column[]>;
|
|
31
|
-
getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<
|
|
32
|
-
getChecks(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<
|
|
33
|
-
protected mapIndexes(indexes:
|
|
38
|
+
getIndexes(connection: AbstractSqlConnection, tableName: string, schemaName?: string): Promise<IndexDef[]>;
|
|
39
|
+
getChecks(connection: AbstractSqlConnection, tableName: string, schemaName?: string, columns?: Column[]): Promise<CheckDef[]>;
|
|
40
|
+
protected mapIndexes(indexes: IndexDef[]): Promise<IndexDef[]>;
|
|
34
41
|
getForeignKeysSQL(tableName: string, schemaName?: string): string;
|
|
35
42
|
mapForeignKeys(fks: any[], tableName: string, schemaName?: string): Dictionary;
|
|
36
43
|
normalizeDefaultValue(defaultValue: string, length?: number, defaultValues?: Dictionary<string[]>): string | number;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SchemaHelper = void 0;
|
|
4
4
|
const core_1 = require("@mikro-orm/core");
|
|
5
5
|
class SchemaHelper {
|
|
6
|
+
platform;
|
|
6
7
|
constructor(platform) {
|
|
7
8
|
this.platform = platform;
|
|
8
9
|
}
|
|
@@ -24,34 +25,69 @@ class SchemaHelper {
|
|
|
24
25
|
supportsSchemaConstraints() {
|
|
25
26
|
return true;
|
|
26
27
|
}
|
|
27
|
-
async getPrimaryKeys(connection, indexes, tableName, schemaName) {
|
|
28
|
-
const
|
|
29
|
-
return
|
|
28
|
+
async getPrimaryKeys(connection, indexes = [], tableName, schemaName) {
|
|
29
|
+
const pks = indexes.filter(i => i.primary).map(pk => pk.columnNames);
|
|
30
|
+
return core_1.Utils.flatten(pks);
|
|
30
31
|
}
|
|
31
32
|
async getForeignKeys(connection, tableName, schemaName) {
|
|
32
33
|
const fks = await connection.execute(this.getForeignKeysSQL(tableName, schemaName));
|
|
33
34
|
return this.mapForeignKeys(fks, tableName, schemaName);
|
|
34
35
|
}
|
|
36
|
+
getTableKey(t) {
|
|
37
|
+
const unquote = (str) => str.replace(/['"`]/g, '');
|
|
38
|
+
const parts = t.table_name.split('.');
|
|
39
|
+
if (parts.length > 1) {
|
|
40
|
+
return `${unquote(parts[0])}.${unquote(parts[1])}`;
|
|
41
|
+
}
|
|
42
|
+
if (t.schema_name) {
|
|
43
|
+
return `${unquote(t.schema_name)}.${unquote(t.table_name)}`;
|
|
44
|
+
}
|
|
45
|
+
return unquote(t.table_name);
|
|
46
|
+
}
|
|
35
47
|
async getEnumDefinitions(connection, checks, tableName, schemaName) {
|
|
36
48
|
return {};
|
|
37
49
|
}
|
|
50
|
+
getDropNativeEnumSQL(name, schema) {
|
|
51
|
+
throw new Error('Not supported by given driver');
|
|
52
|
+
}
|
|
53
|
+
getAlterNativeEnumSQL(name, schema, value) {
|
|
54
|
+
throw new Error('Not supported by given driver');
|
|
55
|
+
}
|
|
56
|
+
async loadInformationSchema(schema, connection, tables, schemas) {
|
|
57
|
+
for (const t of tables) {
|
|
58
|
+
const table = schema.addTable(t.table_name, t.schema_name);
|
|
59
|
+
table.comment = t.table_comment;
|
|
60
|
+
const cols = await this.getColumns(connection, table.name, table.schema);
|
|
61
|
+
const indexes = await this.getIndexes(connection, table.name, table.schema);
|
|
62
|
+
const checks = await this.getChecks(connection, table.name, table.schema, cols);
|
|
63
|
+
const pks = await this.getPrimaryKeys(connection, indexes, table.name, table.schema);
|
|
64
|
+
const fks = await this.getForeignKeys(connection, table.name, table.schema);
|
|
65
|
+
const enums = await this.getEnumDefinitions(connection, checks, table.name, table.schema);
|
|
66
|
+
table.init(cols, indexes, checks, pks, fks, enums);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
38
69
|
getListTablesSQL(schemaName) {
|
|
39
70
|
throw new Error('Not supported by given driver');
|
|
40
71
|
}
|
|
41
|
-
getRenameColumnSQL(tableName, oldColumnName, to) {
|
|
72
|
+
getRenameColumnSQL(tableName, oldColumnName, to, schemaName) {
|
|
42
73
|
tableName = this.platform.quoteIdentifier(tableName);
|
|
43
74
|
oldColumnName = this.platform.quoteIdentifier(oldColumnName);
|
|
44
75
|
const columnName = this.platform.quoteIdentifier(to.name);
|
|
45
|
-
|
|
76
|
+
const schemaReference = (schemaName !== undefined && schemaName !== 'public') ? ('"' + schemaName + '".') : '';
|
|
77
|
+
const tableReference = schemaReference + tableName;
|
|
78
|
+
return `alter table ${tableReference} rename column ${oldColumnName} to ${columnName}`;
|
|
46
79
|
}
|
|
47
|
-
getCreateIndexSQL(tableName, index) {
|
|
48
|
-
|
|
49
|
-
if (index.expression) {
|
|
80
|
+
getCreateIndexSQL(tableName, index, partialExpression = false) {
|
|
81
|
+
if (index.expression && !partialExpression) {
|
|
50
82
|
return index.expression;
|
|
51
83
|
}
|
|
52
84
|
tableName = this.platform.quoteIdentifier(tableName);
|
|
53
85
|
const keyName = this.platform.quoteIdentifier(index.keyName);
|
|
54
|
-
|
|
86
|
+
const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
|
|
87
|
+
if (index.expression && partialExpression) {
|
|
88
|
+
return `${sql}(${index.expression})`;
|
|
89
|
+
}
|
|
90
|
+
return `${sql}(${index.columnNames.map(c => this.platform.quoteIdentifier(c)).join(', ')})`;
|
|
55
91
|
}
|
|
56
92
|
getDropIndexSQL(tableName, index) {
|
|
57
93
|
return `drop index ${this.platform.quoteIdentifier(index.keyName)}`;
|
|
@@ -59,23 +95,36 @@ class SchemaHelper {
|
|
|
59
95
|
getRenameIndexSQL(tableName, index, oldIndexName) {
|
|
60
96
|
return [this.getDropIndexSQL(tableName, { ...index, keyName: oldIndexName }), this.getCreateIndexSQL(tableName, index)].join(';\n');
|
|
61
97
|
}
|
|
98
|
+
hasNonDefaultPrimaryKeyName(table) {
|
|
99
|
+
const pkIndex = table.getPrimaryKey();
|
|
100
|
+
if (!pkIndex || !this.platform.supportsCustomPrimaryKeyNames()) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const defaultName = this.platform.getDefaultPrimaryName(table.name, pkIndex.columnNames);
|
|
104
|
+
return pkIndex?.keyName !== defaultName;
|
|
105
|
+
}
|
|
62
106
|
createTableColumn(table, column, fromTable, changedProperties) {
|
|
63
107
|
const compositePK = fromTable.getPrimaryKey()?.composite;
|
|
64
|
-
if (column.autoincrement && !compositePK && (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
|
|
108
|
+
if (column.autoincrement && !column.generated && !compositePK && (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
|
|
109
|
+
const primaryKey = !changedProperties && !this.hasNonDefaultPrimaryKeyName(fromTable);
|
|
65
110
|
if (column.mappedType instanceof core_1.BigIntType) {
|
|
66
|
-
return table.bigIncrements(column.name, { primaryKey
|
|
111
|
+
return table.bigIncrements(column.name, { primaryKey });
|
|
67
112
|
}
|
|
68
|
-
return table.increments(column.name, { primaryKey
|
|
113
|
+
return table.increments(column.name, { primaryKey });
|
|
69
114
|
}
|
|
70
115
|
if (column.mappedType instanceof core_1.EnumType && column.enumItems?.every(item => core_1.Utils.isString(item))) {
|
|
71
116
|
return table.enum(column.name, column.enumItems);
|
|
72
117
|
}
|
|
73
|
-
|
|
118
|
+
let columnType = column.type;
|
|
119
|
+
if (column.generated) {
|
|
120
|
+
columnType += ` generated always as ${column.generated}`;
|
|
121
|
+
}
|
|
122
|
+
return table.specificType(column.name, columnType);
|
|
74
123
|
}
|
|
75
124
|
configureColumn(column, col, knex, changedProperties) {
|
|
76
125
|
const guard = (key) => !changedProperties || changedProperties.has(key);
|
|
77
126
|
core_1.Utils.runIfNotEmpty(() => col.nullable(), column.nullable && guard('nullable'));
|
|
78
|
-
core_1.Utils.runIfNotEmpty(() => col.notNullable(), !column.nullable);
|
|
127
|
+
core_1.Utils.runIfNotEmpty(() => col.notNullable(), !column.nullable && !column.generated);
|
|
79
128
|
core_1.Utils.runIfNotEmpty(() => col.unsigned(), column.unsigned);
|
|
80
129
|
core_1.Utils.runIfNotEmpty(() => col.comment(column.comment), column.comment);
|
|
81
130
|
this.configureColumnDefault(column, col, knex, changedProperties);
|
|
@@ -87,26 +136,29 @@ class SchemaHelper {
|
|
|
87
136
|
core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), guard('default'));
|
|
88
137
|
}
|
|
89
138
|
else {
|
|
90
|
-
core_1.Utils.runIfNotEmpty(() => col.defaultTo(
|
|
139
|
+
core_1.Utils.runIfNotEmpty(() => col.defaultTo(knex.raw(column.default)), column.default != null && column.default !== 'null');
|
|
91
140
|
}
|
|
92
141
|
return col;
|
|
93
142
|
}
|
|
94
143
|
getPreAlterTable(tableDiff, safe) {
|
|
95
144
|
return '';
|
|
96
145
|
}
|
|
97
|
-
getAlterColumnAutoincrement(tableName, column) {
|
|
146
|
+
getAlterColumnAutoincrement(tableName, column, schemaName) {
|
|
98
147
|
return '';
|
|
99
148
|
}
|
|
100
|
-
getChangeColumnCommentSQL(tableName, to) {
|
|
149
|
+
getChangeColumnCommentSQL(tableName, to, schemaName) {
|
|
101
150
|
return '';
|
|
102
151
|
}
|
|
152
|
+
async getNamespaces(connection) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
103
155
|
async getColumns(connection, tableName, schemaName) {
|
|
104
156
|
throw new Error('Not supported by given driver');
|
|
105
157
|
}
|
|
106
158
|
async getIndexes(connection, tableName, schemaName) {
|
|
107
159
|
throw new Error('Not supported by given driver');
|
|
108
160
|
}
|
|
109
|
-
async getChecks(connection, tableName, schemaName) {
|
|
161
|
+
async getChecks(connection, tableName, schemaName, columns) {
|
|
110
162
|
throw new Error('Not supported by given driver');
|
|
111
163
|
}
|
|
112
164
|
async mapIndexes(indexes) {
|