@mikro-orm/sql 7.0.0-dev.215 → 7.0.0-dev.217
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/AbstractSqlDriver.d.ts +9 -9
- package/AbstractSqlDriver.js +61 -57
- package/AbstractSqlPlatform.d.ts +3 -3
- package/SqlEntityManager.d.ts +1 -1
- package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +2 -2
- package/package.json +2 -2
- package/query/CriteriaNode.d.ts +1 -0
- package/query/CriteriaNode.js +2 -0
- package/query/CriteriaNodeFactory.d.ts +5 -5
- package/query/CriteriaNodeFactory.js +17 -17
- package/query/NativeQueryBuilder.d.ts +3 -2
- package/query/ObjectCriteriaNode.js +5 -0
- package/query/QueryBuilder.d.ts +477 -64
- package/query/QueryBuilder.js +225 -29
- package/query/QueryBuilderHelper.d.ts +7 -7
- package/query/QueryBuilderHelper.js +3 -10
- package/query/raw.d.ts +11 -3
- package/query/raw.js +1 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/typings.d.ts +17 -19
package/AbstractSqlDriver.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { QueryBuilder } from './query/QueryBuilder.js';
|
|
|
5
5
|
import { type NativeQueryBuilder } from './query/NativeQueryBuilder.js';
|
|
6
6
|
import { QueryType } from './query/enums.js';
|
|
7
7
|
import { SqlEntityManager } from './SqlEntityManager.js';
|
|
8
|
-
import type {
|
|
8
|
+
import type { InternalField } from './typings.js';
|
|
9
9
|
export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection = AbstractSqlConnection, Platform extends AbstractSqlPlatform = AbstractSqlPlatform> extends DatabaseDriver<Connection> {
|
|
10
10
|
[EntityManagerType]: SqlEntityManager<this>;
|
|
11
11
|
protected readonly connection: Connection;
|
|
@@ -57,12 +57,12 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
57
57
|
* @internal
|
|
58
58
|
*/
|
|
59
59
|
mergeJoinedResult<T extends object>(rawResults: EntityData<T>[], meta: EntityMetadata<T>, joinedProps: PopulateOptions<T>[]): EntityData<T>[];
|
|
60
|
-
protected shouldHaveColumn<T, U>(meta: EntityMetadata<T>, prop: EntityProperty<U>, populate: readonly PopulateOptions<U>[], fields?: readonly
|
|
61
|
-
protected getFieldsForJoinedLoad<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, options: FieldsForJoinedLoadOptions<T>):
|
|
60
|
+
protected shouldHaveColumn<T, U>(meta: EntityMetadata<T>, prop: EntityProperty<U>, populate: readonly PopulateOptions<U>[], fields?: readonly InternalField<U>[], exclude?: readonly InternalField<U>[]): boolean;
|
|
61
|
+
protected getFieldsForJoinedLoad<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, options: FieldsForJoinedLoadOptions<T>): InternalField<T>[];
|
|
62
62
|
/**
|
|
63
63
|
* @internal
|
|
64
64
|
*/
|
|
65
|
-
mapPropToFieldNames<T extends object>(qb: QueryBuilder<T, any, any, any>, prop: EntityProperty<T>, tableAlias: string, meta: EntityMetadata<T>, schema?: string, explicitFields?: readonly
|
|
65
|
+
mapPropToFieldNames<T extends object>(qb: QueryBuilder<T, any, any, any, any, any>, prop: EntityProperty<T>, tableAlias: string, meta: EntityMetadata<T>, schema?: string, explicitFields?: readonly InternalField<T>[]): InternalField<T>[];
|
|
66
66
|
/** @internal */
|
|
67
67
|
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T, any, any, any>, ctx?: Transaction, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean, loggerContext?: LoggingOptions, alias?: string, em?: SqlEntityManager): QueryBuilder<T, any, any, any>;
|
|
68
68
|
protected resolveConnectionType(args: {
|
|
@@ -76,13 +76,13 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
76
76
|
protected buildOrderBy<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], options: Pick<FindOptions<any>, 'strategy' | 'orderBy' | 'populateOrderBy'>): QueryOrderMap<T>[];
|
|
77
77
|
protected buildPopulateOrderBy<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, populateOrderBy: QueryOrderMap<T>[], parentPath: string, explicit: boolean, parentAlias?: string): QueryOrderMap<T>[];
|
|
78
78
|
protected buildJoinedPropsOrderBy<T extends object>(qb: QueryBuilder<T, any, any, any>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], options?: Pick<FindOptions<any>, 'strategy' | 'orderBy' | 'populateOrderBy'>, parentPath?: string): QueryOrderMap<T>[];
|
|
79
|
-
protected normalizeFields<T extends object>(fields:
|
|
80
|
-
protected processField<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T> | undefined, field: string, ret:
|
|
81
|
-
protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T, any, any, any>, alias: string, options: Pick<FindOptions<T, any, any, any>, 'strategy' | 'fields' | 'exclude'>, schema?: string):
|
|
79
|
+
protected normalizeFields<T extends object>(fields: InternalField<T>[], prefix?: string): string[];
|
|
80
|
+
protected processField<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T> | undefined, field: string, ret: InternalField<T>[]): void;
|
|
81
|
+
protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T, any, any, any>, alias: string, options: Pick<FindOptions<T, any, any, any>, 'strategy' | 'fields' | 'exclude'>, schema?: string): InternalField<T>[];
|
|
82
82
|
}
|
|
83
83
|
interface FieldsForJoinedLoadOptions<T extends object> {
|
|
84
|
-
explicitFields?: readonly
|
|
85
|
-
exclude?: readonly
|
|
84
|
+
explicitFields?: readonly InternalField<T>[];
|
|
85
|
+
exclude?: readonly InternalField<T>[];
|
|
86
86
|
populate?: readonly PopulateOptions<T>[];
|
|
87
87
|
strategy?: Options['loadStrategy'];
|
|
88
88
|
populateWhere?: FindOptions<any>['populateWhere'];
|
package/AbstractSqlDriver.js
CHANGED
|
@@ -26,8 +26,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
26
26
|
const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
|
|
27
27
|
const joinedProps = this.joinedProps(meta, populate, options);
|
|
28
28
|
const schema = this.getSchemaName(meta, options);
|
|
29
|
-
const qb = this.createQueryBuilder(meta.class, options.ctx, connectionType, false, options.logging, undefined, options.em)
|
|
30
|
-
.withSchema(schema);
|
|
29
|
+
const qb = this.createQueryBuilder(meta.class, options.ctx, connectionType, false, options.logging, undefined, options.em).withSchema(schema);
|
|
31
30
|
const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options, schema);
|
|
32
31
|
const orderBy = this.buildOrderBy(qb, meta, populate, options);
|
|
33
32
|
const populateWhere = this.buildPopulateWhere(meta, joinedProps, options);
|
|
@@ -168,19 +167,10 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
168
167
|
async wrapVirtualExpressionInSubquery(meta, expression, where, options, type) {
|
|
169
168
|
const qb = await this.createQueryBuilderFromOptions(meta, where, options);
|
|
170
169
|
qb.setFlag(QueryFlag.DISABLE_PAGINATE);
|
|
171
|
-
const isCursorPagination = [
|
|
172
|
-
options.first,
|
|
173
|
-
options.last,
|
|
174
|
-
options.before,
|
|
175
|
-
options.after,
|
|
176
|
-
].some(v => v != null);
|
|
170
|
+
const isCursorPagination = [options.first, options.last, options.before, options.after].some(v => v != null);
|
|
177
171
|
const native = qb.getNativeQuery(false);
|
|
178
172
|
if (type === QueryType.COUNT) {
|
|
179
|
-
native
|
|
180
|
-
.clear('select')
|
|
181
|
-
.clear('limit')
|
|
182
|
-
.clear('offset')
|
|
183
|
-
.count();
|
|
173
|
+
native.clear('select').clear('limit').clear('offset').count();
|
|
184
174
|
}
|
|
185
175
|
native.from(raw(`(${expression}) as ${this.platform.quoteIdentifier(qb.alias)}`));
|
|
186
176
|
const query = native.compile();
|
|
@@ -243,7 +233,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
243
233
|
// pivot ref joins via joined strategy need to be handled separately here, as they dont join the target entity
|
|
244
234
|
if (pivotRefJoin) {
|
|
245
235
|
let item;
|
|
246
|
-
if (prop.inverseJoinColumns.length > 1) {
|
|
236
|
+
if (prop.inverseJoinColumns.length > 1) {
|
|
237
|
+
// composite keys
|
|
247
238
|
item = prop.inverseJoinColumns.map(name => root[`${relationAlias}__${name}`]);
|
|
248
239
|
}
|
|
249
240
|
else {
|
|
@@ -259,9 +250,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
259
250
|
return;
|
|
260
251
|
}
|
|
261
252
|
const mapToPk = !hint.dataOnly && !!(ref || prop.mapToPk);
|
|
262
|
-
const targetProps = mapToPk
|
|
263
|
-
? meta2.getPrimaryProps()
|
|
264
|
-
: meta2.props.filter(prop => this.platform.shouldHaveColumn(prop, hint.children || []));
|
|
253
|
+
const targetProps = mapToPk ? meta2.getPrimaryProps() : meta2.props.filter(prop => this.platform.shouldHaveColumn(prop, hint.children || []));
|
|
265
254
|
// If the primary key value for the relation is null, we know we haven't joined to anything
|
|
266
255
|
// and therefore we don't return any record (since all values would be null)
|
|
267
256
|
const hasPK = meta2.getPrimaryProps().every(pk => pk.fieldNames.every(name => {
|
|
@@ -286,7 +275,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
286
275
|
.filter(prop => !ref && prop.persist === false && prop.fieldNames)
|
|
287
276
|
.forEach(prop => {
|
|
288
277
|
/* v8 ignore next */
|
|
289
|
-
if (prop.fieldNames.length > 1) {
|
|
278
|
+
if (prop.fieldNames.length > 1) {
|
|
279
|
+
// composite keys
|
|
290
280
|
relationPojo[prop.name] = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
291
281
|
}
|
|
292
282
|
else {
|
|
@@ -299,7 +289,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
299
289
|
if (prop.fieldNames.every(name => typeof root[`${relationAlias}__${name}`] === 'undefined')) {
|
|
300
290
|
continue;
|
|
301
291
|
}
|
|
302
|
-
if (prop.fieldNames.length > 1) {
|
|
292
|
+
if (prop.fieldNames.length > 1) {
|
|
293
|
+
// composite keys
|
|
303
294
|
const fk = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
304
295
|
const pk = Utils.mapFlatCompositePrimaryKey(fk, prop);
|
|
305
296
|
relationPojo[prop.name] = pk.every(val => val != null) ? pk : null;
|
|
@@ -323,7 +314,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
323
314
|
if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
|
|
324
315
|
const item = parseJsonSafe(relationPojo[prop.name]);
|
|
325
316
|
if (Array.isArray(item)) {
|
|
326
|
-
relationPojo[prop.name] = item.map(row => row == null ? row : this.comparator.mapResult(prop.targetMeta, row));
|
|
317
|
+
relationPojo[prop.name] = item.map(row => (row == null ? row : this.comparator.mapResult(prop.targetMeta, row)));
|
|
327
318
|
}
|
|
328
319
|
else {
|
|
329
320
|
relationPojo[prop.name] = item == null ? item : this.comparator.mapResult(prop.targetMeta, item);
|
|
@@ -390,7 +381,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
390
381
|
const res = await this.rethrow(qb.insert(data).execute('run', false));
|
|
391
382
|
res.row = res.row || {};
|
|
392
383
|
let pk;
|
|
393
|
-
if (meta.primaryKeys.length > 1) {
|
|
384
|
+
if (meta.primaryKeys.length > 1) {
|
|
385
|
+
// owner has composite pk
|
|
394
386
|
pk = Utils.getPrimaryKeyCond(data, meta.primaryKeys);
|
|
395
387
|
}
|
|
396
388
|
else {
|
|
@@ -422,7 +414,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
422
414
|
sql += fields.length > 0 ? '(' + fields.map(k => this.platform.quoteIdentifier(k)).join(', ') + ')' : `(${this.platform.quoteIdentifier(pks[0])})`;
|
|
423
415
|
if (this.platform.usesOutputStatement()) {
|
|
424
416
|
const returningProps = meta.props
|
|
425
|
-
.filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
|
|
417
|
+
.filter(prop => (prop.persist !== false && prop.defaultRaw) || prop.autoincrement || prop.generated)
|
|
426
418
|
.filter(prop => !(prop.name in data[0]) || isRaw(data[0][prop.name]));
|
|
427
419
|
const returningFields = Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
428
420
|
sql += returningFields.length > 0 ? ` output ${returningFields.map(field => 'inserted.' + this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
@@ -463,7 +455,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
463
455
|
params.push(value);
|
|
464
456
|
};
|
|
465
457
|
if (fields.length > 0 || this.platform.usesDefaultKeyword()) {
|
|
466
|
-
sql += data
|
|
458
|
+
sql += data
|
|
459
|
+
.map(row => {
|
|
467
460
|
const keys = [];
|
|
468
461
|
const usedDups = [];
|
|
469
462
|
props.forEach(prop => {
|
|
@@ -516,11 +509,12 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
516
509
|
}
|
|
517
510
|
});
|
|
518
511
|
return '(' + (keys.join(', ') || 'default') + ')';
|
|
519
|
-
})
|
|
512
|
+
})
|
|
513
|
+
.join(', ');
|
|
520
514
|
}
|
|
521
515
|
if (meta && this.platform.usesReturningStatement()) {
|
|
522
516
|
const returningProps = meta.props
|
|
523
|
-
.filter(prop => prop.persist !== false && prop.defaultRaw || prop.autoincrement || prop.generated)
|
|
517
|
+
.filter(prop => (prop.persist !== false && prop.defaultRaw) || prop.autoincrement || prop.generated)
|
|
524
518
|
.filter(prop => !(prop.name in data[0]) || isRaw(data[0][prop.name]));
|
|
525
519
|
const returningFields = Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
526
520
|
/* v8 ignore next */
|
|
@@ -532,7 +526,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
532
526
|
const res = await this.execute(sql, params, 'run', options.ctx, options.loggerContext);
|
|
533
527
|
let pk;
|
|
534
528
|
/* v8 ignore next */
|
|
535
|
-
if (pks.length > 1) {
|
|
529
|
+
if (pks.length > 1) {
|
|
530
|
+
// owner has composite pk
|
|
536
531
|
pk = data.map(d => Utils.getPrimaryKeyCond(d, pks));
|
|
537
532
|
}
|
|
538
533
|
else {
|
|
@@ -557,8 +552,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
557
552
|
where = { [meta.primaryKeys[0] ?? pks[0]]: where };
|
|
558
553
|
}
|
|
559
554
|
if (Utils.hasObjectKeys(data)) {
|
|
560
|
-
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes, options.loggerContext)
|
|
561
|
-
.withSchema(this.getSchemaName(meta, options));
|
|
555
|
+
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes, options.loggerContext).withSchema(this.getSchemaName(meta, options));
|
|
562
556
|
if (options.upsert) {
|
|
563
557
|
/* v8 ignore next */
|
|
564
558
|
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(where) ? Utils.keys(where) : meta.primaryKeys);
|
|
@@ -581,9 +575,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
581
575
|
qb.update(data).where(where);
|
|
582
576
|
// reload generated columns and version fields
|
|
583
577
|
const returning = [];
|
|
584
|
-
meta.props
|
|
585
|
-
.filter(prop => (prop.generated && !prop.primary) || prop.version)
|
|
586
|
-
.forEach(prop => returning.push(prop.name));
|
|
578
|
+
meta.props.filter(prop => (prop.generated && !prop.primary) || prop.version).forEach(prop => returning.push(prop.name));
|
|
587
579
|
qb.returning(returning);
|
|
588
580
|
}
|
|
589
581
|
res = await this.rethrow(qb.execute('run', false));
|
|
@@ -598,7 +590,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
598
590
|
options.convertCustomTypes ??= true;
|
|
599
591
|
const meta = this.metadata.get(entityName);
|
|
600
592
|
if (options.upsert) {
|
|
601
|
-
const uniqueFields = options.onConflictFields ??
|
|
593
|
+
const uniqueFields = options.onConflictFields ??
|
|
594
|
+
(Utils.isPlainObject(where[0]) ? Object.keys(where[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
|
|
602
595
|
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes, options.loggerContext).withSchema(this.getSchemaName(meta, options));
|
|
603
596
|
const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
|
|
604
597
|
qb.insert(data)
|
|
@@ -629,10 +622,10 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
629
622
|
}
|
|
630
623
|
}
|
|
631
624
|
// reload generated columns and version fields
|
|
632
|
-
meta.props
|
|
633
|
-
|
|
634
|
-
.
|
|
635
|
-
|
|
625
|
+
meta.props.filter(prop => prop.generated || prop.version || prop.primary).forEach(prop => returning.add(prop.name));
|
|
626
|
+
const pkCond = Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames))
|
|
627
|
+
.map(pk => `${this.platform.quoteIdentifier(pk)} = ?`)
|
|
628
|
+
.join(' and ');
|
|
636
629
|
const params = [];
|
|
637
630
|
let sql = `update ${this.getTableName(meta, options)} set `;
|
|
638
631
|
const addParams = (prop, value) => {
|
|
@@ -727,7 +720,9 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
727
720
|
if (Utils.isPrimaryKey(where) && pks.length === 1) {
|
|
728
721
|
where = { [pks[0]]: where };
|
|
729
722
|
}
|
|
730
|
-
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', false, options.loggerContext)
|
|
723
|
+
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', false, options.loggerContext)
|
|
724
|
+
.delete(where)
|
|
725
|
+
.withSchema(this.getSchemaName(meta, options));
|
|
731
726
|
return this.rethrow(qb.execute('run', false));
|
|
732
727
|
}
|
|
733
728
|
/**
|
|
@@ -776,24 +771,22 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
776
771
|
}
|
|
777
772
|
if (coll.property.kind === ReferenceKind.ONE_TO_MANY) {
|
|
778
773
|
const cols = coll.property.referencedColumnNames;
|
|
779
|
-
const qb = this.createQueryBuilder(coll.property.targetMeta.class, options?.ctx, 'write')
|
|
780
|
-
.withSchema(this.getSchemaName(meta, options));
|
|
774
|
+
const qb = this.createQueryBuilder(coll.property.targetMeta.class, options?.ctx, 'write').withSchema(this.getSchemaName(meta, options));
|
|
781
775
|
if (coll.getSnapshot() === undefined) {
|
|
782
776
|
if (coll.property.orphanRemoval) {
|
|
783
|
-
const query = qb.delete({ [coll.property.mappedBy]: pks })
|
|
784
|
-
.andWhere({ [cols.join(Utils.PK_SEPARATOR)]: { $nin: insertDiff } });
|
|
777
|
+
const query = qb.delete({ [coll.property.mappedBy]: pks }).andWhere({ [cols.join(Utils.PK_SEPARATOR)]: { $nin: insertDiff } });
|
|
785
778
|
await this.rethrow(query.execute());
|
|
786
779
|
continue;
|
|
787
780
|
}
|
|
788
|
-
const query = qb
|
|
781
|
+
const query = qb
|
|
782
|
+
.update({ [coll.property.mappedBy]: null })
|
|
789
783
|
.where({ [coll.property.mappedBy]: pks })
|
|
790
784
|
.andWhere({ [cols.join(Utils.PK_SEPARATOR)]: { $nin: insertDiff } });
|
|
791
785
|
await this.rethrow(query.execute());
|
|
792
786
|
continue;
|
|
793
787
|
}
|
|
794
788
|
/* v8 ignore next */
|
|
795
|
-
const query = qb.update({ [coll.property.mappedBy]: pks })
|
|
796
|
-
.where({ [cols.join(Utils.PK_SEPARATOR)]: { $in: insertDiff } });
|
|
789
|
+
const query = qb.update({ [coll.property.mappedBy]: pks }).where({ [cols.join(Utils.PK_SEPARATOR)]: { $in: insertDiff } });
|
|
797
790
|
await this.rethrow(query.execute());
|
|
798
791
|
continue;
|
|
799
792
|
}
|
|
@@ -801,19 +794,19 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
801
794
|
let schema = pivotMeta.schema;
|
|
802
795
|
if (schema === '*') {
|
|
803
796
|
if (coll.property.owner) {
|
|
804
|
-
schema = wrapped.getSchema() === '*' ? options?.schema ?? this.config.get('schema') : wrapped.getSchema();
|
|
797
|
+
schema = wrapped.getSchema() === '*' ? (options?.schema ?? this.config.get('schema')) : wrapped.getSchema();
|
|
805
798
|
}
|
|
806
799
|
else {
|
|
807
800
|
const targetMeta = coll.property.targetMeta;
|
|
808
801
|
const targetSchema = (coll[0] ?? snap?.[0]) && helper(coll[0] ?? snap?.[0]).getSchema();
|
|
809
|
-
schema = targetMeta.schema === '*' ? options?.schema ?? targetSchema ?? this.config.get('schema') : targetMeta.schema;
|
|
802
|
+
schema = targetMeta.schema === '*' ? (options?.schema ?? targetSchema ?? this.config.get('schema')) : targetMeta.schema;
|
|
810
803
|
}
|
|
811
804
|
}
|
|
812
805
|
else if (schema == null) {
|
|
813
806
|
schema = this.config.get('schema');
|
|
814
807
|
}
|
|
815
808
|
const tableName = `${schema ?? '_'}.${pivotMeta.tableName}`;
|
|
816
|
-
const persister = groups[tableName] ??= new PivotCollectionPersister(pivotMeta, this, options?.ctx, schema, options?.loggerContext);
|
|
809
|
+
const persister = (groups[tableName] ??= new PivotCollectionPersister(pivotMeta, this, options?.ctx, schema, options?.loggerContext));
|
|
817
810
|
persister.enqueueUpdate(coll.property, insertDiff, deleteDiff, pks, coll.isInitialized());
|
|
818
811
|
}
|
|
819
812
|
for (const persister of Utils.values(groups)) {
|
|
@@ -839,20 +832,28 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
839
832
|
const populate = this.autoJoinOneToOneOwner(prop.targetMeta, options?.populate ?? [], options?.fields);
|
|
840
833
|
const childFields = !Utils.isEmpty(options?.fields) ? options.fields.map(f => `${pivotProp1.name}.${f}`) : [];
|
|
841
834
|
const childExclude = !Utils.isEmpty(options?.exclude) ? options.exclude.map(f => `${pivotProp1.name}.${f}`) : [];
|
|
842
|
-
const fields = pivotJoin
|
|
843
|
-
? [pivotProp1.name, pivotProp2.name]
|
|
844
|
-
: [pivotProp1.name, pivotProp2.name, ...childFields];
|
|
835
|
+
const fields = pivotJoin ? [pivotProp1.name, pivotProp2.name] : [pivotProp1.name, pivotProp2.name, ...childFields];
|
|
845
836
|
const res = await this.find(pivotMeta.class, where, {
|
|
846
837
|
ctx,
|
|
847
838
|
...options,
|
|
848
839
|
fields,
|
|
849
840
|
exclude: childExclude,
|
|
850
841
|
orderBy: this.getPivotOrderBy(prop, pivotProp1, orderBy, options?.orderBy),
|
|
851
|
-
populate: [
|
|
842
|
+
populate: [
|
|
843
|
+
{
|
|
844
|
+
field: populateField,
|
|
845
|
+
strategy: LoadStrategy.JOINED,
|
|
846
|
+
joinType: JoinType.innerJoin,
|
|
847
|
+
children: populate,
|
|
848
|
+
dataOnly: pivotProp1.mapToPk && !pivotJoin,
|
|
849
|
+
},
|
|
850
|
+
],
|
|
852
851
|
populateWhere: undefined,
|
|
853
852
|
// @ts-ignore
|
|
854
853
|
_populateWhere: 'infer',
|
|
855
|
-
populateFilter: !Utils.isEmpty(options?.populateFilter) || RawQueryFragment.hasObjectFragments(options?.populateFilter)
|
|
854
|
+
populateFilter: !Utils.isEmpty(options?.populateFilter) || RawQueryFragment.hasObjectFragments(options?.populateFilter)
|
|
855
|
+
? { [pivotProp2.name]: options?.populateFilter }
|
|
856
|
+
: undefined,
|
|
856
857
|
});
|
|
857
858
|
const map = {};
|
|
858
859
|
for (const owner of owners) {
|
|
@@ -1041,7 +1042,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1041
1042
|
: (hint.filter && !prop.nullable) || mandatoryToOneProperty
|
|
1042
1043
|
? JoinType.innerJoin
|
|
1043
1044
|
: JoinType.leftJoin;
|
|
1044
|
-
const schema = prop.targetMeta.schema === '*' ? options?.schema ?? this.config.get('schema') : prop.targetMeta.schema;
|
|
1045
|
+
const schema = prop.targetMeta.schema === '*' ? (options?.schema ?? this.config.get('schema')) : prop.targetMeta.schema;
|
|
1045
1046
|
qb.join(field, tableAlias, {}, joinType, path, schema);
|
|
1046
1047
|
if (pivotRefJoin) {
|
|
1047
1048
|
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}`)));
|
|
@@ -1119,7 +1120,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1119
1120
|
toString: () => alias.toString(),
|
|
1120
1121
|
};
|
|
1121
1122
|
const columns = meta.createColumnMappingObject();
|
|
1122
|
-
return [raw(`${
|
|
1123
|
+
return [raw(`${prop.formula(table, columns)} as ${aliased}`)];
|
|
1123
1124
|
}
|
|
1124
1125
|
return prop.fieldNames.map(fieldName => {
|
|
1125
1126
|
return `${tableAlias}.${fieldName} as ${tableAlias}__${fieldName}`;
|
|
@@ -1171,7 +1172,9 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1171
1172
|
const meta = helper(entity).__meta;
|
|
1172
1173
|
const qb = this.createQueryBuilder(meta.class, options.ctx, undefined, undefined, options.logging).withSchema(options.schema ?? meta.schema);
|
|
1173
1174
|
const cond = Utils.getPrimaryKeyCond(entity, meta.primaryKeys);
|
|
1174
|
-
qb.select(raw('1'))
|
|
1175
|
+
qb.select(raw('1'))
|
|
1176
|
+
.where(cond)
|
|
1177
|
+
.setLockMode(options.lockMode, options.lockTableAliases);
|
|
1175
1178
|
await this.rethrow(qb.execute());
|
|
1176
1179
|
}
|
|
1177
1180
|
buildPopulateWhere(meta, joinedProps, options) {
|
|
@@ -1228,7 +1231,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1228
1231
|
}
|
|
1229
1232
|
let path = parentPath;
|
|
1230
1233
|
const meta2 = prop.targetMeta;
|
|
1231
|
-
if (prop.kind !== ReferenceKind.SCALAR &&
|
|
1234
|
+
if (prop.kind !== ReferenceKind.SCALAR &&
|
|
1235
|
+
(![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) || !prop.owner || Utils.isPlainObject(childOrder))) {
|
|
1232
1236
|
path += `.${field}`;
|
|
1233
1237
|
}
|
|
1234
1238
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && typeof childOrder !== 'object') {
|
|
@@ -1403,7 +1407,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1403
1407
|
qualifiedName,
|
|
1404
1408
|
toString: () => a.toString(),
|
|
1405
1409
|
};
|
|
1406
|
-
ret.push(raw(`${
|
|
1410
|
+
ret.push(raw(`${prop.formula(table, columns)} as ${aliased}`));
|
|
1407
1411
|
}
|
|
1408
1412
|
if (!prop.object && (prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL)) {
|
|
1409
1413
|
ret.push(prop.name);
|
package/AbstractSqlPlatform.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Constructor, type EntityManager, type EntityRepository, type IDatabaseDriver, type IsolationLevel, type MikroORM, Platform } from '@mikro-orm/core';
|
|
1
|
+
import { type RawQueryFragment, type Constructor, type EntityManager, type EntityRepository, type IDatabaseDriver, type IsolationLevel, type MikroORM, Platform } from '@mikro-orm/core';
|
|
2
2
|
import { SqlSchemaGenerator } from './schema/SqlSchemaGenerator.js';
|
|
3
3
|
import { type SchemaHelper } from './schema/SchemaHelper.js';
|
|
4
4
|
import type { IndexDef } from './typings.js';
|
|
@@ -24,8 +24,8 @@ export declare abstract class AbstractSqlPlatform extends Platform {
|
|
|
24
24
|
getRollbackToSavepointSQL(savepointName: string): string;
|
|
25
25
|
getReleaseSavepointSQL(savepointName: string): string;
|
|
26
26
|
quoteValue(value: any): string;
|
|
27
|
-
getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string;
|
|
28
|
-
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string;
|
|
27
|
+
getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string | RawQueryFragment;
|
|
28
|
+
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string | RawQueryFragment;
|
|
29
29
|
getJsonIndexDefinition(index: IndexDef): string[];
|
|
30
30
|
supportsSchemas(): boolean;
|
|
31
31
|
/** @inheritDoc */
|
package/SqlEntityManager.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export declare class SqlEntityManager<Driver extends AbstractSqlDriver = Abstrac
|
|
|
20
20
|
/**
|
|
21
21
|
* Shortcut for `createQueryBuilder()`
|
|
22
22
|
*/
|
|
23
|
-
qb<Entity extends object, RootAlias extends string = never>(entityName: EntityName<Entity>, alias?: RootAlias, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<Entity, RootAlias, never, never>;
|
|
23
|
+
qb<Entity extends object, RootAlias extends string = never>(entityName: EntityName<Entity>, alias?: RootAlias, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<Entity, RootAlias, never, never, never, "*">;
|
|
24
24
|
/**
|
|
25
25
|
* Returns configured Kysely instance.
|
|
26
26
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EntityProperty, type IsolationLevel, type SimpleColumnMeta, Type } from '@mikro-orm/core';
|
|
1
|
+
import { type EntityProperty, type IsolationLevel, RawQueryFragment, type SimpleColumnMeta, Type } from '@mikro-orm/core';
|
|
2
2
|
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
|
|
3
3
|
import type { IndexDef } from '../../typings.js';
|
|
4
4
|
import { PostgreSqlNativeQueryBuilder } from './PostgreSqlNativeQueryBuilder.js';
|
|
@@ -78,7 +78,7 @@ export declare class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
78
78
|
}): string;
|
|
79
79
|
getBlobDeclarationSQL(): string;
|
|
80
80
|
getJsonDeclarationSQL(): string;
|
|
81
|
-
getSearchJsonPropertyKey(path: string[], type: string | undefined | Type, aliased: boolean, value?: unknown): string;
|
|
81
|
+
getSearchJsonPropertyKey(path: string[], type: string | undefined | Type, aliased: boolean, value?: unknown): string | RawQueryFragment;
|
|
82
82
|
getJsonIndexDefinition(index: IndexDef): string[];
|
|
83
83
|
quoteIdentifier(id: string | {
|
|
84
84
|
toString: () => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.0.0-dev.
|
|
3
|
+
"version": "7.0.0-dev.217",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"@mikro-orm/core": "^6.6.4"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@mikro-orm/core": "7.0.0-dev.
|
|
59
|
+
"@mikro-orm/core": "7.0.0-dev.217"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/query/CriteriaNode.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export declare class CriteriaNode<T extends object> implements ICriteriaNode<T>
|
|
|
10
10
|
readonly entityName: EntityName<T>;
|
|
11
11
|
readonly parent?: ICriteriaNode<T> | undefined;
|
|
12
12
|
readonly key?: (EntityKey<T> | RawQueryFragmentSymbol) | undefined;
|
|
13
|
+
readonly validate: boolean;
|
|
13
14
|
readonly strict: boolean;
|
|
14
15
|
payload: any;
|
|
15
16
|
prop?: EntityProperty<T>;
|
package/query/CriteriaNode.js
CHANGED
|
@@ -9,6 +9,7 @@ export class CriteriaNode {
|
|
|
9
9
|
entityName;
|
|
10
10
|
parent;
|
|
11
11
|
key;
|
|
12
|
+
validate;
|
|
12
13
|
strict;
|
|
13
14
|
payload;
|
|
14
15
|
prop;
|
|
@@ -18,6 +19,7 @@ export class CriteriaNode {
|
|
|
18
19
|
this.entityName = entityName;
|
|
19
20
|
this.parent = parent;
|
|
20
21
|
this.key = key;
|
|
22
|
+
this.validate = validate;
|
|
21
23
|
this.strict = strict;
|
|
22
24
|
const meta = parent && metadata.find(parent.entityName);
|
|
23
25
|
if (meta && key && !RawQueryFragment.isKnownFragmentSymbol(key)) {
|
|
@@ -4,9 +4,9 @@ import type { ICriteriaNode } from '../typings.js';
|
|
|
4
4
|
* @internal
|
|
5
5
|
*/
|
|
6
6
|
export declare class CriteriaNodeFactory {
|
|
7
|
-
static createNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol): ICriteriaNode<T>;
|
|
8
|
-
static createScalarNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol): ICriteriaNode<T>;
|
|
9
|
-
static createArrayNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any[], parent?: ICriteriaNode<T>, key?: EntityKey<T
|
|
10
|
-
static createObjectNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: Dictionary, parent?: ICriteriaNode<T>, key?: EntityKey<T
|
|
11
|
-
static createObjectItemNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, node: ICriteriaNode<T>, payload: Dictionary, key: EntityKey<T> | RawQueryFragmentSymbol, meta?: EntityMetadata<T
|
|
7
|
+
static createNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol, validate?: boolean): ICriteriaNode<T>;
|
|
8
|
+
static createScalarNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol, validate?: boolean): ICriteriaNode<T>;
|
|
9
|
+
static createArrayNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any[], parent?: ICriteriaNode<T>, key?: EntityKey<T>, validate?: boolean): ICriteriaNode<T>;
|
|
10
|
+
static createObjectNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: Dictionary, parent?: ICriteriaNode<T>, key?: EntityKey<T>, validate?: boolean): ICriteriaNode<T>;
|
|
11
|
+
static createObjectItemNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, node: ICriteriaNode<T>, payload: Dictionary, key: EntityKey<T> | RawQueryFragmentSymbol, meta?: EntityMetadata<T>, validate?: boolean): ICriteriaNode<T>;
|
|
12
12
|
}
|
|
@@ -6,26 +6,26 @@ import { ScalarCriteriaNode } from './ScalarCriteriaNode.js';
|
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
8
8
|
export class CriteriaNodeFactory {
|
|
9
|
-
static createNode(metadata, entityName, payload, parent, key) {
|
|
9
|
+
static createNode(metadata, entityName, payload, parent, key, validate = true) {
|
|
10
10
|
const rawField = RawQueryFragment.isKnownFragmentSymbol(key);
|
|
11
11
|
const scalar = Utils.isPrimaryKey(payload) || isRaw(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
|
|
12
12
|
if (Array.isArray(payload) && !scalar) {
|
|
13
|
-
return this.createArrayNode(metadata, entityName, payload, parent, key);
|
|
13
|
+
return this.createArrayNode(metadata, entityName, payload, parent, key, validate);
|
|
14
14
|
}
|
|
15
15
|
if (Utils.isPlainObject(payload) && !scalar) {
|
|
16
|
-
return this.createObjectNode(metadata, entityName, payload, parent, key);
|
|
16
|
+
return this.createObjectNode(metadata, entityName, payload, parent, key, validate);
|
|
17
17
|
}
|
|
18
|
-
return this.createScalarNode(metadata, entityName, payload, parent, key);
|
|
18
|
+
return this.createScalarNode(metadata, entityName, payload, parent, key, validate);
|
|
19
19
|
}
|
|
20
|
-
static createScalarNode(metadata, entityName, payload, parent, key) {
|
|
21
|
-
const node = new ScalarCriteriaNode(metadata, entityName, parent, key);
|
|
20
|
+
static createScalarNode(metadata, entityName, payload, parent, key, validate = true) {
|
|
21
|
+
const node = new ScalarCriteriaNode(metadata, entityName, parent, key, validate);
|
|
22
22
|
node.payload = payload;
|
|
23
23
|
return node;
|
|
24
24
|
}
|
|
25
|
-
static createArrayNode(metadata, entityName, payload, parent, key) {
|
|
26
|
-
const node = new ArrayCriteriaNode(metadata, entityName, parent, key);
|
|
25
|
+
static createArrayNode(metadata, entityName, payload, parent, key, validate = true) {
|
|
26
|
+
const node = new ArrayCriteriaNode(metadata, entityName, parent, key, validate);
|
|
27
27
|
node.payload = payload.map((item, index) => {
|
|
28
|
-
const n = this.createNode(metadata, entityName, item, node);
|
|
28
|
+
const n = this.createNode(metadata, entityName, item, node, undefined, validate);
|
|
29
29
|
// we care about branching only for $and
|
|
30
30
|
if (key === '$and' && payload.length > 1) {
|
|
31
31
|
n.index = index;
|
|
@@ -34,36 +34,36 @@ export class CriteriaNodeFactory {
|
|
|
34
34
|
});
|
|
35
35
|
return node;
|
|
36
36
|
}
|
|
37
|
-
static createObjectNode(metadata, entityName, payload, parent, key) {
|
|
37
|
+
static createObjectNode(metadata, entityName, payload, parent, key, validate = true) {
|
|
38
38
|
const meta = metadata.find(entityName);
|
|
39
|
-
const node = new ObjectCriteriaNode(metadata, entityName, parent, key,
|
|
39
|
+
const node = new ObjectCriteriaNode(metadata, entityName, parent, key, validate, payload.__strict);
|
|
40
40
|
node.payload = {};
|
|
41
41
|
for (const k of Utils.getObjectQueryKeys(payload)) {
|
|
42
|
-
node.payload[k] = this.createObjectItemNode(metadata, entityName, node, payload, k, meta);
|
|
42
|
+
node.payload[k] = this.createObjectItemNode(metadata, entityName, node, payload, k, meta, validate);
|
|
43
43
|
}
|
|
44
44
|
return node;
|
|
45
45
|
}
|
|
46
|
-
static createObjectItemNode(metadata, entityName, node, payload, key, meta) {
|
|
46
|
+
static createObjectItemNode(metadata, entityName, node, payload, key, meta, validate = true) {
|
|
47
47
|
const rawField = RawQueryFragment.isKnownFragmentSymbol(key);
|
|
48
48
|
const prop = rawField ? null : meta?.properties[key];
|
|
49
49
|
const childEntity = prop && prop.kind !== ReferenceKind.SCALAR ? prop.targetMeta.class : entityName;
|
|
50
50
|
const isNotEmbedded = rawField || prop?.kind !== ReferenceKind.EMBEDDED;
|
|
51
51
|
const val = payload[key];
|
|
52
52
|
if (isNotEmbedded && prop?.customType instanceof JsonType) {
|
|
53
|
-
return this.createScalarNode(metadata, childEntity, val, node, key);
|
|
53
|
+
return this.createScalarNode(metadata, childEntity, val, node, key, validate);
|
|
54
54
|
}
|
|
55
55
|
if (prop?.kind === ReferenceKind.SCALAR && val != null && Object.keys(val).some(f => f in GroupOperator)) {
|
|
56
56
|
throw ValidationError.cannotUseGroupOperatorsInsideScalars(entityName, prop.name, payload);
|
|
57
57
|
}
|
|
58
58
|
if (isNotEmbedded) {
|
|
59
|
-
return this.createNode(metadata, childEntity, val, node, key);
|
|
59
|
+
return this.createNode(metadata, childEntity, val, node, key, validate);
|
|
60
60
|
}
|
|
61
61
|
if (val == null) {
|
|
62
62
|
const map = Object.keys(prop.embeddedProps).reduce((oo, k) => {
|
|
63
63
|
oo[prop.embeddedProps[k].name] = null;
|
|
64
64
|
return oo;
|
|
65
65
|
}, {});
|
|
66
|
-
return this.createNode(metadata, entityName, map, node, key);
|
|
66
|
+
return this.createNode(metadata, entityName, map, node, key, validate);
|
|
67
67
|
}
|
|
68
68
|
// array operators can be used on embedded properties
|
|
69
69
|
const allowedOperators = ['$contains', '$contained', '$overlap'];
|
|
@@ -87,6 +87,6 @@ export class CriteriaNodeFactory {
|
|
|
87
87
|
}
|
|
88
88
|
return oo;
|
|
89
89
|
}, {});
|
|
90
|
-
return this.createNode(metadata, entityName, map, node, key);
|
|
90
|
+
return this.createNode(metadata, entityName, map, node, key, validate);
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Dictionary, LockMode, type QueryFlag, RawQueryFragment } from '@mikro-orm/core';
|
|
1
|
+
import { type Dictionary, LockMode, type QueryFlag, RawQueryFragment, type Subquery } from '@mikro-orm/core';
|
|
2
2
|
import { QueryType } from './enums.js';
|
|
3
3
|
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';
|
|
4
4
|
interface Options {
|
|
@@ -48,8 +48,9 @@ interface OnConflictClause {
|
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
/** @internal */
|
|
51
|
-
export declare class NativeQueryBuilder {
|
|
51
|
+
export declare class NativeQueryBuilder implements Subquery {
|
|
52
52
|
protected readonly platform: AbstractSqlPlatform;
|
|
53
|
+
readonly __subquery: true;
|
|
53
54
|
protected type?: QueryType;
|
|
54
55
|
protected parts: string[];
|
|
55
56
|
protected params: unknown[];
|
|
@@ -106,6 +106,11 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
106
106
|
const rawField = RawQueryFragment.getKnownFragment(field);
|
|
107
107
|
o[raw(rawField.sql.replaceAll(ALIAS_REPLACEMENT, alias), rawField.params)] = payload;
|
|
108
108
|
}
|
|
109
|
+
else if (!childNode.validate && !childNode.prop && !field.includes('.') && !operator) {
|
|
110
|
+
// wrap unknown fields in raw() to prevent alias prefixing (e.g. raw SQL aliases in HAVING)
|
|
111
|
+
// use '??' placeholder to properly quote the identifier
|
|
112
|
+
o[raw('??', [field])] = payload;
|
|
113
|
+
}
|
|
109
114
|
else if (primaryKey || virtual || operator || field.includes('.') || ![QueryType.SELECT, QueryType.COUNT].includes(qb.type)) {
|
|
110
115
|
this.inlineCondition(field.replaceAll(ALIAS_REPLACEMENT, alias), o, payload);
|
|
111
116
|
}
|