@mikro-orm/knex 6.0.0-dev.7 → 6.0.0-dev.71
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 +22 -14
- package/AbstractSqlDriver.d.ts +17 -17
- package/AbstractSqlDriver.js +111 -48
- package/AbstractSqlPlatform.d.ts +1 -0
- package/AbstractSqlPlatform.js +20 -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.d.ts +1 -0
- package/index.js +1 -0
- package/index.mjs +174 -0
- package/package.json +5 -5
- 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 +20 -5
- package/query/QueryBuilder.js +215 -50
- package/query/QueryBuilderHelper.d.ts +3 -5
- package/query/QueryBuilderHelper.js +90 -74
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/schema/DatabaseSchema.d.ts +4 -1
- package/schema/DatabaseSchema.js +22 -6
- package/schema/DatabaseTable.d.ts +10 -9
- package/schema/DatabaseTable.js +25 -24
- package/schema/SchemaComparator.d.ts +4 -4
- package/schema/SchemaComparator.js +9 -2
- package/schema/SchemaHelper.d.ts +14 -12
- package/schema/SchemaHelper.js +10 -4
- package/schema/SqlSchemaGenerator.d.ts +2 -4
- package/schema/SqlSchemaGenerator.js +40 -20
- package/typings.d.ts +15 -13
|
@@ -19,6 +19,10 @@ class QueryBuilderHelper {
|
|
|
19
19
|
this.metadata = this.driver.getMetadata();
|
|
20
20
|
}
|
|
21
21
|
mapper(field, type = enums_1.QueryType.SELECT, value, alias) {
|
|
22
|
+
if (core_1.Utils.isRawSql(field)) {
|
|
23
|
+
return this.knex.raw(field.sql, field.params);
|
|
24
|
+
}
|
|
25
|
+
/* istanbul ignore next */
|
|
22
26
|
if (typeof field !== 'string') {
|
|
23
27
|
return field;
|
|
24
28
|
}
|
|
@@ -36,12 +40,26 @@ class QueryBuilderHelper {
|
|
|
36
40
|
parts.push(this.mapper(a !== this.alias ? `${a}.${f}` : f, type, value, alias));
|
|
37
41
|
}
|
|
38
42
|
}
|
|
43
|
+
// flatten the value if we see we are expanding nested composite key
|
|
44
|
+
// hackish, but cleaner solution would require quite a lot of refactoring
|
|
45
|
+
if (fields.length !== parts.length && Array.isArray(value)) {
|
|
46
|
+
value.forEach(row => {
|
|
47
|
+
if (Array.isArray(row)) {
|
|
48
|
+
const tmp = core_1.Utils.flatten(row);
|
|
49
|
+
row.length = 0;
|
|
50
|
+
row.push(...tmp);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
39
54
|
return this.knex.raw('(' + parts.map(part => this.knex.ref(part)).join(', ') + ')');
|
|
40
55
|
}
|
|
41
|
-
|
|
42
|
-
|
|
56
|
+
const rawField = core_1.RawQueryFragment.getKnownFragment(field);
|
|
57
|
+
if (rawField) {
|
|
58
|
+
return this.knex.raw(rawField.sql, rawField.params);
|
|
59
|
+
}
|
|
43
60
|
const [a, f] = this.splitField(field);
|
|
44
61
|
const prop = this.getProperty(f, a);
|
|
62
|
+
let ret = field;
|
|
45
63
|
// embeddable nested path instead of a regular property with table alias, reset alias
|
|
46
64
|
if (prop?.name === a && prop.embeddedProps[f]) {
|
|
47
65
|
return this.alias + '.' + prop.fieldNames[0];
|
|
@@ -56,7 +74,7 @@ class QueryBuilderHelper {
|
|
|
56
74
|
const as = alias === null ? '' : ` as ${aliased}`;
|
|
57
75
|
return this.knex.raw(`${prop.formula(alias2)}${as}`);
|
|
58
76
|
}
|
|
59
|
-
if (prop?.
|
|
77
|
+
if (prop?.hasConvertToJSValueSQL) {
|
|
60
78
|
const prefixed = this.prefix(field, isTableNameAliasRequired, true);
|
|
61
79
|
const valueSQL = prop.customType.convertToJSValueSQL(prefixed, this.platform);
|
|
62
80
|
if (alias === null) {
|
|
@@ -65,15 +83,12 @@ class QueryBuilderHelper {
|
|
|
65
83
|
return this.knex.raw(`${valueSQL} as ${this.platform.quoteIdentifier(alias ?? prop.fieldNames[0])}`);
|
|
66
84
|
}
|
|
67
85
|
// do not wrap custom expressions
|
|
68
|
-
if (!
|
|
86
|
+
if (!rawField) {
|
|
69
87
|
ret = this.prefix(field);
|
|
70
88
|
}
|
|
71
89
|
if (alias) {
|
|
72
90
|
ret += ' as ' + alias;
|
|
73
91
|
}
|
|
74
|
-
if (customExpression) {
|
|
75
|
-
return this.knex.raw(ret, value);
|
|
76
|
-
}
|
|
77
92
|
if (!isTableNameAliasRequired || this.isPrefixed(ret) || noPrefix) {
|
|
78
93
|
return ret;
|
|
79
94
|
}
|
|
@@ -162,6 +177,11 @@ class QueryBuilderHelper {
|
|
|
162
177
|
const right = `${join.alias}.${join.joinColumns[idx]}`;
|
|
163
178
|
conditions.push(`${this.knex.ref(left)} = ${this.knex.ref(right)}`);
|
|
164
179
|
});
|
|
180
|
+
if (join.prop.targetMeta.discriminatorValue && !join.path?.endsWith('[pivot]')) {
|
|
181
|
+
const typeProperty = join.prop.targetMeta.root.discriminatorColumn;
|
|
182
|
+
const alias = !join.prop.owner ? join.inverseAlias ?? join.alias : join.ownerAlias;
|
|
183
|
+
join.cond[`${alias}.${typeProperty}`] = join.prop.targetMeta.discriminatorValue;
|
|
184
|
+
}
|
|
165
185
|
Object.keys(join.cond).forEach(key => {
|
|
166
186
|
conditions.push(this.processJoinClause(key, join.cond[key], params));
|
|
167
187
|
});
|
|
@@ -212,20 +232,14 @@ class QueryBuilderHelper {
|
|
|
212
232
|
if (operator === '$exists') {
|
|
213
233
|
value = null;
|
|
214
234
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const { sql, bindings } = k.toSQL().toNative();
|
|
223
|
-
if (params2.length > 0) {
|
|
224
|
-
params.push(...bindings);
|
|
225
|
-
params.push(...params2);
|
|
226
|
-
return sql + ' = ?';
|
|
235
|
+
const rawField = core_1.RawQueryFragment.getKnownFragment(key);
|
|
236
|
+
if (rawField) {
|
|
237
|
+
let sql = rawField.sql;
|
|
238
|
+
params.push(...rawField.params);
|
|
239
|
+
params.push(...core_1.Utils.asArray(value));
|
|
240
|
+
if (core_1.Utils.asArray(value).length > 0) {
|
|
241
|
+
sql += ' = ?';
|
|
227
242
|
}
|
|
228
|
-
params.push(...bindings);
|
|
229
243
|
return sql;
|
|
230
244
|
}
|
|
231
245
|
const sql = this.mapper(key);
|
|
@@ -241,7 +255,7 @@ class QueryBuilderHelper {
|
|
|
241
255
|
return `(${parts.join(` ${core_1.GroupOperator[operator]} `)})`;
|
|
242
256
|
}
|
|
243
257
|
mapJoinColumns(type, join) {
|
|
244
|
-
if (join.prop && join.prop.
|
|
258
|
+
if (join.prop && join.prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !join.prop.owner) {
|
|
245
259
|
return join.prop.fieldNames.map((fieldName, idx) => {
|
|
246
260
|
return this.mapper(`${join.alias}.${join.inverseJoinColumns[idx]}`, type, undefined, fieldName);
|
|
247
261
|
});
|
|
@@ -254,7 +268,7 @@ class QueryBuilderHelper {
|
|
|
254
268
|
isOneToOneInverse(field) {
|
|
255
269
|
const meta = this.metadata.find(this.entityName);
|
|
256
270
|
const prop = meta.properties[field];
|
|
257
|
-
return prop && prop.
|
|
271
|
+
return prop && prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner;
|
|
258
272
|
}
|
|
259
273
|
getTableName(entityName) {
|
|
260
274
|
const meta = this.metadata.find(entityName);
|
|
@@ -293,13 +307,13 @@ class QueryBuilderHelper {
|
|
|
293
307
|
}
|
|
294
308
|
appendOnConflictClause(type, onConflict, qb) {
|
|
295
309
|
onConflict.forEach(item => {
|
|
296
|
-
const sub = qb.onConflict(item.fields);
|
|
310
|
+
const sub = item.fields.length > 0 ? qb.onConflict(item.fields) : qb.onConflict();
|
|
297
311
|
core_1.Utils.runIfNotEmpty(() => sub.ignore(), item.ignore);
|
|
298
312
|
core_1.Utils.runIfNotEmpty(() => {
|
|
299
313
|
let mergeParam = item.merge;
|
|
300
314
|
if (core_1.Utils.isObject(item.merge)) {
|
|
301
315
|
mergeParam = {};
|
|
302
|
-
|
|
316
|
+
core_1.Utils.keys(item.merge).forEach(key => {
|
|
303
317
|
const k = this.mapper(key, type);
|
|
304
318
|
mergeParam[k] = item.merge[key];
|
|
305
319
|
});
|
|
@@ -336,28 +350,20 @@ class QueryBuilderHelper {
|
|
|
336
350
|
if (core_1.Utils.isPlainObject(cond[key]) || cond[key] instanceof RegExp) {
|
|
337
351
|
return this.processObjectSubCondition(cond, key, qb, method, m, type);
|
|
338
352
|
}
|
|
339
|
-
if (QueryBuilderHelper.isCustomExpression(key)) {
|
|
340
|
-
return this.processCustomExpression(qb, m, key, cond, type);
|
|
341
|
-
}
|
|
342
353
|
const op = cond[key] === null ? 'is' : '=';
|
|
354
|
+
const raw = core_1.RawQueryFragment.getKnownFragment(key);
|
|
355
|
+
if (raw) {
|
|
356
|
+
const value = core_1.Utils.asArray(cond[key]);
|
|
357
|
+
if (value.length > 0) {
|
|
358
|
+
return void qb[m](this.knex.raw(raw.sql, raw.params), op, value[0]);
|
|
359
|
+
}
|
|
360
|
+
return void qb[m](this.knex.raw(raw.sql, raw.params));
|
|
361
|
+
}
|
|
343
362
|
if (this.subQueries[key]) {
|
|
344
363
|
return void qb[m](this.knex.raw(`(${this.subQueries[key]})`), op, cond[key]);
|
|
345
364
|
}
|
|
346
365
|
qb[m](this.mapper(key, type, cond[key], null), op, cond[key]);
|
|
347
366
|
}
|
|
348
|
-
processCustomExpression(clause, m, key, cond, type) {
|
|
349
|
-
// unwind parameters when ? found in field name
|
|
350
|
-
const count = key.concat('?').match(/\?/g).length - 1;
|
|
351
|
-
const value = core_1.Utils.asArray(cond[key]);
|
|
352
|
-
const params1 = value.slice(0, count).map((c) => core_1.Utils.isObject(c) ? JSON.stringify(c) : c);
|
|
353
|
-
const params2 = value.slice(count);
|
|
354
|
-
const k = this.mapper(key, type, params1);
|
|
355
|
-
if (params2.length > 0) {
|
|
356
|
-
const val = params2.length === 1 && params2[0] === null ? null : this.knex.raw('?', params2);
|
|
357
|
-
return void clause[m](k, val);
|
|
358
|
-
}
|
|
359
|
-
clause[m](k);
|
|
360
|
-
}
|
|
361
367
|
processObjectSubCondition(cond, key, qb, method, m, type) {
|
|
362
368
|
// grouped condition for one field
|
|
363
369
|
let value = cond[key];
|
|
@@ -394,7 +400,8 @@ class QueryBuilderHelper {
|
|
|
394
400
|
}));
|
|
395
401
|
}
|
|
396
402
|
else {
|
|
397
|
-
|
|
403
|
+
const mappedKey = this.mapper(key, type, value[op], null);
|
|
404
|
+
qb[m](mappedKey, replacement, value[op]);
|
|
398
405
|
}
|
|
399
406
|
}
|
|
400
407
|
getOperatorReplacement(op, value) {
|
|
@@ -422,20 +429,21 @@ class QueryBuilderHelper {
|
|
|
422
429
|
}
|
|
423
430
|
getQueryOrderFromObject(type, orderBy, populate) {
|
|
424
431
|
const ret = [];
|
|
425
|
-
Object.keys(orderBy).forEach(
|
|
426
|
-
const direction = orderBy[
|
|
432
|
+
Object.keys(orderBy).forEach(key => {
|
|
433
|
+
const direction = orderBy[key];
|
|
427
434
|
const order = core_1.Utils.isNumber(direction) ? core_1.QueryOrderNumeric[direction] : direction;
|
|
428
|
-
|
|
429
|
-
|
|
435
|
+
const raw = core_1.RawQueryFragment.getKnownFragment(key);
|
|
436
|
+
if (raw) {
|
|
437
|
+
ret.push(`${this.platform.formatQuery(raw.sql, raw.params)} ${order.toLowerCase()}`);
|
|
430
438
|
return;
|
|
431
439
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const prop = this.getProperty(
|
|
437
|
-
const noPrefix = (prop && prop.persist === false && !prop.formula) ||
|
|
438
|
-
const column = this.mapper(noPrefix ?
|
|
440
|
+
core_1.Utils.splitPrimaryKeys(key).forEach(f => {
|
|
441
|
+
// eslint-disable-next-line prefer-const
|
|
442
|
+
let [alias, field] = this.splitField(f, true);
|
|
443
|
+
alias = populate[alias] || alias;
|
|
444
|
+
const prop = this.getProperty(field, alias);
|
|
445
|
+
const noPrefix = (prop && prop.persist === false && !prop.formula) || core_1.RawQueryFragment.isKnownFragment(f);
|
|
446
|
+
const column = this.mapper(noPrefix ? field : `${alias}.${field}`, type, undefined, null);
|
|
439
447
|
/* istanbul ignore next */
|
|
440
448
|
const rawColumn = core_1.Utils.isString(column) ? column.split('.').map(e => this.knex.ref(e)).join('.') : column;
|
|
441
449
|
const customOrder = prop?.customOrder;
|
|
@@ -447,11 +455,23 @@ class QueryBuilderHelper {
|
|
|
447
455
|
});
|
|
448
456
|
return ret.join(', ');
|
|
449
457
|
}
|
|
450
|
-
finalize(type, qb, meta) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
458
|
+
finalize(type, qb, meta, data) {
|
|
459
|
+
if (!meta || !data || !this.platform.usesReturningStatement()) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (type === enums_1.QueryType.INSERT) {
|
|
463
|
+
const returningProps = meta.hydrateProps
|
|
464
|
+
.filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw))
|
|
465
|
+
.filter(prop => !(prop.name in data) || core_1.Utils.isRawSql(data[prop.name]));
|
|
466
|
+
if (returningProps.length > 0) {
|
|
467
|
+
qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (type === enums_1.QueryType.UPDATE) {
|
|
471
|
+
const returningProps = meta.hydrateProps.filter(prop => core_1.Utils.isRawSql(data[prop.name]));
|
|
472
|
+
if (returningProps.length > 0) {
|
|
473
|
+
qb.returning(core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames)));
|
|
474
|
+
}
|
|
455
475
|
}
|
|
456
476
|
}
|
|
457
477
|
splitField(field, greedyAlias = false) {
|
|
@@ -494,18 +514,13 @@ class QueryBuilderHelper {
|
|
|
494
514
|
}
|
|
495
515
|
qb.update(versionProperty.fieldNames[0], this.knex.raw(sql));
|
|
496
516
|
}
|
|
497
|
-
static isCustomExpression(field, hasAlias = false) {
|
|
498
|
-
// if we do not have alias, we don't consider spaces as custom expressions
|
|
499
|
-
const re = hasAlias ? /[ ?<>=()'"`:]|^\d/ : /[?<>=()'"`:]|^\d/;
|
|
500
|
-
return !!field.match(re);
|
|
501
|
-
}
|
|
502
517
|
prefix(field, always = false, quote = false) {
|
|
503
518
|
let ret;
|
|
504
519
|
if (!this.isPrefixed(field)) {
|
|
505
520
|
const alias = always ? (quote ? this.alias : this.platform.quoteIdentifier(this.alias)) + '.' : '';
|
|
506
521
|
const fieldName = this.fieldName(field, this.alias, always);
|
|
507
|
-
if (
|
|
508
|
-
return fieldName;
|
|
522
|
+
if (fieldName instanceof core_1.RawQueryFragment) {
|
|
523
|
+
return fieldName.sql;
|
|
509
524
|
}
|
|
510
525
|
ret = alias + fieldName;
|
|
511
526
|
}
|
|
@@ -545,15 +560,15 @@ class QueryBuilderHelper {
|
|
|
545
560
|
}
|
|
546
561
|
if (prop.fieldNameRaw) {
|
|
547
562
|
if (!always) {
|
|
548
|
-
return prop.fieldNameRaw
|
|
549
|
-
.replace(
|
|
550
|
-
.replace(this.platform.quoteIdentifier('') + '.', '');
|
|
563
|
+
return (0, core_1.raw)(prop.fieldNameRaw
|
|
564
|
+
.replace(new RegExp(core_1.ALIAS_REPLACEMENT_RE + '\\.?', 'g'), '')
|
|
565
|
+
.replace(this.platform.quoteIdentifier('') + '.', ''));
|
|
551
566
|
}
|
|
552
567
|
if (alias) {
|
|
553
|
-
return prop.fieldNameRaw.replace(
|
|
568
|
+
return (0, core_1.raw)(prop.fieldNameRaw.replace(new RegExp(core_1.ALIAS_REPLACEMENT_RE, 'g'), alias));
|
|
554
569
|
}
|
|
555
570
|
/* istanbul ignore next */
|
|
556
|
-
return prop.fieldNameRaw;
|
|
571
|
+
return (0, core_1.raw)(prop.fieldNameRaw);
|
|
557
572
|
}
|
|
558
573
|
/* istanbul ignore next */
|
|
559
574
|
return prop.fieldNames?.[0] ?? field;
|
|
@@ -564,7 +579,7 @@ class QueryBuilderHelper {
|
|
|
564
579
|
// check if `alias` is not matching an embedded property name instead of alias, e.g. `address.city`
|
|
565
580
|
if (alias && meta) {
|
|
566
581
|
const prop = meta.properties[alias];
|
|
567
|
-
if (prop?.
|
|
582
|
+
if (prop?.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
568
583
|
// we want to select the full object property so hydration works as expected
|
|
569
584
|
if (prop.object) {
|
|
570
585
|
return prop;
|
|
@@ -596,17 +611,18 @@ class QueryBuilderHelper {
|
|
|
596
611
|
return;
|
|
597
612
|
}
|
|
598
613
|
if (prop.joinColumns && Array.isArray(data[k])) {
|
|
599
|
-
const copy = data[k];
|
|
614
|
+
const copy = core_1.Utils.flatten(data[k]);
|
|
600
615
|
delete data[k];
|
|
601
616
|
prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
|
|
602
617
|
return;
|
|
603
618
|
}
|
|
604
619
|
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' });
|
|
620
|
+
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, { fromQuery: true, key: k, mode: 'query-data' });
|
|
606
621
|
}
|
|
607
|
-
if (prop.
|
|
622
|
+
if (prop.hasConvertToDatabaseValueSQL && !this.platform.isRaw(data[k])) {
|
|
608
623
|
const quoted = this.platform.quoteValue(data[k]);
|
|
609
|
-
|
|
624
|
+
const sql = prop.customType.convertToDatabaseValueSQL(quoted, this.platform);
|
|
625
|
+
data[k] = this.knex.raw(sql.replace(/\?/, '\\?'));
|
|
610
626
|
}
|
|
611
627
|
if (!prop.customType && (Array.isArray(data[k]) || core_1.Utils.isPlainObject(data[k]))) {
|
|
612
628
|
data[k] = JSON.stringify(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
|
}
|
|
@@ -10,14 +10,17 @@ export declare class DatabaseSchema {
|
|
|
10
10
|
readonly name: string;
|
|
11
11
|
private tables;
|
|
12
12
|
private namespaces;
|
|
13
|
+
private nativeEnums;
|
|
13
14
|
constructor(platform: AbstractSqlPlatform, name: string);
|
|
14
15
|
addTable(name: string, schema: string | undefined | null, comment?: string): DatabaseTable;
|
|
15
16
|
getTables(): DatabaseTable[];
|
|
16
17
|
getTable(name: string): DatabaseTable | undefined;
|
|
17
18
|
hasTable(name: string): boolean;
|
|
19
|
+
setNativeEnums(nativeEnums: Dictionary<unknown[]>): void;
|
|
20
|
+
getNativeEnums(): Dictionary<unknown[]>;
|
|
18
21
|
hasNamespace(namespace: string): boolean;
|
|
19
22
|
getNamespaces(): string[];
|
|
20
|
-
static create(connection: AbstractSqlConnection, platform: AbstractSqlPlatform, config: Configuration, schemaName?: string): Promise<DatabaseSchema>;
|
|
23
|
+
static create(connection: AbstractSqlConnection, platform: AbstractSqlPlatform, config: Configuration, schemaName?: string, schemas?: string[]): Promise<DatabaseSchema>;
|
|
21
24
|
static fromMetadata(metadata: EntityMetadata[], platform: AbstractSqlPlatform, config: Configuration, schemaName?: string): DatabaseSchema;
|
|
22
25
|
private static getSchemaName;
|
|
23
26
|
private static shouldHaveColumn;
|
package/schema/DatabaseSchema.js
CHANGED
|
@@ -12,10 +12,12 @@ class DatabaseSchema {
|
|
|
12
12
|
this.name = name;
|
|
13
13
|
this.tables = [];
|
|
14
14
|
this.namespaces = new Set();
|
|
15
|
+
this.nativeEnums = {}; // for postgres
|
|
15
16
|
}
|
|
16
17
|
addTable(name, schema, comment) {
|
|
17
18
|
const namespaceName = schema ?? this.name;
|
|
18
19
|
const table = new DatabaseTable_1.DatabaseTable(this.platform, name, namespaceName);
|
|
20
|
+
table.nativeEnums = this.nativeEnums;
|
|
19
21
|
table.comment = comment;
|
|
20
22
|
this.tables.push(table);
|
|
21
23
|
if (namespaceName != null) {
|
|
@@ -32,24 +34,38 @@ class DatabaseSchema {
|
|
|
32
34
|
hasTable(name) {
|
|
33
35
|
return !!this.getTable(name);
|
|
34
36
|
}
|
|
37
|
+
setNativeEnums(nativeEnums) {
|
|
38
|
+
this.nativeEnums = nativeEnums;
|
|
39
|
+
this.tables.forEach(t => t.nativeEnums = nativeEnums);
|
|
40
|
+
}
|
|
41
|
+
getNativeEnums() {
|
|
42
|
+
return this.nativeEnums;
|
|
43
|
+
}
|
|
35
44
|
hasNamespace(namespace) {
|
|
36
45
|
return this.namespaces.has(namespace);
|
|
37
46
|
}
|
|
38
47
|
getNamespaces() {
|
|
39
48
|
return [...this.namespaces];
|
|
40
49
|
}
|
|
41
|
-
static async create(connection, platform, config, schemaName) {
|
|
42
|
-
const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema'));
|
|
50
|
+
static async create(connection, platform, config, schemaName, schemas) {
|
|
51
|
+
const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema') ?? platform.getDefaultSchemaName());
|
|
43
52
|
const allTables = await connection.execute(platform.getSchemaHelper().getListTablesSQL());
|
|
44
53
|
const parts = config.get('migrations').tableName.split('.');
|
|
45
54
|
const migrationsTableName = parts[1] ?? parts[0];
|
|
46
55
|
const migrationsSchemaName = parts.length > 1 ? parts[0] : config.get('schema', platform.getDefaultSchemaName());
|
|
47
56
|
const tables = allTables.filter(t => t.table_name !== migrationsTableName || (t.schema_name && t.schema_name !== migrationsSchemaName));
|
|
48
|
-
await platform.getSchemaHelper().loadInformationSchema(schema, connection, tables);
|
|
57
|
+
await platform.getSchemaHelper().loadInformationSchema(schema, connection, tables, schemas && schemas.length > 0 ? schemas : undefined);
|
|
49
58
|
return schema;
|
|
50
59
|
}
|
|
51
60
|
static fromMetadata(metadata, platform, config, schemaName) {
|
|
52
61
|
const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema'));
|
|
62
|
+
const nativeEnums = {};
|
|
63
|
+
for (const meta of metadata) {
|
|
64
|
+
meta.props
|
|
65
|
+
.filter(prop => prop.nativeEnumName)
|
|
66
|
+
.forEach(prop => nativeEnums[prop.nativeEnumName] = prop.items?.map(val => '' + val) ?? []);
|
|
67
|
+
}
|
|
68
|
+
schema.setNativeEnums(nativeEnums);
|
|
53
69
|
for (const meta of metadata) {
|
|
54
70
|
const table = schema.addTable(meta.collection, this.getSchemaName(meta, config, schemaName));
|
|
55
71
|
table.comment = meta.comment;
|
|
@@ -78,15 +94,15 @@ class DatabaseSchema {
|
|
|
78
94
|
if (prop.persist === false || !prop.fieldNames) {
|
|
79
95
|
return false;
|
|
80
96
|
}
|
|
81
|
-
if (meta.pivotTable || (core_1.
|
|
97
|
+
if (meta.pivotTable || (core_1.ReferenceKind.EMBEDDED && prop.object)) {
|
|
82
98
|
return true;
|
|
83
99
|
}
|
|
84
100
|
const getRootProperty = (prop) => prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop;
|
|
85
101
|
const rootProp = getRootProperty(prop);
|
|
86
|
-
if (rootProp.
|
|
102
|
+
if (rootProp.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
87
103
|
return prop === rootProp || !rootProp.object;
|
|
88
104
|
}
|
|
89
|
-
return [core_1.
|
|
105
|
+
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
106
|
}
|
|
91
107
|
toJSON() {
|
|
92
108
|
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
|
|
@@ -13,13 +13,14 @@ export declare class DatabaseTable {
|
|
|
13
13
|
private indexes;
|
|
14
14
|
private checks;
|
|
15
15
|
private foreignKeys;
|
|
16
|
+
nativeEnums: Dictionary<unknown[]>;
|
|
16
17
|
comment?: string;
|
|
17
18
|
constructor(platform: AbstractSqlPlatform, name: string, schema?: string | undefined);
|
|
18
19
|
getColumns(): Column[];
|
|
19
20
|
getColumn(name: string): Column | undefined;
|
|
20
|
-
getIndexes():
|
|
21
|
-
getChecks():
|
|
22
|
-
init(cols: Column[], indexes:
|
|
21
|
+
getIndexes(): IndexDef[];
|
|
22
|
+
getChecks(): CheckDef[];
|
|
23
|
+
init(cols: Column[], indexes: IndexDef[] | undefined, checks: CheckDef<unknown>[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
|
|
23
24
|
addColumn(column: Column): void;
|
|
24
25
|
addColumnFromProperty(prop: EntityProperty, meta: EntityMetadata): void;
|
|
25
26
|
private getIndexName;
|
|
@@ -30,14 +31,14 @@ export declare class DatabaseTable {
|
|
|
30
31
|
getShortestName(): string;
|
|
31
32
|
getForeignKeys(): Dictionary<ForeignKey>;
|
|
32
33
|
hasColumn(columnName: string): boolean;
|
|
33
|
-
getIndex(indexName: string):
|
|
34
|
+
getIndex(indexName: string): IndexDef | undefined;
|
|
34
35
|
hasIndex(indexName: string): boolean;
|
|
35
|
-
getCheck(checkName: string):
|
|
36
|
+
getCheck(checkName: string): CheckDef<unknown> | undefined;
|
|
36
37
|
hasCheck(checkName: string): boolean;
|
|
37
|
-
getPrimaryKey():
|
|
38
|
+
getPrimaryKey(): IndexDef | undefined;
|
|
38
39
|
hasPrimaryKey(): boolean;
|
|
39
40
|
private getPropertyDeclaration;
|
|
40
|
-
private
|
|
41
|
+
private getReferenceKind;
|
|
41
42
|
private getPropertyName;
|
|
42
43
|
private getPropertyType;
|
|
43
44
|
private getPropertyDefaultValue;
|
|
@@ -48,6 +49,6 @@ export declare class DatabaseTable {
|
|
|
48
49
|
expression?: string;
|
|
49
50
|
options?: Dictionary;
|
|
50
51
|
}, type: 'index' | 'unique' | 'primary'): void;
|
|
51
|
-
addCheck(check:
|
|
52
|
+
addCheck(check: CheckDef): void;
|
|
52
53
|
toJSON(): Dictionary;
|
|
53
54
|
}
|