@mikro-orm/knex 7.0.0-dev.1 → 7.0.0-dev.10
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 +2 -2
- package/AbstractSqlConnection.js +33 -31
- package/AbstractSqlDriver.d.ts +14 -12
- package/AbstractSqlDriver.js +198 -186
- package/AbstractSqlPlatform.d.ts +4 -4
- package/AbstractSqlPlatform.js +17 -21
- package/PivotCollectionPersister.d.ts +1 -1
- package/PivotCollectionPersister.js +5 -8
- package/SqlEntityManager.d.ts +4 -3
- package/SqlEntityManager.js +2 -6
- package/SqlEntityRepository.d.ts +2 -2
- package/SqlEntityRepository.js +2 -6
- package/dialects/index.d.ts +4 -4
- package/dialects/index.js +4 -20
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +29 -29
- package/dialects/mssql/index.d.ts +1 -1
- package/dialects/mssql/index.js +1 -17
- package/dialects/mysql/MySqlExceptionConverter.js +16 -19
- package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/mysql/MySqlNativeQueryBuilder.js +13 -17
- package/dialects/mysql/MySqlPlatform.d.ts +5 -5
- package/dialects/mysql/MySqlPlatform.js +16 -20
- package/dialects/mysql/MySqlSchemaHelper.d.ts +5 -5
- package/dialects/mysql/MySqlSchemaHelper.js +8 -12
- package/dialects/mysql/index.d.ts +4 -4
- package/dialects/mysql/index.js +4 -20
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +2 -6
- package/dialects/postgresql/index.d.ts +1 -1
- package/dialects/postgresql/index.js +1 -17
- package/dialects/sqlite/BaseSqliteConnection.d.ts +2 -2
- package/dialects/sqlite/BaseSqliteConnection.js +14 -12
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +4 -5
- package/dialects/sqlite/BaseSqlitePlatform.js +11 -19
- package/dialects/sqlite/SqliteExceptionConverter.js +16 -19
- package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +1 -1
- package/dialects/sqlite/SqliteNativeQueryBuilder.js +2 -6
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +5 -5
- package/dialects/sqlite/SqliteSchemaHelper.js +22 -26
- package/dialects/sqlite/index.d.ts +5 -5
- package/dialects/sqlite/index.js +5 -21
- package/index.d.ts +11 -11
- package/index.js +13 -34
- package/package.json +7 -16
- package/query/ArrayCriteriaNode.d.ts +2 -2
- package/query/ArrayCriteriaNode.js +2 -6
- package/query/CriteriaNode.d.ts +1 -1
- package/query/CriteriaNode.js +25 -33
- package/query/CriteriaNodeFactory.d.ts +1 -1
- package/query/CriteriaNodeFactory.js +17 -21
- package/query/NativeQueryBuilder.d.ts +2 -2
- package/query/NativeQueryBuilder.js +33 -37
- package/query/ObjectCriteriaNode.d.ts +2 -2
- package/query/ObjectCriteriaNode.js +43 -43
- package/query/QueryBuilder.d.ts +17 -15
- package/query/QueryBuilder.js +204 -193
- package/query/QueryBuilderHelper.d.ts +4 -4
- package/query/QueryBuilderHelper.js +86 -96
- package/query/ScalarCriteriaNode.d.ts +2 -2
- package/query/ScalarCriteriaNode.js +12 -16
- package/query/enums.js +4 -7
- package/query/index.d.ts +9 -9
- package/query/index.js +9 -25
- package/schema/DatabaseSchema.d.ts +3 -3
- package/schema/DatabaseSchema.js +7 -11
- package/schema/DatabaseTable.d.ts +3 -3
- package/schema/DatabaseTable.js +44 -33
- package/schema/SchemaComparator.d.ts +4 -4
- package/schema/SchemaComparator.js +15 -19
- package/schema/SchemaHelper.d.ts +5 -5
- package/schema/SchemaHelper.js +22 -26
- package/schema/SqlSchemaGenerator.d.ts +4 -4
- package/schema/SqlSchemaGenerator.js +23 -36
- package/schema/index.d.ts +5 -5
- package/schema/index.js +5 -21
- package/typings.d.ts +7 -4
- package/typings.js +1 -2
- package/index.mjs +0 -232
package/AbstractSqlDriver.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
9
|
-
[core_1.EntityManagerType];
|
|
1
|
+
import { ALIAS_REPLACEMENT_RE, DatabaseDriver, EntityManagerType, getOnConflictFields, getOnConflictReturningFields, helper, isRaw, LoadStrategy, parseJsonSafe, QueryFlag, QueryHelper, QueryOrder, raw, RawQueryFragment, ReferenceKind, Utils, } from '@mikro-orm/core';
|
|
2
|
+
import { QueryBuilder } from './query/QueryBuilder.js';
|
|
3
|
+
import { JoinType, QueryType } from './query/enums.js';
|
|
4
|
+
import { SqlEntityManager } from './SqlEntityManager.js';
|
|
5
|
+
import { PivotCollectionPersister } from './PivotCollectionPersister.js';
|
|
6
|
+
export class AbstractSqlDriver extends DatabaseDriver {
|
|
7
|
+
[EntityManagerType];
|
|
10
8
|
connection;
|
|
11
9
|
replicas = [];
|
|
12
10
|
platform;
|
|
@@ -20,7 +18,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
20
18
|
return this.platform;
|
|
21
19
|
}
|
|
22
20
|
createEntityManager(useContext) {
|
|
23
|
-
const EntityManagerClass = this.config.get('entityManager',
|
|
21
|
+
const EntityManagerClass = this.config.get('entityManager', SqlEntityManager);
|
|
24
22
|
return new EntityManagerClass(this.config, this, this.metadata, useContext);
|
|
25
23
|
}
|
|
26
24
|
async find(entityName, where, options = {}) {
|
|
@@ -35,9 +33,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
35
33
|
const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options);
|
|
36
34
|
const orderBy = this.buildOrderBy(qb, meta, populate, options);
|
|
37
35
|
const populateWhere = this.buildPopulateWhere(meta, joinedProps, options);
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
where = { [
|
|
36
|
+
Utils.asArray(options.flags).forEach(flag => qb.setFlag(flag));
|
|
37
|
+
if (Utils.isPrimaryKey(where, meta.compositePK)) {
|
|
38
|
+
where = { [Utils.getPrimaryKeyHash(meta.primaryKeys)]: where };
|
|
41
39
|
}
|
|
42
40
|
const { first, last, before, after } = options;
|
|
43
41
|
const isCursorPagination = [first, last, before, after].some(v => v != null);
|
|
@@ -65,6 +63,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
65
63
|
if (options.lockMode) {
|
|
66
64
|
qb.setLockMode(options.lockMode, options.lockTableAliases);
|
|
67
65
|
}
|
|
66
|
+
if (options.em) {
|
|
67
|
+
await qb.applyJoinedFilters(options.em, options.filters);
|
|
68
|
+
}
|
|
68
69
|
const result = await this.rethrow(qb.execute('all'));
|
|
69
70
|
if (isCursorPagination && !first && !!last) {
|
|
70
71
|
result.reverse();
|
|
@@ -80,9 +81,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
80
81
|
if (joinedProps.length === 0 || !hasToManyJoins) {
|
|
81
82
|
opts.limit = 1;
|
|
82
83
|
}
|
|
83
|
-
if (opts.limit > 0 && !opts.flags?.includes(
|
|
84
|
+
if (opts.limit > 0 && !opts.flags?.includes(QueryFlag.DISABLE_PAGINATE)) {
|
|
84
85
|
opts.flags ??= [];
|
|
85
|
-
opts.flags.push(
|
|
86
|
+
opts.flags.push(QueryFlag.DISABLE_PAGINATE);
|
|
86
87
|
}
|
|
87
88
|
const res = await this.find(entityName, where, opts);
|
|
88
89
|
return res[0] || null;
|
|
@@ -90,7 +91,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
90
91
|
hasToManyJoins(hint, meta) {
|
|
91
92
|
const [propName] = hint.field.split(':', 2);
|
|
92
93
|
const prop = meta.properties[propName];
|
|
93
|
-
if (prop && [
|
|
94
|
+
if (prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
94
95
|
return true;
|
|
95
96
|
}
|
|
96
97
|
if (hint.children && prop.targetMeta) {
|
|
@@ -99,16 +100,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
99
100
|
return false;
|
|
100
101
|
}
|
|
101
102
|
async findVirtual(entityName, where, options) {
|
|
102
|
-
return this.findFromVirtual(entityName, where, options,
|
|
103
|
+
return this.findFromVirtual(entityName, where, options, QueryType.SELECT);
|
|
103
104
|
}
|
|
104
105
|
async countVirtual(entityName, where, options) {
|
|
105
|
-
return this.findFromVirtual(entityName, where, options,
|
|
106
|
+
return this.findFromVirtual(entityName, where, options, QueryType.COUNT);
|
|
106
107
|
}
|
|
107
108
|
async findFromVirtual(entityName, where, options, type) {
|
|
108
109
|
const meta = this.metadata.get(entityName);
|
|
109
|
-
/*
|
|
110
|
+
/* v8 ignore next 3 */
|
|
110
111
|
if (!meta.expression) {
|
|
111
|
-
return type ===
|
|
112
|
+
return type === QueryType.SELECT ? [] : 0;
|
|
112
113
|
}
|
|
113
114
|
if (typeof meta.expression === 'string') {
|
|
114
115
|
return this.wrapVirtualExpressionInSubquery(meta, meta.expression, where, options, type);
|
|
@@ -119,14 +120,14 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
119
120
|
if (typeof res === 'string') {
|
|
120
121
|
return this.wrapVirtualExpressionInSubquery(meta, res, where, options, type);
|
|
121
122
|
}
|
|
122
|
-
if (res instanceof
|
|
123
|
+
if (res instanceof QueryBuilder) {
|
|
123
124
|
return this.wrapVirtualExpressionInSubquery(meta, res.getFormattedQuery(), where, options, type);
|
|
124
125
|
}
|
|
125
|
-
if (res instanceof
|
|
126
|
+
if (res instanceof RawQueryFragment) {
|
|
126
127
|
const expr = this.platform.formatQuery(res.sql, res.params);
|
|
127
128
|
return this.wrapVirtualExpressionInSubquery(meta, expr, where, options, type);
|
|
128
129
|
}
|
|
129
|
-
/*
|
|
130
|
+
/* v8 ignore next */
|
|
130
131
|
return res;
|
|
131
132
|
}
|
|
132
133
|
async wrapVirtualExpressionInSubquery(meta, expression, where, options, type) {
|
|
@@ -137,7 +138,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
137
138
|
qb.where(where);
|
|
138
139
|
const { first, last, before, after } = options;
|
|
139
140
|
const isCursorPagination = [first, last, before, after].some(v => v != null);
|
|
140
|
-
if (type !==
|
|
141
|
+
if (type !== QueryType.COUNT) {
|
|
141
142
|
if (options.orderBy) {
|
|
142
143
|
if (isCursorPagination) {
|
|
143
144
|
const { orderBy: newOrderBy, where } = this.processCursorOptions(meta, options, options.orderBy);
|
|
@@ -150,16 +151,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
150
151
|
qb.limit(options?.limit, options?.offset);
|
|
151
152
|
}
|
|
152
153
|
const native = qb.getNativeQuery(false).clear('select');
|
|
153
|
-
if (type ===
|
|
154
|
+
if (type === QueryType.COUNT) {
|
|
154
155
|
native.count();
|
|
155
156
|
}
|
|
156
157
|
else { // select
|
|
157
158
|
native.select('*');
|
|
158
159
|
}
|
|
159
|
-
native.from(
|
|
160
|
+
native.from(raw(`(${expression}) as ${this.platform.quoteIdentifier(qb.alias)}`));
|
|
160
161
|
const query = native.compile();
|
|
161
162
|
const res = await this.execute(query.sql, query.params, 'all', options.ctx);
|
|
162
|
-
if (type ===
|
|
163
|
+
if (type === QueryType.COUNT) {
|
|
163
164
|
return res[0].count;
|
|
164
165
|
}
|
|
165
166
|
if (isCursorPagination && !first && !!last) {
|
|
@@ -169,7 +170,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
169
170
|
}
|
|
170
171
|
mapResult(result, meta, populate = [], qb, map = {}) {
|
|
171
172
|
const ret = super.mapResult(result, meta);
|
|
172
|
-
/*
|
|
173
|
+
/* v8 ignore next 3 */
|
|
173
174
|
if (!ret) {
|
|
174
175
|
return null;
|
|
175
176
|
}
|
|
@@ -184,11 +185,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
184
185
|
joinedProps.forEach(hint => {
|
|
185
186
|
const [propName, ref] = hint.field.split(':', 2);
|
|
186
187
|
const prop = meta.properties[propName];
|
|
187
|
-
/*
|
|
188
|
+
/* v8 ignore next 3 */
|
|
188
189
|
if (!prop) {
|
|
189
190
|
return;
|
|
190
191
|
}
|
|
191
|
-
const pivotRefJoin = prop.kind ===
|
|
192
|
+
const pivotRefJoin = prop.kind === ReferenceKind.MANY_TO_MANY && ref;
|
|
192
193
|
const meta2 = this.metadata.find(prop.type);
|
|
193
194
|
let path = parentJoinPath ? `${parentJoinPath}.${prop.name}` : `${meta.name}.${prop.name}`;
|
|
194
195
|
if (!parentJoinPath) {
|
|
@@ -198,7 +199,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
198
199
|
path += '[pivot]';
|
|
199
200
|
}
|
|
200
201
|
const relationAlias = qb.getAliasForJoinPath(path, { matchPopulateJoins: true });
|
|
201
|
-
/*
|
|
202
|
+
/* v8 ignore next 3 */
|
|
202
203
|
if (!relationAlias) {
|
|
203
204
|
return;
|
|
204
205
|
}
|
|
@@ -226,10 +227,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
226
227
|
return root[`${relationAlias}__${name}`] != null;
|
|
227
228
|
}));
|
|
228
229
|
if (!hasPK) {
|
|
229
|
-
if ([
|
|
230
|
+
if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
230
231
|
result[prop.name] = [];
|
|
231
232
|
}
|
|
232
|
-
if ([
|
|
233
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
233
234
|
result[prop.name] = null;
|
|
234
235
|
}
|
|
235
236
|
return;
|
|
@@ -239,7 +240,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
239
240
|
.filter(prop => !ref && prop.persist === false && prop.fieldNames)
|
|
240
241
|
.filter(prop => !prop.lazy || populate.some(p => p.field === prop.name || p.all))
|
|
241
242
|
.forEach(prop => {
|
|
242
|
-
/*
|
|
243
|
+
/* v8 ignore next 3 */
|
|
243
244
|
if (prop.fieldNames.length > 1) { // composite keys
|
|
244
245
|
relationPojo[prop.name] = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
245
246
|
}
|
|
@@ -254,9 +255,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
254
255
|
: meta2.props.filter(prop => this.platform.shouldHaveColumn(prop, hint.children || []));
|
|
255
256
|
const tz = this.platform.getTimezone();
|
|
256
257
|
for (const prop of targetProps) {
|
|
258
|
+
if (prop.fieldNames.every(name => typeof root[`${relationAlias}__${name}`] === 'undefined')) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
257
261
|
if (prop.fieldNames.length > 1) { // composite keys
|
|
258
262
|
const fk = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
259
|
-
const pk =
|
|
263
|
+
const pk = Utils.mapFlatCompositePrimaryKey(fk, prop);
|
|
260
264
|
relationPojo[prop.name] = pk.every(val => val != null) ? pk : null;
|
|
261
265
|
}
|
|
262
266
|
else if (prop.runtimeType === 'Date') {
|
|
@@ -275,8 +279,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
275
279
|
else {
|
|
276
280
|
const alias = `${relationAlias}__${prop.fieldNames[0]}`;
|
|
277
281
|
relationPojo[prop.name] = root[alias];
|
|
278
|
-
if (prop.kind ===
|
|
279
|
-
const item =
|
|
282
|
+
if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
|
|
283
|
+
const item = parseJsonSafe(relationPojo[prop.name]);
|
|
280
284
|
if (Array.isArray(item)) {
|
|
281
285
|
relationPojo[prop.name] = item.map(row => row == null ? row : this.comparator.mapResult(prop.type, row));
|
|
282
286
|
}
|
|
@@ -293,10 +297,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
293
297
|
}
|
|
294
298
|
if (mapToPk) {
|
|
295
299
|
const tmp = Object.values(relationPojo);
|
|
296
|
-
/*
|
|
300
|
+
/* v8 ignore next */
|
|
297
301
|
relationPojo = (meta2.compositePK ? tmp : tmp[0]);
|
|
298
302
|
}
|
|
299
|
-
if ([
|
|
303
|
+
if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
300
304
|
result[prop.name] ??= [];
|
|
301
305
|
result[prop.name].push(relationPojo);
|
|
302
306
|
}
|
|
@@ -324,7 +328,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
324
328
|
.populate(populate, joinedProps.length > 0 ? populateWhere : undefined, joinedProps.length > 0 ? options.populateFilter : undefined)
|
|
325
329
|
.withSchema(this.getSchemaName(meta, options))
|
|
326
330
|
.where(where);
|
|
327
|
-
if (meta && !
|
|
331
|
+
if (meta && !Utils.isEmpty(populate)) {
|
|
328
332
|
this.buildFields(meta, populate, joinedProps, qb, qb.alias, options, true);
|
|
329
333
|
}
|
|
330
334
|
return this.rethrow(qb.getCount());
|
|
@@ -339,10 +343,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
339
343
|
res.row = res.row || {};
|
|
340
344
|
let pk;
|
|
341
345
|
if (pks.length > 1) { // owner has composite pk
|
|
342
|
-
pk =
|
|
346
|
+
pk = Utils.getPrimaryKeyCond(data, pks);
|
|
343
347
|
}
|
|
344
348
|
else {
|
|
345
|
-
/*
|
|
349
|
+
/* v8 ignore next */
|
|
346
350
|
res.insertId = data[pks[0]] ?? res.insertId ?? res.row[pks[0]];
|
|
347
351
|
pk = [res.insertId];
|
|
348
352
|
}
|
|
@@ -356,23 +360,23 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
356
360
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
357
361
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
358
362
|
const set = new Set();
|
|
359
|
-
data.forEach(row =>
|
|
363
|
+
data.forEach(row => Utils.keys(row).forEach(k => set.add(k)));
|
|
360
364
|
const props = [...set].map(name => meta?.properties[name] ?? { name, fieldNames: [name] });
|
|
361
|
-
let fields =
|
|
362
|
-
const duplicates =
|
|
365
|
+
let fields = Utils.flatten(props.map(prop => prop.fieldNames));
|
|
366
|
+
const duplicates = Utils.findDuplicates(fields);
|
|
363
367
|
const params = [];
|
|
364
368
|
if (duplicates.length) {
|
|
365
|
-
fields =
|
|
369
|
+
fields = Utils.unique(fields);
|
|
366
370
|
}
|
|
367
|
-
/*
|
|
371
|
+
/* v8 ignore next */
|
|
368
372
|
const tableName = meta ? this.getTableName(meta, options) : this.platform.quoteIdentifier(entityName);
|
|
369
373
|
let sql = `insert into ${tableName} `;
|
|
370
374
|
sql += fields.length > 0 ? '(' + fields.map(k => this.platform.quoteIdentifier(k)).join(', ') + ')' : `(${this.platform.quoteIdentifier(pks[0])})`;
|
|
371
375
|
if (meta && this.platform.usesOutputStatement()) {
|
|
372
376
|
const returningProps = meta.props
|
|
373
377
|
.filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
|
|
374
|
-
.filter(prop => !(prop.name in data[0]) ||
|
|
375
|
-
const returningFields =
|
|
378
|
+
.filter(prop => !(prop.name in data[0]) || isRaw(data[0][prop.name]));
|
|
379
|
+
const returningFields = Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
376
380
|
sql += returningFields.length > 0 ? ` output ${returningFields.map(field => 'inserted.' + this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
377
381
|
}
|
|
378
382
|
if (fields.length > 0 || this.platform.usesDefaultKeyword()) {
|
|
@@ -383,7 +387,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
383
387
|
}
|
|
384
388
|
const addParams = (prop, row) => {
|
|
385
389
|
let value = row[prop.name] ?? prop.default;
|
|
386
|
-
if (prop.kind ===
|
|
390
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
387
391
|
if (prop.array && value) {
|
|
388
392
|
value = this.platform.cloneEmbeddable(value);
|
|
389
393
|
for (let i = 0; i < value.length; i++) {
|
|
@@ -400,7 +404,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
400
404
|
return;
|
|
401
405
|
}
|
|
402
406
|
if (typeof value === 'undefined' && this.platform.usesDefaultKeyword()) {
|
|
403
|
-
params.push(
|
|
407
|
+
params.push(raw('default'));
|
|
404
408
|
return;
|
|
405
409
|
}
|
|
406
410
|
params.push(value);
|
|
@@ -412,7 +416,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
412
416
|
props.forEach(prop => {
|
|
413
417
|
if (prop.fieldNames.length > 1) {
|
|
414
418
|
const newFields = [];
|
|
415
|
-
const allParam = [...
|
|
419
|
+
const allParam = [...(Utils.asArray(row[prop.name]) ?? prop.fieldNames.map(() => null))];
|
|
416
420
|
// TODO(v7): instead of making this conditional here, the entity snapshot should respect `ownColumns`,
|
|
417
421
|
// but that means changing the compiled PK getters, which might be seen as breaking
|
|
418
422
|
const columns = allParam.length > 1 ? prop.fieldNames : prop.ownColumns;
|
|
@@ -424,7 +428,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
424
428
|
newFields.push(field);
|
|
425
429
|
newParam.push(allParam[idx]);
|
|
426
430
|
});
|
|
427
|
-
const param =
|
|
431
|
+
const param = Utils.flatten(newParam);
|
|
428
432
|
newFields.forEach((field, idx) => {
|
|
429
433
|
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
430
434
|
params.push(param[idx]);
|
|
@@ -436,7 +440,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
436
440
|
else {
|
|
437
441
|
const field = prop.fieldNames[0];
|
|
438
442
|
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
439
|
-
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !
|
|
443
|
+
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && row[prop.name] != null && !isRaw(row[prop.name])) {
|
|
440
444
|
keys.push(prop.customType.convertToDatabaseValueSQL('?', this.platform));
|
|
441
445
|
}
|
|
442
446
|
else {
|
|
@@ -453,9 +457,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
453
457
|
if (meta && this.platform.usesReturningStatement()) {
|
|
454
458
|
const returningProps = meta.props
|
|
455
459
|
.filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
|
|
456
|
-
.filter(prop => !(prop.name in data[0]) ||
|
|
457
|
-
const returningFields =
|
|
458
|
-
/*
|
|
460
|
+
.filter(prop => !(prop.name in data[0]) || isRaw(data[0][prop.name]));
|
|
461
|
+
const returningFields = Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
462
|
+
/* v8 ignore next */
|
|
459
463
|
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
460
464
|
}
|
|
461
465
|
if (transform) {
|
|
@@ -463,9 +467,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
463
467
|
}
|
|
464
468
|
const res = await this.execute(sql, params, 'run', options.ctx);
|
|
465
469
|
let pk;
|
|
466
|
-
/*
|
|
470
|
+
/* v8 ignore next 3 */
|
|
467
471
|
if (pks.length > 1) { // owner has composite pk
|
|
468
|
-
pk = data.map(d =>
|
|
472
|
+
pk = data.map(d => Utils.getPrimaryKeyCond(d, pks));
|
|
469
473
|
}
|
|
470
474
|
else {
|
|
471
475
|
res.row ??= {};
|
|
@@ -484,22 +488,22 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
484
488
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
485
489
|
const collections = this.extractManyToMany(entityName, data);
|
|
486
490
|
let res = { affectedRows: 0, insertId: 0, row: {} };
|
|
487
|
-
if (
|
|
488
|
-
/*
|
|
491
|
+
if (Utils.isPrimaryKey(where) && pks.length === 1) {
|
|
492
|
+
/* v8 ignore next */
|
|
489
493
|
where = { [meta?.primaryKeys[0] ?? pks[0]]: where };
|
|
490
494
|
}
|
|
491
|
-
if (
|
|
495
|
+
if (Utils.hasObjectKeys(data)) {
|
|
492
496
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes)
|
|
493
497
|
.withSchema(this.getSchemaName(meta, options));
|
|
494
498
|
if (options.upsert) {
|
|
495
|
-
/*
|
|
496
|
-
const uniqueFields = options.onConflictFields ?? (
|
|
497
|
-
const returning =
|
|
499
|
+
/* v8 ignore next */
|
|
500
|
+
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(where) ? Utils.keys(where) : meta.primaryKeys);
|
|
501
|
+
const returning = getOnConflictReturningFields(meta, data, uniqueFields, options);
|
|
498
502
|
qb.insert(data)
|
|
499
503
|
.onConflict(uniqueFields)
|
|
500
504
|
.returning(returning);
|
|
501
505
|
if (!options.onConflictAction || options.onConflictAction === 'merge') {
|
|
502
|
-
const fields =
|
|
506
|
+
const fields = getOnConflictFields(meta, data, uniqueFields, options);
|
|
503
507
|
qb.merge(fields);
|
|
504
508
|
}
|
|
505
509
|
if (options.onConflictAction === 'ignore') {
|
|
@@ -517,8 +521,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
517
521
|
}
|
|
518
522
|
res = await this.rethrow(qb.execute('run', false));
|
|
519
523
|
}
|
|
520
|
-
/*
|
|
521
|
-
const pk = pks.map(pk =>
|
|
524
|
+
/* v8 ignore next */
|
|
525
|
+
const pk = pks.map(pk => Utils.extractPK(data[pk] || where, meta));
|
|
522
526
|
await this.processManyToMany(meta, pk, collections, true, options);
|
|
523
527
|
return res;
|
|
524
528
|
}
|
|
@@ -527,14 +531,14 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
527
531
|
options.convertCustomTypes ??= true;
|
|
528
532
|
const meta = this.metadata.get(entityName);
|
|
529
533
|
if (options.upsert) {
|
|
530
|
-
const uniqueFields = options.onConflictFields ?? (
|
|
534
|
+
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(where[0]) ? Object.keys(where[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
|
|
531
535
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes).withSchema(this.getSchemaName(meta, options));
|
|
532
|
-
const returning =
|
|
536
|
+
const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
|
|
533
537
|
qb.insert(data)
|
|
534
538
|
.onConflict(uniqueFields)
|
|
535
539
|
.returning(returning);
|
|
536
540
|
if (!options.onConflictAction || options.onConflictAction === 'merge') {
|
|
537
|
-
const fields =
|
|
541
|
+
const fields = getOnConflictFields(meta, data[0], uniqueFields, options);
|
|
538
542
|
qb.merge(fields);
|
|
539
543
|
}
|
|
540
544
|
if (options.onConflictAction === 'ignore') {
|
|
@@ -547,9 +551,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
547
551
|
const fields = new Set();
|
|
548
552
|
const returning = new Set();
|
|
549
553
|
for (const row of data) {
|
|
550
|
-
for (const k of
|
|
554
|
+
for (const k of Utils.keys(row)) {
|
|
551
555
|
keys.add(k);
|
|
552
|
-
if (
|
|
556
|
+
if (isRaw(row[k])) {
|
|
553
557
|
returning.add(k);
|
|
554
558
|
}
|
|
555
559
|
}
|
|
@@ -558,11 +562,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
558
562
|
meta?.props
|
|
559
563
|
.filter(prop => prop.generated || prop.version || prop.primary)
|
|
560
564
|
.forEach(prop => returning.add(prop.name));
|
|
561
|
-
const pkCond =
|
|
565
|
+
const pkCond = Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
|
|
562
566
|
const params = [];
|
|
563
567
|
let sql = `update ${this.getTableName(meta, options)} set `;
|
|
564
568
|
const addParams = (prop, value) => {
|
|
565
|
-
if (prop.kind ===
|
|
569
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
566
570
|
if (prop.array && value) {
|
|
567
571
|
for (let i = 0; i < value.length; i++) {
|
|
568
572
|
const item = value[i];
|
|
@@ -585,9 +589,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
585
589
|
sql += `${this.platform.quoteIdentifier(fieldName)} = case`;
|
|
586
590
|
where.forEach((cond, idx) => {
|
|
587
591
|
if (key in data[idx]) {
|
|
588
|
-
const pks =
|
|
592
|
+
const pks = Utils.getOrderedPrimaryKeys(cond, meta);
|
|
589
593
|
sql += ` when (${pkCond}) then `;
|
|
590
|
-
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !
|
|
594
|
+
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && data[idx][prop.name] != null && !isRaw(data[idx][key])) {
|
|
591
595
|
sql += prop.customType.convertToDatabaseValueSQL('?', this.platform);
|
|
592
596
|
}
|
|
593
597
|
else {
|
|
@@ -615,16 +619,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
615
619
|
}
|
|
616
620
|
sql = sql.substring(0, sql.length - 2) + ' where ';
|
|
617
621
|
const pkProps = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
|
|
618
|
-
const pks =
|
|
622
|
+
const pks = Utils.flatten(pkProps.map(pk => meta.properties[pk].fieldNames));
|
|
619
623
|
sql += pks.length > 1 ? `(${pks.map(pk => `${this.platform.quoteIdentifier(pk)}`).join(', ')})` : this.platform.quoteIdentifier(pks[0]);
|
|
620
624
|
const conds = where.map(cond => {
|
|
621
|
-
if (
|
|
625
|
+
if (Utils.isPlainObject(cond) && Utils.getObjectKeysSize(cond) === 1) {
|
|
622
626
|
cond = Object.values(cond)[0];
|
|
623
627
|
}
|
|
624
628
|
if (pks.length > 1) {
|
|
625
629
|
pkProps.forEach(pk => {
|
|
626
630
|
if (Array.isArray(cond[pk])) {
|
|
627
|
-
params.push(...
|
|
631
|
+
params.push(...Utils.flatten(cond[pk]));
|
|
628
632
|
}
|
|
629
633
|
else {
|
|
630
634
|
params.push(cond[pk]);
|
|
@@ -637,8 +641,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
637
641
|
});
|
|
638
642
|
sql += ` in (${conds.join(', ')})`;
|
|
639
643
|
if (this.platform.usesReturningStatement() && returning.size > 0) {
|
|
640
|
-
const returningFields =
|
|
641
|
-
/*
|
|
644
|
+
const returningFields = Utils.flatten([...returning].map(prop => meta.properties[prop].fieldNames));
|
|
645
|
+
/* v8 ignore next */
|
|
642
646
|
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
643
647
|
}
|
|
644
648
|
const res = await this.rethrow(this.execute(sql, params, 'run', options.ctx));
|
|
@@ -650,7 +654,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
650
654
|
async nativeDelete(entityName, where, options = {}) {
|
|
651
655
|
const meta = this.metadata.find(entityName);
|
|
652
656
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
653
|
-
if (
|
|
657
|
+
if (Utils.isPrimaryKey(where) && pks.length === 1) {
|
|
654
658
|
where = { [pks[0]]: where };
|
|
655
659
|
}
|
|
656
660
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', false).delete(where).withSchema(this.getSchemaName(meta, options));
|
|
@@ -669,7 +673,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
669
673
|
}
|
|
670
674
|
}
|
|
671
675
|
else {
|
|
672
|
-
if (!
|
|
676
|
+
if (!Utils.equals(a[i], b[i])) {
|
|
673
677
|
return false;
|
|
674
678
|
}
|
|
675
679
|
}
|
|
@@ -679,17 +683,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
679
683
|
async syncCollections(collections, options) {
|
|
680
684
|
const groups = {};
|
|
681
685
|
for (const coll of collections) {
|
|
682
|
-
const wrapped =
|
|
686
|
+
const wrapped = helper(coll.owner);
|
|
683
687
|
const meta = wrapped.__meta;
|
|
684
688
|
const pks = wrapped.getPrimaryKeys(true);
|
|
685
689
|
const snap = coll.getSnapshot();
|
|
686
690
|
const includes = (arr, item) => !!arr.find(i => this.comparePrimaryKeyArrays(i, item));
|
|
687
|
-
const snapshot = snap ? snap.map(item =>
|
|
688
|
-
const current = coll.getItems(false).map(item =>
|
|
691
|
+
const snapshot = snap ? snap.map(item => helper(item).getPrimaryKeys(true)) : [];
|
|
692
|
+
const current = coll.getItems(false).map(item => helper(item).getPrimaryKeys(true));
|
|
689
693
|
const deleteDiff = snap ? snapshot.filter(item => !includes(current, item)) : true;
|
|
690
694
|
const insertDiff = current.filter(item => !includes(snapshot, item));
|
|
691
695
|
const target = snapshot.filter(item => includes(current, item)).concat(...insertDiff);
|
|
692
|
-
const equals =
|
|
696
|
+
const equals = Utils.equals(current, target);
|
|
693
697
|
// wrong order if we just delete and insert to the end (only owning sides can have fixed order)
|
|
694
698
|
if (coll.property.owner && coll.property.fixedOrder && !equals && Array.isArray(deleteDiff)) {
|
|
695
699
|
deleteDiff.length = insertDiff.length = 0;
|
|
@@ -700,46 +704,50 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
700
704
|
insertDiff.push(item);
|
|
701
705
|
}
|
|
702
706
|
}
|
|
703
|
-
if (coll.property.kind ===
|
|
707
|
+
if (coll.property.kind === ReferenceKind.ONE_TO_MANY) {
|
|
704
708
|
const cols = coll.property.referencedColumnNames;
|
|
705
709
|
const qb = this.createQueryBuilder(coll.property.type, options?.ctx, 'write')
|
|
706
710
|
.withSchema(this.getSchemaName(meta, options));
|
|
707
711
|
if (coll.getSnapshot() === undefined) {
|
|
708
712
|
if (coll.property.orphanRemoval) {
|
|
709
713
|
const query = qb.delete({ [coll.property.mappedBy]: pks })
|
|
710
|
-
.andWhere({ [cols.join(
|
|
714
|
+
.andWhere({ [cols.join(Utils.PK_SEPARATOR)]: { $nin: insertDiff } });
|
|
711
715
|
await this.rethrow(query.execute());
|
|
712
716
|
continue;
|
|
713
717
|
}
|
|
714
718
|
const query = qb.update({ [coll.property.mappedBy]: null })
|
|
715
719
|
.where({ [coll.property.mappedBy]: pks })
|
|
716
|
-
.andWhere({ [cols.join(
|
|
717
|
-
await this.rethrow(query.execute());
|
|
718
|
-
continue;
|
|
719
|
-
}
|
|
720
|
-
/* istanbul ignore next */
|
|
721
|
-
{
|
|
722
|
-
const query = qb.update({ [coll.property.mappedBy]: pks })
|
|
723
|
-
.where({ [cols.join(core_1.Utils.PK_SEPARATOR)]: { $in: insertDiff } });
|
|
720
|
+
.andWhere({ [cols.join(Utils.PK_SEPARATOR)]: { $nin: insertDiff } });
|
|
724
721
|
await this.rethrow(query.execute());
|
|
725
722
|
continue;
|
|
726
723
|
}
|
|
724
|
+
/* v8 ignore next 5 */
|
|
725
|
+
const query = qb.update({ [coll.property.mappedBy]: pks })
|
|
726
|
+
.where({ [cols.join(Utils.PK_SEPARATOR)]: { $in: insertDiff } });
|
|
727
|
+
await this.rethrow(query.execute());
|
|
728
|
+
continue;
|
|
727
729
|
}
|
|
728
|
-
/*
|
|
730
|
+
/* v8 ignore next */
|
|
729
731
|
const pivotMeta = this.metadata.find(coll.property.pivotEntity);
|
|
730
732
|
let schema = pivotMeta.schema;
|
|
731
733
|
if (schema === '*') {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
+
if (coll.property.owner) {
|
|
735
|
+
schema = wrapped.getSchema() === '*' ? options?.schema ?? this.config.get('schema') : wrapped.getSchema();
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
const targetMeta = coll.property.targetMeta;
|
|
739
|
+
const targetSchema = (coll[0] ?? snap?.[0]) && helper(coll[0] ?? snap?.[0]).getSchema();
|
|
740
|
+
schema = targetMeta.schema === '*' ? options?.schema ?? targetSchema ?? this.config.get('schema') : targetMeta.schema;
|
|
741
|
+
}
|
|
734
742
|
}
|
|
735
743
|
else if (schema == null) {
|
|
736
744
|
schema = this.config.get('schema');
|
|
737
745
|
}
|
|
738
746
|
const tableName = `${schema ?? '_'}.${pivotMeta.tableName}`;
|
|
739
|
-
const persister = groups[tableName] ??= new
|
|
747
|
+
const persister = groups[tableName] ??= new PivotCollectionPersister(pivotMeta, this, options?.ctx, schema);
|
|
740
748
|
persister.enqueueUpdate(coll.property, insertDiff, deleteDiff, pks);
|
|
741
749
|
}
|
|
742
|
-
for (const persister of
|
|
750
|
+
for (const persister of Utils.values(groups)) {
|
|
743
751
|
await this.rethrow(persister.execute());
|
|
744
752
|
}
|
|
745
753
|
}
|
|
@@ -755,12 +763,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
755
763
|
.comment(options.comments)
|
|
756
764
|
.hintComment(options.hintComments);
|
|
757
765
|
const pivotAlias = qb.alias;
|
|
758
|
-
const pivotKey = pivotProp2.joinColumns.map(column => `${pivotAlias}.${column}`).join(
|
|
766
|
+
const pivotKey = pivotProp2.joinColumns.map(column => `${pivotAlias}.${column}`).join(Utils.PK_SEPARATOR);
|
|
759
767
|
const cond = {
|
|
760
768
|
[pivotKey]: { $in: ownerMeta.compositePK ? owners : owners.map(o => o[0]) },
|
|
761
769
|
};
|
|
762
|
-
/*
|
|
763
|
-
if (!
|
|
770
|
+
/* v8 ignore next 3 */
|
|
771
|
+
if (!Utils.isEmpty(where) && Object.keys(where).every(k => Utils.isOperator(k, false))) {
|
|
764
772
|
where = cond;
|
|
765
773
|
}
|
|
766
774
|
else {
|
|
@@ -781,13 +789,15 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
781
789
|
const targetSchema = this.getSchemaName(prop.targetMeta, options) ?? this.platform.getDefaultSchemaName();
|
|
782
790
|
qb.innerJoin(pivotProp1.name, targetAlias, {}, targetSchema);
|
|
783
791
|
const targetFields = this.buildFields(prop.targetMeta, (options.populate ?? []), [], qb, targetAlias, options);
|
|
792
|
+
const additionalFields = [];
|
|
784
793
|
for (const field of targetFields) {
|
|
785
794
|
const f = field.toString();
|
|
786
|
-
|
|
787
|
-
if (
|
|
795
|
+
additionalFields.push(f.includes('.') ? field : `${targetAlias}.${f}`);
|
|
796
|
+
if (RawQueryFragment.isKnownFragment(field)) {
|
|
788
797
|
qb.rawFragments.add(f);
|
|
789
798
|
}
|
|
790
799
|
}
|
|
800
|
+
fields.unshift(...additionalFields);
|
|
791
801
|
// we need to handle 1:1 owner auto-joins explicitly, as the QB type is the pivot table, not the target
|
|
792
802
|
populate.forEach(hint => {
|
|
793
803
|
const alias = qb.getNextAlias(prop.targetMeta.tableName);
|
|
@@ -819,35 +829,35 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
819
829
|
const map = {};
|
|
820
830
|
const pkProps = ownerMeta.getPrimaryProps();
|
|
821
831
|
for (const owner of owners) {
|
|
822
|
-
const key =
|
|
832
|
+
const key = Utils.getPrimaryKeyHash(prop.joinColumns.map((_col, idx) => {
|
|
823
833
|
const pkProp = pkProps[idx];
|
|
824
834
|
return pkProp.customType ? pkProp.customType.convertToJSValue(owner[idx], this.platform) : owner[idx];
|
|
825
835
|
}));
|
|
826
836
|
map[key] = [];
|
|
827
837
|
}
|
|
828
838
|
for (const item of items) {
|
|
829
|
-
const key =
|
|
839
|
+
const key = Utils.getPrimaryKeyHash(prop.joinColumns.map((col, idx) => {
|
|
830
840
|
const pkProp = pkProps[idx];
|
|
831
841
|
return pkProp.customType ? pkProp.customType.convertToJSValue(item[`fk__${col}`], this.platform) : item[`fk__${col}`];
|
|
832
842
|
}));
|
|
833
843
|
map[key].push(item);
|
|
834
844
|
prop.joinColumns.forEach(col => delete item[`fk__${col}`]);
|
|
835
845
|
prop.inverseJoinColumns.forEach((col, idx) => {
|
|
836
|
-
|
|
846
|
+
Utils.renameKey(item, `fk__${col}`, prop.targetMeta.primaryKeys[idx]);
|
|
837
847
|
});
|
|
838
848
|
}
|
|
839
849
|
return map;
|
|
840
850
|
}
|
|
841
851
|
getPivotOrderBy(prop, pivotProp, pivotAlias, orderBy) {
|
|
842
852
|
// FIXME this is ignoring the rest of the array items
|
|
843
|
-
if (!
|
|
844
|
-
return [{ [pivotProp.name]:
|
|
853
|
+
if (!Utils.isEmpty(orderBy)) {
|
|
854
|
+
return [{ [pivotProp.name]: Utils.asArray(orderBy)[0] }];
|
|
845
855
|
}
|
|
846
|
-
if (!
|
|
847
|
-
return [{ [pivotProp.name]:
|
|
856
|
+
if (!Utils.isEmpty(prop.orderBy)) {
|
|
857
|
+
return [{ [pivotProp.name]: Utils.asArray(prop.orderBy)[0] }];
|
|
848
858
|
}
|
|
849
859
|
if (prop.fixedOrder) {
|
|
850
|
-
return [{ [`${pivotAlias}.${prop.fixedOrderColumn}`]:
|
|
860
|
+
return [{ [`${pivotAlias}.${prop.fixedOrderColumn}`]: QueryOrder.ASC }];
|
|
851
861
|
}
|
|
852
862
|
return [];
|
|
853
863
|
}
|
|
@@ -863,7 +873,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
863
873
|
}
|
|
864
874
|
const relationsToPopulate = populate.map(({ field }) => field.split(':')[0]);
|
|
865
875
|
const toPopulate = meta.relations
|
|
866
|
-
.filter(prop => prop.kind ===
|
|
876
|
+
.filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !prop.lazy && !relationsToPopulate.includes(prop.name))
|
|
867
877
|
.filter(prop => fields.length === 0 || fields.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
868
878
|
.map(prop => ({ field: `${prop.name}:ref`, strategy: prop.strategy }));
|
|
869
879
|
return [...populate, ...toPopulate];
|
|
@@ -875,18 +885,18 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
875
885
|
return populate.filter(hint => {
|
|
876
886
|
const [propName, ref] = hint.field.split(':', 2);
|
|
877
887
|
const prop = meta.properties[propName] || {};
|
|
878
|
-
if (hint.filter && hint.strategy ===
|
|
888
|
+
if (hint.filter && hint.strategy === LoadStrategy.JOINED) {
|
|
879
889
|
return true;
|
|
880
890
|
}
|
|
881
891
|
// skip redundant joins for 1:1 owner population hints when using `mapToPk`
|
|
882
|
-
if (prop.kind ===
|
|
892
|
+
if (prop.kind === ReferenceKind.ONE_TO_ONE && prop.mapToPk && prop.owner) {
|
|
883
893
|
return false;
|
|
884
894
|
}
|
|
885
|
-
if ((options?.strategy || hint.strategy || prop.strategy || this.config.get('loadStrategy')) !==
|
|
895
|
+
if ((options?.strategy || hint.strategy || prop.strategy || this.config.get('loadStrategy')) !== LoadStrategy.JOINED) {
|
|
886
896
|
// force joined strategy for explicit 1:1 owner populate hint as it would require a join anyway
|
|
887
|
-
return prop.kind ===
|
|
897
|
+
return prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner;
|
|
888
898
|
}
|
|
889
|
-
return ![
|
|
899
|
+
return ![ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind);
|
|
890
900
|
});
|
|
891
901
|
}
|
|
892
902
|
/**
|
|
@@ -896,7 +906,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
896
906
|
const res = [];
|
|
897
907
|
const map = {};
|
|
898
908
|
for (const item of rawResults) {
|
|
899
|
-
const pk =
|
|
909
|
+
const pk = Utils.getCompositeKeyHash(item, meta);
|
|
900
910
|
if (map[pk]) {
|
|
901
911
|
for (const hint of joinedProps) {
|
|
902
912
|
const [propName, ref] = hint.field.split(':', 2);
|
|
@@ -904,17 +914,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
904
914
|
if (!item[propName]) {
|
|
905
915
|
continue;
|
|
906
916
|
}
|
|
907
|
-
if ([
|
|
917
|
+
if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) && ref) {
|
|
908
918
|
map[pk][propName] = [...map[pk][propName], ...item[propName]];
|
|
909
919
|
continue;
|
|
910
920
|
}
|
|
911
921
|
switch (prop.kind) {
|
|
912
|
-
case
|
|
913
|
-
case
|
|
922
|
+
case ReferenceKind.ONE_TO_MANY:
|
|
923
|
+
case ReferenceKind.MANY_TO_MANY:
|
|
914
924
|
map[pk][propName] = this.mergeJoinedResult([...map[pk][propName], ...item[propName]], prop.targetMeta, hint.children ?? []);
|
|
915
925
|
break;
|
|
916
|
-
case
|
|
917
|
-
case
|
|
926
|
+
case ReferenceKind.MANY_TO_ONE:
|
|
927
|
+
case ReferenceKind.ONE_TO_ONE:
|
|
918
928
|
map[pk][propName] = this.mergeJoinedResult([map[pk][propName], item[propName]], prop.targetMeta, hint.children ?? [])[0];
|
|
919
929
|
break;
|
|
920
930
|
}
|
|
@@ -931,35 +941,35 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
931
941
|
const fields = [];
|
|
932
942
|
const populate = options.populate ?? [];
|
|
933
943
|
const joinedProps = this.joinedProps(meta, populate, options);
|
|
934
|
-
const shouldHaveColumn = (prop, populate, fields) => {
|
|
944
|
+
const shouldHaveColumn = (meta, prop, populate, fields) => {
|
|
935
945
|
if (!this.platform.shouldHaveColumn(prop, populate, options.exclude)) {
|
|
936
946
|
return false;
|
|
937
947
|
}
|
|
938
|
-
if (!fields || fields.includes('*') || prop.primary) {
|
|
948
|
+
if (!fields || fields.includes('*') || prop.primary || meta.root.discriminatorColumn === prop.name) {
|
|
939
949
|
return true;
|
|
940
950
|
}
|
|
941
951
|
return fields.some(f => f === prop.name || f.toString().startsWith(prop.name + '.'));
|
|
942
952
|
};
|
|
943
|
-
const populateWhereAll = options?._populateWhere === 'all' ||
|
|
953
|
+
const populateWhereAll = options?._populateWhere === 'all' || Utils.isEmpty(options?._populateWhere);
|
|
944
954
|
// root entity is already handled, skip that
|
|
945
955
|
if (options.parentJoinPath) {
|
|
946
956
|
// alias all fields in the primary table
|
|
947
957
|
meta.props
|
|
948
|
-
.filter(prop => shouldHaveColumn(prop, populate, options.explicitFields))
|
|
958
|
+
.filter(prop => shouldHaveColumn(meta, prop, populate, options.explicitFields))
|
|
949
959
|
.forEach(prop => fields.push(...this.mapPropToFieldNames(qb, prop, options.parentTableAlias)));
|
|
950
960
|
}
|
|
951
961
|
for (const hint of joinedProps) {
|
|
952
962
|
const [propName, ref] = hint.field.split(':', 2);
|
|
953
963
|
const prop = meta.properties[propName];
|
|
954
964
|
// ignore ref joins of known FKs unless it's a filter hint
|
|
955
|
-
if (ref && !hint.filter && (prop.kind ===
|
|
965
|
+
if (ref && !hint.filter && (prop.kind === ReferenceKind.MANY_TO_ONE || (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner))) {
|
|
956
966
|
continue;
|
|
957
967
|
}
|
|
958
|
-
if (options.count &&
|
|
968
|
+
if (options.count && !options?.populateFilter?.[prop.name]) {
|
|
959
969
|
continue;
|
|
960
970
|
}
|
|
961
971
|
const meta2 = this.metadata.find(prop.type);
|
|
962
|
-
const pivotRefJoin = prop.kind ===
|
|
972
|
+
const pivotRefJoin = prop.kind === ReferenceKind.MANY_TO_MANY && ref;
|
|
963
973
|
const tableAlias = qb.getNextAlias(prop.name);
|
|
964
974
|
const field = `${options.parentTableAlias}.${prop.name}`;
|
|
965
975
|
let path = options.parentJoinPath ? `${options.parentJoinPath}.${prop.name}` : `${meta.name}.${prop.name}`;
|
|
@@ -967,15 +977,15 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
967
977
|
path = '[populate]' + path;
|
|
968
978
|
}
|
|
969
979
|
const joinType = pivotRefJoin
|
|
970
|
-
?
|
|
980
|
+
? JoinType.pivotJoin
|
|
971
981
|
: hint.filter && !prop.nullable
|
|
972
|
-
?
|
|
973
|
-
:
|
|
982
|
+
? JoinType.innerJoin
|
|
983
|
+
: JoinType.leftJoin;
|
|
974
984
|
qb.join(field, tableAlias, {}, joinType, path);
|
|
975
985
|
if (pivotRefJoin) {
|
|
976
986
|
fields.push(...prop.joinColumns.map(col => qb.helper.mapper(`${tableAlias}.${col}`, qb.type, undefined, `${tableAlias}__${col}`)), ...prop.inverseJoinColumns.map(col => qb.helper.mapper(`${tableAlias}.${col}`, qb.type, undefined, `${tableAlias}__${col}`)));
|
|
977
987
|
}
|
|
978
|
-
if (prop.kind ===
|
|
988
|
+
if (prop.kind === ReferenceKind.ONE_TO_MANY && ref) {
|
|
979
989
|
fields.push(...this.getFieldsForJoinedLoad(qb, meta2, {
|
|
980
990
|
...options,
|
|
981
991
|
explicitFields: prop.referencedColumnNames,
|
|
@@ -985,13 +995,13 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
985
995
|
parentJoinPath: path,
|
|
986
996
|
}));
|
|
987
997
|
}
|
|
988
|
-
const childExplicitFields = options.explicitFields?.filter(f =>
|
|
998
|
+
const childExplicitFields = options.explicitFields?.filter(f => Utils.isPlainObject(f)).map(o => o[prop.name])[0] || [];
|
|
989
999
|
options.explicitFields?.forEach(f => {
|
|
990
1000
|
if (typeof f === 'string' && f.startsWith(`${prop.name}.`)) {
|
|
991
1001
|
childExplicitFields.push(f.substring(prop.name.length + 1));
|
|
992
1002
|
}
|
|
993
1003
|
});
|
|
994
|
-
const childExclude = options.exclude ?
|
|
1004
|
+
const childExclude = options.exclude ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
|
|
995
1005
|
if (!ref && !prop.mapToPk) {
|
|
996
1006
|
fields.push(...this.getFieldsForJoinedLoad(qb, meta2, {
|
|
997
1007
|
...options,
|
|
@@ -1020,16 +1030,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1020
1030
|
}
|
|
1021
1031
|
const prefixed = this.platform.quoteIdentifier(`${tableAlias}.${col}`);
|
|
1022
1032
|
const aliased = this.platform.quoteIdentifier(`${tableAlias}__${col}`);
|
|
1023
|
-
return
|
|
1033
|
+
return raw(`${prop.customTypes[idx].convertToJSValueSQL(prefixed, this.platform)} as ${aliased}`);
|
|
1024
1034
|
});
|
|
1025
1035
|
}
|
|
1026
1036
|
if (prop.customType?.convertToJSValueSQL) {
|
|
1027
1037
|
const prefixed = this.platform.quoteIdentifier(`${tableAlias}.${prop.fieldNames[0]}`);
|
|
1028
|
-
return [
|
|
1038
|
+
return [raw(`${prop.customType.convertToJSValueSQL(prefixed, this.platform)} as ${aliased}`)];
|
|
1029
1039
|
}
|
|
1030
1040
|
if (prop.formula) {
|
|
1031
1041
|
const alias = this.platform.quoteIdentifier(tableAlias);
|
|
1032
|
-
return [
|
|
1042
|
+
return [raw(`${prop.formula(alias)} as ${aliased}`)];
|
|
1033
1043
|
}
|
|
1034
1044
|
return prop.fieldNames.map(fieldName => {
|
|
1035
1045
|
return `${tableAlias}.${fieldName} as ${tableAlias}__${fieldName}`;
|
|
@@ -1039,9 +1049,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1039
1049
|
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes, loggerContext, alias, em) {
|
|
1040
1050
|
// do not compute the connectionType if EM is provided as it will be computed from it in the QB later on
|
|
1041
1051
|
const connectionType = em ? preferredConnectionType : this.resolveConnectionType({ ctx, connectionType: preferredConnectionType });
|
|
1042
|
-
const qb = new
|
|
1052
|
+
const qb = new QueryBuilder(entityName, this.metadata, this, ctx, alias, connectionType, em, loggerContext);
|
|
1043
1053
|
if (!convertCustomTypes) {
|
|
1044
|
-
qb.unsetFlag(
|
|
1054
|
+
qb.unsetFlag(QueryFlag.CONVERT_CUSTOM_TYPES);
|
|
1045
1055
|
}
|
|
1046
1056
|
return qb;
|
|
1047
1057
|
}
|
|
@@ -1063,8 +1073,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1063
1073
|
}
|
|
1064
1074
|
const ret = {};
|
|
1065
1075
|
this.metadata.find(entityName).relations.forEach(prop => {
|
|
1066
|
-
if (prop.kind ===
|
|
1067
|
-
ret[prop.name] = data[prop.name].map((item) =>
|
|
1076
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && data[prop.name]) {
|
|
1077
|
+
ret[prop.name] = data[prop.name].map((item) => Utils.asArray(item));
|
|
1068
1078
|
delete data[prop.name];
|
|
1069
1079
|
}
|
|
1070
1080
|
});
|
|
@@ -1077,17 +1087,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1077
1087
|
for (const prop of meta.relations) {
|
|
1078
1088
|
if (collections[prop.name]) {
|
|
1079
1089
|
const pivotMeta = this.metadata.find(prop.pivotEntity);
|
|
1080
|
-
const persister = new
|
|
1090
|
+
const persister = new PivotCollectionPersister(pivotMeta, this, options?.ctx, options?.schema);
|
|
1081
1091
|
persister.enqueueUpdate(prop, collections[prop.name], clear, pks);
|
|
1082
1092
|
await this.rethrow(persister.execute());
|
|
1083
1093
|
}
|
|
1084
1094
|
}
|
|
1085
1095
|
}
|
|
1086
1096
|
async lockPessimistic(entity, options) {
|
|
1087
|
-
const meta =
|
|
1097
|
+
const meta = helper(entity).__meta;
|
|
1088
1098
|
const qb = this.createQueryBuilder(entity.constructor.name, options.ctx, undefined, undefined, options.logging).withSchema(options.schema ?? meta.schema);
|
|
1089
|
-
const cond =
|
|
1090
|
-
qb.select(
|
|
1099
|
+
const cond = Utils.getPrimaryKeyCond(entity, meta.primaryKeys);
|
|
1100
|
+
qb.select(raw('1')).where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
1091
1101
|
await this.rethrow(qb.execute());
|
|
1092
1102
|
}
|
|
1093
1103
|
buildPopulateWhere(meta, joinedProps, options) {
|
|
@@ -1095,45 +1105,45 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1095
1105
|
for (const hint of joinedProps) {
|
|
1096
1106
|
const [propName] = hint.field.split(':', 2);
|
|
1097
1107
|
const prop = meta.properties[propName];
|
|
1098
|
-
if (!
|
|
1099
|
-
where[prop.name] =
|
|
1108
|
+
if (!Utils.isEmpty(prop.where)) {
|
|
1109
|
+
where[prop.name] = Utils.copy(prop.where);
|
|
1100
1110
|
}
|
|
1101
1111
|
if (hint.children) {
|
|
1102
1112
|
const inner = this.buildPopulateWhere(prop.targetMeta, hint.children, {});
|
|
1103
|
-
if (!
|
|
1113
|
+
if (!Utils.isEmpty(inner)) {
|
|
1104
1114
|
where[prop.name] ??= {};
|
|
1105
1115
|
Object.assign(where[prop.name], inner);
|
|
1106
1116
|
}
|
|
1107
1117
|
}
|
|
1108
1118
|
}
|
|
1109
|
-
if (
|
|
1119
|
+
if (Utils.isEmpty(options.populateWhere)) {
|
|
1110
1120
|
return where;
|
|
1111
1121
|
}
|
|
1112
|
-
if (
|
|
1122
|
+
if (Utils.isEmpty(where)) {
|
|
1113
1123
|
return options.populateWhere;
|
|
1114
1124
|
}
|
|
1115
|
-
/*
|
|
1125
|
+
/* v8 ignore next */
|
|
1116
1126
|
return { $and: [options.populateWhere, where] };
|
|
1117
1127
|
}
|
|
1118
1128
|
buildOrderBy(qb, meta, populate, options) {
|
|
1119
1129
|
const joinedProps = this.joinedProps(meta, populate, options);
|
|
1120
1130
|
// `options._populateWhere` is a copy of the value provided by user with a fallback to the global config option
|
|
1121
1131
|
// as `options.populateWhere` will be always recomputed to respect filters
|
|
1122
|
-
const populateWhereAll = options._populateWhere !== 'infer' && !
|
|
1132
|
+
const populateWhereAll = options._populateWhere !== 'infer' && !Utils.isEmpty(options._populateWhere);
|
|
1123
1133
|
const path = (populateWhereAll ? '[populate]' : '') + meta.className;
|
|
1124
|
-
const populateOrderBy = this.buildPopulateOrderBy(qb, meta,
|
|
1134
|
+
const populateOrderBy = this.buildPopulateOrderBy(qb, meta, Utils.asArray(options.populateOrderBy ?? options.orderBy), path, !!options.populateOrderBy);
|
|
1125
1135
|
const joinedPropsOrderBy = this.buildJoinedPropsOrderBy(qb, meta, joinedProps, options, path);
|
|
1126
|
-
return [...
|
|
1136
|
+
return [...Utils.asArray(options.orderBy), ...populateOrderBy, ...joinedPropsOrderBy];
|
|
1127
1137
|
}
|
|
1128
1138
|
buildPopulateOrderBy(qb, meta, populateOrderBy, parentPath, explicit, parentAlias = qb.alias) {
|
|
1129
1139
|
const orderBy = [];
|
|
1130
1140
|
for (let i = 0; i < populateOrderBy.length; i++) {
|
|
1131
1141
|
const orderHint = populateOrderBy[i];
|
|
1132
|
-
for (const propName of
|
|
1133
|
-
const raw =
|
|
1142
|
+
for (const propName of Utils.keys(orderHint)) {
|
|
1143
|
+
const raw = RawQueryFragment.getKnownFragment(propName, explicit);
|
|
1134
1144
|
if (raw) {
|
|
1135
|
-
const sql = raw.sql.replace(new RegExp(
|
|
1136
|
-
const raw2 = new
|
|
1145
|
+
const sql = raw.sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), parentAlias);
|
|
1146
|
+
const raw2 = new RawQueryFragment(sql, raw.params);
|
|
1137
1147
|
orderBy.push({ [raw2]: orderHint[propName] });
|
|
1138
1148
|
continue;
|
|
1139
1149
|
}
|
|
@@ -1144,10 +1154,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1144
1154
|
let path = parentPath;
|
|
1145
1155
|
const meta2 = this.metadata.find(prop.type);
|
|
1146
1156
|
const childOrder = orderHint[prop.name];
|
|
1147
|
-
if (![
|
|
1157
|
+
if (![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) || !prop.owner || Utils.isPlainObject(childOrder)) {
|
|
1148
1158
|
path += `.${propName}`;
|
|
1149
1159
|
}
|
|
1150
|
-
if (prop.kind ===
|
|
1160
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && typeof childOrder !== 'object') {
|
|
1151
1161
|
path += '[pivot]';
|
|
1152
1162
|
}
|
|
1153
1163
|
const join = qb.getJoinForPath(path, { matchPopulateJoins: true });
|
|
@@ -1155,12 +1165,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1155
1165
|
if (!join && parentAlias === qb.alias) {
|
|
1156
1166
|
continue;
|
|
1157
1167
|
}
|
|
1158
|
-
if (![
|
|
1159
|
-
const children = this.buildPopulateOrderBy(qb, meta2,
|
|
1168
|
+
if (![ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind) && typeof childOrder === 'object') {
|
|
1169
|
+
const children = this.buildPopulateOrderBy(qb, meta2, Utils.asArray(childOrder), path, explicit, propAlias);
|
|
1160
1170
|
orderBy.push(...children);
|
|
1161
1171
|
continue;
|
|
1162
1172
|
}
|
|
1163
|
-
if (prop.kind ===
|
|
1173
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && join) {
|
|
1164
1174
|
if (prop.fixedOrderColumn) {
|
|
1165
1175
|
orderBy.push({ [`${join.alias}.${prop.fixedOrderColumn}`]: childOrder });
|
|
1166
1176
|
}
|
|
@@ -1187,23 +1197,23 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1187
1197
|
const prop = meta.properties[propName];
|
|
1188
1198
|
const propOrderBy = prop.orderBy;
|
|
1189
1199
|
let path = `${parentPath}.${propName}`;
|
|
1190
|
-
if (prop.kind ===
|
|
1200
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && ref) {
|
|
1191
1201
|
path += '[pivot]';
|
|
1192
1202
|
}
|
|
1193
1203
|
const join = qb.getJoinForPath(path, { matchPopulateJoins: true });
|
|
1194
1204
|
const propAlias = qb.getAliasForJoinPath(join ?? path, { matchPopulateJoins: true });
|
|
1195
1205
|
const meta2 = this.metadata.find(prop.type);
|
|
1196
|
-
if (prop.kind ===
|
|
1206
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.fixedOrder && join) {
|
|
1197
1207
|
const alias = ref ? propAlias : join.ownerAlias;
|
|
1198
|
-
orderBy.push({ [`${alias}.${prop.fixedOrderColumn}`]:
|
|
1208
|
+
orderBy.push({ [`${alias}.${prop.fixedOrderColumn}`]: QueryOrder.ASC });
|
|
1199
1209
|
}
|
|
1200
1210
|
if (propOrderBy) {
|
|
1201
|
-
for (const item of
|
|
1202
|
-
for (const field of
|
|
1203
|
-
const rawField =
|
|
1211
|
+
for (const item of Utils.asArray(propOrderBy)) {
|
|
1212
|
+
for (const field of Utils.keys(item)) {
|
|
1213
|
+
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
1204
1214
|
if (rawField) {
|
|
1205
|
-
const sql = propAlias ? rawField.sql.replace(new RegExp(
|
|
1206
|
-
const raw2 =
|
|
1215
|
+
const sql = propAlias ? rawField.sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), propAlias) : rawField.sql;
|
|
1216
|
+
const raw2 = raw(sql, rawField.params);
|
|
1207
1217
|
orderBy.push({ [raw2.toString()]: item[field] });
|
|
1208
1218
|
continue;
|
|
1209
1219
|
}
|
|
@@ -1225,7 +1235,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1225
1235
|
ret.push(prefix + field);
|
|
1226
1236
|
continue;
|
|
1227
1237
|
}
|
|
1228
|
-
if (
|
|
1238
|
+
if (Utils.isPlainObject(field)) {
|
|
1229
1239
|
for (const key of Object.keys(field)) {
|
|
1230
1240
|
ret.push(...this.normalizeFields(field[key], key + '.'));
|
|
1231
1241
|
}
|
|
@@ -1234,10 +1244,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1234
1244
|
return ret;
|
|
1235
1245
|
}
|
|
1236
1246
|
processField(meta, prop, field, ret, populate, joinedProps, qb) {
|
|
1237
|
-
if (!prop || (prop.kind ===
|
|
1247
|
+
if (!prop || (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner)) {
|
|
1238
1248
|
return;
|
|
1239
1249
|
}
|
|
1240
|
-
if (prop.kind ===
|
|
1250
|
+
if (prop.kind === ReferenceKind.EMBEDDED) {
|
|
1241
1251
|
if (prop.object) {
|
|
1242
1252
|
ret.push(prop.name);
|
|
1243
1253
|
return;
|
|
@@ -1281,7 +1291,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1281
1291
|
}
|
|
1282
1292
|
const parts = field.split('.');
|
|
1283
1293
|
const rootPropName = parts.shift(); // first one is the `prop`
|
|
1284
|
-
const prop =
|
|
1294
|
+
const prop = QueryHelper.findProperty(rootPropName, {
|
|
1285
1295
|
metadata: this.metadata,
|
|
1286
1296
|
platform: this.platform,
|
|
1287
1297
|
entityName: meta.className,
|
|
@@ -1293,8 +1303,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1293
1303
|
if (!options.fields.includes('*') && !options.fields.includes(`${qb.alias}.*`)) {
|
|
1294
1304
|
ret.unshift(...meta.primaryKeys.filter(pk => !options.fields.includes(pk)));
|
|
1295
1305
|
}
|
|
1306
|
+
if (meta.root.discriminatorColumn && !options.fields.includes(`${qb.alias}.${meta.root.discriminatorColumn}`)) {
|
|
1307
|
+
ret.push(meta.root.discriminatorColumn);
|
|
1308
|
+
}
|
|
1296
1309
|
}
|
|
1297
|
-
else if (!
|
|
1310
|
+
else if (!Utils.isEmpty(options.exclude) || lazyProps.some(p => !p.formula && (p.kind !== '1:1' || p.owner))) {
|
|
1298
1311
|
const props = meta.props.filter(prop => this.platform.shouldHaveColumn(prop, populate, options.exclude, false));
|
|
1299
1312
|
ret.push(...props.filter(p => !lazyProps.includes(p)).map(p => p.name));
|
|
1300
1313
|
addFormulas = true;
|
|
@@ -1312,7 +1325,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1312
1325
|
.forEach(prop => {
|
|
1313
1326
|
const a = this.platform.quoteIdentifier(alias);
|
|
1314
1327
|
const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
1315
|
-
ret.push(
|
|
1328
|
+
ret.push(raw(`${prop.formula(a)} as ${aliased}`));
|
|
1316
1329
|
});
|
|
1317
1330
|
meta.props
|
|
1318
1331
|
.filter(prop => !prop.object && (prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL))
|
|
@@ -1329,7 +1342,6 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1329
1342
|
...options,
|
|
1330
1343
|
}));
|
|
1331
1344
|
}
|
|
1332
|
-
return
|
|
1345
|
+
return Utils.unique(ret);
|
|
1333
1346
|
}
|
|
1334
1347
|
}
|
|
1335
|
-
exports.AbstractSqlDriver = AbstractSqlDriver;
|