@mikro-orm/knex 7.0.0-dev.6 → 7.0.0-dev.8
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.js +1 -0
- package/AbstractSqlDriver.d.ts +5 -5
- package/AbstractSqlDriver.js +5 -2
- package/package.json +3 -3
- package/query/CriteriaNode.js +1 -1
- package/query/ObjectCriteriaNode.js +4 -2
- package/query/QueryBuilder.d.ts +10 -1
- package/query/QueryBuilder.js +29 -1
- package/schema/DatabaseTable.js +15 -3
- package/typings.d.ts +1 -0
package/AbstractSqlConnection.js
CHANGED
|
@@ -81,6 +81,7 @@ export class AbstractSqlConnection extends Connection {
|
|
|
81
81
|
this.logQuery(this.platform.getSavepointSQL(savepointName));
|
|
82
82
|
return trx;
|
|
83
83
|
}
|
|
84
|
+
await this.ensureConnection();
|
|
84
85
|
await options.eventBroadcaster?.dispatchEvent(EventType.beforeTransactionStart);
|
|
85
86
|
let trxBuilder = this.client.startTransaction();
|
|
86
87
|
if (options.isolationLevel) {
|
package/AbstractSqlDriver.d.ts
CHANGED
|
@@ -14,12 +14,12 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
14
14
|
protected constructor(config: Configuration, platform: Platform, connection: Constructor<Connection>, connector: string[]);
|
|
15
15
|
getPlatform(): Platform;
|
|
16
16
|
createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
|
|
17
|
-
find<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: string, where:
|
|
18
|
-
findOne<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: string, where:
|
|
17
|
+
find<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: string, where: ObjectQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
|
|
18
|
+
findOne<T extends object, P extends string = never, F extends string = PopulatePath.ALL, E extends string = never>(entityName: string, where: ObjectQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
|
|
19
19
|
protected hasToManyJoins<T extends object>(hint: PopulateOptions<T>, meta: EntityMetadata<T>): boolean;
|
|
20
|
-
findVirtual<T extends object>(entityName: string, where:
|
|
21
|
-
countVirtual<T extends object>(entityName: string, where:
|
|
22
|
-
protected findFromVirtual<T extends object>(entityName: string, where:
|
|
20
|
+
findVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
|
|
21
|
+
countVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: CountOptions<T, any>): Promise<number>;
|
|
22
|
+
protected findFromVirtual<T extends object>(entityName: string, where: ObjectQuery<T>, options: FindOptions<T, any> | CountOptions<T, any>, type: QueryType): Promise<EntityData<T>[] | number>;
|
|
23
23
|
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any>, type: QueryType): Promise<T[] | number>;
|
|
24
24
|
mapResult<T extends object>(result: EntityData<T>, meta: EntityMetadata<T>, populate?: PopulateOptions<T>[], qb?: QueryBuilder<T, any, any, any>, map?: Dictionary): EntityData<T> | null;
|
|
25
25
|
private mapJoinedProps;
|
package/AbstractSqlDriver.js
CHANGED
|
@@ -63,6 +63,9 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
63
63
|
if (options.lockMode) {
|
|
64
64
|
qb.setLockMode(options.lockMode, options.lockTableAliases);
|
|
65
65
|
}
|
|
66
|
+
if (options.em) {
|
|
67
|
+
await qb.applyJoinedFilters(options.em, options.filters);
|
|
68
|
+
}
|
|
66
69
|
const result = await this.rethrow(qb.execute('all'));
|
|
67
70
|
if (isCursorPagination && !first && !!last) {
|
|
68
71
|
result.reverse();
|
|
@@ -437,7 +440,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
437
440
|
else {
|
|
438
441
|
const field = prop.fieldNames[0];
|
|
439
442
|
if (!duplicates.includes(field) || !usedDups.includes(field)) {
|
|
440
|
-
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !isRaw(row[prop.name])) {
|
|
443
|
+
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && row[prop.name] != null && !isRaw(row[prop.name])) {
|
|
441
444
|
keys.push(prop.customType.convertToDatabaseValueSQL('?', this.platform));
|
|
442
445
|
}
|
|
443
446
|
else {
|
|
@@ -588,7 +591,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
588
591
|
if (key in data[idx]) {
|
|
589
592
|
const pks = Utils.getOrderedPrimaryKeys(cond, meta);
|
|
590
593
|
sql += ` when (${pkCond}) then `;
|
|
591
|
-
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && !isRaw(data[idx][key])) {
|
|
594
|
+
if (prop.customType && !prop.object && 'convertToDatabaseValueSQL' in prop.customType && data[idx][prop.name] != null && !isRaw(data[idx][key])) {
|
|
592
595
|
sql += prop.customType.convertToDatabaseValueSQL('?', this.platform);
|
|
593
596
|
}
|
|
594
597
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/knex",
|
|
3
|
-
"version": "7.0.0-dev.
|
|
3
|
+
"version": "7.0.0-dev.8",
|
|
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": {
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"sqlstring": "2.3.3"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@mikro-orm/core": "^6.4.
|
|
57
|
+
"@mikro-orm/core": "^6.4.9"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@mikro-orm/core": "7.0.0-dev.
|
|
60
|
+
"@mikro-orm/core": "7.0.0-dev.8"
|
|
61
61
|
}
|
|
62
62
|
}
|
package/query/CriteriaNode.js
CHANGED
|
@@ -69,7 +69,7 @@ export class CriteriaNode {
|
|
|
69
69
|
let joinAlias = qb.getAliasForJoinPath(this.getPath());
|
|
70
70
|
if (!joinAlias && this.parent && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind) && this.prop.owner) {
|
|
71
71
|
joinAlias = qb.getAliasForJoinPath(this.parent.getPath());
|
|
72
|
-
return Utils.getPrimaryKeyHash(this.prop.
|
|
72
|
+
return Utils.getPrimaryKeyHash(this.prop.joinColumns.map(col => `${joinAlias ?? qb.alias}.${col}`));
|
|
73
73
|
}
|
|
74
74
|
const alias = joinAlias ?? qb.alias;
|
|
75
75
|
if (this.prop.kind === ReferenceKind.MANY_TO_MANY) {
|
|
@@ -200,16 +200,18 @@ export class ObjectCriteriaNode extends CriteriaNode {
|
|
|
200
200
|
const operator = Utils.isPlainObject(this.payload) && Object.keys(this.payload).every(k => Utils.isOperator(k, false));
|
|
201
201
|
const field = `${alias}.${this.prop.name}`;
|
|
202
202
|
const method = qb.hasFlag(QueryFlag.INFER_POPULATE) ? 'joinAndSelect' : 'join';
|
|
203
|
+
const path = this.getPath();
|
|
203
204
|
if (this.prop.kind === ReferenceKind.MANY_TO_MANY && (scalar || operator)) {
|
|
204
|
-
qb.join(field, nestedAlias, undefined, JoinType.pivotJoin,
|
|
205
|
+
qb.join(field, nestedAlias, undefined, JoinType.pivotJoin, path);
|
|
205
206
|
}
|
|
206
207
|
else {
|
|
207
208
|
const prev = qb._fields?.slice();
|
|
208
|
-
qb[method](field, nestedAlias, undefined, JoinType.leftJoin,
|
|
209
|
+
qb[method](field, nestedAlias, undefined, JoinType.leftJoin, path);
|
|
209
210
|
if (!qb.hasFlag(QueryFlag.INFER_POPULATE)) {
|
|
210
211
|
qb._fields = prev;
|
|
211
212
|
}
|
|
212
213
|
}
|
|
214
|
+
qb.scheduleFilterCheck(path);
|
|
213
215
|
return nestedAlias;
|
|
214
216
|
}
|
|
215
217
|
isPrefixed(field) {
|
package/query/QueryBuilder.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { inspect } from 'node:util';
|
|
2
|
-
import { type AnyEntity, type ConnectionType, type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityName, type EntityProperty, type ExpandProperty, type FlushMode, type GroupOperator, type Loaded, LockMode, type LoggingOptions, type MetadataStorage, type ObjectQuery, PopulateHint, type PopulateOptions, type QBFilterQuery, type QBQueryOrderMap, QueryFlag, type QueryOrderMap, type QueryResult, RawQueryFragment, type RequiredEntityData, type Transaction } from '@mikro-orm/core';
|
|
2
|
+
import { type AnyEntity, type ConnectionType, type Dictionary, type EntityData, type EntityKey, type EntityManager, type EntityMetadata, type EntityName, type EntityProperty, type ExpandProperty, type FlushMode, type GroupOperator, type Loaded, LockMode, type LoggingOptions, type MetadataStorage, type ObjectQuery, PopulateHint, type PopulateOptions, type QBFilterQuery, type QBQueryOrderMap, QueryFlag, type QueryOrderMap, type QueryResult, RawQueryFragment, type RequiredEntityData, type Transaction } from '@mikro-orm/core';
|
|
3
3
|
import { JoinType, QueryType } from './enums.js';
|
|
4
4
|
import type { AbstractSqlDriver } from '../AbstractSqlDriver.js';
|
|
5
5
|
import { type Alias, type OnConflictClause, QueryBuilderHelper } from './QueryBuilderHelper.js';
|
|
@@ -141,6 +141,15 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
141
141
|
* Apply filters to the QB where condition.
|
|
142
142
|
*/
|
|
143
143
|
applyFilters(filterOptions?: Dictionary<boolean | Dictionary> | string[] | boolean): Promise<void>;
|
|
144
|
+
private readonly autoJoinedPaths;
|
|
145
|
+
/**
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
scheduleFilterCheck(path: string): void;
|
|
149
|
+
/**
|
|
150
|
+
* @internal
|
|
151
|
+
*/
|
|
152
|
+
applyJoinedFilters(em: EntityManager, filterOptions?: Dictionary<boolean | Dictionary> | string[] | boolean): Promise<void>;
|
|
144
153
|
withSubQuery(subQuery: RawQueryFragment | NativeQueryBuilder, alias: string): this;
|
|
145
154
|
where(cond: QBFilterQuery<Entity>, operator?: keyof typeof GroupOperator): this;
|
|
146
155
|
where(cond: string, params?: any[], operator?: keyof typeof GroupOperator): this;
|
package/query/QueryBuilder.js
CHANGED
|
@@ -257,6 +257,34 @@ export class QueryBuilder {
|
|
|
257
257
|
const cond = await this.em.applyFilters(this.mainAlias.entityName, {}, filterOptions, 'read');
|
|
258
258
|
this.andWhere(cond);
|
|
259
259
|
}
|
|
260
|
+
autoJoinedPaths = [];
|
|
261
|
+
/**
|
|
262
|
+
* @internal
|
|
263
|
+
*/
|
|
264
|
+
scheduleFilterCheck(path) {
|
|
265
|
+
this.autoJoinedPaths.push(path);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* @internal
|
|
269
|
+
*/
|
|
270
|
+
async applyJoinedFilters(em, filterOptions = {}) {
|
|
271
|
+
for (const path of this.autoJoinedPaths) {
|
|
272
|
+
const join = this.getJoinForPath(path);
|
|
273
|
+
if (join.type === JoinType.pivotJoin) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const cond = await em.applyFilters(join.prop.type, join.cond, filterOptions, 'read');
|
|
277
|
+
if (Utils.hasObjectKeys(cond)) {
|
|
278
|
+
if (Utils.hasObjectKeys(join.cond)) {
|
|
279
|
+
/* istanbul ignore next */
|
|
280
|
+
join.cond = { $and: [join.cond, cond] };
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
join.cond = { ...cond };
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
260
288
|
withSubQuery(subQuery, alias) {
|
|
261
289
|
this.ensureNotFinalized();
|
|
262
290
|
if (subQuery instanceof RawQueryFragment) {
|
|
@@ -1152,7 +1180,7 @@ export class QueryBuilder {
|
|
|
1152
1180
|
let joins = Object.values(this._joins);
|
|
1153
1181
|
for (const join of joins) {
|
|
1154
1182
|
join.cond_ ??= join.cond;
|
|
1155
|
-
join.cond =
|
|
1183
|
+
join.cond = { ...join.cond };
|
|
1156
1184
|
}
|
|
1157
1185
|
if (typeof this[key] === 'object') {
|
|
1158
1186
|
const cond = CriteriaNodeFactory
|
package/schema/DatabaseTable.js
CHANGED
|
@@ -699,16 +699,28 @@ export class DatabaseTable {
|
|
|
699
699
|
}
|
|
700
700
|
addIndex(meta, index, type) {
|
|
701
701
|
const properties = Utils.unique(Utils.flatten(Utils.asArray(index.properties).map(prop => {
|
|
702
|
-
const
|
|
702
|
+
const parts = prop.split('.');
|
|
703
|
+
const root = parts[0];
|
|
703
704
|
if (meta.properties[prop]) {
|
|
704
705
|
if (meta.properties[prop].embeddedPath) {
|
|
705
706
|
return [meta.properties[prop].embeddedPath.join('.')];
|
|
706
707
|
}
|
|
707
708
|
return meta.properties[prop].fieldNames;
|
|
708
709
|
}
|
|
710
|
+
const rootProp = meta.properties[root];
|
|
711
|
+
// inline embedded property index, we need to find the field name of the child property
|
|
712
|
+
if (rootProp?.embeddable && !rootProp.object && parts.length > 1) {
|
|
713
|
+
const expand = (p, i) => {
|
|
714
|
+
if (parts.length === i) {
|
|
715
|
+
return p.fieldNames[0];
|
|
716
|
+
}
|
|
717
|
+
return expand(p.embeddedProps[parts[i]], i + 1);
|
|
718
|
+
};
|
|
719
|
+
return [expand(rootProp, 1)];
|
|
720
|
+
}
|
|
709
721
|
// json index, we need to rename the column only
|
|
710
|
-
if (
|
|
711
|
-
return [prop.replace(root,
|
|
722
|
+
if (rootProp) {
|
|
723
|
+
return [prop.replace(root, rootProp.fieldNames[0])];
|
|
712
724
|
}
|
|
713
725
|
/* v8 ignore next */
|
|
714
726
|
return [prop];
|
package/typings.d.ts
CHANGED
|
@@ -163,6 +163,7 @@ export interface IQueryBuilder<T> {
|
|
|
163
163
|
setFlag(flag: QueryFlag): this;
|
|
164
164
|
unsetFlag(flag: QueryFlag): this;
|
|
165
165
|
hasFlag(flag: QueryFlag): boolean;
|
|
166
|
+
scheduleFilterCheck(path: string): void;
|
|
166
167
|
}
|
|
167
168
|
export interface ICriteriaNodeProcessOptions {
|
|
168
169
|
alias?: string;
|