@mikro-orm/knex 6.4.6-dev.8 → 7.0.0-dev.0
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 +15 -25
- package/AbstractSqlConnection.js +98 -126
- package/AbstractSqlDriver.d.ts +20 -13
- package/AbstractSqlDriver.js +73 -54
- package/AbstractSqlPlatform.d.ts +15 -3
- package/AbstractSqlPlatform.js +32 -11
- package/README.md +0 -2
- package/SqlEntityManager.d.ts +5 -6
- package/SqlEntityManager.js +5 -5
- package/SqlEntityRepository.d.ts +1 -6
- package/SqlEntityRepository.js +0 -6
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -0
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +161 -0
- package/dialects/mssql/index.d.ts +1 -1
- package/dialects/mssql/index.js +1 -1
- package/dialects/mysql/MySqlExceptionConverter.js +1 -0
- package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +7 -0
- package/dialects/mysql/MySqlNativeQueryBuilder.js +81 -0
- package/dialects/mysql/MySqlPlatform.d.ts +5 -1
- package/dialects/mysql/MySqlPlatform.js +9 -1
- package/dialects/mysql/MySqlSchemaHelper.d.ts +6 -12
- package/dialects/mysql/MySqlSchemaHelper.js +42 -75
- package/dialects/mysql/index.d.ts +1 -3
- package/dialects/mysql/index.js +1 -3
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +5 -0
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +12 -0
- package/dialects/postgresql/index.d.ts +1 -1
- package/dialects/postgresql/index.js +1 -1
- package/dialects/sqlite/BaseSqliteConnection.d.ts +0 -5
- package/dialects/sqlite/BaseSqliteConnection.js +4 -42
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +15 -3
- package/dialects/sqlite/BaseSqlitePlatform.js +20 -4
- package/dialects/sqlite/SqliteExceptionConverter.d.ts +9 -0
- package/dialects/sqlite/SqliteExceptionConverter.js +55 -0
- package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +6 -0
- package/dialects/sqlite/SqliteNativeQueryBuilder.js +15 -0
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +38 -0
- package/dialects/sqlite/SqliteSchemaHelper.js +384 -0
- package/dialects/sqlite/index.d.ts +3 -5
- package/dialects/sqlite/index.js +3 -5
- package/index.d.ts +1 -2
- package/index.js +3 -5
- package/index.mjs +10 -13
- package/package.json +4 -18
- package/query/CriteriaNodeFactory.js +5 -5
- package/query/NativeQueryBuilder.d.ts +108 -0
- package/query/NativeQueryBuilder.js +429 -0
- package/query/ObjectCriteriaNode.js +3 -3
- package/query/QueryBuilder.d.ts +30 -34
- package/query/QueryBuilder.js +112 -123
- package/query/QueryBuilderHelper.d.ts +27 -23
- package/query/QueryBuilderHelper.js +174 -168
- package/query/ScalarCriteriaNode.js +4 -0
- package/query/index.d.ts +1 -0
- package/query/index.js +1 -0
- package/schema/DatabaseSchema.js +9 -6
- package/schema/DatabaseTable.d.ts +2 -1
- package/schema/DatabaseTable.js +9 -5
- package/schema/SchemaComparator.d.ts +1 -2
- package/schema/SchemaComparator.js +31 -18
- package/schema/SchemaHelper.d.ts +27 -33
- package/schema/SchemaHelper.js +294 -184
- package/schema/SqlSchemaGenerator.d.ts +3 -9
- package/schema/SqlSchemaGenerator.js +105 -229
- package/typings.d.ts +7 -17
- package/MonkeyPatchable.d.ts +0 -18
- package/MonkeyPatchable.js +0 -60
- package/dialects/mssql/MsSqlColumnCompiler.d.ts +0 -4
- package/dialects/mssql/MsSqlColumnCompiler.js +0 -10
- package/dialects/mssql/MsSqlKnexDialect.d.ts +0 -6
- package/dialects/mssql/MsSqlKnexDialect.js +0 -22
- package/dialects/mssql/MsSqlQueryCompiler.d.ts +0 -12
- package/dialects/mssql/MsSqlQueryCompiler.js +0 -94
- package/dialects/mssql/MsSqlTableCompiler.d.ts +0 -9
- package/dialects/mssql/MsSqlTableCompiler.js +0 -40
- package/dialects/mysql/MariaDbKnexDialect.d.ts +0 -6
- package/dialects/mysql/MariaDbKnexDialect.js +0 -16
- package/dialects/mysql/MySqlColumnCompiler.d.ts +0 -7
- package/dialects/mysql/MySqlColumnCompiler.js +0 -26
- package/dialects/mysql/MySqlConnection.d.ts +0 -8
- package/dialects/mysql/MySqlConnection.js +0 -43
- package/dialects/mysql/MySqlKnexDialect.d.ts +0 -5
- package/dialects/mysql/MySqlKnexDialect.js +0 -17
- package/dialects/mysql/MySqlQueryCompiler.d.ts +0 -5
- package/dialects/mysql/MySqlQueryCompiler.js +0 -23
- package/dialects/postgresql/PostgreSqlKnexDialect.d.ts +0 -7
- package/dialects/postgresql/PostgreSqlKnexDialect.js +0 -20
- package/dialects/postgresql/PostgreSqlQueryCompiler.d.ts +0 -4
- package/dialects/postgresql/PostgreSqlQueryCompiler.js +0 -13
- package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +0 -11
- package/dialects/postgresql/PostgreSqlTableCompiler.js +0 -89
- package/dialects/sqlite/BaseSqliteSchemaHelper.d.ts +0 -28
- package/dialects/sqlite/BaseSqliteSchemaHelper.js +0 -200
- package/dialects/sqlite/BetterSqliteKnexDialect.d.ts +0 -5
- package/dialects/sqlite/BetterSqliteKnexDialect.js +0 -15
- package/dialects/sqlite/LibSqlKnexDialect.d.ts +0 -11
- package/dialects/sqlite/LibSqlKnexDialect.js +0 -85
- package/dialects/sqlite/SqliteKnexDialect.d.ts +0 -8
- package/dialects/sqlite/SqliteKnexDialect.js +0 -67
- package/dialects/sqlite/SqliteTableCompiler.d.ts +0 -6
- package/dialects/sqlite/SqliteTableCompiler.js +0 -71
package/query/QueryBuilder.js
CHANGED
|
@@ -6,6 +6,7 @@ const core_1 = require("@mikro-orm/core");
|
|
|
6
6
|
const enums_1 = require("./enums");
|
|
7
7
|
const QueryBuilderHelper_1 = require("./QueryBuilderHelper");
|
|
8
8
|
const CriteriaNodeFactory_1 = require("./CriteriaNodeFactory");
|
|
9
|
+
const NativeQueryBuilder_1 = require("./NativeQueryBuilder");
|
|
9
10
|
/**
|
|
10
11
|
* SQL query builder with fluent interface.
|
|
11
12
|
*
|
|
@@ -43,19 +44,12 @@ class QueryBuilder {
|
|
|
43
44
|
this.ensureFromClause();
|
|
44
45
|
return this._helper;
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
_fields;
|
|
47
|
+
get type() {
|
|
48
|
+
return this._type ?? enums_1.QueryType.SELECT;
|
|
49
|
+
}
|
|
50
50
|
/** @internal */
|
|
51
51
|
_populate = [];
|
|
52
52
|
/** @internal */
|
|
53
|
-
_populateWhere;
|
|
54
|
-
/** @internal */
|
|
55
|
-
_populateFilter;
|
|
56
|
-
/** @internal */
|
|
57
|
-
__populateWhere;
|
|
58
|
-
/** @internal */
|
|
59
53
|
_populateMap = {};
|
|
60
54
|
/** @internal */
|
|
61
55
|
rawFragments = new Set();
|
|
@@ -90,7 +84,6 @@ class QueryBuilder {
|
|
|
90
84
|
_helper;
|
|
91
85
|
_query;
|
|
92
86
|
platform;
|
|
93
|
-
knex;
|
|
94
87
|
/**
|
|
95
88
|
* @internal
|
|
96
89
|
*/
|
|
@@ -102,7 +95,6 @@ class QueryBuilder {
|
|
|
102
95
|
this.em = em;
|
|
103
96
|
this.loggerContext = loggerContext;
|
|
104
97
|
this.platform = this.driver.getPlatform();
|
|
105
|
-
this.knex = this.driver.getConnection(this.connectionType).getKnex();
|
|
106
98
|
if (alias) {
|
|
107
99
|
this.aliasCounter++;
|
|
108
100
|
this._explicitAlias = true;
|
|
@@ -120,7 +112,7 @@ class QueryBuilder {
|
|
|
120
112
|
}
|
|
121
113
|
addSelect(fields) {
|
|
122
114
|
this.ensureNotFinalized();
|
|
123
|
-
if (this.
|
|
115
|
+
if (this._type && this._type !== enums_1.QueryType.SELECT) {
|
|
124
116
|
return this;
|
|
125
117
|
}
|
|
126
118
|
return this.select([...core_1.Utils.asArray(this._fields), ...core_1.Utils.asArray(fields)]);
|
|
@@ -170,23 +162,24 @@ class QueryBuilder {
|
|
|
170
162
|
this.join(field, alias, cond, enums_1.JoinType.innerJoin, undefined, schema);
|
|
171
163
|
return this;
|
|
172
164
|
}
|
|
173
|
-
innerJoinLateral(field, alias, cond
|
|
165
|
+
innerJoinLateral(field, alias, cond, schema) {
|
|
174
166
|
this.join(field, alias, cond, enums_1.JoinType.innerJoinLateral, undefined, schema);
|
|
175
167
|
return this;
|
|
176
168
|
}
|
|
177
169
|
leftJoin(field, alias, cond = {}, schema) {
|
|
178
170
|
return this.join(field, alias, cond, enums_1.JoinType.leftJoin, undefined, schema);
|
|
179
171
|
}
|
|
180
|
-
leftJoinLateral(field, alias, cond
|
|
172
|
+
leftJoinLateral(field, alias, cond, schema) {
|
|
181
173
|
return this.join(field, alias, cond, enums_1.JoinType.leftJoinLateral, undefined, schema);
|
|
182
174
|
}
|
|
183
175
|
joinAndSelect(field, alias, cond = {}, type = enums_1.JoinType.innerJoin, path, fields, schema) {
|
|
184
|
-
if (!this.
|
|
176
|
+
if (!this._type) {
|
|
185
177
|
this.select('*');
|
|
186
178
|
}
|
|
187
179
|
let subquery;
|
|
188
180
|
if (Array.isArray(field)) {
|
|
189
|
-
|
|
181
|
+
const rawFragment = field[1] instanceof QueryBuilder ? field[1].toRaw() : field[1];
|
|
182
|
+
subquery = this.platform.formatQuery(rawFragment.sql, rawFragment.params);
|
|
190
183
|
field = field[0];
|
|
191
184
|
}
|
|
192
185
|
const prop = this.joinReference(field, alias, cond, type, path, schema, subquery);
|
|
@@ -269,7 +262,12 @@ class QueryBuilder {
|
|
|
269
262
|
}
|
|
270
263
|
withSubQuery(subQuery, alias) {
|
|
271
264
|
this.ensureNotFinalized();
|
|
272
|
-
|
|
265
|
+
if (subQuery instanceof core_1.RawQueryFragment) {
|
|
266
|
+
this.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
this.subQueries[alias] = subQuery.toString();
|
|
270
|
+
}
|
|
273
271
|
return this;
|
|
274
272
|
}
|
|
275
273
|
where(cond, params, operator) {
|
|
@@ -291,7 +289,7 @@ class QueryBuilder {
|
|
|
291
289
|
metadata: this.metadata,
|
|
292
290
|
platform: this.platform,
|
|
293
291
|
aliasMap: this.getAliasMap(),
|
|
294
|
-
aliased:
|
|
292
|
+
aliased: [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
295
293
|
convertCustomTypes: this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES),
|
|
296
294
|
});
|
|
297
295
|
}
|
|
@@ -336,7 +334,7 @@ class QueryBuilder {
|
|
|
336
334
|
metadata: this.metadata,
|
|
337
335
|
platform: this.platform,
|
|
338
336
|
aliasMap: this.getAliasMap(),
|
|
339
|
-
aliased:
|
|
337
|
+
aliased: [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
340
338
|
convertCustomTypes: false,
|
|
341
339
|
type: 'orderBy',
|
|
342
340
|
});
|
|
@@ -375,7 +373,7 @@ class QueryBuilder {
|
|
|
375
373
|
this.ensureNotFinalized();
|
|
376
374
|
this._onConflict ??= [];
|
|
377
375
|
this._onConflict.push({
|
|
378
|
-
fields: core_1.
|
|
376
|
+
fields: (0, core_1.isRaw)(fields)
|
|
379
377
|
? fields
|
|
380
378
|
: core_1.Utils.asArray(fields).flatMap(f => {
|
|
381
379
|
const key = f.toString();
|
|
@@ -506,38 +504,33 @@ class QueryBuilder {
|
|
|
506
504
|
}
|
|
507
505
|
return this;
|
|
508
506
|
}
|
|
509
|
-
|
|
507
|
+
getNativeQuery(processVirtualEntity = true) {
|
|
510
508
|
if (this._query?.qb) {
|
|
511
509
|
return this._query.qb;
|
|
512
510
|
}
|
|
513
511
|
this._query = {};
|
|
514
512
|
this.finalize();
|
|
515
513
|
const qb = this.getQueryBase(processVirtualEntity);
|
|
516
|
-
|
|
517
|
-
qb.__raw = true; // tag it as there is now way to check via `instanceof`
|
|
518
|
-
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(type, this._cond, qb), this._cond && !this._onConflict);
|
|
514
|
+
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
|
|
519
515
|
core_1.Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
|
|
520
|
-
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(type, this._having, qb, undefined, 'having'), this._having);
|
|
516
|
+
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), this._having);
|
|
521
517
|
core_1.Utils.runIfNotEmpty(() => {
|
|
522
|
-
const queryOrder = this.helper.getQueryOrder(type, this._orderBy, this._populateMap);
|
|
518
|
+
const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
|
|
523
519
|
if (queryOrder.length > 0) {
|
|
524
520
|
const sql = core_1.Utils.unique(queryOrder).join(', ');
|
|
525
|
-
qb.
|
|
521
|
+
qb.orderBy(sql);
|
|
526
522
|
return;
|
|
527
523
|
}
|
|
528
524
|
}, this._orderBy);
|
|
529
525
|
core_1.Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
|
|
530
526
|
core_1.Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
|
|
531
|
-
core_1.Utils.runIfNotEmpty(() =>
|
|
532
|
-
core_1.Utils.runIfNotEmpty(() =>
|
|
527
|
+
core_1.Utils.runIfNotEmpty(() => qb.comment(this._comments), this._comments);
|
|
528
|
+
core_1.Utils.runIfNotEmpty(() => qb.hintComment(this._hintComments), this._hintComments);
|
|
533
529
|
core_1.Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(enums_1.QueryType.UPSERT, this._onConflict, qb), this._onConflict);
|
|
534
|
-
if (this.type === enums_1.QueryType.TRUNCATE && this.platform.usesCascadeStatement()) {
|
|
535
|
-
return this._query.qb = this.knex.raw(qb.toSQL().toNative().sql + ' cascade');
|
|
536
|
-
}
|
|
537
530
|
if (this.lockMode) {
|
|
538
531
|
this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
|
|
539
532
|
}
|
|
540
|
-
this.helper.finalize(type, qb, this.mainAlias.metadata, this._data, this._returning);
|
|
533
|
+
this.helper.finalize(this.type, qb, this.mainAlias.metadata, this._data, this._returning);
|
|
541
534
|
this.clearRawFragmentsCache();
|
|
542
535
|
return this._query.qb = qb;
|
|
543
536
|
}
|
|
@@ -554,16 +547,21 @@ class QueryBuilder {
|
|
|
554
547
|
getQuery() {
|
|
555
548
|
return this.toQuery().sql;
|
|
556
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Returns raw fragment representation of this QueryBuilder.
|
|
552
|
+
*/
|
|
553
|
+
toRaw() {
|
|
554
|
+
const { sql, params } = this.toQuery();
|
|
555
|
+
return (0, core_1.raw)(sql, params);
|
|
556
|
+
}
|
|
557
557
|
toQuery() {
|
|
558
558
|
if (this._query?.sql) {
|
|
559
|
-
return { sql: this._query.sql,
|
|
559
|
+
return { sql: this._query.sql, params: this._query.params };
|
|
560
560
|
}
|
|
561
|
-
const
|
|
562
|
-
const query = sql.toNative();
|
|
561
|
+
const query = this.getNativeQuery().compile();
|
|
563
562
|
this._query.sql = query.sql;
|
|
564
|
-
this._query.
|
|
565
|
-
this._query.params
|
|
566
|
-
return { sql: this._query.sql, _sql: this._query._sql, params: this._query.params };
|
|
563
|
+
this._query.params = query.params;
|
|
564
|
+
return { sql: this._query.sql, params: this._query.params };
|
|
567
565
|
}
|
|
568
566
|
/**
|
|
569
567
|
* Returns the list of all parameters for this query.
|
|
@@ -575,8 +573,8 @@ class QueryBuilder {
|
|
|
575
573
|
* Returns raw interpolated query string with all the parameters inlined.
|
|
576
574
|
*/
|
|
577
575
|
getFormattedQuery() {
|
|
578
|
-
const query = this.toQuery()
|
|
579
|
-
return this.platform.formatQuery(query.sql, query.
|
|
576
|
+
const query = this.toQuery();
|
|
577
|
+
return this.platform.formatQuery(query.sql, query.params);
|
|
580
578
|
}
|
|
581
579
|
/**
|
|
582
580
|
* @internal
|
|
@@ -642,7 +640,7 @@ class QueryBuilder {
|
|
|
642
640
|
options = typeof options === 'boolean' ? { mapResults: options } : (options ?? {});
|
|
643
641
|
options.mergeResults ??= true;
|
|
644
642
|
options.mapResults ??= true;
|
|
645
|
-
const isRunType = [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type
|
|
643
|
+
const isRunType = [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type);
|
|
646
644
|
method ??= isRunType ? 'run' : 'all';
|
|
647
645
|
if (!this.connectionType && isRunType) {
|
|
648
646
|
this.connectionType = 'write';
|
|
@@ -650,15 +648,15 @@ class QueryBuilder {
|
|
|
650
648
|
if (!this.finalized && method === 'get' && this.type === enums_1.QueryType.SELECT) {
|
|
651
649
|
this.limit(1);
|
|
652
650
|
}
|
|
653
|
-
const query = this.toQuery()
|
|
654
|
-
const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.
|
|
651
|
+
const query = this.toQuery();
|
|
652
|
+
const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.params, method]);
|
|
655
653
|
if (cached?.data) {
|
|
656
654
|
return cached.data;
|
|
657
655
|
}
|
|
658
656
|
const write = method === 'run' || !this.platform.getConfig().get('preferReadReplicas');
|
|
659
657
|
const type = this.connectionType || (write ? 'write' : 'read');
|
|
660
658
|
const loggerContext = { id: this.em?.id, ...this.loggerContext };
|
|
661
|
-
const res = await this.driver.getConnection(type).execute(query.sql, query.
|
|
659
|
+
const res = await this.driver.getConnection(type).execute(query.sql, query.params, method, this.context, loggerContext);
|
|
662
660
|
const meta = this.mainAlias.metadata;
|
|
663
661
|
if (!options.mapResults || !meta) {
|
|
664
662
|
await this.em?.storeCache(this._cache, cached, res);
|
|
@@ -742,7 +740,7 @@ class QueryBuilder {
|
|
|
742
740
|
res = await this.execute('get', false);
|
|
743
741
|
}
|
|
744
742
|
else {
|
|
745
|
-
const qb = this.
|
|
743
|
+
const qb = this._type === undefined ? this : this.clone();
|
|
746
744
|
qb.processPopulateHint(); // needs to happen sooner so `qb.hasToManyJoins()` reports correctly
|
|
747
745
|
qb.count(field, distinct ?? qb.hasToManyJoins()).limit(undefined).offset(undefined).orderBy([]);
|
|
748
746
|
res = await qb.execute('get', false);
|
|
@@ -762,7 +760,7 @@ class QueryBuilder {
|
|
|
762
760
|
* Provides promise-like interface so we can await the QB instance.
|
|
763
761
|
*/
|
|
764
762
|
then(onfulfilled, onrejected) {
|
|
765
|
-
let type = this.type
|
|
763
|
+
let type = this.type;
|
|
766
764
|
if (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY)) {
|
|
767
765
|
type = enums_1.QueryType.UPDATE;
|
|
768
766
|
}
|
|
@@ -779,21 +777,21 @@ class QueryBuilder {
|
|
|
779
777
|
}
|
|
780
778
|
}
|
|
781
779
|
/**
|
|
782
|
-
* Returns
|
|
780
|
+
* Returns native query builder instance with sub-query aliased with given alias.
|
|
783
781
|
* You can provide `EntityName.propName` as alias, then the field name will be used based on the metadata
|
|
784
782
|
*/
|
|
785
783
|
as(alias) {
|
|
786
|
-
const qb = this.
|
|
784
|
+
const qb = this.getNativeQuery();
|
|
787
785
|
if (alias.includes('.')) {
|
|
788
786
|
const [a, f] = alias.split('.');
|
|
789
787
|
const meta = this.metadata.find(a);
|
|
790
788
|
/* istanbul ignore next */
|
|
791
789
|
alias = meta?.properties[f]?.fieldNames[0] ?? alias;
|
|
792
790
|
}
|
|
793
|
-
|
|
791
|
+
qb.as(alias);
|
|
794
792
|
// tag the instance, so it is possible to detect it easily
|
|
795
|
-
Object.defineProperty(
|
|
796
|
-
return
|
|
793
|
+
Object.defineProperty(qb, '__as', { enumerable: false, value: alias });
|
|
794
|
+
return qb;
|
|
797
795
|
}
|
|
798
796
|
clone(reset) {
|
|
799
797
|
const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
|
|
@@ -809,7 +807,7 @@ class QueryBuilder {
|
|
|
809
807
|
];
|
|
810
808
|
core_1.RawQueryFragment.cloneRegistry = this.rawFragments;
|
|
811
809
|
for (const prop of Object.keys(this)) {
|
|
812
|
-
if (reset.includes(prop) ||
|
|
810
|
+
if (reset.includes(prop) || ['_helper', '_query'].includes(prop)) {
|
|
813
811
|
continue;
|
|
814
812
|
}
|
|
815
813
|
qb[prop] = properties.includes(prop) ? core_1.Utils.copy(this[prop]) : this[prop];
|
|
@@ -824,28 +822,6 @@ class QueryBuilder {
|
|
|
824
822
|
qb.finalized = false;
|
|
825
823
|
return qb;
|
|
826
824
|
}
|
|
827
|
-
getKnex(processVirtualEntity = true) {
|
|
828
|
-
const qb = this.knex.queryBuilder();
|
|
829
|
-
const { subQuery, aliasName, entityName, metadata } = this.mainAlias;
|
|
830
|
-
const ref = subQuery ? subQuery : this.knex.ref(this.helper.getTableName(entityName));
|
|
831
|
-
if (this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type))) {
|
|
832
|
-
ref.as(aliasName);
|
|
833
|
-
}
|
|
834
|
-
const schema = this.getSchema(this.mainAlias);
|
|
835
|
-
if (schema && schema !== this.platform.getDefaultSchemaName()) {
|
|
836
|
-
ref.withSchema(schema);
|
|
837
|
-
}
|
|
838
|
-
if (metadata?.virtual && processVirtualEntity) {
|
|
839
|
-
qb.fromRaw(this.fromVirtual(metadata));
|
|
840
|
-
}
|
|
841
|
-
else {
|
|
842
|
-
qb.from(ref);
|
|
843
|
-
}
|
|
844
|
-
if (this.context) {
|
|
845
|
-
qb.transacting(this.context);
|
|
846
|
-
}
|
|
847
|
-
return qb;
|
|
848
|
-
}
|
|
849
825
|
/**
|
|
850
826
|
* Sets logger context for this query builder.
|
|
851
827
|
*/
|
|
@@ -870,9 +846,8 @@ class QueryBuilder {
|
|
|
870
846
|
if (res instanceof QueryBuilder) {
|
|
871
847
|
return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
872
848
|
}
|
|
873
|
-
if (core_1.
|
|
874
|
-
const
|
|
875
|
-
const query = this.platform.formatQuery(sql, bindings);
|
|
849
|
+
if (res instanceof core_1.RawQueryFragment) {
|
|
850
|
+
const query = this.platform.formatQuery(res.sql, res.params);
|
|
876
851
|
return `(${query}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
877
852
|
}
|
|
878
853
|
/* istanbul ignore next */
|
|
@@ -888,7 +863,10 @@ class QueryBuilder {
|
|
|
888
863
|
if (field instanceof QueryBuilder) {
|
|
889
864
|
prop.type = field.mainAlias.entityName;
|
|
890
865
|
prop.targetMeta = field.mainAlias.metadata;
|
|
891
|
-
field = field.
|
|
866
|
+
field = field.getNativeQuery();
|
|
867
|
+
}
|
|
868
|
+
if (field instanceof core_1.RawQueryFragment) {
|
|
869
|
+
field = this.platform.formatQuery(field.sql, field.params);
|
|
892
870
|
}
|
|
893
871
|
this._joins[`${this.alias}.${prop.name}#${alias}`] = {
|
|
894
872
|
prop,
|
|
@@ -922,7 +900,7 @@ class QueryBuilder {
|
|
|
922
900
|
metadata: this.metadata,
|
|
923
901
|
platform: this.platform,
|
|
924
902
|
aliasMap: this.getAliasMap(),
|
|
925
|
-
aliased:
|
|
903
|
+
aliased: [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
926
904
|
});
|
|
927
905
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
928
906
|
path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
|
|
@@ -954,16 +932,12 @@ class QueryBuilder {
|
|
|
954
932
|
prepareFields(fields, type = 'where') {
|
|
955
933
|
const ret = [];
|
|
956
934
|
const getFieldName = (name) => {
|
|
957
|
-
|
|
958
|
-
return this.helper.mapper(name, this.type, undefined, null);
|
|
959
|
-
}
|
|
960
|
-
return this.helper.mapper(name, this.type);
|
|
935
|
+
return this.helper.mapper(name, this.type, undefined, type === 'groupBy' ? null : undefined);
|
|
961
936
|
};
|
|
962
937
|
fields.forEach(field => {
|
|
963
|
-
const rawField = core_1.RawQueryFragment.getKnownFragment(field);
|
|
938
|
+
const rawField = core_1.RawQueryFragment.getKnownFragment(field, false);
|
|
964
939
|
if (rawField) {
|
|
965
|
-
|
|
966
|
-
ret.push(this.knex.raw(sql));
|
|
940
|
+
ret.push(rawField);
|
|
967
941
|
return;
|
|
968
942
|
}
|
|
969
943
|
if (!core_1.Utils.isString(field)) {
|
|
@@ -972,7 +946,7 @@ class QueryBuilder {
|
|
|
972
946
|
}
|
|
973
947
|
const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
|
|
974
948
|
if (join && type === 'where') {
|
|
975
|
-
ret.push(...this.helper.mapJoinColumns(this.type
|
|
949
|
+
ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
|
|
976
950
|
return;
|
|
977
951
|
}
|
|
978
952
|
const [a, f] = this.helper.splitField(field);
|
|
@@ -1020,7 +994,7 @@ class QueryBuilder {
|
|
|
1020
994
|
}
|
|
1021
995
|
for (const f of Object.keys(this._populateMap)) {
|
|
1022
996
|
if (type === 'where' && this._joins[f]) {
|
|
1023
|
-
const cols = this.helper.mapJoinColumns(this.type
|
|
997
|
+
const cols = this.helper.mapJoinColumns(this.type, this._joins[f]);
|
|
1024
998
|
for (const col of cols) {
|
|
1025
999
|
ret.push(col);
|
|
1026
1000
|
}
|
|
@@ -1030,7 +1004,7 @@ class QueryBuilder {
|
|
|
1030
1004
|
}
|
|
1031
1005
|
init(type, data, cond) {
|
|
1032
1006
|
this.ensureNotFinalized();
|
|
1033
|
-
this.
|
|
1007
|
+
this._type = type;
|
|
1034
1008
|
if ([enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE].includes(type) && core_1.Utils.hasObjectKeys(this._cond)) {
|
|
1035
1009
|
throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
|
|
1036
1010
|
}
|
|
@@ -1049,18 +1023,22 @@ class QueryBuilder {
|
|
|
1049
1023
|
return this;
|
|
1050
1024
|
}
|
|
1051
1025
|
getQueryBase(processVirtualEntity) {
|
|
1052
|
-
const qb = this.
|
|
1026
|
+
const qb = this.platform.createNativeQueryBuilder().setFlags(this.flags);
|
|
1027
|
+
const { subQuery, aliasName, entityName, metadata } = this.mainAlias;
|
|
1028
|
+
const requiresAlias = this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type));
|
|
1029
|
+
const alias = requiresAlias ? aliasName : undefined;
|
|
1053
1030
|
const schema = this.getSchema(this.mainAlias);
|
|
1054
|
-
|
|
1031
|
+
const tableName = subQuery ? subQuery.as(aliasName) : this.helper.getTableName(entityName);
|
|
1055
1032
|
const joinSchema = this._schema ?? this.em?.schema ?? schema;
|
|
1056
|
-
if (
|
|
1057
|
-
qb.
|
|
1033
|
+
if (metadata?.virtual && processVirtualEntity) {
|
|
1034
|
+
qb.from((0, core_1.raw)(this.fromVirtual(metadata)), { indexHint: this._indexHint });
|
|
1058
1035
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1036
|
+
else {
|
|
1037
|
+
qb.from(tableName, {
|
|
1038
|
+
schema,
|
|
1039
|
+
alias,
|
|
1040
|
+
indexHint: this._indexHint,
|
|
1041
|
+
});
|
|
1064
1042
|
}
|
|
1065
1043
|
switch (this.type) {
|
|
1066
1044
|
case enums_1.QueryType.SELECT:
|
|
@@ -1074,8 +1052,8 @@ class QueryBuilder {
|
|
|
1074
1052
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1075
1053
|
break;
|
|
1076
1054
|
case enums_1.QueryType.COUNT: {
|
|
1077
|
-
const
|
|
1078
|
-
qb
|
|
1055
|
+
const fields = this._fields.map(f => this.helper.mapper(f, this.type));
|
|
1056
|
+
qb.count(fields, this.flags.has(core_1.QueryFlag.DISTINCT));
|
|
1079
1057
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1080
1058
|
break;
|
|
1081
1059
|
}
|
|
@@ -1118,7 +1096,7 @@ class QueryBuilder {
|
|
|
1118
1096
|
if (this.finalized) {
|
|
1119
1097
|
return;
|
|
1120
1098
|
}
|
|
1121
|
-
if (!this.
|
|
1099
|
+
if (!this._type) {
|
|
1122
1100
|
this.select('*');
|
|
1123
1101
|
}
|
|
1124
1102
|
const meta = this.mainAlias.metadata;
|
|
@@ -1128,8 +1106,8 @@ class QueryBuilder {
|
|
|
1128
1106
|
meta.props
|
|
1129
1107
|
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(core_1.QueryFlag.INCLUDE_LAZY_FORMULAS)))
|
|
1130
1108
|
.map(prop => {
|
|
1131
|
-
const alias = this.
|
|
1132
|
-
const aliased = this.
|
|
1109
|
+
const alias = this.platform.quoteIdentifier(this.mainAlias.aliasName);
|
|
1110
|
+
const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
1133
1111
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
1134
1112
|
})
|
|
1135
1113
|
.filter(field => !this._fields.some(f => {
|
|
@@ -1280,14 +1258,15 @@ class QueryBuilder {
|
|
|
1280
1258
|
if (!prop?.persist && !prop?.formula && !prop?.hasConvertToJSValueSQL && !pks.includes(fieldName)) {
|
|
1281
1259
|
addToSelect.push(fieldName);
|
|
1282
1260
|
}
|
|
1283
|
-
const
|
|
1261
|
+
const quoted = this.platform.quoteIdentifier(fieldName);
|
|
1262
|
+
const key = (0, core_1.raw)(`min(${quoted}${type})`);
|
|
1284
1263
|
orderBy.push({ [key]: direction });
|
|
1285
1264
|
}
|
|
1286
1265
|
}
|
|
1287
1266
|
subQuery.orderBy(orderBy);
|
|
1288
1267
|
}
|
|
1289
1268
|
subQuery.finalized = true;
|
|
1290
|
-
const
|
|
1269
|
+
const innerQuery = subQuery.as(this.mainAlias.aliasName).clear('select').select(pks);
|
|
1291
1270
|
if (addToSelect.length > 0) {
|
|
1292
1271
|
addToSelect.forEach(prop => {
|
|
1293
1272
|
const field = this._fields.find(field => {
|
|
@@ -1302,24 +1281,29 @@ class QueryBuilder {
|
|
|
1302
1281
|
});
|
|
1303
1282
|
/* istanbul ignore next */
|
|
1304
1283
|
if (field instanceof core_1.RawQueryFragment) {
|
|
1305
|
-
|
|
1306
|
-
|
|
1284
|
+
innerQuery.select(field);
|
|
1285
|
+
}
|
|
1286
|
+
else if (field instanceof NativeQueryBuilder_1.NativeQueryBuilder) {
|
|
1287
|
+
innerQuery.select(field.toRaw());
|
|
1307
1288
|
}
|
|
1308
1289
|
else if (field) {
|
|
1309
|
-
|
|
1290
|
+
innerQuery.select(field);
|
|
1310
1291
|
}
|
|
1311
1292
|
});
|
|
1312
1293
|
}
|
|
1313
1294
|
// multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
|
|
1314
1295
|
// https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
|
|
1315
|
-
const subSubQuery = this.
|
|
1316
|
-
subSubQuery.
|
|
1296
|
+
const subSubQuery = this.platform.createNativeQueryBuilder();
|
|
1297
|
+
subSubQuery.select(pks).from(innerQuery);
|
|
1317
1298
|
this._limit = undefined;
|
|
1318
1299
|
this._offset = undefined;
|
|
1319
|
-
if (this._fields.some(f => core_1.RawQueryFragment.isKnownFragment(f))) {
|
|
1320
|
-
this.
|
|
1321
|
-
return;
|
|
1300
|
+
if (!this._fields.some(f => core_1.RawQueryFragment.isKnownFragment(f))) {
|
|
1301
|
+
this.pruneExtraJoins(meta);
|
|
1322
1302
|
}
|
|
1303
|
+
const { sql, params } = subSubQuery.compile();
|
|
1304
|
+
this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: (0, core_1.raw)(sql, params) } });
|
|
1305
|
+
}
|
|
1306
|
+
pruneExtraJoins(meta) {
|
|
1323
1307
|
// remove joins that are not used for population or ordering to improve performance
|
|
1324
1308
|
const populate = new Set();
|
|
1325
1309
|
const orderByAliases = this._orderBy
|
|
@@ -1353,26 +1337,31 @@ class QueryBuilder {
|
|
|
1353
1337
|
delete this._joins[key];
|
|
1354
1338
|
}
|
|
1355
1339
|
}
|
|
1356
|
-
this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery } });
|
|
1357
1340
|
}
|
|
1358
1341
|
wrapModifySubQuery(meta) {
|
|
1359
1342
|
const subQuery = this.clone();
|
|
1360
1343
|
subQuery.finalized = true;
|
|
1361
1344
|
// wrap one more time to get around MySQL limitations
|
|
1362
1345
|
// https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
|
|
1363
|
-
const subSubQuery = this.
|
|
1364
|
-
subSubQuery.__raw = true; // tag it as there is now way to check via `instanceof`
|
|
1346
|
+
const subSubQuery = this.platform.createNativeQueryBuilder();
|
|
1365
1347
|
const method = this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
|
|
1348
|
+
const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
|
|
1366
1349
|
this._cond = {}; // otherwise we would trigger validation error
|
|
1367
1350
|
this._joins = {}; // included in the subquery
|
|
1351
|
+
subSubQuery.select(pks).from(subQuery.as(this.mainAlias.aliasName));
|
|
1352
|
+
const { sql, params } = subSubQuery.compile();
|
|
1368
1353
|
this[method](this._data).where({
|
|
1369
|
-
[core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in:
|
|
1354
|
+
[core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: (0, core_1.raw)(sql, params) },
|
|
1370
1355
|
});
|
|
1371
1356
|
}
|
|
1372
1357
|
getSchema(alias) {
|
|
1373
1358
|
const { metadata } = alias;
|
|
1374
1359
|
const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
|
|
1375
|
-
|
|
1360
|
+
const schema = this._schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
|
|
1361
|
+
if (schema === this.platform.getDefaultSchemaName()) {
|
|
1362
|
+
return undefined;
|
|
1363
|
+
}
|
|
1364
|
+
return schema;
|
|
1376
1365
|
}
|
|
1377
1366
|
createAlias(entityName, aliasName, subQuery) {
|
|
1378
1367
|
const metadata = this.metadata.find(entityName);
|
|
@@ -1386,7 +1375,7 @@ class QueryBuilder {
|
|
|
1386
1375
|
return this._mainAlias;
|
|
1387
1376
|
}
|
|
1388
1377
|
fromSubQuery(target, aliasName) {
|
|
1389
|
-
const subQuery = target.
|
|
1378
|
+
const subQuery = target.getNativeQuery();
|
|
1390
1379
|
const { entityName } = target.mainAlias;
|
|
1391
1380
|
aliasName ??= this.getNextAlias(entityName);
|
|
1392
1381
|
this.createMainAlias(entityName, aliasName, subQuery);
|
|
@@ -1396,7 +1385,7 @@ class QueryBuilder {
|
|
|
1396
1385
|
this.createMainAlias(entityName, aliasName);
|
|
1397
1386
|
}
|
|
1398
1387
|
createQueryBuilderHelper() {
|
|
1399
|
-
return new QueryBuilderHelper_1.QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.
|
|
1388
|
+
return new QueryBuilderHelper_1.QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.driver);
|
|
1400
1389
|
}
|
|
1401
1390
|
ensureFromClause() {
|
|
1402
1391
|
/* istanbul ignore next */
|
|
@@ -1413,7 +1402,7 @@ class QueryBuilder {
|
|
|
1413
1402
|
/** @ignore */
|
|
1414
1403
|
[node_util_1.inspect.custom](depth = 2) {
|
|
1415
1404
|
const object = { ...this };
|
|
1416
|
-
const hidden = ['metadata', 'driver', 'context', 'platform', '
|
|
1405
|
+
const hidden = ['metadata', 'driver', 'context', 'platform', 'type'];
|
|
1417
1406
|
Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
|
|
1418
1407
|
Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
|
|
1419
1408
|
hidden.forEach(k => delete object[k]);
|