@mikro-orm/knex 6.0.0-dev.11 → 6.0.0-dev.111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AbstractSqlConnection.d.ts +8 -4
- package/AbstractSqlConnection.js +30 -18
- package/AbstractSqlDriver.d.ts +16 -17
- package/AbstractSqlDriver.js +283 -118
- package/AbstractSqlPlatform.d.ts +5 -4
- package/AbstractSqlPlatform.js +34 -5
- package/MonkeyPatchable.d.ts +1 -0
- package/MonkeyPatchable.js +3 -0
- package/README.md +64 -107
- package/SqlEntityManager.d.ts +2 -6
- package/SqlEntityManager.js +5 -9
- package/SqlEntityRepository.d.ts +7 -6
- package/SqlEntityRepository.js +11 -8
- package/index.mjs +22 -6
- package/package.json +8 -8
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +16 -9
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +10 -13
- package/query/ObjectCriteriaNode.d.ts +3 -3
- package/query/ObjectCriteriaNode.js +12 -8
- package/query/QueryBuilder.d.ts +39 -19
- package/query/QueryBuilder.js +331 -111
- package/query/QueryBuilderHelper.d.ts +9 -13
- package/query/QueryBuilderHelper.js +153 -107
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/query/enums.js +1 -1
- package/schema/DatabaseSchema.d.ts +5 -2
- package/schema/DatabaseSchema.js +26 -8
- package/schema/DatabaseTable.d.ts +4 -2
- package/schema/DatabaseTable.js +55 -30
- package/schema/SchemaComparator.js +12 -2
- package/schema/SchemaHelper.d.ts +6 -4
- package/schema/SchemaHelper.js +11 -4
- package/schema/SqlSchemaGenerator.d.ts +3 -6
- package/schema/SqlSchemaGenerator.js +61 -28
- package/typings.d.ts +13 -7
package/AbstractSqlDriver.js
CHANGED
|
@@ -5,9 +5,12 @@ const core_1 = require("@mikro-orm/core");
|
|
|
5
5
|
const query_1 = require("./query");
|
|
6
6
|
const SqlEntityManager_1 = require("./SqlEntityManager");
|
|
7
7
|
class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
8
|
+
[core_1.EntityManagerType];
|
|
9
|
+
connection;
|
|
10
|
+
replicas = [];
|
|
11
|
+
platform;
|
|
8
12
|
constructor(config, platform, connection, connector) {
|
|
9
13
|
super(config, connector);
|
|
10
|
-
this.replicas = [];
|
|
11
14
|
this.connection = new connection(this.config);
|
|
12
15
|
this.replicas = this.createReplicas(conf => new connection(this.config, conf, 'read'));
|
|
13
16
|
this.platform = platform;
|
|
@@ -26,19 +29,31 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
26
29
|
}
|
|
27
30
|
const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
|
|
28
31
|
const joinedProps = this.joinedProps(meta, populate);
|
|
29
|
-
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false);
|
|
32
|
+
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging);
|
|
30
33
|
const fields = this.buildFields(meta, populate, joinedProps, qb, options.fields);
|
|
31
34
|
const joinedPropsOrderBy = this.buildJoinedPropsOrderBy(entityName, qb, meta, joinedProps);
|
|
35
|
+
const orderBy = [...core_1.Utils.asArray(options.orderBy), ...joinedPropsOrderBy];
|
|
32
36
|
if (core_1.Utils.isPrimaryKey(where, meta.compositePK)) {
|
|
33
37
|
where = { [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: where };
|
|
34
38
|
}
|
|
39
|
+
const { first, last, before, after } = options;
|
|
40
|
+
const isCursorPagination = [first, last, before, after].some(v => v != null);
|
|
35
41
|
qb.select(fields)
|
|
36
42
|
.populate(populate, joinedProps.length > 0 ? options.populateWhere : undefined)
|
|
37
43
|
.where(where)
|
|
38
|
-
.orderBy([...core_1.Utils.asArray(options.orderBy), ...joinedPropsOrderBy])
|
|
39
44
|
.groupBy(options.groupBy)
|
|
40
45
|
.having(options.having)
|
|
46
|
+
.indexHint(options.indexHint)
|
|
47
|
+
.comment(options.comments)
|
|
48
|
+
.hintComment(options.hintComments)
|
|
41
49
|
.withSchema(this.getSchemaName(meta, options));
|
|
50
|
+
if (isCursorPagination) {
|
|
51
|
+
const { orderBy: newOrderBy, where } = this.processCursorOptions(meta, options, orderBy);
|
|
52
|
+
qb.andWhere(where).orderBy(newOrderBy);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
qb.orderBy(orderBy);
|
|
56
|
+
}
|
|
42
57
|
if (options.limit !== undefined) {
|
|
43
58
|
qb.limit(options.limit, options.offset);
|
|
44
59
|
}
|
|
@@ -47,8 +62,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
47
62
|
}
|
|
48
63
|
core_1.Utils.asArray(options.flags).forEach(flag => qb.setFlag(flag));
|
|
49
64
|
const result = await this.rethrow(qb.execute('all'));
|
|
65
|
+
if (isCursorPagination && !first && !!last) {
|
|
66
|
+
result.reverse();
|
|
67
|
+
}
|
|
50
68
|
if (joinedProps.length > 0) {
|
|
51
|
-
return this.mergeJoinedResult(result, meta);
|
|
69
|
+
return this.mergeJoinedResult(result, meta, joinedProps);
|
|
52
70
|
}
|
|
53
71
|
return result;
|
|
54
72
|
}
|
|
@@ -61,58 +79,57 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
61
79
|
opts.limit = 1;
|
|
62
80
|
}
|
|
63
81
|
if (opts.limit > 0 && !opts.flags?.includes(core_1.QueryFlag.DISABLE_PAGINATE)) {
|
|
64
|
-
opts.flags
|
|
82
|
+
opts.flags ??= [];
|
|
65
83
|
opts.flags.push(core_1.QueryFlag.DISABLE_PAGINATE);
|
|
66
84
|
}
|
|
67
85
|
const res = await this.find(entityName, where, opts);
|
|
68
86
|
return res[0] || null;
|
|
69
87
|
}
|
|
70
88
|
async findVirtual(entityName, where, options) {
|
|
71
|
-
|
|
72
|
-
/* istanbul ignore next */
|
|
73
|
-
if (!meta.expression) {
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
if (typeof meta.expression === 'string') {
|
|
77
|
-
return this.wrapVirtualExpressionInSubquery(meta, meta.expression, where, options);
|
|
78
|
-
}
|
|
79
|
-
const em = this.createEntityManager(false);
|
|
80
|
-
em.setTransactionContext(options.ctx);
|
|
81
|
-
const res = meta.expression(em, where, options);
|
|
82
|
-
if (res instanceof (query_1.QueryBuilder)) {
|
|
83
|
-
return this.wrapVirtualExpressionInSubquery(meta, res.getFormattedQuery(), where, options);
|
|
84
|
-
}
|
|
85
|
-
/* istanbul ignore next */
|
|
86
|
-
return res;
|
|
89
|
+
return this.findFromVirtual(entityName, where, options, query_1.QueryType.SELECT);
|
|
87
90
|
}
|
|
88
91
|
async countVirtual(entityName, where, options) {
|
|
92
|
+
return this.findFromVirtual(entityName, where, options, query_1.QueryType.COUNT);
|
|
93
|
+
}
|
|
94
|
+
async findFromVirtual(entityName, where, options, type) {
|
|
89
95
|
const meta = this.metadata.get(entityName);
|
|
90
96
|
/* istanbul ignore next */
|
|
91
97
|
if (!meta.expression) {
|
|
92
|
-
return 0;
|
|
98
|
+
return type === query_1.QueryType.SELECT ? [] : 0;
|
|
93
99
|
}
|
|
94
100
|
if (typeof meta.expression === 'string') {
|
|
95
|
-
return this.wrapVirtualExpressionInSubquery(meta, meta.expression, where, options,
|
|
101
|
+
return this.wrapVirtualExpressionInSubquery(meta, meta.expression, where, options, type);
|
|
96
102
|
}
|
|
97
103
|
const em = this.createEntityManager(false);
|
|
98
104
|
em.setTransactionContext(options.ctx);
|
|
99
105
|
const res = meta.expression(em, where, options);
|
|
100
|
-
if (res
|
|
101
|
-
return this.wrapVirtualExpressionInSubquery(meta, res
|
|
106
|
+
if (typeof res === 'string') {
|
|
107
|
+
return this.wrapVirtualExpressionInSubquery(meta, res, where, options, type);
|
|
108
|
+
}
|
|
109
|
+
if (res instanceof query_1.QueryBuilder) {
|
|
110
|
+
return this.wrapVirtualExpressionInSubquery(meta, res.getFormattedQuery(), where, options, type);
|
|
111
|
+
}
|
|
112
|
+
if (core_1.Utils.isObject(res)) {
|
|
113
|
+
const { sql, bindings } = res.toSQL();
|
|
114
|
+
const query = this.platform.formatQuery(sql, bindings);
|
|
115
|
+
return this.wrapVirtualExpressionInSubquery(meta, query, where, options, type);
|
|
102
116
|
}
|
|
103
117
|
/* istanbul ignore next */
|
|
104
118
|
return res;
|
|
105
119
|
}
|
|
106
|
-
async wrapVirtualExpressionInSubquery(meta, expression, where, options, type
|
|
120
|
+
async wrapVirtualExpressionInSubquery(meta, expression, where, options, type) {
|
|
107
121
|
const qb = this.createQueryBuilder(meta.className, options?.ctx, options.connectionType, options.convertCustomTypes)
|
|
108
|
-
.limit(options?.limit, options?.offset)
|
|
122
|
+
.limit(options?.limit, options?.offset)
|
|
123
|
+
.indexHint(options.indexHint)
|
|
124
|
+
.comment(options.comments)
|
|
125
|
+
.hintComment(options.hintComments);
|
|
109
126
|
if (options.orderBy) {
|
|
110
127
|
qb.orderBy(options.orderBy);
|
|
111
128
|
}
|
|
112
129
|
qb.where(where);
|
|
113
130
|
const kqb = qb.getKnexQuery().clear('select');
|
|
114
131
|
if (type === query_1.QueryType.COUNT) {
|
|
115
|
-
kqb.select(
|
|
132
|
+
kqb.select(this.connection.getKnex().raw('count(*) as count'));
|
|
116
133
|
}
|
|
117
134
|
else { // select
|
|
118
135
|
kqb.select('*');
|
|
@@ -131,7 +148,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
131
148
|
return null;
|
|
132
149
|
}
|
|
133
150
|
if (qb) {
|
|
151
|
+
// here we map the aliased results (cartesian product) to an object graph
|
|
134
152
|
this.mapJoinedProps(ret, meta, populate, qb, ret, map);
|
|
153
|
+
// we need to remove the cycles from the mapped values
|
|
154
|
+
core_1.Utils.removeCycles(ret, meta);
|
|
135
155
|
}
|
|
136
156
|
return ret;
|
|
137
157
|
}
|
|
@@ -146,19 +166,33 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
146
166
|
const meta2 = this.metadata.find(relation.type);
|
|
147
167
|
const path = parentJoinPath ? `${parentJoinPath}.${relation.name}` : `${meta.name}.${relation.name}`;
|
|
148
168
|
const relationAlias = qb.getAliasForJoinPath(path);
|
|
149
|
-
|
|
169
|
+
let relationPojo = {};
|
|
150
170
|
// If the primary key value for the relation is null, we know we haven't joined to anything
|
|
151
171
|
// and therefore we don't return any record (since all values would be null)
|
|
152
172
|
const hasPK = meta2.primaryKeys.every(pk => meta2.properties[pk].fieldNames.every(name => {
|
|
153
173
|
return root[`${relationAlias}__${name}`] != null;
|
|
154
174
|
}));
|
|
155
175
|
if (!hasPK) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
176
|
+
if ([core_1.ReferenceKind.MANY_TO_MANY, core_1.ReferenceKind.ONE_TO_MANY].includes(relation.kind)) {
|
|
177
|
+
result[relation.name] ??= [];
|
|
178
|
+
}
|
|
179
|
+
if ([core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(relation.kind)) {
|
|
180
|
+
result[relation.name] = null;
|
|
159
181
|
}
|
|
160
182
|
return;
|
|
161
183
|
}
|
|
184
|
+
const tz = this.platform.getTimezone();
|
|
185
|
+
meta2.props
|
|
186
|
+
.filter(prop => prop.persist === false && prop.fieldNames)
|
|
187
|
+
.forEach(prop => {
|
|
188
|
+
if (prop.fieldNames.length > 1) { // composite keys
|
|
189
|
+
relationPojo[prop.name] = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
const alias = `${relationAlias}__${prop.fieldNames[0]}`;
|
|
193
|
+
relationPojo[prop.name] = root[alias];
|
|
194
|
+
}
|
|
195
|
+
});
|
|
162
196
|
meta2.props
|
|
163
197
|
.filter(prop => this.platform.shouldHaveColumn(prop, p.children || []))
|
|
164
198
|
.forEach(prop => {
|
|
@@ -166,21 +200,37 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
166
200
|
relationPojo[prop.name] = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
167
201
|
prop.fieldNames.map(name => delete root[`${relationAlias}__${name}`]);
|
|
168
202
|
}
|
|
203
|
+
else if (prop.runtimeType === 'Date') {
|
|
204
|
+
const alias = `${relationAlias}__${prop.fieldNames[0]}`;
|
|
205
|
+
relationPojo[prop.name] = (typeof root[alias] === 'string' ? new Date(root[alias]) : root[alias]);
|
|
206
|
+
delete root[alias];
|
|
207
|
+
}
|
|
169
208
|
else {
|
|
170
209
|
const alias = `${relationAlias}__${prop.fieldNames[0]}`;
|
|
171
210
|
relationPojo[prop.name] = root[alias];
|
|
172
211
|
delete root[alias];
|
|
173
212
|
}
|
|
174
213
|
});
|
|
175
|
-
const key = `${meta.name}-${
|
|
214
|
+
const key = `${meta.name}-${core_1.Utils.getCompositeKeyHash(result, meta)}`;
|
|
215
|
+
const key2 = `${meta2.name}-${core_1.Utils.getCompositeKeyHash(relationPojo, meta2)}`;
|
|
216
|
+
if (map[key2]) {
|
|
217
|
+
const old = map[key2];
|
|
218
|
+
core_1.Utils.keys(relationPojo)
|
|
219
|
+
.filter(k => relationPojo[k] != null)
|
|
220
|
+
.forEach(k => old[k] = relationPojo[k]);
|
|
221
|
+
relationPojo = old;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
map[key2] = relationPojo;
|
|
225
|
+
}
|
|
176
226
|
if (map[key]) {
|
|
177
227
|
result[relation.name] = map[key][relation.name];
|
|
178
228
|
}
|
|
179
229
|
else {
|
|
180
230
|
map[key] = result;
|
|
181
231
|
}
|
|
182
|
-
if ([core_1.
|
|
183
|
-
result[relation.name]
|
|
232
|
+
if ([core_1.ReferenceKind.MANY_TO_MANY, core_1.ReferenceKind.ONE_TO_MANY].includes(relation.kind)) {
|
|
233
|
+
result[relation.name] ??= [];
|
|
184
234
|
this.appendToCollection(meta2, result[relation.name], relationPojo);
|
|
185
235
|
}
|
|
186
236
|
else {
|
|
@@ -207,6 +257,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
207
257
|
return this.countVirtual(entityName, where, options);
|
|
208
258
|
}
|
|
209
259
|
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false)
|
|
260
|
+
.indexHint(options.indexHint)
|
|
261
|
+
.comment(options.comments)
|
|
262
|
+
.hintComment(options.hintComments)
|
|
210
263
|
.groupBy(options.groupBy)
|
|
211
264
|
.having(options.having)
|
|
212
265
|
.populate(options.populate ?? [])
|
|
@@ -215,7 +268,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
215
268
|
return this.rethrow(qb.getCount());
|
|
216
269
|
}
|
|
217
270
|
async nativeInsert(entityName, data, options = {}) {
|
|
218
|
-
options.convertCustomTypes
|
|
271
|
+
options.convertCustomTypes ??= true;
|
|
219
272
|
const meta = this.metadata.find(entityName);
|
|
220
273
|
const collections = this.extractManyToMany(entityName, data);
|
|
221
274
|
const pks = meta?.primaryKeys ?? [this.config.getNamingStrategy().referenceColumnName()];
|
|
@@ -235,16 +288,20 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
235
288
|
return res;
|
|
236
289
|
}
|
|
237
290
|
async nativeInsertMany(entityName, data, options = {}) {
|
|
238
|
-
options.processCollections
|
|
239
|
-
options.convertCustomTypes
|
|
240
|
-
const meta = this.metadata.find(entityName);
|
|
291
|
+
options.processCollections ??= true;
|
|
292
|
+
options.convertCustomTypes ??= true;
|
|
293
|
+
const meta = this.metadata.find(entityName)?.root;
|
|
241
294
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
242
295
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
243
296
|
const set = new Set();
|
|
244
|
-
data.forEach(row =>
|
|
297
|
+
data.forEach(row => core_1.Utils.keys(row).forEach(k => set.add(k)));
|
|
245
298
|
const props = [...set].map(name => meta?.properties[name] ?? { name, fieldNames: [name] });
|
|
246
|
-
|
|
299
|
+
let fields = core_1.Utils.flatten(props.map(prop => prop.fieldNames));
|
|
300
|
+
const duplicates = core_1.Utils.findDuplicates(fields);
|
|
247
301
|
const params = [];
|
|
302
|
+
if (duplicates.length) {
|
|
303
|
+
fields = core_1.Utils.unique(fields);
|
|
304
|
+
}
|
|
248
305
|
/* istanbul ignore next */
|
|
249
306
|
const tableName = meta ? this.getTableName(meta, options) : this.platform.quoteIdentifier(entityName);
|
|
250
307
|
let sql = `insert into ${tableName} `;
|
|
@@ -255,29 +312,50 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
255
312
|
else {
|
|
256
313
|
sql += ' ' + data.map(() => `select null as ${this.platform.quoteIdentifier(pks[0])}`).join(' union all ');
|
|
257
314
|
}
|
|
315
|
+
const addParams = (prop, row) => {
|
|
316
|
+
if (options.convertCustomTypes && prop.customType) {
|
|
317
|
+
params.push(prop.customType.convertToDatabaseValue(row[prop.name], this.platform, { key: prop.name, mode: 'query-data' }));
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
params.push(row[prop.name]);
|
|
321
|
+
};
|
|
258
322
|
if (fields.length > 0 || this.platform.usesDefaultKeyword()) {
|
|
259
323
|
sql += data.map(row => {
|
|
260
324
|
const keys = [];
|
|
325
|
+
const usedDups = [];
|
|
261
326
|
props.forEach(prop => {
|
|
262
327
|
if (prop.fieldNames.length > 1) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
328
|
+
const param = core_1.Utils.flatten([...row[prop.name] ?? prop.fieldNames.map(() => null)]);
|
|
329
|
+
const key = param.map(() => '?');
|
|
330
|
+
prop.fieldNames.forEach((field, idx) => {
|
|
331
|
+
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
332
|
+
params.push(param[idx]);
|
|
333
|
+
keys.push(key[idx]);
|
|
334
|
+
usedDups.push(field);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
269
337
|
}
|
|
270
338
|
else {
|
|
271
|
-
|
|
272
|
-
|
|
339
|
+
const field = prop.fieldNames[0];
|
|
340
|
+
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
341
|
+
if (prop.customType && 'convertToDatabaseValueSQL' in prop.customType && !this.platform.isRaw(row[prop.name])) {
|
|
342
|
+
keys.push(prop.customType.convertToDatabaseValueSQL('?', this.platform));
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
keys.push('?');
|
|
346
|
+
}
|
|
347
|
+
addParams(prop, row);
|
|
348
|
+
usedDups.push(field);
|
|
349
|
+
}
|
|
273
350
|
}
|
|
274
351
|
});
|
|
275
352
|
return '(' + (keys.join(', ') || 'default') + ')';
|
|
276
353
|
}).join(', ');
|
|
277
354
|
}
|
|
278
|
-
if (this.platform.usesReturningStatement()) {
|
|
279
|
-
|
|
280
|
-
|
|
355
|
+
if (meta && this.platform.usesReturningStatement()) {
|
|
356
|
+
const returningProps = meta.props
|
|
357
|
+
.filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw))
|
|
358
|
+
.filter(prop => !(prop.name in data[0]) || core_1.Utils.isRawSql(data[0][prop.name]));
|
|
281
359
|
const returningFields = core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
282
360
|
/* istanbul ignore next */
|
|
283
361
|
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
@@ -289,8 +367,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
289
367
|
pk = data.map(d => core_1.Utils.getPrimaryKeyCond(d, pks));
|
|
290
368
|
}
|
|
291
369
|
else {
|
|
292
|
-
res.row
|
|
293
|
-
res.rows
|
|
370
|
+
res.row ??= {};
|
|
371
|
+
res.rows ??= [];
|
|
294
372
|
pk = data.map((d, i) => d[pks[0]] ?? res.rows[i]?.[pks[0]]).map(d => [d]);
|
|
295
373
|
res.insertId = res.insertId || res.row[pks[0]];
|
|
296
374
|
}
|
|
@@ -300,7 +378,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
300
378
|
return res;
|
|
301
379
|
}
|
|
302
380
|
async nativeUpdate(entityName, where, data, options = {}) {
|
|
303
|
-
options.convertCustomTypes
|
|
381
|
+
options.convertCustomTypes ??= true;
|
|
304
382
|
const meta = this.metadata.find(entityName);
|
|
305
383
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
306
384
|
const collections = this.extractManyToMany(entityName, data);
|
|
@@ -314,11 +392,18 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
314
392
|
.withSchema(this.getSchemaName(meta, options));
|
|
315
393
|
if (options.upsert) {
|
|
316
394
|
/* istanbul ignore next */
|
|
317
|
-
const uniqueFields = core_1.Utils.isPlainObject(where) ?
|
|
318
|
-
|
|
395
|
+
const uniqueFields = options.onConflictFields ?? (core_1.Utils.isPlainObject(where) ? core_1.Utils.keys(where) : meta.primaryKeys);
|
|
396
|
+
const returning = (0, core_1.getOnConflictReturningFields)(meta, data, uniqueFields, options);
|
|
319
397
|
qb.insert(data)
|
|
320
|
-
.onConflict(uniqueFields
|
|
321
|
-
.
|
|
398
|
+
.onConflict(uniqueFields)
|
|
399
|
+
.returning(returning);
|
|
400
|
+
if (!options.onConflictAction || options.onConflictAction === 'merge') {
|
|
401
|
+
const fields = (0, core_1.getOnConflictFields)(data, uniqueFields, options);
|
|
402
|
+
qb.merge(fields);
|
|
403
|
+
}
|
|
404
|
+
if (options.onConflictAction === 'ignore') {
|
|
405
|
+
qb.ignore();
|
|
406
|
+
}
|
|
322
407
|
}
|
|
323
408
|
else {
|
|
324
409
|
qb.update(data).where(where);
|
|
@@ -331,20 +416,36 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
331
416
|
return res;
|
|
332
417
|
}
|
|
333
418
|
async nativeUpdateMany(entityName, where, data, options = {}) {
|
|
334
|
-
options.processCollections
|
|
335
|
-
options.convertCustomTypes
|
|
419
|
+
options.processCollections ??= true;
|
|
420
|
+
options.convertCustomTypes ??= true;
|
|
336
421
|
const meta = this.metadata.get(entityName);
|
|
337
422
|
if (options.upsert) {
|
|
338
|
-
const uniqueFields = core_1.Utils.isPlainObject(where[0]) ? Object.keys(where[0]) : meta.primaryKeys;
|
|
423
|
+
const uniqueFields = options.onConflictFields ?? (core_1.Utils.isPlainObject(where[0]) ? Object.keys(where[0]) : meta.primaryKeys);
|
|
339
424
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes).withSchema(this.getSchemaName(meta, options));
|
|
425
|
+
const returning = (0, core_1.getOnConflictReturningFields)(meta, data[0], uniqueFields, options);
|
|
340
426
|
qb.insert(data)
|
|
341
|
-
.onConflict(uniqueFields
|
|
342
|
-
.
|
|
427
|
+
.onConflict(uniqueFields)
|
|
428
|
+
.returning(returning);
|
|
429
|
+
if (!options.onConflictAction || options.onConflictAction === 'merge') {
|
|
430
|
+
const fields = (0, core_1.getOnConflictFields)(data[0], uniqueFields, options);
|
|
431
|
+
qb.merge(fields);
|
|
432
|
+
}
|
|
433
|
+
if (options.onConflictAction === 'ignore') {
|
|
434
|
+
qb.ignore();
|
|
435
|
+
}
|
|
343
436
|
return qb.execute('run', false);
|
|
344
437
|
}
|
|
345
438
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
346
439
|
const keys = new Set();
|
|
347
|
-
|
|
440
|
+
const returning = new Set();
|
|
441
|
+
data.forEach(row => {
|
|
442
|
+
core_1.Utils.keys(row).forEach(k => {
|
|
443
|
+
keys.add(k);
|
|
444
|
+
if (core_1.Utils.isRawSql(row[k])) {
|
|
445
|
+
returning.add(k);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
});
|
|
348
449
|
const pkCond = core_1.Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
|
|
349
450
|
const params = [];
|
|
350
451
|
let sql = `update ${this.getTableName(meta, options)} set `;
|
|
@@ -373,7 +474,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
373
474
|
const versionProperty = meta.properties[meta.versionProperty];
|
|
374
475
|
const quotedFieldName = this.platform.quoteIdentifier(versionProperty.fieldNames[0]);
|
|
375
476
|
sql += `${quotedFieldName} = `;
|
|
376
|
-
if (versionProperty.
|
|
477
|
+
if (versionProperty.runtimeType === 'Date') {
|
|
377
478
|
sql += this.platform.getCurrentTimestampSQL(versionProperty.length);
|
|
378
479
|
}
|
|
379
480
|
else {
|
|
@@ -404,6 +505,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
404
505
|
return '?';
|
|
405
506
|
});
|
|
406
507
|
sql += ` in (${conds.join(', ')})`;
|
|
508
|
+
if (this.platform.usesReturningStatement() && returning.size > 0) {
|
|
509
|
+
const returningFields = core_1.Utils.flatten([...returning].map(prop => meta.properties[prop].fieldNames));
|
|
510
|
+
/* istanbul ignore next */
|
|
511
|
+
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
512
|
+
}
|
|
407
513
|
const res = await this.rethrow(this.execute(sql, params, 'run', options.ctx));
|
|
408
514
|
for (let i = 0; i < collections.length; i++) {
|
|
409
515
|
await this.processManyToMany(meta, where[i], collections[i], false, options);
|
|
@@ -438,30 +544,53 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
438
544
|
deleteDiff.push(...snapshot);
|
|
439
545
|
insertDiff.push(...current);
|
|
440
546
|
}
|
|
441
|
-
if (coll.property.
|
|
547
|
+
if (coll.property.kind === core_1.ReferenceKind.ONE_TO_MANY) {
|
|
442
548
|
const cols = coll.property.referencedColumnNames;
|
|
443
549
|
const qb = this.createQueryBuilder(coll.property.type, ctx, 'write')
|
|
444
|
-
.withSchema(this.getSchemaName(meta, options))
|
|
445
|
-
|
|
550
|
+
.withSchema(this.getSchemaName(meta, options));
|
|
551
|
+
if (coll.getSnapshot() === undefined) {
|
|
552
|
+
if (coll.property.orphanRemoval) {
|
|
553
|
+
const kqb = qb.delete({ [coll.property.mappedBy]: pks })
|
|
554
|
+
.getKnexQuery()
|
|
555
|
+
.whereNotIn(cols, insertDiff);
|
|
556
|
+
return this.rethrow(this.execute(kqb));
|
|
557
|
+
}
|
|
558
|
+
const kqb = qb.update({ [coll.property.mappedBy]: null })
|
|
559
|
+
.getKnexQuery()
|
|
560
|
+
.whereNotIn(cols, insertDiff);
|
|
561
|
+
return this.rethrow(this.execute(kqb));
|
|
562
|
+
}
|
|
563
|
+
const kqb = qb.update({ [coll.property.mappedBy]: pks })
|
|
446
564
|
.getKnexQuery()
|
|
447
565
|
.whereIn(cols, insertDiff);
|
|
448
|
-
return this.rethrow(this.execute(
|
|
566
|
+
return this.rethrow(this.execute(kqb));
|
|
449
567
|
}
|
|
450
568
|
/* istanbul ignore next */
|
|
451
569
|
const ownerSchema = wrapped.getSchema() === '*' ? this.config.get('schema') : wrapped.getSchema();
|
|
452
570
|
const pivotMeta = this.metadata.find(coll.property.pivotEntity);
|
|
453
571
|
if (pivotMeta.schema === '*') {
|
|
454
572
|
/* istanbul ignore next */
|
|
455
|
-
options
|
|
573
|
+
options ??= {};
|
|
456
574
|
options.schema = ownerSchema;
|
|
457
575
|
}
|
|
458
576
|
return this.rethrow(this.updateCollectionDiff(meta, coll.property, pks, deleteDiff, insertDiff, options));
|
|
459
577
|
}
|
|
460
578
|
async loadFromPivotTable(prop, owners, where = {}, orderBy, ctx, options) {
|
|
461
579
|
const pivotProp2 = this.getPivotInverseProperty(prop);
|
|
580
|
+
const prop2 = prop.targetMeta.properties[prop.mappedBy ?? prop.inversedBy];
|
|
462
581
|
const ownerMeta = this.metadata.find(pivotProp2.type);
|
|
463
582
|
const pivotMeta = this.metadata.find(prop.pivotEntity);
|
|
464
|
-
|
|
583
|
+
options = { ...options };
|
|
584
|
+
const qb = this.createQueryBuilder(prop.type, ctx, options.connectionType)
|
|
585
|
+
.withSchema(this.getSchemaName(prop.targetMeta, options))
|
|
586
|
+
.indexHint(options.indexHint)
|
|
587
|
+
.comment(options.comments)
|
|
588
|
+
.hintComment(options.hintComments);
|
|
589
|
+
const pivotAlias = qb.getNextAlias(pivotMeta.tableName);
|
|
590
|
+
const pivotKey = pivotProp2.joinColumns.map(column => `${pivotAlias}.${column}`).join(core_1.Utils.PK_SEPARATOR);
|
|
591
|
+
const cond = {
|
|
592
|
+
[pivotKey]: { $in: ownerMeta.compositePK ? owners : owners.map(o => o[0]) },
|
|
593
|
+
};
|
|
465
594
|
/* istanbul ignore if */
|
|
466
595
|
if (!core_1.Utils.isEmpty(where) && Object.keys(where).every(k => core_1.Utils.isOperator(k, false))) {
|
|
467
596
|
where = cond;
|
|
@@ -469,22 +598,32 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
469
598
|
else {
|
|
470
599
|
where = { ...where, ...cond };
|
|
471
600
|
}
|
|
472
|
-
orderBy = this.getPivotOrderBy(prop, orderBy);
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
601
|
+
orderBy = this.getPivotOrderBy(prop, pivotAlias, orderBy);
|
|
602
|
+
const populate = this.autoJoinOneToOneOwner(prop.targetMeta, []);
|
|
603
|
+
const fields = this.buildFields(prop.targetMeta, (options.populate ?? []), [], qb, options.fields);
|
|
604
|
+
const k1 = !prop.owner ? 'joinColumns' : 'inverseJoinColumns';
|
|
605
|
+
const k2 = prop.owner ? 'joinColumns' : 'inverseJoinColumns';
|
|
606
|
+
const cols = [
|
|
607
|
+
...prop[k1].map(col => `${pivotAlias}.${col} as fk__${col}`),
|
|
608
|
+
...prop[k2].map(col => `${pivotAlias}.${col} as fk__${col}`),
|
|
609
|
+
];
|
|
610
|
+
fields.push(...cols);
|
|
611
|
+
qb.select(fields)
|
|
612
|
+
.join(prop2.name, pivotAlias, {}, 'pivotJoin', undefined, options.schema)
|
|
613
|
+
.populate(populate)
|
|
614
|
+
.where(where)
|
|
615
|
+
.orderBy(orderBy)
|
|
616
|
+
.setLockMode(options.lockMode, options.lockTableAliases);
|
|
617
|
+
if (owners.length === 1 && (options.offset != null || options.limit != null)) {
|
|
480
618
|
qb.limit(options.limit, options.offset);
|
|
481
619
|
}
|
|
482
|
-
|
|
620
|
+
const schema = this.config.get('schema');
|
|
621
|
+
if (prop.targetMeta.schema !== '*' && pivotMeta.schema === '*' && options.schema) {
|
|
483
622
|
// eslint-disable-next-line dot-notation
|
|
484
623
|
qb['finalize']();
|
|
485
624
|
// eslint-disable-next-line dot-notation
|
|
486
625
|
Object.values(qb['_joins']).forEach(join => {
|
|
487
|
-
join.schema =
|
|
626
|
+
join.schema = schema;
|
|
488
627
|
});
|
|
489
628
|
}
|
|
490
629
|
const items = owners.length ? await this.rethrow(qb.execute('all')) : [];
|
|
@@ -508,6 +647,18 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
508
647
|
});
|
|
509
648
|
return map;
|
|
510
649
|
}
|
|
650
|
+
getPivotOrderBy(prop, pivotAlias, orderBy) {
|
|
651
|
+
if (!core_1.Utils.isEmpty(orderBy)) {
|
|
652
|
+
return orderBy;
|
|
653
|
+
}
|
|
654
|
+
if (!core_1.Utils.isEmpty(prop.orderBy)) {
|
|
655
|
+
return core_1.Utils.asArray(prop.orderBy);
|
|
656
|
+
}
|
|
657
|
+
if (prop.fixedOrder) {
|
|
658
|
+
return [{ [`${pivotAlias}.${prop.fixedOrderColumn}`]: core_1.QueryOrder.ASC }];
|
|
659
|
+
}
|
|
660
|
+
return [];
|
|
661
|
+
}
|
|
511
662
|
async execute(queryOrKnex, params = [], method = 'all', ctx) {
|
|
512
663
|
return this.rethrow(this.connection.execute(queryOrKnex, params, method, ctx));
|
|
513
664
|
}
|
|
@@ -520,7 +671,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
520
671
|
}
|
|
521
672
|
const relationsToPopulate = populate.map(({ field }) => field);
|
|
522
673
|
const toPopulate = meta.relations
|
|
523
|
-
.filter(prop => prop.
|
|
674
|
+
.filter(prop => prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name))
|
|
524
675
|
.filter(prop => fields.length === 0 || fields.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
525
676
|
.map(prop => ({ field: prop.name, strategy: prop.strategy }));
|
|
526
677
|
return [...populate, ...toPopulate];
|
|
@@ -528,23 +679,30 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
528
679
|
joinedProps(meta, populate) {
|
|
529
680
|
return populate.filter(p => {
|
|
530
681
|
const prop = meta.properties[p.field] || {};
|
|
531
|
-
return (p.strategy || prop.strategy || this.config.get('loadStrategy')) === core_1.LoadStrategy.JOINED && prop.
|
|
682
|
+
return (p.strategy || prop.strategy || this.config.get('loadStrategy')) === core_1.LoadStrategy.JOINED && prop.kind !== core_1.ReferenceKind.SCALAR;
|
|
532
683
|
});
|
|
533
684
|
}
|
|
534
685
|
/**
|
|
535
686
|
* @internal
|
|
536
687
|
*/
|
|
537
|
-
mergeJoinedResult(rawResults, meta) {
|
|
688
|
+
mergeJoinedResult(rawResults, meta, joinedProps) {
|
|
538
689
|
// group by the root entity primary key first
|
|
539
690
|
const map = {};
|
|
540
691
|
const res = [];
|
|
541
692
|
rawResults.forEach(item => {
|
|
542
693
|
const pk = core_1.Utils.getCompositeKeyHash(item, meta);
|
|
543
694
|
if (map[pk]) {
|
|
544
|
-
|
|
695
|
+
joinedProps.forEach(hint => {
|
|
696
|
+
// Sometimes we might join a M:N relation with additional filter on the target entity, and as a result, we get
|
|
697
|
+
// the first result with `null` for all target values, which is mapped as empty array. When we see that happen,
|
|
698
|
+
// we need to merge the results of the next item.
|
|
699
|
+
if (Array.isArray(map[pk][hint.field]) && Array.isArray(item[hint.field]) && map[pk][hint.field].length === 0) {
|
|
700
|
+
item[hint.field].forEach((el) => map[pk][hint.field].push(el));
|
|
701
|
+
}
|
|
702
|
+
});
|
|
545
703
|
}
|
|
546
704
|
else {
|
|
547
|
-
map[pk] =
|
|
705
|
+
map[pk] = item;
|
|
548
706
|
res.push(item);
|
|
549
707
|
}
|
|
550
708
|
});
|
|
@@ -553,14 +711,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
553
711
|
getFieldsForJoinedLoad(qb, meta, explicitFields, populate = [], parentTableAlias, parentJoinPath) {
|
|
554
712
|
const fields = [];
|
|
555
713
|
const joinedProps = this.joinedProps(meta, populate);
|
|
714
|
+
if (explicitFields?.includes('*')) {
|
|
715
|
+
fields.push('*');
|
|
716
|
+
}
|
|
556
717
|
const shouldHaveColumn = (prop, populate, fields) => {
|
|
557
718
|
if (!this.platform.shouldHaveColumn(prop, populate)) {
|
|
558
719
|
return false;
|
|
559
720
|
}
|
|
560
721
|
if (!fields || prop.primary) {
|
|
561
|
-
return
|
|
722
|
+
return !fields?.includes('*');
|
|
562
723
|
}
|
|
563
|
-
return fields.
|
|
724
|
+
return fields.some(f => f === prop.name || f.toString().startsWith(prop.name + '.'));
|
|
564
725
|
};
|
|
565
726
|
// alias all fields in the primary table
|
|
566
727
|
meta.props
|
|
@@ -587,24 +748,25 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
587
748
|
* @internal
|
|
588
749
|
*/
|
|
589
750
|
mapPropToFieldNames(qb, prop, tableAlias) {
|
|
590
|
-
const
|
|
751
|
+
const knex = this.connection.getKnex();
|
|
752
|
+
const aliased = knex.ref(tableAlias ? `${tableAlias}__${prop.fieldNames[0]}` : prop.fieldNames[0]).toString();
|
|
591
753
|
if (prop.customType?.convertToJSValueSQL && tableAlias) {
|
|
592
|
-
const prefixed =
|
|
593
|
-
return [
|
|
754
|
+
const prefixed = knex.ref(prop.fieldNames[0]).withSchema(tableAlias).toString();
|
|
755
|
+
return [(0, core_1.raw)(`${prop.customType.convertToJSValueSQL(prefixed, this.platform)} as ${aliased}`)];
|
|
594
756
|
}
|
|
595
757
|
if (prop.formula) {
|
|
596
|
-
const alias =
|
|
597
|
-
return [`${prop.formula(alias)} as ${aliased}`];
|
|
758
|
+
const alias = knex.ref(tableAlias ?? qb.alias).toString();
|
|
759
|
+
return [(0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`)];
|
|
598
760
|
}
|
|
599
761
|
if (tableAlias) {
|
|
600
|
-
return prop.fieldNames.map(fieldName =>
|
|
762
|
+
return prop.fieldNames.map(fieldName => knex.ref(fieldName).withSchema(tableAlias).as(`${tableAlias}__${fieldName}`));
|
|
601
763
|
}
|
|
602
764
|
return prop.fieldNames;
|
|
603
765
|
}
|
|
604
766
|
/** @internal */
|
|
605
|
-
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes) {
|
|
767
|
+
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes, logging) {
|
|
606
768
|
const connectionType = this.resolveConnectionType({ ctx, connectionType: preferredConnectionType });
|
|
607
|
-
const qb = new query_1.QueryBuilder(entityName, this.metadata, this, ctx, undefined, connectionType);
|
|
769
|
+
const qb = new query_1.QueryBuilder(entityName, this.metadata, this, ctx, undefined, connectionType, undefined, logging);
|
|
608
770
|
if (!convertCustomTypes) {
|
|
609
771
|
qb.unsetFlag(core_1.QueryFlag.CONVERT_CUSTOM_TYPES);
|
|
610
772
|
}
|
|
@@ -628,7 +790,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
628
790
|
}
|
|
629
791
|
const ret = {};
|
|
630
792
|
this.metadata.find(entityName).relations.forEach(prop => {
|
|
631
|
-
if (prop.
|
|
793
|
+
if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY && data[prop.name]) {
|
|
632
794
|
ret[prop.name] = data[prop.name].map((item) => core_1.Utils.asArray(item));
|
|
633
795
|
delete data[prop.name];
|
|
634
796
|
}
|
|
@@ -649,10 +811,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
649
811
|
if (!deleteDiff) {
|
|
650
812
|
deleteDiff = [];
|
|
651
813
|
}
|
|
814
|
+
const pivotMeta = this.metadata.find(prop.pivotEntity);
|
|
652
815
|
if (deleteDiff === true || deleteDiff.length > 0) {
|
|
653
|
-
const qb1 = this.createQueryBuilder(prop.pivotEntity, options?.ctx, 'write')
|
|
654
|
-
.withSchema(this.getSchemaName(meta, options))
|
|
655
|
-
.unsetFlag(core_1.QueryFlag.CONVERT_CUSTOM_TYPES);
|
|
816
|
+
const qb1 = this.createQueryBuilder(prop.pivotEntity, options?.ctx, 'write').withSchema(this.getSchemaName(pivotMeta, options));
|
|
656
817
|
const knex = qb1.getKnex();
|
|
657
818
|
if (Array.isArray(deleteDiff)) {
|
|
658
819
|
knex.whereIn(prop.inverseJoinColumns, deleteDiff);
|
|
@@ -671,13 +832,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
671
832
|
});
|
|
672
833
|
/* istanbul ignore else */
|
|
673
834
|
if (this.platform.allowsMultiInsert()) {
|
|
674
|
-
await this.nativeInsertMany(prop.pivotEntity, items, {
|
|
835
|
+
await this.nativeInsertMany(prop.pivotEntity, items, {
|
|
836
|
+
...options,
|
|
837
|
+
convertCustomTypes: false,
|
|
838
|
+
processCollections: false,
|
|
839
|
+
});
|
|
675
840
|
}
|
|
676
841
|
else {
|
|
677
842
|
await core_1.Utils.runSerial(items, item => {
|
|
678
843
|
return this.createQueryBuilder(prop.pivotEntity, options?.ctx, 'write')
|
|
679
|
-
.
|
|
680
|
-
.withSchema(this.getSchemaName(meta, options))
|
|
844
|
+
.withSchema(this.getSchemaName(pivotMeta, options))
|
|
681
845
|
.insert(item)
|
|
682
846
|
.execute('run', false);
|
|
683
847
|
});
|
|
@@ -685,9 +849,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
685
849
|
}
|
|
686
850
|
async lockPessimistic(entity, options) {
|
|
687
851
|
const meta = (0, core_1.helper)(entity).__meta;
|
|
688
|
-
const qb = this.createQueryBuilder(entity.constructor.name, options.ctx).
|
|
852
|
+
const qb = this.createQueryBuilder(entity.constructor.name, options.ctx).withSchema(options.schema ?? meta.schema);
|
|
689
853
|
const cond = core_1.Utils.getPrimaryKeyCond(entity, meta.primaryKeys);
|
|
690
|
-
qb.select('1').where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
854
|
+
qb.select((0, core_1.raw)('1')).where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
691
855
|
await this.rethrow(qb.execute());
|
|
692
856
|
}
|
|
693
857
|
buildJoinedPropsOrderBy(entityName, qb, meta, populate, parentPath) {
|
|
@@ -699,7 +863,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
699
863
|
const path = `${parentPath ? parentPath : entityName}.${relation.field}`;
|
|
700
864
|
const propAlias = qb.getAliasForJoinPath(path);
|
|
701
865
|
if (propOrderBy) {
|
|
702
|
-
|
|
866
|
+
core_1.Utils.keys(propOrderBy).forEach(field => {
|
|
703
867
|
orderBy.push({ [`${propAlias}.${field}`]: propOrderBy[field] });
|
|
704
868
|
});
|
|
705
869
|
}
|
|
@@ -726,12 +890,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
726
890
|
return ret;
|
|
727
891
|
}
|
|
728
892
|
processField(meta, prop, field, ret, populate, joinedProps, qb) {
|
|
729
|
-
if (!prop || (prop.
|
|
893
|
+
if (!prop || (prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner)) {
|
|
730
894
|
return;
|
|
731
895
|
}
|
|
732
|
-
if (prop.
|
|
896
|
+
if (prop.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
733
897
|
if (prop.object) {
|
|
734
|
-
ret.push(prop.
|
|
898
|
+
ret.push(prop.name);
|
|
735
899
|
return;
|
|
736
900
|
}
|
|
737
901
|
const parts = field.split('.');
|
|
@@ -743,9 +907,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
743
907
|
}
|
|
744
908
|
return;
|
|
745
909
|
}
|
|
746
|
-
|
|
747
|
-
ret.push(prop.fieldNames[0]);
|
|
748
|
-
}
|
|
910
|
+
ret.push(prop.name);
|
|
749
911
|
}
|
|
750
912
|
buildFields(meta, populate, joinedProps, qb, fields) {
|
|
751
913
|
const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => p.field === prop.name || p.all));
|
|
@@ -753,6 +915,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
753
915
|
const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL);
|
|
754
916
|
const hasExplicitFields = !!fields;
|
|
755
917
|
const ret = [];
|
|
918
|
+
let addFormulas = false;
|
|
756
919
|
if (joinedProps.length > 0) {
|
|
757
920
|
ret.push(...this.getFieldsForJoinedLoad(qb, meta, fields, populate));
|
|
758
921
|
}
|
|
@@ -778,20 +941,22 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
778
941
|
else if (lazyProps.filter(p => !p.formula).length > 0) {
|
|
779
942
|
const props = meta.props.filter(prop => this.platform.shouldHaveColumn(prop, populate, false));
|
|
780
943
|
ret.push(...core_1.Utils.flatten(props.filter(p => !lazyProps.includes(p)).map(p => p.fieldNames)));
|
|
944
|
+
addFormulas = true;
|
|
781
945
|
}
|
|
782
946
|
else if (hasLazyFormulas || requiresSQLConversion) {
|
|
783
947
|
ret.push('*');
|
|
948
|
+
addFormulas = true;
|
|
784
949
|
}
|
|
785
|
-
if (ret.length > 0 && !hasExplicitFields) {
|
|
950
|
+
if (ret.length > 0 && !hasExplicitFields && addFormulas) {
|
|
786
951
|
meta.props
|
|
787
952
|
.filter(prop => prop.formula && !lazyProps.includes(prop))
|
|
788
953
|
.forEach(prop => {
|
|
789
|
-
const alias =
|
|
790
|
-
const aliased =
|
|
791
|
-
ret.push(`${prop.formula(alias)} as ${aliased}`);
|
|
954
|
+
const alias = this.connection.getKnex().ref(qb.alias).toString();
|
|
955
|
+
const aliased = this.connection.getKnex().ref(prop.fieldNames[0]).toString();
|
|
956
|
+
ret.push((0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`));
|
|
792
957
|
});
|
|
793
958
|
meta.props
|
|
794
|
-
.filter(prop => prop.
|
|
959
|
+
.filter(prop => prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL)
|
|
795
960
|
.forEach(prop => ret.push(prop.name));
|
|
796
961
|
}
|
|
797
962
|
return ret.length > 0 ? core_1.Utils.unique(ret) : ['*'];
|