@mikro-orm/knex 6.0.0-dev.11 → 6.0.0-dev.110
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 +8 -4
- package/AbstractSqlConnection.js +30 -18
- package/AbstractSqlDriver.d.ts +16 -17
- package/AbstractSqlDriver.js +271 -113
- package/AbstractSqlPlatform.d.ts +5 -4
- package/AbstractSqlPlatform.js +34 -5
- package/MonkeyPatchable.d.ts +1 -0
- package/MonkeyPatchable.js +3 -0
- package/README.md +64 -107
- package/SqlEntityManager.d.ts +2 -6
- package/SqlEntityManager.js +5 -9
- package/SqlEntityRepository.d.ts +7 -6
- package/SqlEntityRepository.js +11 -8
- package/index.mjs +22 -6
- package/package.json +8 -8
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +16 -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 +39 -19
- package/query/QueryBuilder.js +331 -111
- package/query/QueryBuilderHelper.d.ts +9 -13
- package/query/QueryBuilderHelper.js +153 -107
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/query/enums.js +1 -1
- package/schema/DatabaseSchema.d.ts +5 -2
- package/schema/DatabaseSchema.js +26 -8
- package/schema/DatabaseTable.d.ts +4 -2
- package/schema/DatabaseTable.js +54 -29
- package/schema/SchemaComparator.js +12 -2
- package/schema/SchemaHelper.d.ts +6 -4
- package/schema/SchemaHelper.js +11 -4
- package/schema/SqlSchemaGenerator.d.ts +3 -6
- package/schema/SqlSchemaGenerator.js +61 -28
- package/typings.d.ts +13 -7
|
@@ -5,22 +5,12 @@ const core_1 = require("@mikro-orm/core");
|
|
|
5
5
|
const DatabaseSchema_1 = require("./DatabaseSchema");
|
|
6
6
|
const SchemaComparator_1 = require("./SchemaComparator");
|
|
7
7
|
class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this.options = this.config.get('schemaGenerator');
|
|
12
|
-
}
|
|
8
|
+
helper = this.platform.getSchemaHelper();
|
|
9
|
+
options = this.config.get('schemaGenerator');
|
|
10
|
+
lastEnsuredDatabase;
|
|
13
11
|
static register(orm) {
|
|
14
12
|
orm.config.registerExtension('@mikro-orm/schema-generator', () => new SqlSchemaGenerator(orm.em));
|
|
15
13
|
}
|
|
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
14
|
async createSchema(options) {
|
|
25
15
|
await this.ensureDatabase();
|
|
26
16
|
const sql = await this.getCreateSchemaSQL(options);
|
|
@@ -101,7 +91,8 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
101
91
|
await this.ensureDatabase();
|
|
102
92
|
const wrap = options.wrap ?? this.options.disableForeignKeys;
|
|
103
93
|
const metadata = this.getOrderedMetadata(options.schema).reverse();
|
|
104
|
-
const
|
|
94
|
+
const schemas = this.getTargetSchema(options.schema).getNamespaces();
|
|
95
|
+
const schema = await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas);
|
|
105
96
|
let ret = '';
|
|
106
97
|
// remove FKs explicitly if we can't use cascading statement and we don't disable FK checks (we need this for circular relations)
|
|
107
98
|
for (const meta of metadata) {
|
|
@@ -118,6 +109,12 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
118
109
|
for (const meta of metadata) {
|
|
119
110
|
ret += await this.dump(this.dropTable(meta.collection, this.getSchemaName(meta, options)), '\n');
|
|
120
111
|
}
|
|
112
|
+
if (this.platform.supportsNativeEnums()) {
|
|
113
|
+
for (const columnName of Object.keys(schema.getNativeEnums())) {
|
|
114
|
+
const sql = this.helper.getDropNativeEnumSQL(columnName, options.schema ?? this.config.get('schema'));
|
|
115
|
+
ret += await this.dump(this.knex.schema.raw(sql), '\n');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
121
118
|
if (options.dropMigrationsTable) {
|
|
122
119
|
ret += await this.dump(this.dropTable(this.config.get('migrations').tableName, this.config.get('schema')), '\n');
|
|
123
120
|
}
|
|
@@ -140,7 +137,9 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
140
137
|
return this.diffToSQL(diffUp, options);
|
|
141
138
|
}
|
|
142
139
|
async getUpdateSchemaMigrationSQL(options = {}) {
|
|
143
|
-
|
|
140
|
+
if (!options.fromSchema) {
|
|
141
|
+
await this.ensureDatabase();
|
|
142
|
+
}
|
|
144
143
|
const { fromSchema, toSchema } = await this.prepareSchemaForComparison(options);
|
|
145
144
|
const comparator = new SchemaComparator_1.SchemaComparator(this.platform);
|
|
146
145
|
const diffUp = comparator.compare(fromSchema, toSchema);
|
|
@@ -151,14 +150,16 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
151
150
|
};
|
|
152
151
|
}
|
|
153
152
|
async prepareSchemaForComparison(options) {
|
|
154
|
-
options.wrap
|
|
155
|
-
options.safe
|
|
156
|
-
options.dropTables
|
|
153
|
+
options.wrap ??= this.options.disableForeignKeys;
|
|
154
|
+
options.safe ??= false;
|
|
155
|
+
options.dropTables ??= true;
|
|
157
156
|
const toSchema = this.getTargetSchema(options.schema);
|
|
158
|
-
const
|
|
157
|
+
const schemas = toSchema.getNamespaces();
|
|
158
|
+
const fromSchema = options.fromSchema ?? await DatabaseSchema_1.DatabaseSchema.create(this.connection, this.platform, this.config, options.schema, schemas);
|
|
159
159
|
const wildcardSchemaTables = Object.values(this.metadata.getAll()).filter(meta => meta.schema === '*').map(meta => meta.tableName);
|
|
160
160
|
fromSchema.prune(options.schema, wildcardSchemaTables);
|
|
161
161
|
toSchema.prune(options.schema, wildcardSchemaTables);
|
|
162
|
+
toSchema.setNativeEnums(fromSchema.getNativeEnums());
|
|
162
163
|
return { fromSchema, toSchema };
|
|
163
164
|
}
|
|
164
165
|
async diffToSQL(schemaDiff, options) {
|
|
@@ -262,6 +263,12 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
262
263
|
alterTable(diff, safe) {
|
|
263
264
|
const ret = [];
|
|
264
265
|
const [schemaName, tableName] = this.splitTableName(diff.name);
|
|
266
|
+
const changedNativeEnums = [];
|
|
267
|
+
for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
|
|
268
|
+
if (column.nativeEnumName && changedProperties.has('enumItems') && column.nativeEnumName in diff.fromTable.nativeEnums) {
|
|
269
|
+
changedNativeEnums.push([column.nativeEnumName, column.enumItems, diff.fromTable.getColumn(column.name).enumItems]);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
265
272
|
ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
|
|
266
273
|
for (const index of Object.values(diff.removedIndexes)) {
|
|
267
274
|
this.dropIndex(table, index);
|
|
@@ -298,17 +305,20 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
298
305
|
if (changedProperties.size === 1 && changedProperties.has('comment')) {
|
|
299
306
|
continue;
|
|
300
307
|
}
|
|
308
|
+
if (changedProperties.size === 1 && changedProperties.has('enumItems') && column.nativeEnumName) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
301
311
|
const col = this.helper.createTableColumn(table, column, diff.fromTable, changedProperties).alter();
|
|
302
312
|
this.helper.configureColumn(column, col, this.knex, changedProperties);
|
|
303
313
|
}
|
|
304
314
|
for (const { column } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
|
|
305
|
-
this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column));
|
|
315
|
+
this.helper.pushTableQuery(table, this.helper.getAlterColumnAutoincrement(tableName, column, schemaName));
|
|
306
316
|
}
|
|
307
317
|
for (const { column, changedProperties } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('comment'))) {
|
|
308
318
|
if (['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems'].some(t => changedProperties.has(t))) {
|
|
309
319
|
continue; // will be handled via knex
|
|
310
320
|
}
|
|
311
|
-
this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column));
|
|
321
|
+
this.helper.pushTableQuery(table, this.helper.getChangeColumnCommentSQL(tableName, column, schemaName));
|
|
312
322
|
}
|
|
313
323
|
for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
|
|
314
324
|
this.helper.pushTableQuery(table, this.helper.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
|
|
@@ -345,6 +355,13 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
345
355
|
table.comment(comment);
|
|
346
356
|
}
|
|
347
357
|
}));
|
|
358
|
+
if (this.platform.supportsNativeEnums()) {
|
|
359
|
+
changedNativeEnums.forEach(([enumName, itemsNew, itemsOld]) => {
|
|
360
|
+
// postgres allows only adding new items
|
|
361
|
+
const newItems = itemsNew.filter(val => !itemsOld.includes(val));
|
|
362
|
+
ret.push(...newItems.map(val => this.knex.schema.raw(this.helper.getAlterNativeEnumSQL(enumName, schemaName, val))));
|
|
363
|
+
});
|
|
364
|
+
}
|
|
348
365
|
return ret;
|
|
349
366
|
}
|
|
350
367
|
/**
|
|
@@ -356,24 +373,26 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
356
373
|
await this.driver.reconnect();
|
|
357
374
|
}
|
|
358
375
|
async dropDatabase(name) {
|
|
376
|
+
name ??= this.config.get('dbName');
|
|
359
377
|
this.config.set('dbName', this.helper.getManagementDbName());
|
|
360
378
|
await this.driver.reconnect();
|
|
361
379
|
await this.driver.execute(this.helper.getDropDatabaseSQL('' + this.knex.ref(name)));
|
|
362
380
|
}
|
|
363
381
|
async execute(sql, options = {}) {
|
|
364
|
-
options.wrap
|
|
382
|
+
options.wrap ??= false;
|
|
365
383
|
const lines = this.wrapSchema(sql, options).split('\n').filter(i => i.trim());
|
|
366
384
|
if (lines.length === 0) {
|
|
367
385
|
return;
|
|
368
386
|
}
|
|
369
387
|
if (this.platform.supportsMultipleStatements()) {
|
|
370
388
|
const query = lines.join('\n');
|
|
371
|
-
|
|
389
|
+
await this.driver.execute(query);
|
|
390
|
+
return;
|
|
372
391
|
}
|
|
373
392
|
await core_1.Utils.runSerial(lines, line => this.driver.execute(line));
|
|
374
393
|
}
|
|
375
|
-
wrapSchema(sql, options
|
|
376
|
-
options.wrap
|
|
394
|
+
wrapSchema(sql, options) {
|
|
395
|
+
options.wrap ??= this.options.disableForeignKeys;
|
|
377
396
|
if (!options.wrap || sql.trim() === '') {
|
|
378
397
|
return sql;
|
|
379
398
|
}
|
|
@@ -423,7 +442,14 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
423
442
|
table.primary(index.columnNames, keyName);
|
|
424
443
|
}
|
|
425
444
|
else if (index.unique) {
|
|
426
|
-
|
|
445
|
+
// JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
|
|
446
|
+
if (index.columnNames.some(column => column.includes('.'))) {
|
|
447
|
+
const columns = this.platform.getJsonIndexDefinition(index);
|
|
448
|
+
table.index(columns.map(column => this.knex.raw(`(${column})`)), index.keyName, { indexType: 'unique' });
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
table.unique(index.columnNames, { indexName: index.keyName });
|
|
452
|
+
}
|
|
427
453
|
}
|
|
428
454
|
else if (index.expression) {
|
|
429
455
|
this.helper.pushTableQuery(table, index.expression);
|
|
@@ -435,14 +461,21 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
|
|
|
435
461
|
}
|
|
436
462
|
}
|
|
437
463
|
else {
|
|
438
|
-
|
|
464
|
+
// JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
|
|
465
|
+
if (index.columnNames.some(column => column.includes('.'))) {
|
|
466
|
+
const columns = this.platform.getJsonIndexDefinition(index);
|
|
467
|
+
table.index(columns.map(column => this.knex.raw(`(${column})`)), index.keyName, index.type);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
table.index(index.columnNames, index.keyName, index.type);
|
|
471
|
+
}
|
|
439
472
|
}
|
|
440
473
|
}
|
|
441
474
|
dropIndex(table, index, oldIndexName = index.keyName) {
|
|
442
475
|
if (index.primary) {
|
|
443
476
|
table.dropPrimary(oldIndexName);
|
|
444
477
|
}
|
|
445
|
-
else if (index.unique) {
|
|
478
|
+
else if (index.unique && index.constraint) {
|
|
446
479
|
table.dropUnique(index.columnNames, oldIndexName);
|
|
447
480
|
}
|
|
448
481
|
else {
|
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,8 @@ export interface JoinOptions {
|
|
|
25
25
|
path?: string;
|
|
26
26
|
prop: EntityProperty;
|
|
27
27
|
cond: Dictionary;
|
|
28
|
+
cond_?: Dictionary;
|
|
29
|
+
subquery?: string;
|
|
28
30
|
}
|
|
29
31
|
export interface Column {
|
|
30
32
|
name: string;
|
|
@@ -38,6 +40,7 @@ export interface Column {
|
|
|
38
40
|
scale?: number;
|
|
39
41
|
default?: string | null;
|
|
40
42
|
comment?: string;
|
|
43
|
+
nativeEnumName?: string;
|
|
41
44
|
enumItems?: string[];
|
|
42
45
|
primary?: boolean;
|
|
43
46
|
unique?: boolean;
|
|
@@ -58,9 +61,11 @@ export interface IndexDef {
|
|
|
58
61
|
columnNames: string[];
|
|
59
62
|
keyName: string;
|
|
60
63
|
unique: boolean;
|
|
64
|
+
constraint: boolean;
|
|
61
65
|
primary: boolean;
|
|
62
66
|
composite?: boolean;
|
|
63
67
|
expression?: string;
|
|
68
|
+
options?: Dictionary;
|
|
64
69
|
type?: string | Readonly<{
|
|
65
70
|
indexType?: string;
|
|
66
71
|
storageEngineIndexType?: 'hash' | 'btree';
|
|
@@ -122,7 +127,8 @@ export interface IQueryBuilder<T> {
|
|
|
122
127
|
join(field: string, alias: string, cond?: QBFilterQuery, type?: 'leftJoin' | 'innerJoin' | 'pivotJoin', path?: string): this;
|
|
123
128
|
leftJoin(field: string, alias: string, cond?: QBFilterQuery): this;
|
|
124
129
|
joinAndSelect(field: string, alias: string, cond?: QBFilterQuery): this;
|
|
125
|
-
leftJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery): this;
|
|
130
|
+
leftJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery, fields?: string[]): this;
|
|
131
|
+
innerJoinAndSelect(field: string, alias: string, cond?: QBFilterQuery, fields?: string[]): this;
|
|
126
132
|
withSubQuery(subQuery: Knex.QueryBuilder, alias: string): this;
|
|
127
133
|
where(cond: QBFilterQuery<T>, operator?: keyof typeof GroupOperator): this;
|
|
128
134
|
where(cond: string, params?: any[], operator?: keyof typeof GroupOperator): this;
|
|
@@ -136,16 +142,16 @@ export interface IQueryBuilder<T> {
|
|
|
136
142
|
getAliasForJoinPath(path: string): string | undefined;
|
|
137
143
|
getNextAlias(entityName?: string): string;
|
|
138
144
|
}
|
|
139
|
-
export interface ICriteriaNode {
|
|
145
|
+
export interface ICriteriaNode<T extends object> {
|
|
140
146
|
readonly entityName: string;
|
|
141
|
-
readonly parent?: ICriteriaNode | undefined;
|
|
147
|
+
readonly parent?: ICriteriaNode<T> | undefined;
|
|
142
148
|
readonly key?: string | undefined;
|
|
143
149
|
payload: any;
|
|
144
150
|
prop?: EntityProperty;
|
|
145
151
|
index?: number;
|
|
146
|
-
process
|
|
152
|
+
process(qb: IQueryBuilder<T>, alias?: string): any;
|
|
147
153
|
shouldInline(payload: any): boolean;
|
|
148
|
-
willAutoJoin
|
|
154
|
+
willAutoJoin(qb: IQueryBuilder<T>, alias?: string): boolean;
|
|
149
155
|
shouldRename(payload: any): boolean;
|
|
150
156
|
renameFieldToPK<T>(qb: IQueryBuilder<T>): string;
|
|
151
157
|
getPath(addIndex?: boolean): string;
|