@mikro-orm/knex 7.0.0-dev.1 → 7.0.0-dev.3
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 +22 -25
- package/AbstractSqlDriver.d.ts +9 -7
- package/AbstractSqlDriver.js +175 -180
- 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 +21 -25
- 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 +1 -1
- package/dialects/sqlite/BaseSqliteConnection.js +7 -11
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +4 -4
- package/dialects/sqlite/BaseSqlitePlatform.js +11 -15
- 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 +5 -14
- package/query/ArrayCriteriaNode.d.ts +2 -2
- package/query/ArrayCriteriaNode.js +2 -6
- package/query/CriteriaNode.d.ts +1 -1
- package/query/CriteriaNode.js +26 -30
- 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 +37 -41
- package/query/QueryBuilder.d.ts +7 -14
- package/query/QueryBuilder.js +163 -187
- package/query/QueryBuilderHelper.d.ts +4 -4
- package/query/QueryBuilderHelper.js +84 -88
- 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 +26 -30
- 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 +20 -34
- package/schema/index.d.ts +5 -5
- package/schema/index.js +5 -21
- package/typings.d.ts +5 -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);
|
|
@@ -80,9 +78,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
80
78
|
if (joinedProps.length === 0 || !hasToManyJoins) {
|
|
81
79
|
opts.limit = 1;
|
|
82
80
|
}
|
|
83
|
-
if (opts.limit > 0 && !opts.flags?.includes(
|
|
81
|
+
if (opts.limit > 0 && !opts.flags?.includes(QueryFlag.DISABLE_PAGINATE)) {
|
|
84
82
|
opts.flags ??= [];
|
|
85
|
-
opts.flags.push(
|
|
83
|
+
opts.flags.push(QueryFlag.DISABLE_PAGINATE);
|
|
86
84
|
}
|
|
87
85
|
const res = await this.find(entityName, where, opts);
|
|
88
86
|
return res[0] || null;
|
|
@@ -90,7 +88,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
90
88
|
hasToManyJoins(hint, meta) {
|
|
91
89
|
const [propName] = hint.field.split(':', 2);
|
|
92
90
|
const prop = meta.properties[propName];
|
|
93
|
-
if (prop && [
|
|
91
|
+
if (prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
94
92
|
return true;
|
|
95
93
|
}
|
|
96
94
|
if (hint.children && prop.targetMeta) {
|
|
@@ -99,16 +97,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
99
97
|
return false;
|
|
100
98
|
}
|
|
101
99
|
async findVirtual(entityName, where, options) {
|
|
102
|
-
return this.findFromVirtual(entityName, where, options,
|
|
100
|
+
return this.findFromVirtual(entityName, where, options, QueryType.SELECT);
|
|
103
101
|
}
|
|
104
102
|
async countVirtual(entityName, where, options) {
|
|
105
|
-
return this.findFromVirtual(entityName, where, options,
|
|
103
|
+
return this.findFromVirtual(entityName, where, options, QueryType.COUNT);
|
|
106
104
|
}
|
|
107
105
|
async findFromVirtual(entityName, where, options, type) {
|
|
108
106
|
const meta = this.metadata.get(entityName);
|
|
109
|
-
/*
|
|
107
|
+
/* v8 ignore next 3 */
|
|
110
108
|
if (!meta.expression) {
|
|
111
|
-
return type ===
|
|
109
|
+
return type === QueryType.SELECT ? [] : 0;
|
|
112
110
|
}
|
|
113
111
|
if (typeof meta.expression === 'string') {
|
|
114
112
|
return this.wrapVirtualExpressionInSubquery(meta, meta.expression, where, options, type);
|
|
@@ -119,14 +117,14 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
119
117
|
if (typeof res === 'string') {
|
|
120
118
|
return this.wrapVirtualExpressionInSubquery(meta, res, where, options, type);
|
|
121
119
|
}
|
|
122
|
-
if (res instanceof
|
|
120
|
+
if (res instanceof QueryBuilder) {
|
|
123
121
|
return this.wrapVirtualExpressionInSubquery(meta, res.getFormattedQuery(), where, options, type);
|
|
124
122
|
}
|
|
125
|
-
if (res instanceof
|
|
123
|
+
if (res instanceof RawQueryFragment) {
|
|
126
124
|
const expr = this.platform.formatQuery(res.sql, res.params);
|
|
127
125
|
return this.wrapVirtualExpressionInSubquery(meta, expr, where, options, type);
|
|
128
126
|
}
|
|
129
|
-
/*
|
|
127
|
+
/* v8 ignore next */
|
|
130
128
|
return res;
|
|
131
129
|
}
|
|
132
130
|
async wrapVirtualExpressionInSubquery(meta, expression, where, options, type) {
|
|
@@ -137,7 +135,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
137
135
|
qb.where(where);
|
|
138
136
|
const { first, last, before, after } = options;
|
|
139
137
|
const isCursorPagination = [first, last, before, after].some(v => v != null);
|
|
140
|
-
if (type !==
|
|
138
|
+
if (type !== QueryType.COUNT) {
|
|
141
139
|
if (options.orderBy) {
|
|
142
140
|
if (isCursorPagination) {
|
|
143
141
|
const { orderBy: newOrderBy, where } = this.processCursorOptions(meta, options, options.orderBy);
|
|
@@ -150,16 +148,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
150
148
|
qb.limit(options?.limit, options?.offset);
|
|
151
149
|
}
|
|
152
150
|
const native = qb.getNativeQuery(false).clear('select');
|
|
153
|
-
if (type ===
|
|
151
|
+
if (type === QueryType.COUNT) {
|
|
154
152
|
native.count();
|
|
155
153
|
}
|
|
156
154
|
else { // select
|
|
157
155
|
native.select('*');
|
|
158
156
|
}
|
|
159
|
-
native.from(
|
|
157
|
+
native.from(raw(`(${expression}) as ${this.platform.quoteIdentifier(qb.alias)}`));
|
|
160
158
|
const query = native.compile();
|
|
161
159
|
const res = await this.execute(query.sql, query.params, 'all', options.ctx);
|
|
162
|
-
if (type ===
|
|
160
|
+
if (type === QueryType.COUNT) {
|
|
163
161
|
return res[0].count;
|
|
164
162
|
}
|
|
165
163
|
if (isCursorPagination && !first && !!last) {
|
|
@@ -169,7 +167,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
169
167
|
}
|
|
170
168
|
mapResult(result, meta, populate = [], qb, map = {}) {
|
|
171
169
|
const ret = super.mapResult(result, meta);
|
|
172
|
-
/*
|
|
170
|
+
/* v8 ignore next 3 */
|
|
173
171
|
if (!ret) {
|
|
174
172
|
return null;
|
|
175
173
|
}
|
|
@@ -184,11 +182,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
184
182
|
joinedProps.forEach(hint => {
|
|
185
183
|
const [propName, ref] = hint.field.split(':', 2);
|
|
186
184
|
const prop = meta.properties[propName];
|
|
187
|
-
/*
|
|
185
|
+
/* v8 ignore next 3 */
|
|
188
186
|
if (!prop) {
|
|
189
187
|
return;
|
|
190
188
|
}
|
|
191
|
-
const pivotRefJoin = prop.kind ===
|
|
189
|
+
const pivotRefJoin = prop.kind === ReferenceKind.MANY_TO_MANY && ref;
|
|
192
190
|
const meta2 = this.metadata.find(prop.type);
|
|
193
191
|
let path = parentJoinPath ? `${parentJoinPath}.${prop.name}` : `${meta.name}.${prop.name}`;
|
|
194
192
|
if (!parentJoinPath) {
|
|
@@ -198,7 +196,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
198
196
|
path += '[pivot]';
|
|
199
197
|
}
|
|
200
198
|
const relationAlias = qb.getAliasForJoinPath(path, { matchPopulateJoins: true });
|
|
201
|
-
/*
|
|
199
|
+
/* v8 ignore next 3 */
|
|
202
200
|
if (!relationAlias) {
|
|
203
201
|
return;
|
|
204
202
|
}
|
|
@@ -226,10 +224,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
226
224
|
return root[`${relationAlias}__${name}`] != null;
|
|
227
225
|
}));
|
|
228
226
|
if (!hasPK) {
|
|
229
|
-
if ([
|
|
227
|
+
if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
230
228
|
result[prop.name] = [];
|
|
231
229
|
}
|
|
232
|
-
if ([
|
|
230
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
233
231
|
result[prop.name] = null;
|
|
234
232
|
}
|
|
235
233
|
return;
|
|
@@ -239,7 +237,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
239
237
|
.filter(prop => !ref && prop.persist === false && prop.fieldNames)
|
|
240
238
|
.filter(prop => !prop.lazy || populate.some(p => p.field === prop.name || p.all))
|
|
241
239
|
.forEach(prop => {
|
|
242
|
-
/*
|
|
240
|
+
/* v8 ignore next 3 */
|
|
243
241
|
if (prop.fieldNames.length > 1) { // composite keys
|
|
244
242
|
relationPojo[prop.name] = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
245
243
|
}
|
|
@@ -256,7 +254,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
256
254
|
for (const prop of targetProps) {
|
|
257
255
|
if (prop.fieldNames.length > 1) { // composite keys
|
|
258
256
|
const fk = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
259
|
-
const pk =
|
|
257
|
+
const pk = Utils.mapFlatCompositePrimaryKey(fk, prop);
|
|
260
258
|
relationPojo[prop.name] = pk.every(val => val != null) ? pk : null;
|
|
261
259
|
}
|
|
262
260
|
else if (prop.runtimeType === 'Date') {
|
|
@@ -275,8 +273,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
275
273
|
else {
|
|
276
274
|
const alias = `${relationAlias}__${prop.fieldNames[0]}`;
|
|
277
275
|
relationPojo[prop.name] = root[alias];
|
|
278
|
-
if (prop.kind ===
|
|
279
|
-
const item =
|
|
276
|
+
if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
|
|
277
|
+
const item = parseJsonSafe(relationPojo[prop.name]);
|
|
280
278
|
if (Array.isArray(item)) {
|
|
281
279
|
relationPojo[prop.name] = item.map(row => row == null ? row : this.comparator.mapResult(prop.type, row));
|
|
282
280
|
}
|
|
@@ -293,10 +291,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
293
291
|
}
|
|
294
292
|
if (mapToPk) {
|
|
295
293
|
const tmp = Object.values(relationPojo);
|
|
296
|
-
/*
|
|
294
|
+
/* v8 ignore next */
|
|
297
295
|
relationPojo = (meta2.compositePK ? tmp : tmp[0]);
|
|
298
296
|
}
|
|
299
|
-
if ([
|
|
297
|
+
if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
300
298
|
result[prop.name] ??= [];
|
|
301
299
|
result[prop.name].push(relationPojo);
|
|
302
300
|
}
|
|
@@ -324,7 +322,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
324
322
|
.populate(populate, joinedProps.length > 0 ? populateWhere : undefined, joinedProps.length > 0 ? options.populateFilter : undefined)
|
|
325
323
|
.withSchema(this.getSchemaName(meta, options))
|
|
326
324
|
.where(where);
|
|
327
|
-
if (meta && !
|
|
325
|
+
if (meta && !Utils.isEmpty(populate)) {
|
|
328
326
|
this.buildFields(meta, populate, joinedProps, qb, qb.alias, options, true);
|
|
329
327
|
}
|
|
330
328
|
return this.rethrow(qb.getCount());
|
|
@@ -339,10 +337,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
339
337
|
res.row = res.row || {};
|
|
340
338
|
let pk;
|
|
341
339
|
if (pks.length > 1) { // owner has composite pk
|
|
342
|
-
pk =
|
|
340
|
+
pk = Utils.getPrimaryKeyCond(data, pks);
|
|
343
341
|
}
|
|
344
342
|
else {
|
|
345
|
-
/*
|
|
343
|
+
/* v8 ignore next */
|
|
346
344
|
res.insertId = data[pks[0]] ?? res.insertId ?? res.row[pks[0]];
|
|
347
345
|
pk = [res.insertId];
|
|
348
346
|
}
|
|
@@ -356,23 +354,23 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
356
354
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
357
355
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
358
356
|
const set = new Set();
|
|
359
|
-
data.forEach(row =>
|
|
357
|
+
data.forEach(row => Utils.keys(row).forEach(k => set.add(k)));
|
|
360
358
|
const props = [...set].map(name => meta?.properties[name] ?? { name, fieldNames: [name] });
|
|
361
|
-
let fields =
|
|
362
|
-
const duplicates =
|
|
359
|
+
let fields = Utils.flatten(props.map(prop => prop.fieldNames));
|
|
360
|
+
const duplicates = Utils.findDuplicates(fields);
|
|
363
361
|
const params = [];
|
|
364
362
|
if (duplicates.length) {
|
|
365
|
-
fields =
|
|
363
|
+
fields = Utils.unique(fields);
|
|
366
364
|
}
|
|
367
|
-
/*
|
|
365
|
+
/* v8 ignore next */
|
|
368
366
|
const tableName = meta ? this.getTableName(meta, options) : this.platform.quoteIdentifier(entityName);
|
|
369
367
|
let sql = `insert into ${tableName} `;
|
|
370
368
|
sql += fields.length > 0 ? '(' + fields.map(k => this.platform.quoteIdentifier(k)).join(', ') + ')' : `(${this.platform.quoteIdentifier(pks[0])})`;
|
|
371
369
|
if (meta && this.platform.usesOutputStatement()) {
|
|
372
370
|
const returningProps = meta.props
|
|
373
371
|
.filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
|
|
374
|
-
.filter(prop => !(prop.name in data[0]) ||
|
|
375
|
-
const returningFields =
|
|
372
|
+
.filter(prop => !(prop.name in data[0]) || isRaw(data[0][prop.name]));
|
|
373
|
+
const returningFields = Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
376
374
|
sql += returningFields.length > 0 ? ` output ${returningFields.map(field => 'inserted.' + this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
377
375
|
}
|
|
378
376
|
if (fields.length > 0 || this.platform.usesDefaultKeyword()) {
|
|
@@ -383,7 +381,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
383
381
|
}
|
|
384
382
|
const addParams = (prop, row) => {
|
|
385
383
|
let value = row[prop.name] ?? prop.default;
|
|
386
|
-
if (prop.kind ===
|
|
384
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
387
385
|
if (prop.array && value) {
|
|
388
386
|
value = this.platform.cloneEmbeddable(value);
|
|
389
387
|
for (let i = 0; i < value.length; i++) {
|
|
@@ -400,7 +398,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
400
398
|
return;
|
|
401
399
|
}
|
|
402
400
|
if (typeof value === 'undefined' && this.platform.usesDefaultKeyword()) {
|
|
403
|
-
params.push(
|
|
401
|
+
params.push(raw('default'));
|
|
404
402
|
return;
|
|
405
403
|
}
|
|
406
404
|
params.push(value);
|
|
@@ -412,7 +410,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
412
410
|
props.forEach(prop => {
|
|
413
411
|
if (prop.fieldNames.length > 1) {
|
|
414
412
|
const newFields = [];
|
|
415
|
-
const allParam = [...
|
|
413
|
+
const allParam = [...(Utils.asArray(row[prop.name]) ?? prop.fieldNames.map(() => null))];
|
|
416
414
|
// TODO(v7): instead of making this conditional here, the entity snapshot should respect `ownColumns`,
|
|
417
415
|
// but that means changing the compiled PK getters, which might be seen as breaking
|
|
418
416
|
const columns = allParam.length > 1 ? prop.fieldNames : prop.ownColumns;
|
|
@@ -424,7 +422,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
424
422
|
newFields.push(field);
|
|
425
423
|
newParam.push(allParam[idx]);
|
|
426
424
|
});
|
|
427
|
-
const param =
|
|
425
|
+
const param = Utils.flatten(newParam);
|
|
428
426
|
newFields.forEach((field, idx) => {
|
|
429
427
|
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
430
428
|
params.push(param[idx]);
|
|
@@ -436,7 +434,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
436
434
|
else {
|
|
437
435
|
const field = prop.fieldNames[0];
|
|
438
436
|
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
439
|
-
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !
|
|
437
|
+
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !isRaw(row[prop.name])) {
|
|
440
438
|
keys.push(prop.customType.convertToDatabaseValueSQL('?', this.platform));
|
|
441
439
|
}
|
|
442
440
|
else {
|
|
@@ -453,9 +451,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
453
451
|
if (meta && this.platform.usesReturningStatement()) {
|
|
454
452
|
const returningProps = meta.props
|
|
455
453
|
.filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
|
|
456
|
-
.filter(prop => !(prop.name in data[0]) ||
|
|
457
|
-
const returningFields =
|
|
458
|
-
/*
|
|
454
|
+
.filter(prop => !(prop.name in data[0]) || isRaw(data[0][prop.name]));
|
|
455
|
+
const returningFields = Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
456
|
+
/* v8 ignore next */
|
|
459
457
|
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
460
458
|
}
|
|
461
459
|
if (transform) {
|
|
@@ -463,9 +461,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
463
461
|
}
|
|
464
462
|
const res = await this.execute(sql, params, 'run', options.ctx);
|
|
465
463
|
let pk;
|
|
466
|
-
/*
|
|
464
|
+
/* v8 ignore next 3 */
|
|
467
465
|
if (pks.length > 1) { // owner has composite pk
|
|
468
|
-
pk = data.map(d =>
|
|
466
|
+
pk = data.map(d => Utils.getPrimaryKeyCond(d, pks));
|
|
469
467
|
}
|
|
470
468
|
else {
|
|
471
469
|
res.row ??= {};
|
|
@@ -484,22 +482,22 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
484
482
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
485
483
|
const collections = this.extractManyToMany(entityName, data);
|
|
486
484
|
let res = { affectedRows: 0, insertId: 0, row: {} };
|
|
487
|
-
if (
|
|
488
|
-
/*
|
|
485
|
+
if (Utils.isPrimaryKey(where) && pks.length === 1) {
|
|
486
|
+
/* v8 ignore next */
|
|
489
487
|
where = { [meta?.primaryKeys[0] ?? pks[0]]: where };
|
|
490
488
|
}
|
|
491
|
-
if (
|
|
489
|
+
if (Utils.hasObjectKeys(data)) {
|
|
492
490
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes)
|
|
493
491
|
.withSchema(this.getSchemaName(meta, options));
|
|
494
492
|
if (options.upsert) {
|
|
495
|
-
/*
|
|
496
|
-
const uniqueFields = options.onConflictFields ?? (
|
|
497
|
-
const returning =
|
|
493
|
+
/* v8 ignore next */
|
|
494
|
+
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(where) ? Utils.keys(where) : meta.primaryKeys);
|
|
495
|
+
const returning = getOnConflictReturningFields(meta, data, uniqueFields, options);
|
|
498
496
|
qb.insert(data)
|
|
499
497
|
.onConflict(uniqueFields)
|
|
500
498
|
.returning(returning);
|
|
501
499
|
if (!options.onConflictAction || options.onConflictAction === 'merge') {
|
|
502
|
-
const fields =
|
|
500
|
+
const fields = getOnConflictFields(meta, data, uniqueFields, options);
|
|
503
501
|
qb.merge(fields);
|
|
504
502
|
}
|
|
505
503
|
if (options.onConflictAction === 'ignore') {
|
|
@@ -517,8 +515,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
517
515
|
}
|
|
518
516
|
res = await this.rethrow(qb.execute('run', false));
|
|
519
517
|
}
|
|
520
|
-
/*
|
|
521
|
-
const pk = pks.map(pk =>
|
|
518
|
+
/* v8 ignore next */
|
|
519
|
+
const pk = pks.map(pk => Utils.extractPK(data[pk] || where, meta));
|
|
522
520
|
await this.processManyToMany(meta, pk, collections, true, options);
|
|
523
521
|
return res;
|
|
524
522
|
}
|
|
@@ -527,14 +525,14 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
527
525
|
options.convertCustomTypes ??= true;
|
|
528
526
|
const meta = this.metadata.get(entityName);
|
|
529
527
|
if (options.upsert) {
|
|
530
|
-
const uniqueFields = options.onConflictFields ?? (
|
|
528
|
+
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(where[0]) ? Object.keys(where[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
|
|
531
529
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes).withSchema(this.getSchemaName(meta, options));
|
|
532
|
-
const returning =
|
|
530
|
+
const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
|
|
533
531
|
qb.insert(data)
|
|
534
532
|
.onConflict(uniqueFields)
|
|
535
533
|
.returning(returning);
|
|
536
534
|
if (!options.onConflictAction || options.onConflictAction === 'merge') {
|
|
537
|
-
const fields =
|
|
535
|
+
const fields = getOnConflictFields(meta, data[0], uniqueFields, options);
|
|
538
536
|
qb.merge(fields);
|
|
539
537
|
}
|
|
540
538
|
if (options.onConflictAction === 'ignore') {
|
|
@@ -547,9 +545,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
547
545
|
const fields = new Set();
|
|
548
546
|
const returning = new Set();
|
|
549
547
|
for (const row of data) {
|
|
550
|
-
for (const k of
|
|
548
|
+
for (const k of Utils.keys(row)) {
|
|
551
549
|
keys.add(k);
|
|
552
|
-
if (
|
|
550
|
+
if (isRaw(row[k])) {
|
|
553
551
|
returning.add(k);
|
|
554
552
|
}
|
|
555
553
|
}
|
|
@@ -558,11 +556,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
558
556
|
meta?.props
|
|
559
557
|
.filter(prop => prop.generated || prop.version || prop.primary)
|
|
560
558
|
.forEach(prop => returning.add(prop.name));
|
|
561
|
-
const pkCond =
|
|
559
|
+
const pkCond = Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
|
|
562
560
|
const params = [];
|
|
563
561
|
let sql = `update ${this.getTableName(meta, options)} set `;
|
|
564
562
|
const addParams = (prop, value) => {
|
|
565
|
-
if (prop.kind ===
|
|
563
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
566
564
|
if (prop.array && value) {
|
|
567
565
|
for (let i = 0; i < value.length; i++) {
|
|
568
566
|
const item = value[i];
|
|
@@ -585,9 +583,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
585
583
|
sql += `${this.platform.quoteIdentifier(fieldName)} = case`;
|
|
586
584
|
where.forEach((cond, idx) => {
|
|
587
585
|
if (key in data[idx]) {
|
|
588
|
-
const pks =
|
|
586
|
+
const pks = Utils.getOrderedPrimaryKeys(cond, meta);
|
|
589
587
|
sql += ` when (${pkCond}) then `;
|
|
590
|
-
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !
|
|
588
|
+
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !isRaw(data[idx][key])) {
|
|
591
589
|
sql += prop.customType.convertToDatabaseValueSQL('?', this.platform);
|
|
592
590
|
}
|
|
593
591
|
else {
|
|
@@ -615,16 +613,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
615
613
|
}
|
|
616
614
|
sql = sql.substring(0, sql.length - 2) + ' where ';
|
|
617
615
|
const pkProps = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
|
|
618
|
-
const pks =
|
|
616
|
+
const pks = Utils.flatten(pkProps.map(pk => meta.properties[pk].fieldNames));
|
|
619
617
|
sql += pks.length > 1 ? `(${pks.map(pk => `${this.platform.quoteIdentifier(pk)}`).join(', ')})` : this.platform.quoteIdentifier(pks[0]);
|
|
620
618
|
const conds = where.map(cond => {
|
|
621
|
-
if (
|
|
619
|
+
if (Utils.isPlainObject(cond) && Utils.getObjectKeysSize(cond) === 1) {
|
|
622
620
|
cond = Object.values(cond)[0];
|
|
623
621
|
}
|
|
624
622
|
if (pks.length > 1) {
|
|
625
623
|
pkProps.forEach(pk => {
|
|
626
624
|
if (Array.isArray(cond[pk])) {
|
|
627
|
-
params.push(...
|
|
625
|
+
params.push(...Utils.flatten(cond[pk]));
|
|
628
626
|
}
|
|
629
627
|
else {
|
|
630
628
|
params.push(cond[pk]);
|
|
@@ -637,8 +635,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
637
635
|
});
|
|
638
636
|
sql += ` in (${conds.join(', ')})`;
|
|
639
637
|
if (this.platform.usesReturningStatement() && returning.size > 0) {
|
|
640
|
-
const returningFields =
|
|
641
|
-
/*
|
|
638
|
+
const returningFields = Utils.flatten([...returning].map(prop => meta.properties[prop].fieldNames));
|
|
639
|
+
/* v8 ignore next */
|
|
642
640
|
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
643
641
|
}
|
|
644
642
|
const res = await this.rethrow(this.execute(sql, params, 'run', options.ctx));
|
|
@@ -650,7 +648,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
650
648
|
async nativeDelete(entityName, where, options = {}) {
|
|
651
649
|
const meta = this.metadata.find(entityName);
|
|
652
650
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
653
|
-
if (
|
|
651
|
+
if (Utils.isPrimaryKey(where) && pks.length === 1) {
|
|
654
652
|
where = { [pks[0]]: where };
|
|
655
653
|
}
|
|
656
654
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', false).delete(where).withSchema(this.getSchemaName(meta, options));
|
|
@@ -669,7 +667,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
669
667
|
}
|
|
670
668
|
}
|
|
671
669
|
else {
|
|
672
|
-
if (!
|
|
670
|
+
if (!Utils.equals(a[i], b[i])) {
|
|
673
671
|
return false;
|
|
674
672
|
}
|
|
675
673
|
}
|
|
@@ -679,17 +677,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
679
677
|
async syncCollections(collections, options) {
|
|
680
678
|
const groups = {};
|
|
681
679
|
for (const coll of collections) {
|
|
682
|
-
const wrapped =
|
|
680
|
+
const wrapped = helper(coll.owner);
|
|
683
681
|
const meta = wrapped.__meta;
|
|
684
682
|
const pks = wrapped.getPrimaryKeys(true);
|
|
685
683
|
const snap = coll.getSnapshot();
|
|
686
684
|
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 =>
|
|
685
|
+
const snapshot = snap ? snap.map(item => helper(item).getPrimaryKeys(true)) : [];
|
|
686
|
+
const current = coll.getItems(false).map(item => helper(item).getPrimaryKeys(true));
|
|
689
687
|
const deleteDiff = snap ? snapshot.filter(item => !includes(current, item)) : true;
|
|
690
688
|
const insertDiff = current.filter(item => !includes(snapshot, item));
|
|
691
689
|
const target = snapshot.filter(item => includes(current, item)).concat(...insertDiff);
|
|
692
|
-
const equals =
|
|
690
|
+
const equals = Utils.equals(current, target);
|
|
693
691
|
// wrong order if we just delete and insert to the end (only owning sides can have fixed order)
|
|
694
692
|
if (coll.property.owner && coll.property.fixedOrder && !equals && Array.isArray(deleteDiff)) {
|
|
695
693
|
deleteDiff.length = insertDiff.length = 0;
|
|
@@ -700,32 +698,30 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
700
698
|
insertDiff.push(item);
|
|
701
699
|
}
|
|
702
700
|
}
|
|
703
|
-
if (coll.property.kind ===
|
|
701
|
+
if (coll.property.kind === ReferenceKind.ONE_TO_MANY) {
|
|
704
702
|
const cols = coll.property.referencedColumnNames;
|
|
705
703
|
const qb = this.createQueryBuilder(coll.property.type, options?.ctx, 'write')
|
|
706
704
|
.withSchema(this.getSchemaName(meta, options));
|
|
707
705
|
if (coll.getSnapshot() === undefined) {
|
|
708
706
|
if (coll.property.orphanRemoval) {
|
|
709
707
|
const query = qb.delete({ [coll.property.mappedBy]: pks })
|
|
710
|
-
.andWhere({ [cols.join(
|
|
708
|
+
.andWhere({ [cols.join(Utils.PK_SEPARATOR)]: { $nin: insertDiff } });
|
|
711
709
|
await this.rethrow(query.execute());
|
|
712
710
|
continue;
|
|
713
711
|
}
|
|
714
712
|
const query = qb.update({ [coll.property.mappedBy]: null })
|
|
715
713
|
.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 } });
|
|
714
|
+
.andWhere({ [cols.join(Utils.PK_SEPARATOR)]: { $nin: insertDiff } });
|
|
724
715
|
await this.rethrow(query.execute());
|
|
725
716
|
continue;
|
|
726
717
|
}
|
|
718
|
+
/* v8 ignore next 5 */
|
|
719
|
+
const query = qb.update({ [coll.property.mappedBy]: pks })
|
|
720
|
+
.where({ [cols.join(Utils.PK_SEPARATOR)]: { $in: insertDiff } });
|
|
721
|
+
await this.rethrow(query.execute());
|
|
722
|
+
continue;
|
|
727
723
|
}
|
|
728
|
-
/*
|
|
724
|
+
/* v8 ignore next */
|
|
729
725
|
const pivotMeta = this.metadata.find(coll.property.pivotEntity);
|
|
730
726
|
let schema = pivotMeta.schema;
|
|
731
727
|
if (schema === '*') {
|
|
@@ -736,10 +732,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
736
732
|
schema = this.config.get('schema');
|
|
737
733
|
}
|
|
738
734
|
const tableName = `${schema ?? '_'}.${pivotMeta.tableName}`;
|
|
739
|
-
const persister = groups[tableName] ??= new
|
|
735
|
+
const persister = groups[tableName] ??= new PivotCollectionPersister(pivotMeta, this, options?.ctx, schema);
|
|
740
736
|
persister.enqueueUpdate(coll.property, insertDiff, deleteDiff, pks);
|
|
741
737
|
}
|
|
742
|
-
for (const persister of
|
|
738
|
+
for (const persister of Utils.values(groups)) {
|
|
743
739
|
await this.rethrow(persister.execute());
|
|
744
740
|
}
|
|
745
741
|
}
|
|
@@ -755,12 +751,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
755
751
|
.comment(options.comments)
|
|
756
752
|
.hintComment(options.hintComments);
|
|
757
753
|
const pivotAlias = qb.alias;
|
|
758
|
-
const pivotKey = pivotProp2.joinColumns.map(column => `${pivotAlias}.${column}`).join(
|
|
754
|
+
const pivotKey = pivotProp2.joinColumns.map(column => `${pivotAlias}.${column}`).join(Utils.PK_SEPARATOR);
|
|
759
755
|
const cond = {
|
|
760
756
|
[pivotKey]: { $in: ownerMeta.compositePK ? owners : owners.map(o => o[0]) },
|
|
761
757
|
};
|
|
762
|
-
/*
|
|
763
|
-
if (!
|
|
758
|
+
/* v8 ignore next 3 */
|
|
759
|
+
if (!Utils.isEmpty(where) && Object.keys(where).every(k => Utils.isOperator(k, false))) {
|
|
764
760
|
where = cond;
|
|
765
761
|
}
|
|
766
762
|
else {
|
|
@@ -784,7 +780,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
784
780
|
for (const field of targetFields) {
|
|
785
781
|
const f = field.toString();
|
|
786
782
|
fields.unshift(f.includes('.') ? field : `${targetAlias}.${f}`);
|
|
787
|
-
if (
|
|
783
|
+
if (RawQueryFragment.isKnownFragment(field)) {
|
|
788
784
|
qb.rawFragments.add(f);
|
|
789
785
|
}
|
|
790
786
|
}
|
|
@@ -819,35 +815,35 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
819
815
|
const map = {};
|
|
820
816
|
const pkProps = ownerMeta.getPrimaryProps();
|
|
821
817
|
for (const owner of owners) {
|
|
822
|
-
const key =
|
|
818
|
+
const key = Utils.getPrimaryKeyHash(prop.joinColumns.map((_col, idx) => {
|
|
823
819
|
const pkProp = pkProps[idx];
|
|
824
820
|
return pkProp.customType ? pkProp.customType.convertToJSValue(owner[idx], this.platform) : owner[idx];
|
|
825
821
|
}));
|
|
826
822
|
map[key] = [];
|
|
827
823
|
}
|
|
828
824
|
for (const item of items) {
|
|
829
|
-
const key =
|
|
825
|
+
const key = Utils.getPrimaryKeyHash(prop.joinColumns.map((col, idx) => {
|
|
830
826
|
const pkProp = pkProps[idx];
|
|
831
827
|
return pkProp.customType ? pkProp.customType.convertToJSValue(item[`fk__${col}`], this.platform) : item[`fk__${col}`];
|
|
832
828
|
}));
|
|
833
829
|
map[key].push(item);
|
|
834
830
|
prop.joinColumns.forEach(col => delete item[`fk__${col}`]);
|
|
835
831
|
prop.inverseJoinColumns.forEach((col, idx) => {
|
|
836
|
-
|
|
832
|
+
Utils.renameKey(item, `fk__${col}`, prop.targetMeta.primaryKeys[idx]);
|
|
837
833
|
});
|
|
838
834
|
}
|
|
839
835
|
return map;
|
|
840
836
|
}
|
|
841
837
|
getPivotOrderBy(prop, pivotProp, pivotAlias, orderBy) {
|
|
842
838
|
// FIXME this is ignoring the rest of the array items
|
|
843
|
-
if (!
|
|
844
|
-
return [{ [pivotProp.name]:
|
|
839
|
+
if (!Utils.isEmpty(orderBy)) {
|
|
840
|
+
return [{ [pivotProp.name]: Utils.asArray(orderBy)[0] }];
|
|
845
841
|
}
|
|
846
|
-
if (!
|
|
847
|
-
return [{ [pivotProp.name]:
|
|
842
|
+
if (!Utils.isEmpty(prop.orderBy)) {
|
|
843
|
+
return [{ [pivotProp.name]: Utils.asArray(prop.orderBy)[0] }];
|
|
848
844
|
}
|
|
849
845
|
if (prop.fixedOrder) {
|
|
850
|
-
return [{ [`${pivotAlias}.${prop.fixedOrderColumn}`]:
|
|
846
|
+
return [{ [`${pivotAlias}.${prop.fixedOrderColumn}`]: QueryOrder.ASC }];
|
|
851
847
|
}
|
|
852
848
|
return [];
|
|
853
849
|
}
|
|
@@ -863,7 +859,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
863
859
|
}
|
|
864
860
|
const relationsToPopulate = populate.map(({ field }) => field.split(':')[0]);
|
|
865
861
|
const toPopulate = meta.relations
|
|
866
|
-
.filter(prop => prop.kind ===
|
|
862
|
+
.filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !prop.lazy && !relationsToPopulate.includes(prop.name))
|
|
867
863
|
.filter(prop => fields.length === 0 || fields.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
868
864
|
.map(prop => ({ field: `${prop.name}:ref`, strategy: prop.strategy }));
|
|
869
865
|
return [...populate, ...toPopulate];
|
|
@@ -875,18 +871,18 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
875
871
|
return populate.filter(hint => {
|
|
876
872
|
const [propName, ref] = hint.field.split(':', 2);
|
|
877
873
|
const prop = meta.properties[propName] || {};
|
|
878
|
-
if (hint.filter && hint.strategy ===
|
|
874
|
+
if (hint.filter && hint.strategy === LoadStrategy.JOINED) {
|
|
879
875
|
return true;
|
|
880
876
|
}
|
|
881
877
|
// skip redundant joins for 1:1 owner population hints when using `mapToPk`
|
|
882
|
-
if (prop.kind ===
|
|
878
|
+
if (prop.kind === ReferenceKind.ONE_TO_ONE && prop.mapToPk && prop.owner) {
|
|
883
879
|
return false;
|
|
884
880
|
}
|
|
885
|
-
if ((options?.strategy || hint.strategy || prop.strategy || this.config.get('loadStrategy')) !==
|
|
881
|
+
if ((options?.strategy || hint.strategy || prop.strategy || this.config.get('loadStrategy')) !== LoadStrategy.JOINED) {
|
|
886
882
|
// force joined strategy for explicit 1:1 owner populate hint as it would require a join anyway
|
|
887
|
-
return prop.kind ===
|
|
883
|
+
return prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner;
|
|
888
884
|
}
|
|
889
|
-
return ![
|
|
885
|
+
return ![ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind);
|
|
890
886
|
});
|
|
891
887
|
}
|
|
892
888
|
/**
|
|
@@ -896,7 +892,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
896
892
|
const res = [];
|
|
897
893
|
const map = {};
|
|
898
894
|
for (const item of rawResults) {
|
|
899
|
-
const pk =
|
|
895
|
+
const pk = Utils.getCompositeKeyHash(item, meta);
|
|
900
896
|
if (map[pk]) {
|
|
901
897
|
for (const hint of joinedProps) {
|
|
902
898
|
const [propName, ref] = hint.field.split(':', 2);
|
|
@@ -904,17 +900,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
904
900
|
if (!item[propName]) {
|
|
905
901
|
continue;
|
|
906
902
|
}
|
|
907
|
-
if ([
|
|
903
|
+
if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) && ref) {
|
|
908
904
|
map[pk][propName] = [...map[pk][propName], ...item[propName]];
|
|
909
905
|
continue;
|
|
910
906
|
}
|
|
911
907
|
switch (prop.kind) {
|
|
912
|
-
case
|
|
913
|
-
case
|
|
908
|
+
case ReferenceKind.ONE_TO_MANY:
|
|
909
|
+
case ReferenceKind.MANY_TO_MANY:
|
|
914
910
|
map[pk][propName] = this.mergeJoinedResult([...map[pk][propName], ...item[propName]], prop.targetMeta, hint.children ?? []);
|
|
915
911
|
break;
|
|
916
|
-
case
|
|
917
|
-
case
|
|
912
|
+
case ReferenceKind.MANY_TO_ONE:
|
|
913
|
+
case ReferenceKind.ONE_TO_ONE:
|
|
918
914
|
map[pk][propName] = this.mergeJoinedResult([map[pk][propName], item[propName]], prop.targetMeta, hint.children ?? [])[0];
|
|
919
915
|
break;
|
|
920
916
|
}
|
|
@@ -940,7 +936,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
940
936
|
}
|
|
941
937
|
return fields.some(f => f === prop.name || f.toString().startsWith(prop.name + '.'));
|
|
942
938
|
};
|
|
943
|
-
const populateWhereAll = options?._populateWhere === 'all' ||
|
|
939
|
+
const populateWhereAll = options?._populateWhere === 'all' || Utils.isEmpty(options?._populateWhere);
|
|
944
940
|
// root entity is already handled, skip that
|
|
945
941
|
if (options.parentJoinPath) {
|
|
946
942
|
// alias all fields in the primary table
|
|
@@ -952,14 +948,14 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
952
948
|
const [propName, ref] = hint.field.split(':', 2);
|
|
953
949
|
const prop = meta.properties[propName];
|
|
954
950
|
// ignore ref joins of known FKs unless it's a filter hint
|
|
955
|
-
if (ref && !hint.filter && (prop.kind ===
|
|
951
|
+
if (ref && !hint.filter && (prop.kind === ReferenceKind.MANY_TO_ONE || (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner))) {
|
|
956
952
|
continue;
|
|
957
953
|
}
|
|
958
|
-
if (options.count &&
|
|
954
|
+
if (options.count && !options?.populateFilter?.[prop.name]) {
|
|
959
955
|
continue;
|
|
960
956
|
}
|
|
961
957
|
const meta2 = this.metadata.find(prop.type);
|
|
962
|
-
const pivotRefJoin = prop.kind ===
|
|
958
|
+
const pivotRefJoin = prop.kind === ReferenceKind.MANY_TO_MANY && ref;
|
|
963
959
|
const tableAlias = qb.getNextAlias(prop.name);
|
|
964
960
|
const field = `${options.parentTableAlias}.${prop.name}`;
|
|
965
961
|
let path = options.parentJoinPath ? `${options.parentJoinPath}.${prop.name}` : `${meta.name}.${prop.name}`;
|
|
@@ -967,15 +963,15 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
967
963
|
path = '[populate]' + path;
|
|
968
964
|
}
|
|
969
965
|
const joinType = pivotRefJoin
|
|
970
|
-
?
|
|
966
|
+
? JoinType.pivotJoin
|
|
971
967
|
: hint.filter && !prop.nullable
|
|
972
|
-
?
|
|
973
|
-
:
|
|
968
|
+
? JoinType.innerJoin
|
|
969
|
+
: JoinType.leftJoin;
|
|
974
970
|
qb.join(field, tableAlias, {}, joinType, path);
|
|
975
971
|
if (pivotRefJoin) {
|
|
976
972
|
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
973
|
}
|
|
978
|
-
if (prop.kind ===
|
|
974
|
+
if (prop.kind === ReferenceKind.ONE_TO_MANY && ref) {
|
|
979
975
|
fields.push(...this.getFieldsForJoinedLoad(qb, meta2, {
|
|
980
976
|
...options,
|
|
981
977
|
explicitFields: prop.referencedColumnNames,
|
|
@@ -985,13 +981,13 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
985
981
|
parentJoinPath: path,
|
|
986
982
|
}));
|
|
987
983
|
}
|
|
988
|
-
const childExplicitFields = options.explicitFields?.filter(f =>
|
|
984
|
+
const childExplicitFields = options.explicitFields?.filter(f => Utils.isPlainObject(f)).map(o => o[prop.name])[0] || [];
|
|
989
985
|
options.explicitFields?.forEach(f => {
|
|
990
986
|
if (typeof f === 'string' && f.startsWith(`${prop.name}.`)) {
|
|
991
987
|
childExplicitFields.push(f.substring(prop.name.length + 1));
|
|
992
988
|
}
|
|
993
989
|
});
|
|
994
|
-
const childExclude = options.exclude ?
|
|
990
|
+
const childExclude = options.exclude ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
|
|
995
991
|
if (!ref && !prop.mapToPk) {
|
|
996
992
|
fields.push(...this.getFieldsForJoinedLoad(qb, meta2, {
|
|
997
993
|
...options,
|
|
@@ -1020,16 +1016,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1020
1016
|
}
|
|
1021
1017
|
const prefixed = this.platform.quoteIdentifier(`${tableAlias}.${col}`);
|
|
1022
1018
|
const aliased = this.platform.quoteIdentifier(`${tableAlias}__${col}`);
|
|
1023
|
-
return
|
|
1019
|
+
return raw(`${prop.customTypes[idx].convertToJSValueSQL(prefixed, this.platform)} as ${aliased}`);
|
|
1024
1020
|
});
|
|
1025
1021
|
}
|
|
1026
1022
|
if (prop.customType?.convertToJSValueSQL) {
|
|
1027
1023
|
const prefixed = this.platform.quoteIdentifier(`${tableAlias}.${prop.fieldNames[0]}`);
|
|
1028
|
-
return [
|
|
1024
|
+
return [raw(`${prop.customType.convertToJSValueSQL(prefixed, this.platform)} as ${aliased}`)];
|
|
1029
1025
|
}
|
|
1030
1026
|
if (prop.formula) {
|
|
1031
1027
|
const alias = this.platform.quoteIdentifier(tableAlias);
|
|
1032
|
-
return [
|
|
1028
|
+
return [raw(`${prop.formula(alias)} as ${aliased}`)];
|
|
1033
1029
|
}
|
|
1034
1030
|
return prop.fieldNames.map(fieldName => {
|
|
1035
1031
|
return `${tableAlias}.${fieldName} as ${tableAlias}__${fieldName}`;
|
|
@@ -1039,9 +1035,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1039
1035
|
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes, loggerContext, alias, em) {
|
|
1040
1036
|
// do not compute the connectionType if EM is provided as it will be computed from it in the QB later on
|
|
1041
1037
|
const connectionType = em ? preferredConnectionType : this.resolveConnectionType({ ctx, connectionType: preferredConnectionType });
|
|
1042
|
-
const qb = new
|
|
1038
|
+
const qb = new QueryBuilder(entityName, this.metadata, this, ctx, alias, connectionType, em, loggerContext);
|
|
1043
1039
|
if (!convertCustomTypes) {
|
|
1044
|
-
qb.unsetFlag(
|
|
1040
|
+
qb.unsetFlag(QueryFlag.CONVERT_CUSTOM_TYPES);
|
|
1045
1041
|
}
|
|
1046
1042
|
return qb;
|
|
1047
1043
|
}
|
|
@@ -1063,8 +1059,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1063
1059
|
}
|
|
1064
1060
|
const ret = {};
|
|
1065
1061
|
this.metadata.find(entityName).relations.forEach(prop => {
|
|
1066
|
-
if (prop.kind ===
|
|
1067
|
-
ret[prop.name] = data[prop.name].map((item) =>
|
|
1062
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && data[prop.name]) {
|
|
1063
|
+
ret[prop.name] = data[prop.name].map((item) => Utils.asArray(item));
|
|
1068
1064
|
delete data[prop.name];
|
|
1069
1065
|
}
|
|
1070
1066
|
});
|
|
@@ -1077,17 +1073,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1077
1073
|
for (const prop of meta.relations) {
|
|
1078
1074
|
if (collections[prop.name]) {
|
|
1079
1075
|
const pivotMeta = this.metadata.find(prop.pivotEntity);
|
|
1080
|
-
const persister = new
|
|
1076
|
+
const persister = new PivotCollectionPersister(pivotMeta, this, options?.ctx, options?.schema);
|
|
1081
1077
|
persister.enqueueUpdate(prop, collections[prop.name], clear, pks);
|
|
1082
1078
|
await this.rethrow(persister.execute());
|
|
1083
1079
|
}
|
|
1084
1080
|
}
|
|
1085
1081
|
}
|
|
1086
1082
|
async lockPessimistic(entity, options) {
|
|
1087
|
-
const meta =
|
|
1083
|
+
const meta = helper(entity).__meta;
|
|
1088
1084
|
const qb = this.createQueryBuilder(entity.constructor.name, options.ctx, undefined, undefined, options.logging).withSchema(options.schema ?? meta.schema);
|
|
1089
|
-
const cond =
|
|
1090
|
-
qb.select(
|
|
1085
|
+
const cond = Utils.getPrimaryKeyCond(entity, meta.primaryKeys);
|
|
1086
|
+
qb.select(raw('1')).where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
1091
1087
|
await this.rethrow(qb.execute());
|
|
1092
1088
|
}
|
|
1093
1089
|
buildPopulateWhere(meta, joinedProps, options) {
|
|
@@ -1095,45 +1091,45 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1095
1091
|
for (const hint of joinedProps) {
|
|
1096
1092
|
const [propName] = hint.field.split(':', 2);
|
|
1097
1093
|
const prop = meta.properties[propName];
|
|
1098
|
-
if (!
|
|
1099
|
-
where[prop.name] =
|
|
1094
|
+
if (!Utils.isEmpty(prop.where)) {
|
|
1095
|
+
where[prop.name] = Utils.copy(prop.where);
|
|
1100
1096
|
}
|
|
1101
1097
|
if (hint.children) {
|
|
1102
1098
|
const inner = this.buildPopulateWhere(prop.targetMeta, hint.children, {});
|
|
1103
|
-
if (!
|
|
1099
|
+
if (!Utils.isEmpty(inner)) {
|
|
1104
1100
|
where[prop.name] ??= {};
|
|
1105
1101
|
Object.assign(where[prop.name], inner);
|
|
1106
1102
|
}
|
|
1107
1103
|
}
|
|
1108
1104
|
}
|
|
1109
|
-
if (
|
|
1105
|
+
if (Utils.isEmpty(options.populateWhere)) {
|
|
1110
1106
|
return where;
|
|
1111
1107
|
}
|
|
1112
|
-
if (
|
|
1108
|
+
if (Utils.isEmpty(where)) {
|
|
1113
1109
|
return options.populateWhere;
|
|
1114
1110
|
}
|
|
1115
|
-
/*
|
|
1111
|
+
/* v8 ignore next */
|
|
1116
1112
|
return { $and: [options.populateWhere, where] };
|
|
1117
1113
|
}
|
|
1118
1114
|
buildOrderBy(qb, meta, populate, options) {
|
|
1119
1115
|
const joinedProps = this.joinedProps(meta, populate, options);
|
|
1120
1116
|
// `options._populateWhere` is a copy of the value provided by user with a fallback to the global config option
|
|
1121
1117
|
// as `options.populateWhere` will be always recomputed to respect filters
|
|
1122
|
-
const populateWhereAll = options._populateWhere !== 'infer' && !
|
|
1118
|
+
const populateWhereAll = options._populateWhere !== 'infer' && !Utils.isEmpty(options._populateWhere);
|
|
1123
1119
|
const path = (populateWhereAll ? '[populate]' : '') + meta.className;
|
|
1124
|
-
const populateOrderBy = this.buildPopulateOrderBy(qb, meta,
|
|
1120
|
+
const populateOrderBy = this.buildPopulateOrderBy(qb, meta, Utils.asArray(options.populateOrderBy ?? options.orderBy), path, !!options.populateOrderBy);
|
|
1125
1121
|
const joinedPropsOrderBy = this.buildJoinedPropsOrderBy(qb, meta, joinedProps, options, path);
|
|
1126
|
-
return [...
|
|
1122
|
+
return [...Utils.asArray(options.orderBy), ...populateOrderBy, ...joinedPropsOrderBy];
|
|
1127
1123
|
}
|
|
1128
1124
|
buildPopulateOrderBy(qb, meta, populateOrderBy, parentPath, explicit, parentAlias = qb.alias) {
|
|
1129
1125
|
const orderBy = [];
|
|
1130
1126
|
for (let i = 0; i < populateOrderBy.length; i++) {
|
|
1131
1127
|
const orderHint = populateOrderBy[i];
|
|
1132
|
-
for (const propName of
|
|
1133
|
-
const raw =
|
|
1128
|
+
for (const propName of Utils.keys(orderHint)) {
|
|
1129
|
+
const raw = RawQueryFragment.getKnownFragment(propName, explicit);
|
|
1134
1130
|
if (raw) {
|
|
1135
|
-
const sql = raw.sql.replace(new RegExp(
|
|
1136
|
-
const raw2 = new
|
|
1131
|
+
const sql = raw.sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), parentAlias);
|
|
1132
|
+
const raw2 = new RawQueryFragment(sql, raw.params);
|
|
1137
1133
|
orderBy.push({ [raw2]: orderHint[propName] });
|
|
1138
1134
|
continue;
|
|
1139
1135
|
}
|
|
@@ -1144,10 +1140,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1144
1140
|
let path = parentPath;
|
|
1145
1141
|
const meta2 = this.metadata.find(prop.type);
|
|
1146
1142
|
const childOrder = orderHint[prop.name];
|
|
1147
|
-
if (![
|
|
1143
|
+
if (![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) || !prop.owner || Utils.isPlainObject(childOrder)) {
|
|
1148
1144
|
path += `.${propName}`;
|
|
1149
1145
|
}
|
|
1150
|
-
if (prop.kind ===
|
|
1146
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && typeof childOrder !== 'object') {
|
|
1151
1147
|
path += '[pivot]';
|
|
1152
1148
|
}
|
|
1153
1149
|
const join = qb.getJoinForPath(path, { matchPopulateJoins: true });
|
|
@@ -1155,12 +1151,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1155
1151
|
if (!join && parentAlias === qb.alias) {
|
|
1156
1152
|
continue;
|
|
1157
1153
|
}
|
|
1158
|
-
if (![
|
|
1159
|
-
const children = this.buildPopulateOrderBy(qb, meta2,
|
|
1154
|
+
if (![ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind) && typeof childOrder === 'object') {
|
|
1155
|
+
const children = this.buildPopulateOrderBy(qb, meta2, Utils.asArray(childOrder), path, explicit, propAlias);
|
|
1160
1156
|
orderBy.push(...children);
|
|
1161
1157
|
continue;
|
|
1162
1158
|
}
|
|
1163
|
-
if (prop.kind ===
|
|
1159
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && join) {
|
|
1164
1160
|
if (prop.fixedOrderColumn) {
|
|
1165
1161
|
orderBy.push({ [`${join.alias}.${prop.fixedOrderColumn}`]: childOrder });
|
|
1166
1162
|
}
|
|
@@ -1187,23 +1183,23 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1187
1183
|
const prop = meta.properties[propName];
|
|
1188
1184
|
const propOrderBy = prop.orderBy;
|
|
1189
1185
|
let path = `${parentPath}.${propName}`;
|
|
1190
|
-
if (prop.kind ===
|
|
1186
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && ref) {
|
|
1191
1187
|
path += '[pivot]';
|
|
1192
1188
|
}
|
|
1193
1189
|
const join = qb.getJoinForPath(path, { matchPopulateJoins: true });
|
|
1194
1190
|
const propAlias = qb.getAliasForJoinPath(join ?? path, { matchPopulateJoins: true });
|
|
1195
1191
|
const meta2 = this.metadata.find(prop.type);
|
|
1196
|
-
if (prop.kind ===
|
|
1192
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.fixedOrder && join) {
|
|
1197
1193
|
const alias = ref ? propAlias : join.ownerAlias;
|
|
1198
|
-
orderBy.push({ [`${alias}.${prop.fixedOrderColumn}`]:
|
|
1194
|
+
orderBy.push({ [`${alias}.${prop.fixedOrderColumn}`]: QueryOrder.ASC });
|
|
1199
1195
|
}
|
|
1200
1196
|
if (propOrderBy) {
|
|
1201
|
-
for (const item of
|
|
1202
|
-
for (const field of
|
|
1203
|
-
const rawField =
|
|
1197
|
+
for (const item of Utils.asArray(propOrderBy)) {
|
|
1198
|
+
for (const field of Utils.keys(item)) {
|
|
1199
|
+
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
1204
1200
|
if (rawField) {
|
|
1205
|
-
const sql = propAlias ? rawField.sql.replace(new RegExp(
|
|
1206
|
-
const raw2 =
|
|
1201
|
+
const sql = propAlias ? rawField.sql.replace(new RegExp(ALIAS_REPLACEMENT_RE, 'g'), propAlias) : rawField.sql;
|
|
1202
|
+
const raw2 = raw(sql, rawField.params);
|
|
1207
1203
|
orderBy.push({ [raw2.toString()]: item[field] });
|
|
1208
1204
|
continue;
|
|
1209
1205
|
}
|
|
@@ -1225,7 +1221,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1225
1221
|
ret.push(prefix + field);
|
|
1226
1222
|
continue;
|
|
1227
1223
|
}
|
|
1228
|
-
if (
|
|
1224
|
+
if (Utils.isPlainObject(field)) {
|
|
1229
1225
|
for (const key of Object.keys(field)) {
|
|
1230
1226
|
ret.push(...this.normalizeFields(field[key], key + '.'));
|
|
1231
1227
|
}
|
|
@@ -1234,10 +1230,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1234
1230
|
return ret;
|
|
1235
1231
|
}
|
|
1236
1232
|
processField(meta, prop, field, ret, populate, joinedProps, qb) {
|
|
1237
|
-
if (!prop || (prop.kind ===
|
|
1233
|
+
if (!prop || (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner)) {
|
|
1238
1234
|
return;
|
|
1239
1235
|
}
|
|
1240
|
-
if (prop.kind ===
|
|
1236
|
+
if (prop.kind === ReferenceKind.EMBEDDED) {
|
|
1241
1237
|
if (prop.object) {
|
|
1242
1238
|
ret.push(prop.name);
|
|
1243
1239
|
return;
|
|
@@ -1281,7 +1277,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1281
1277
|
}
|
|
1282
1278
|
const parts = field.split('.');
|
|
1283
1279
|
const rootPropName = parts.shift(); // first one is the `prop`
|
|
1284
|
-
const prop =
|
|
1280
|
+
const prop = QueryHelper.findProperty(rootPropName, {
|
|
1285
1281
|
metadata: this.metadata,
|
|
1286
1282
|
platform: this.platform,
|
|
1287
1283
|
entityName: meta.className,
|
|
@@ -1294,7 +1290,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1294
1290
|
ret.unshift(...meta.primaryKeys.filter(pk => !options.fields.includes(pk)));
|
|
1295
1291
|
}
|
|
1296
1292
|
}
|
|
1297
|
-
else if (!
|
|
1293
|
+
else if (!Utils.isEmpty(options.exclude) || lazyProps.some(p => !p.formula && (p.kind !== '1:1' || p.owner))) {
|
|
1298
1294
|
const props = meta.props.filter(prop => this.platform.shouldHaveColumn(prop, populate, options.exclude, false));
|
|
1299
1295
|
ret.push(...props.filter(p => !lazyProps.includes(p)).map(p => p.name));
|
|
1300
1296
|
addFormulas = true;
|
|
@@ -1312,7 +1308,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1312
1308
|
.forEach(prop => {
|
|
1313
1309
|
const a = this.platform.quoteIdentifier(alias);
|
|
1314
1310
|
const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
1315
|
-
ret.push(
|
|
1311
|
+
ret.push(raw(`${prop.formula(a)} as ${aliased}`));
|
|
1316
1312
|
});
|
|
1317
1313
|
meta.props
|
|
1318
1314
|
.filter(prop => !prop.object && (prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL))
|
|
@@ -1329,7 +1325,6 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1329
1325
|
...options,
|
|
1330
1326
|
}));
|
|
1331
1327
|
}
|
|
1332
|
-
return
|
|
1328
|
+
return Utils.unique(ret);
|
|
1333
1329
|
}
|
|
1334
1330
|
}
|
|
1335
|
-
exports.AbstractSqlDriver = AbstractSqlDriver;
|