@mikro-orm/knex 6.0.0-dev.110 → 6.0.0-dev.112
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
CHANGED
|
@@ -29,7 +29,7 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
29
29
|
nativeUpdateMany<T extends object>(entityName: string, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>): Promise<QueryResult<T>>;
|
|
30
30
|
nativeDelete<T extends object>(entityName: string, where: FilterQuery<T> | string | any, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
|
|
31
31
|
syncCollection<T extends object, O extends object>(coll: Collection<T, O>, options?: DriverMethodOptions): Promise<void>;
|
|
32
|
-
loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?: OrderDefinition<T>, ctx?: Transaction, options?: FindOptions<T, any, any
|
|
32
|
+
loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?: OrderDefinition<T>, ctx?: Transaction, options?: FindOptions<T, any, any>, pivotJoin?: boolean): Promise<Dictionary<T[]>>;
|
|
33
33
|
private getPivotOrderBy;
|
|
34
34
|
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(queryOrKnex: string | Knex.QueryBuilder | Knex.Raw, params?: any[], method?: 'all' | 'get' | 'run', ctx?: Transaction): Promise<T>;
|
|
35
35
|
/**
|
|
@@ -61,5 +61,5 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
61
61
|
protected buildJoinedPropsOrderBy<T extends object>(entityName: string, qb: QueryBuilder<T>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], parentPath?: string): QueryOrderMap<T>[];
|
|
62
62
|
protected normalizeFields<T extends object>(fields: Field<T>[], prefix?: string): string[];
|
|
63
63
|
protected processField<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T> | undefined, field: string, ret: Field<T>[], populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>): void;
|
|
64
|
-
protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>, fields?: Field<T>[]): Field<T>[];
|
|
64
|
+
protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>, alias: string, fields?: Field<T>[]): Field<T>[];
|
|
65
65
|
}
|
package/AbstractSqlDriver.js
CHANGED
|
@@ -30,7 +30,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
30
30
|
const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
|
|
31
31
|
const joinedProps = this.joinedProps(meta, populate);
|
|
32
32
|
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging);
|
|
33
|
-
const fields = this.buildFields(meta, populate, joinedProps, qb, options.fields);
|
|
33
|
+
const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options.fields);
|
|
34
34
|
const joinedPropsOrderBy = this.buildJoinedPropsOrderBy(entityName, qb, meta, joinedProps);
|
|
35
35
|
const orderBy = [...core_1.Utils.asArray(options.orderBy), ...joinedPropsOrderBy];
|
|
36
36
|
if (core_1.Utils.isPrimaryKey(where, meta.compositePK)) {
|
|
@@ -290,7 +290,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
290
290
|
async nativeInsertMany(entityName, data, options = {}) {
|
|
291
291
|
options.processCollections ??= true;
|
|
292
292
|
options.convertCustomTypes ??= true;
|
|
293
|
-
const meta = this.metadata.find(entityName);
|
|
293
|
+
const meta = this.metadata.find(entityName)?.root;
|
|
294
294
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
295
295
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
296
296
|
const set = new Set();
|
|
@@ -322,24 +322,31 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
322
322
|
if (fields.length > 0 || this.platform.usesDefaultKeyword()) {
|
|
323
323
|
sql += data.map(row => {
|
|
324
324
|
const keys = [];
|
|
325
|
+
const usedDups = [];
|
|
325
326
|
props.forEach(prop => {
|
|
326
327
|
if (prop.fieldNames.length > 1) {
|
|
327
328
|
const param = core_1.Utils.flatten([...row[prop.name] ?? prop.fieldNames.map(() => null)]);
|
|
328
329
|
const key = param.map(() => '?');
|
|
329
330
|
prop.fieldNames.forEach((field, idx) => {
|
|
330
|
-
if (!duplicates.includes(field)) {
|
|
331
|
+
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
331
332
|
params.push(param[idx]);
|
|
332
333
|
keys.push(key[idx]);
|
|
334
|
+
usedDups.push(field);
|
|
333
335
|
}
|
|
334
336
|
});
|
|
335
337
|
}
|
|
336
|
-
else if (prop.customType && 'convertToDatabaseValueSQL' in prop.customType && !this.platform.isRaw(row[prop.name])) {
|
|
337
|
-
keys.push(prop.customType.convertToDatabaseValueSQL('?', this.platform));
|
|
338
|
-
addParams(prop, row);
|
|
339
|
-
}
|
|
340
338
|
else {
|
|
341
|
-
|
|
342
|
-
|
|
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
|
+
}
|
|
343
350
|
}
|
|
344
351
|
});
|
|
345
352
|
return '(' + (keys.join(', ') || 'default') + ')';
|
|
@@ -568,18 +575,18 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
568
575
|
}
|
|
569
576
|
return this.rethrow(this.updateCollectionDiff(meta, coll.property, pks, deleteDiff, insertDiff, options));
|
|
570
577
|
}
|
|
571
|
-
async loadFromPivotTable(prop, owners, where = {}, orderBy, ctx, options) {
|
|
572
|
-
const pivotProp2 = this.getPivotInverseProperty(prop);
|
|
573
|
-
const prop2 = prop.targetMeta.properties[prop.mappedBy ?? prop.inversedBy];
|
|
574
|
-
const ownerMeta = this.metadata.find(pivotProp2.type);
|
|
578
|
+
async loadFromPivotTable(prop, owners, where = {}, orderBy, ctx, options, pivotJoin) {
|
|
575
579
|
const pivotMeta = this.metadata.find(prop.pivotEntity);
|
|
580
|
+
const pivotProp1 = pivotMeta.relations[prop.owner ? 1 : 0];
|
|
581
|
+
const pivotProp2 = pivotMeta.relations[prop.owner ? 0 : 1];
|
|
582
|
+
const ownerMeta = this.metadata.find(pivotProp2.type);
|
|
576
583
|
options = { ...options };
|
|
577
|
-
const qb = this.createQueryBuilder(prop.
|
|
578
|
-
.withSchema(this.getSchemaName(
|
|
584
|
+
const qb = this.createQueryBuilder(prop.pivotEntity, ctx, options.connectionType)
|
|
585
|
+
.withSchema(this.getSchemaName(pivotMeta, options))
|
|
579
586
|
.indexHint(options.indexHint)
|
|
580
587
|
.comment(options.comments)
|
|
581
588
|
.hintComment(options.hintComments);
|
|
582
|
-
const pivotAlias = qb.
|
|
589
|
+
const pivotAlias = qb.alias;
|
|
583
590
|
const pivotKey = pivotProp2.joinColumns.map(column => `${pivotAlias}.${column}`).join(core_1.Utils.PK_SEPARATOR);
|
|
584
591
|
const cond = {
|
|
585
592
|
[pivotKey]: { $in: ownerMeta.compositePK ? owners : owners.map(o => o[0]) },
|
|
@@ -591,9 +598,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
591
598
|
else {
|
|
592
599
|
where = { ...where, ...cond };
|
|
593
600
|
}
|
|
594
|
-
orderBy = this.getPivotOrderBy(prop, pivotAlias, orderBy);
|
|
601
|
+
orderBy = this.getPivotOrderBy(prop, pivotProp1, pivotAlias, orderBy);
|
|
595
602
|
const populate = this.autoJoinOneToOneOwner(prop.targetMeta, []);
|
|
596
|
-
const fields =
|
|
603
|
+
const fields = [];
|
|
597
604
|
const k1 = !prop.owner ? 'joinColumns' : 'inverseJoinColumns';
|
|
598
605
|
const k2 = prop.owner ? 'joinColumns' : 'inverseJoinColumns';
|
|
599
606
|
const cols = [
|
|
@@ -601,25 +608,36 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
601
608
|
...prop[k2].map(col => `${pivotAlias}.${col} as fk__${col}`),
|
|
602
609
|
];
|
|
603
610
|
fields.push(...cols);
|
|
611
|
+
if (!pivotJoin) {
|
|
612
|
+
const targetAlias = qb.getNextAlias(prop.targetMeta.tableName);
|
|
613
|
+
const targetSchema = this.getSchemaName(prop.targetMeta, options) ?? this.platform.getDefaultSchemaName();
|
|
614
|
+
qb.innerJoin(pivotProp1.name, targetAlias, {}, targetSchema);
|
|
615
|
+
const targetFields = this.buildFields(prop.targetMeta, (options.populate ?? []), [], qb, targetAlias, options.fields);
|
|
616
|
+
for (const field of targetFields) {
|
|
617
|
+
const f = field.toString();
|
|
618
|
+
fields.unshift(f.includes('.') ? field : `${targetAlias}.${f}`);
|
|
619
|
+
}
|
|
620
|
+
// we need to handle 1:1 owner auto-joins explicitly, as the QB type is the pivot table, not the target
|
|
621
|
+
populate.forEach(hint => {
|
|
622
|
+
const alias = qb.getNextAlias(prop.targetMeta.tableName);
|
|
623
|
+
qb.leftJoin(`${targetAlias}.${hint.field}`, alias);
|
|
624
|
+
// eslint-disable-next-line dot-notation
|
|
625
|
+
Object.values(qb['_joins']).forEach(join => {
|
|
626
|
+
if (join.alias === alias && join.prop.name === hint.field) {
|
|
627
|
+
fields.push(...qb.helper.mapJoinColumns(qb.type, join));
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
});
|
|
631
|
+
}
|
|
604
632
|
qb.select(fields)
|
|
605
|
-
.
|
|
606
|
-
.populate(populate)
|
|
607
|
-
.where(where)
|
|
633
|
+
.where({ [pivotProp1.name]: where })
|
|
608
634
|
.orderBy(orderBy)
|
|
609
635
|
.setLockMode(options.lockMode, options.lockTableAliases);
|
|
610
636
|
if (owners.length === 1 && (options.offset != null || options.limit != null)) {
|
|
611
637
|
qb.limit(options.limit, options.offset);
|
|
612
638
|
}
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
// eslint-disable-next-line dot-notation
|
|
616
|
-
qb['finalize']();
|
|
617
|
-
// eslint-disable-next-line dot-notation
|
|
618
|
-
Object.values(qb['_joins']).forEach(join => {
|
|
619
|
-
join.schema = schema;
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
const items = owners.length ? await this.rethrow(qb.execute('all')) : [];
|
|
639
|
+
const res = owners.length ? await this.rethrow(qb.execute('all', false)) : [];
|
|
640
|
+
const items = res.map((row) => super.mapResult(row, prop.targetMeta));
|
|
623
641
|
const map = {};
|
|
624
642
|
const pkProps = ownerMeta.getPrimaryProps();
|
|
625
643
|
owners.forEach(owner => {
|
|
@@ -636,16 +654,19 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
636
654
|
}));
|
|
637
655
|
map[key].push(item);
|
|
638
656
|
prop.joinColumns.forEach(col => delete item[`fk__${col}`]);
|
|
639
|
-
prop.inverseJoinColumns.forEach(col =>
|
|
657
|
+
prop.inverseJoinColumns.forEach((col, idx) => {
|
|
658
|
+
core_1.Utils.renameKey(item, `fk__${col}`, prop.targetMeta.primaryKeys[idx]);
|
|
659
|
+
});
|
|
640
660
|
});
|
|
641
661
|
return map;
|
|
642
662
|
}
|
|
643
|
-
getPivotOrderBy(prop, pivotAlias, orderBy) {
|
|
663
|
+
getPivotOrderBy(prop, pivotProp, pivotAlias, orderBy) {
|
|
664
|
+
// FIXME this is ignoring the rest of the array items
|
|
644
665
|
if (!core_1.Utils.isEmpty(orderBy)) {
|
|
645
|
-
return orderBy;
|
|
666
|
+
return [{ [pivotProp.name]: core_1.Utils.asArray(orderBy)[0] }];
|
|
646
667
|
}
|
|
647
668
|
if (!core_1.Utils.isEmpty(prop.orderBy)) {
|
|
648
|
-
return core_1.Utils.asArray(prop.orderBy);
|
|
669
|
+
return [{ [pivotProp.name]: core_1.Utils.asArray(prop.orderBy)[0] }];
|
|
649
670
|
}
|
|
650
671
|
if (prop.fixedOrder) {
|
|
651
672
|
return [{ [`${pivotAlias}.${prop.fixedOrderColumn}`]: core_1.QueryOrder.ASC }];
|
|
@@ -721,7 +742,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
721
742
|
.filter(prop => shouldHaveColumn(prop, populate, explicitFields))
|
|
722
743
|
.forEach(prop => fields.push(...this.mapPropToFieldNames(qb, prop, parentTableAlias)));
|
|
723
744
|
joinedProps.forEach(relation => {
|
|
724
|
-
const
|
|
745
|
+
const [propName] = relation.field.split(':', 2);
|
|
746
|
+
const prop = meta.properties[propName];
|
|
725
747
|
const meta2 = this.metadata.find(prop.type);
|
|
726
748
|
const tableAlias = qb.getNextAlias(prop.name);
|
|
727
749
|
const field = parentTableAlias ? `${parentTableAlias}.${prop.name}` : prop.name;
|
|
@@ -851,7 +873,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
851
873
|
const orderBy = [];
|
|
852
874
|
const joinedProps = this.joinedProps(meta, populate);
|
|
853
875
|
joinedProps.forEach(relation => {
|
|
854
|
-
const
|
|
876
|
+
const [propName] = relation.field.split(':', 2);
|
|
877
|
+
const prop = meta.properties[propName];
|
|
855
878
|
const propOrderBy = prop.orderBy;
|
|
856
879
|
const path = `${parentPath ? parentPath : entityName}.${relation.field}`;
|
|
857
880
|
const propAlias = qb.getAliasForJoinPath(path);
|
|
@@ -902,7 +925,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
902
925
|
}
|
|
903
926
|
ret.push(prop.name);
|
|
904
927
|
}
|
|
905
|
-
buildFields(meta, populate, joinedProps, qb, fields) {
|
|
928
|
+
buildFields(meta, populate, joinedProps, qb, alias, fields) {
|
|
906
929
|
const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => p.field === prop.name || p.all));
|
|
907
930
|
const hasLazyFormulas = meta.props.some(p => p.lazy && p.formula);
|
|
908
931
|
const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL);
|
|
@@ -944,9 +967,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
944
967
|
meta.props
|
|
945
968
|
.filter(prop => prop.formula && !lazyProps.includes(prop))
|
|
946
969
|
.forEach(prop => {
|
|
947
|
-
const
|
|
970
|
+
const a = this.connection.getKnex().ref(alias).toString();
|
|
948
971
|
const aliased = this.connection.getKnex().ref(prop.fieldNames[0]).toString();
|
|
949
|
-
ret.push((0, core_1.raw)(`${prop.formula(
|
|
972
|
+
ret.push((0, core_1.raw)(`${prop.formula(a)} as ${aliased}`));
|
|
950
973
|
});
|
|
951
974
|
meta.props
|
|
952
975
|
.filter(prop => prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/knex",
|
|
3
|
-
"version": "6.0.0-dev.
|
|
3
|
+
"version": "6.0.0-dev.112",
|
|
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
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -66,6 +66,6 @@
|
|
|
66
66
|
"@mikro-orm/core": "^5.8.5"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@mikro-orm/core": "6.0.0-dev.
|
|
69
|
+
"@mikro-orm/core": "6.0.0-dev.112"
|
|
70
70
|
}
|
|
71
71
|
}
|
package/query/QueryBuilder.js
CHANGED
|
@@ -274,6 +274,7 @@ class QueryBuilder {
|
|
|
274
274
|
aliasMap: this.getAliasMap(),
|
|
275
275
|
aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
276
276
|
convertCustomTypes: false,
|
|
277
|
+
type: 'orderBy',
|
|
277
278
|
});
|
|
278
279
|
this._orderBy.push(CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this));
|
|
279
280
|
});
|
|
@@ -26,7 +26,7 @@ export declare class QueryBuilderHelper {
|
|
|
26
26
|
private processJoinClause;
|
|
27
27
|
private wrapQueryGroup;
|
|
28
28
|
mapJoinColumns(type: QueryType, join: JoinOptions): (string | Knex.Raw)[];
|
|
29
|
-
isOneToOneInverse(field: string): boolean;
|
|
29
|
+
isOneToOneInverse(field: string, meta?: EntityMetadata): boolean;
|
|
30
30
|
getTableName(entityName: string): string;
|
|
31
31
|
/**
|
|
32
32
|
* Checks whether the RE can be rewritten to simple LIKE query
|
|
@@ -157,6 +157,8 @@ class QueryBuilderHelper {
|
|
|
157
157
|
const prop2 = prop.owner ? pivotMeta.relations[1] : pivotMeta.relations[0];
|
|
158
158
|
ret[`${pivotAlias}.${prop2.name}#${alias}`] = this.joinManyToOneReference(prop2, pivotAlias, alias, type, cond, schema);
|
|
159
159
|
ret[`${pivotAlias}.${prop2.name}#${alias}`].path = path;
|
|
160
|
+
const tmp = prop2.referencedTableName.split('.');
|
|
161
|
+
ret[`${pivotAlias}.${prop2.name}#${alias}`].schema ??= tmp.length > 1 ? tmp[0] : undefined;
|
|
160
162
|
return ret;
|
|
161
163
|
}
|
|
162
164
|
processJoins(qb, joins, schema) {
|
|
@@ -177,7 +179,7 @@ class QueryBuilderHelper {
|
|
|
177
179
|
conditions.push(`${left} = ${this.knex.ref(right)}`);
|
|
178
180
|
return;
|
|
179
181
|
}
|
|
180
|
-
const left =
|
|
182
|
+
const left = `${join.ownerAlias}.${primaryKey}`;
|
|
181
183
|
conditions.push(`${this.knex.ref(left)} = ${this.knex.ref(right)}`);
|
|
182
184
|
});
|
|
183
185
|
}
|
|
@@ -282,8 +284,8 @@ class QueryBuilderHelper {
|
|
|
282
284
|
...join.inverseJoinColumns.map(col => this.mapper(`${join.alias}.${col}`, type, undefined, `fk__${col}`)),
|
|
283
285
|
];
|
|
284
286
|
}
|
|
285
|
-
isOneToOneInverse(field) {
|
|
286
|
-
|
|
287
|
+
isOneToOneInverse(field, meta) {
|
|
288
|
+
meta ??= this.metadata.find(this.entityName);
|
|
287
289
|
const prop = meta.properties[field];
|
|
288
290
|
return prop && prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner;
|
|
289
291
|
}
|
|
@@ -474,7 +476,12 @@ class QueryBuilderHelper {
|
|
|
474
476
|
if (core_1.Utils.isRawSql(colPart)) {
|
|
475
477
|
colPart = this.platform.formatQuery(colPart.sql, colPart.params);
|
|
476
478
|
}
|
|
477
|
-
|
|
479
|
+
if (Array.isArray(order)) {
|
|
480
|
+
order.forEach(part => ret.push(this.getQueryOrderFromObject(type, part, populate)));
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
ret.push(`${colPart} ${order.toLowerCase()}`);
|
|
484
|
+
}
|
|
478
485
|
});
|
|
479
486
|
});
|
|
480
487
|
return ret.join(', ');
|