@mikro-orm/knex 6.0.0-rc.2 → 6.0.0-rc.3
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 +1 -1
- package/AbstractSqlConnection.js +3 -3
- package/AbstractSqlDriver.d.ts +8 -10
- package/AbstractSqlDriver.js +59 -31
- package/AbstractSqlPlatform.d.ts +5 -1
- package/AbstractSqlPlatform.js +7 -1
- package/SqlEntityManager.d.ts +3 -3
- package/SqlEntityManager.js +4 -4
- package/index.mjs +1 -1
- package/package.json +5 -5
- package/query/CriteriaNode.d.ts +1 -2
- package/query/CriteriaNode.js +3 -6
- package/query/CriteriaNodeFactory.d.ts +1 -1
- package/query/CriteriaNodeFactory.js +1 -2
- package/query/ObjectCriteriaNode.d.ts +1 -1
- package/query/ObjectCriteriaNode.js +13 -9
- package/query/QueryBuilder.d.ts +2 -2
- package/query/QueryBuilder.js +4 -4
- package/query/QueryBuilderHelper.js +1 -1
- package/query/ScalarCriteriaNode.js +6 -0
- package/schema/DatabaseTable.d.ts +2 -2
- package/schema/SchemaComparator.d.ts +2 -0
- package/schema/SchemaComparator.js +11 -2
|
@@ -40,7 +40,7 @@ export declare abstract class AbstractSqlConnection extends Connection {
|
|
|
40
40
|
}): Promise<Knex.Transaction>;
|
|
41
41
|
commit(ctx: Knex.Transaction, eventBroadcaster?: TransactionEventBroadcaster): Promise<void>;
|
|
42
42
|
rollback(ctx: Knex.Transaction, eventBroadcaster?: TransactionEventBroadcaster): Promise<void>;
|
|
43
|
-
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(queryOrKnex: string | Knex.QueryBuilder | Knex.Raw, params?: unknown[], method?: 'all' | 'get' | 'run', ctx?: Transaction,
|
|
43
|
+
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(queryOrKnex: string | Knex.QueryBuilder | Knex.Raw, params?: unknown[], method?: 'all' | 'get' | 'run', ctx?: Transaction, loggerContext?: LoggingOptions): Promise<T>;
|
|
44
44
|
/**
|
|
45
45
|
* Execute raw SQL queries from file
|
|
46
46
|
*/
|
package/AbstractSqlConnection.js
CHANGED
|
@@ -106,7 +106,7 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
106
106
|
await eventBroadcaster?.dispatchEvent(core_1.EventType.afterTransactionRollback, ctx);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
async execute(queryOrKnex, params = [], method = 'all', ctx,
|
|
109
|
+
async execute(queryOrKnex, params = [], method = 'all', ctx, loggerContext) {
|
|
110
110
|
await this.ensureConnection();
|
|
111
111
|
if (core_1.Utils.isObject(queryOrKnex)) {
|
|
112
112
|
ctx ??= (queryOrKnex.client.transacting ? queryOrKnex : null);
|
|
@@ -115,7 +115,7 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
115
115
|
params = q.bindings;
|
|
116
116
|
}
|
|
117
117
|
const formatted = this.platform.formatQuery(queryOrKnex, params);
|
|
118
|
-
const sql = this.getSql(queryOrKnex, formatted,
|
|
118
|
+
const sql = this.getSql(queryOrKnex, formatted, loggerContext);
|
|
119
119
|
return this.executeQuery(sql, async () => {
|
|
120
120
|
const query = this.getKnex().raw(formatted);
|
|
121
121
|
if (ctx) {
|
|
@@ -123,7 +123,7 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
123
123
|
}
|
|
124
124
|
const res = await query;
|
|
125
125
|
return this.transformRawResult(res, method);
|
|
126
|
-
}, { query: queryOrKnex, params, ...
|
|
126
|
+
}, { query: queryOrKnex, params, ...loggerContext });
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
129
|
* Execute raw SQL queries from file
|
package/AbstractSqlDriver.d.ts
CHANGED
|
@@ -13,10 +13,10 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
13
13
|
protected constructor(config: Configuration, platform: Platform, connection: Constructor<Connection>, connector: string[]);
|
|
14
14
|
getPlatform(): Platform;
|
|
15
15
|
createEntityManager<D extends IDatabaseDriver = IDatabaseDriver>(useContext?: boolean): D[typeof EntityManagerType];
|
|
16
|
-
find<T extends object, P extends string = never, F extends string = '*'>(entityName: string, where: FilterQuery<T>, options?: FindOptions<T, P, F>): Promise<EntityData<T>[]>;
|
|
17
|
-
findOne<T extends object, P extends string = never, F extends string = '*'>(entityName: string, where: FilterQuery<T>, options?: FindOneOptions<T, P, F>): Promise<EntityData<T> | null>;
|
|
16
|
+
find<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
|
|
17
|
+
findOne<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
|
|
18
18
|
protected hasToManyJoins<T extends object>(hint: PopulateOptions<T>, meta: EntityMetadata<T>): boolean;
|
|
19
|
-
findVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any, any>): Promise<EntityData<T>[]>;
|
|
19
|
+
findVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
|
|
20
20
|
countVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: CountOptions<T, any>): Promise<number>;
|
|
21
21
|
protected findFromVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any> | CountOptions<T, any>, type: QueryType): Promise<EntityData<T>[] | number>;
|
|
22
22
|
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any>, type: QueryType): Promise<T[] | number>;
|
|
@@ -29,13 +29,13 @@ 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
|
syncCollections<T extends object, O extends object>(collections: Iterable<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>, pivotJoin?: boolean): Promise<Dictionary<T[]>>;
|
|
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, 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
|
/**
|
|
36
36
|
* 1:1 owner side needs to be marked for population so QB auto-joins the owner id
|
|
37
37
|
*/
|
|
38
|
-
protected autoJoinOneToOneOwner<T extends object, P extends string = never>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], fields?: readonly EntityField<T,
|
|
38
|
+
protected autoJoinOneToOneOwner<T extends object, P extends string = never>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], fields?: readonly EntityField<T, any>[]): PopulateOptions<T>[];
|
|
39
39
|
/**
|
|
40
40
|
* @internal
|
|
41
41
|
*/
|
|
@@ -46,7 +46,7 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
46
46
|
* @internal
|
|
47
47
|
*/
|
|
48
48
|
mergeJoinedResult<T extends object>(rawResults: EntityData<T>[], meta: EntityMetadata<T>, joinedProps: PopulateOptions<T>[]): EntityData<T>[];
|
|
49
|
-
protected getFieldsForJoinedLoad<T extends object>(qb: QueryBuilder<T>, meta: EntityMetadata<T>, explicitFields?: Field<T>[], populate?: PopulateOptions<T>[], options?: {
|
|
49
|
+
protected getFieldsForJoinedLoad<T extends object>(qb: QueryBuilder<T>, meta: EntityMetadata<T>, explicitFields?: Field<T>[], exclude?: Field<T>[], populate?: PopulateOptions<T>[], options?: {
|
|
50
50
|
strategy?: Options['loadStrategy'];
|
|
51
51
|
populateWhere?: FindOptions<any>['populateWhere'];
|
|
52
52
|
}, parentTableAlias?: string, parentJoinPath?: string): Field<T>[];
|
|
@@ -55,7 +55,7 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
55
55
|
*/
|
|
56
56
|
mapPropToFieldNames<T extends object>(qb: QueryBuilder<T>, prop: EntityProperty<T>, tableAlias?: string): Field<T>[];
|
|
57
57
|
/** @internal */
|
|
58
|
-
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, ctx?: Transaction<Knex.Transaction>, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean,
|
|
58
|
+
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, ctx?: Transaction<Knex.Transaction>, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean, loggerContext?: LoggingOptions): QueryBuilder<T>;
|
|
59
59
|
protected resolveConnectionType(args: {
|
|
60
60
|
ctx?: Transaction<Knex.Transaction>;
|
|
61
61
|
connectionType?: ConnectionType;
|
|
@@ -68,7 +68,5 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
68
68
|
protected buildJoinedPropsOrderBy<T extends object>(qb: QueryBuilder<T>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], options?: Pick<FindOptions<any>, 'strategy' | 'orderBy' | 'populateOrderBy'>, parentPath?: string): QueryOrderMap<T>[];
|
|
69
69
|
protected normalizeFields<T extends object>(fields: Field<T>[], prefix?: string): string[];
|
|
70
70
|
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;
|
|
71
|
-
protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>, alias: string, fields
|
|
72
|
-
strategy?: Options['loadStrategy'];
|
|
73
|
-
}): Field<T>[];
|
|
71
|
+
protected buildFields<T extends object>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], joinedProps: PopulateOptions<T>[], qb: QueryBuilder<T>, alias: string, options: Pick<FindOptions<T, any, any, any>, 'strategy' | 'fields' | 'exclude'>): Field<T>[];
|
|
74
72
|
}
|
package/AbstractSqlDriver.js
CHANGED
|
@@ -31,7 +31,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
31
31
|
const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
|
|
32
32
|
const joinedProps = this.joinedProps(meta, populate, options);
|
|
33
33
|
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging);
|
|
34
|
-
const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options
|
|
34
|
+
const fields = this.buildFields(meta, populate, joinedProps, qb, qb.alias, options);
|
|
35
35
|
const orderBy = this.buildOrderBy(qb, meta, populate, options);
|
|
36
36
|
core_1.Utils.asArray(options.flags).forEach(flag => qb.setFlag(flag));
|
|
37
37
|
if (core_1.Utils.isPrimaryKey(where, meta.compositePK)) {
|
|
@@ -111,7 +111,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
111
111
|
if (typeof meta.expression === 'string') {
|
|
112
112
|
return this.wrapVirtualExpressionInSubquery(meta, meta.expression, where, options, type);
|
|
113
113
|
}
|
|
114
|
-
const em = this.createEntityManager(
|
|
114
|
+
const em = this.createEntityManager();
|
|
115
115
|
em.setTransactionContext(options.ctx);
|
|
116
116
|
const res = meta.expression(em, where, options);
|
|
117
117
|
if (typeof res === 'string') {
|
|
@@ -217,9 +217,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
217
217
|
}
|
|
218
218
|
return;
|
|
219
219
|
}
|
|
220
|
-
|
|
220
|
+
let relationPojo = {};
|
|
221
221
|
meta2.props
|
|
222
|
-
.filter(prop => prop.persist === false && prop.fieldNames)
|
|
222
|
+
.filter(prop => !ref && prop.persist === false && prop.fieldNames)
|
|
223
223
|
.filter(prop => !prop.lazy || populate.some(p => p.field === prop.name || p.all))
|
|
224
224
|
.forEach(prop => {
|
|
225
225
|
/* istanbul ignore if */
|
|
@@ -231,25 +231,42 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
231
231
|
relationPojo[prop.name] = root[alias];
|
|
232
232
|
}
|
|
233
233
|
});
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
.
|
|
234
|
+
const targetProps = ref
|
|
235
|
+
? meta2.getPrimaryProps()
|
|
236
|
+
: meta2.props.filter(prop => this.platform.shouldHaveColumn(prop, hint.children || []));
|
|
237
|
+
for (const prop of targetProps) {
|
|
237
238
|
if (prop.fieldNames.length > 1) { // composite keys
|
|
238
239
|
const fk = prop.fieldNames.map(name => root[`${relationAlias}__${name}`]);
|
|
239
|
-
prop.fieldNames.map(name => delete root[`${relationAlias}__${name}`]);
|
|
240
240
|
relationPojo[prop.name] = core_1.Utils.mapFlatCompositePrimaryKey(fk, prop);
|
|
241
241
|
}
|
|
242
242
|
else if (prop.runtimeType === 'Date') {
|
|
243
243
|
const alias = `${relationAlias}__${prop.fieldNames[0]}`;
|
|
244
244
|
relationPojo[prop.name] = (typeof root[alias] === 'string' ? new Date(root[alias]) : root[alias]);
|
|
245
|
-
delete root[alias];
|
|
246
245
|
}
|
|
247
246
|
else {
|
|
248
247
|
const alias = `${relationAlias}__${prop.fieldNames[0]}`;
|
|
249
248
|
relationPojo[prop.name] = root[alias];
|
|
250
|
-
|
|
249
|
+
if (prop.kind === core_1.ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
|
|
250
|
+
const item = (0, core_1.parseJsonSafe)(relationPojo[prop.name]);
|
|
251
|
+
if (Array.isArray(item)) {
|
|
252
|
+
relationPojo[prop.name] = item.map(row => row == null ? row : this.comparator.mapResult(prop.type, row));
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
relationPojo[prop.name] = item == null ? item : this.comparator.mapResult(prop.type, item);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
251
258
|
}
|
|
252
|
-
}
|
|
259
|
+
}
|
|
260
|
+
// properties can be mapped to multiple places, e.g. when sharing a column in multiple FKs,
|
|
261
|
+
// so we need to delete them after everything is mapped from given level
|
|
262
|
+
for (const prop of targetProps) {
|
|
263
|
+
prop.fieldNames.map(name => delete root[`${relationAlias}__${name}`]);
|
|
264
|
+
}
|
|
265
|
+
if (ref) {
|
|
266
|
+
const tmp = Object.values(relationPojo);
|
|
267
|
+
/* istanbul ignore next */
|
|
268
|
+
relationPojo = (meta2.compositePK ? tmp : tmp[0]);
|
|
269
|
+
}
|
|
253
270
|
if ([core_1.ReferenceKind.MANY_TO_MANY, core_1.ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
254
271
|
result[prop.name] ??= [];
|
|
255
272
|
result[prop.name].push(relationPojo);
|
|
@@ -465,6 +482,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
465
482
|
}
|
|
466
483
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
467
484
|
const keys = new Set();
|
|
485
|
+
const fields = new Set();
|
|
468
486
|
const returning = new Set();
|
|
469
487
|
data.forEach(row => {
|
|
470
488
|
core_1.Utils.keys(row).forEach(k => {
|
|
@@ -498,6 +516,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
498
516
|
keys.forEach(key => {
|
|
499
517
|
const prop = meta.properties[key];
|
|
500
518
|
prop.fieldNames.forEach((fieldName, fieldNameIdx) => {
|
|
519
|
+
if (fields.has(fieldName)) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
fields.add(fieldName);
|
|
501
523
|
sql += `${this.platform.quoteIdentifier(fieldName)} = case`;
|
|
502
524
|
where.forEach((cond, idx) => {
|
|
503
525
|
if (key in data[idx]) {
|
|
@@ -668,7 +690,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
668
690
|
const targetAlias = qb.getNextAlias(prop.targetMeta.tableName);
|
|
669
691
|
const targetSchema = this.getSchemaName(prop.targetMeta, options) ?? this.platform.getDefaultSchemaName();
|
|
670
692
|
qb.innerJoin(pivotProp1.name, targetAlias, {}, targetSchema);
|
|
671
|
-
const targetFields = this.buildFields(prop.targetMeta, (options.populate ?? []), [], qb, targetAlias, options
|
|
693
|
+
const targetFields = this.buildFields(prop.targetMeta, (options.populate ?? []), [], qb, targetAlias, options);
|
|
672
694
|
for (const field of targetFields) {
|
|
673
695
|
const f = field.toString();
|
|
674
696
|
fields.unshift(f.includes('.') ? field : `${targetAlias}.${f}`);
|
|
@@ -754,11 +776,13 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
754
776
|
return populate.filter(hint => {
|
|
755
777
|
const [propName, ref] = hint.field.split(':', 2);
|
|
756
778
|
const prop = meta.properties[propName] || {};
|
|
779
|
+
if ((options?.strategy || hint.strategy || prop.strategy || this.config.get('loadStrategy')) !== core_1.LoadStrategy.JOINED) {
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
757
782
|
if (ref) {
|
|
758
|
-
|
|
759
|
-
return prop.kind === core_1.ReferenceKind.MANY_TO_MANY;
|
|
783
|
+
return [core_1.ReferenceKind.MANY_TO_MANY, core_1.ReferenceKind.ONE_TO_MANY].includes(prop.kind);
|
|
760
784
|
}
|
|
761
|
-
return
|
|
785
|
+
return ![core_1.ReferenceKind.SCALAR, core_1.ReferenceKind.EMBEDDED].includes(prop.kind);
|
|
762
786
|
});
|
|
763
787
|
}
|
|
764
788
|
/**
|
|
@@ -799,14 +823,14 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
799
823
|
}
|
|
800
824
|
return res;
|
|
801
825
|
}
|
|
802
|
-
getFieldsForJoinedLoad(qb, meta, explicitFields, populate = [], options, parentTableAlias, parentJoinPath) {
|
|
826
|
+
getFieldsForJoinedLoad(qb, meta, explicitFields, exclude, populate = [], options, parentTableAlias, parentJoinPath) {
|
|
803
827
|
const fields = [];
|
|
804
828
|
const joinedProps = this.joinedProps(meta, populate, options);
|
|
805
829
|
if (explicitFields?.includes('*')) {
|
|
806
830
|
fields.push('*');
|
|
807
831
|
}
|
|
808
832
|
const shouldHaveColumn = (prop, populate, fields) => {
|
|
809
|
-
if (!this.platform.shouldHaveColumn(prop, populate)) {
|
|
833
|
+
if (!this.platform.shouldHaveColumn(prop, populate, exclude)) {
|
|
810
834
|
return false;
|
|
811
835
|
}
|
|
812
836
|
if (!fields || prop.primary) {
|
|
@@ -838,14 +862,18 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
838
862
|
if (pivotRefJoin) {
|
|
839
863
|
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}`)));
|
|
840
864
|
}
|
|
865
|
+
if (prop.kind === core_1.ReferenceKind.ONE_TO_MANY && ref) {
|
|
866
|
+
fields.push(...this.getFieldsForJoinedLoad(qb, meta2, prop.referencedColumnNames, undefined, hint.children, options, tableAlias, path));
|
|
867
|
+
}
|
|
841
868
|
const childExplicitFields = explicitFields?.filter(f => core_1.Utils.isPlainObject(f)).map(o => o[prop.name])[0] || [];
|
|
842
869
|
explicitFields?.forEach(f => {
|
|
843
870
|
if (typeof f === 'string' && f.startsWith(`${prop.name}.`)) {
|
|
844
871
|
childExplicitFields.push(f.substring(prop.name.length + 1));
|
|
845
872
|
}
|
|
846
873
|
});
|
|
874
|
+
const childExclude = exclude ? core_1.Utils.extractChildElements(exclude, prop.name) : exclude;
|
|
847
875
|
if (!ref) {
|
|
848
|
-
fields.push(...this.getFieldsForJoinedLoad(qb, meta2, childExplicitFields.length === 0 ? undefined : childExplicitFields, hint.children, options, tableAlias, path));
|
|
876
|
+
fields.push(...this.getFieldsForJoinedLoad(qb, meta2, childExplicitFields.length === 0 ? undefined : childExplicitFields, childExclude, hint.children, options, tableAlias, path));
|
|
849
877
|
}
|
|
850
878
|
});
|
|
851
879
|
return fields;
|
|
@@ -856,9 +884,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
856
884
|
mapPropToFieldNames(qb, prop, tableAlias) {
|
|
857
885
|
const knex = this.connection.getKnex();
|
|
858
886
|
const aliased = knex.ref(tableAlias ? `${tableAlias}__${prop.fieldNames[0]}` : prop.fieldNames[0]).toString();
|
|
859
|
-
if (tableAlias && prop.customTypes?.some(type => type
|
|
887
|
+
if (tableAlias && prop.customTypes?.some(type => type?.convertToJSValueSQL)) {
|
|
860
888
|
return prop.fieldNames.map((col, idx) => {
|
|
861
|
-
if (!prop.customTypes[idx]
|
|
889
|
+
if (!prop.customTypes[idx]?.convertToJSValueSQL) {
|
|
862
890
|
return col;
|
|
863
891
|
}
|
|
864
892
|
const prefixed = knex.ref(col).withSchema(tableAlias).toString();
|
|
@@ -880,9 +908,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
880
908
|
return prop.fieldNames;
|
|
881
909
|
}
|
|
882
910
|
/** @internal */
|
|
883
|
-
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes,
|
|
911
|
+
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes, loggerContext) {
|
|
884
912
|
const connectionType = this.resolveConnectionType({ ctx, connectionType: preferredConnectionType });
|
|
885
|
-
const qb = new query_1.QueryBuilder(entityName, this.metadata, this, ctx, undefined, connectionType, undefined,
|
|
913
|
+
const qb = new query_1.QueryBuilder(entityName, this.metadata, this, ctx, undefined, connectionType, undefined, loggerContext);
|
|
886
914
|
if (!convertCustomTypes) {
|
|
887
915
|
qb.unsetFlag(core_1.QueryFlag.CONVERT_CUSTOM_TYPES);
|
|
888
916
|
}
|
|
@@ -1047,16 +1075,16 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1047
1075
|
}
|
|
1048
1076
|
ret.push(prop.name);
|
|
1049
1077
|
}
|
|
1050
|
-
buildFields(meta, populate, joinedProps, qb, alias,
|
|
1078
|
+
buildFields(meta, populate, joinedProps, qb, alias, options) {
|
|
1051
1079
|
const lazyProps = meta.props.filter(prop => prop.lazy && !populate.some(p => p.field === prop.name || p.all));
|
|
1052
1080
|
const hasLazyFormulas = meta.props.some(p => p.lazy && p.formula);
|
|
1053
1081
|
const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL && p.persist !== false);
|
|
1054
|
-
const hasExplicitFields = !!fields;
|
|
1082
|
+
const hasExplicitFields = !!options.fields;
|
|
1055
1083
|
const ret = [];
|
|
1056
1084
|
let addFormulas = false;
|
|
1057
1085
|
// handle root entity properties first, this is used for both strategies in the same way
|
|
1058
|
-
if (fields) {
|
|
1059
|
-
for (const field of this.normalizeFields(fields)) {
|
|
1086
|
+
if (options.fields) {
|
|
1087
|
+
for (const field of this.normalizeFields(options.fields)) {
|
|
1060
1088
|
if (field === '*') {
|
|
1061
1089
|
ret.push('*');
|
|
1062
1090
|
continue;
|
|
@@ -1072,12 +1100,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1072
1100
|
});
|
|
1073
1101
|
this.processField(meta, prop, parts.join('.'), ret, populate, joinedProps, qb);
|
|
1074
1102
|
}
|
|
1075
|
-
if (!fields.includes('*') && !fields.includes(`${qb.alias}.*`)) {
|
|
1076
|
-
ret.unshift(...meta.primaryKeys.filter(pk => !fields.includes(pk)));
|
|
1103
|
+
if (!options.fields.includes('*') && !options.fields.includes(`${qb.alias}.*`)) {
|
|
1104
|
+
ret.unshift(...meta.primaryKeys.filter(pk => !options.fields.includes(pk)));
|
|
1077
1105
|
}
|
|
1078
1106
|
}
|
|
1079
|
-
else if (lazyProps.
|
|
1080
|
-
const props = meta.props.filter(prop => this.platform.shouldHaveColumn(prop, populate, false));
|
|
1107
|
+
else if (!core_1.Utils.isEmpty(options.exclude) || lazyProps.some(p => !p.formula)) {
|
|
1108
|
+
const props = meta.props.filter(prop => this.platform.shouldHaveColumn(prop, populate, options.exclude, false));
|
|
1081
1109
|
ret.push(...core_1.Utils.flatten(props.filter(p => !lazyProps.includes(p)).map(p => p.fieldNames)));
|
|
1082
1110
|
addFormulas = true;
|
|
1083
1111
|
}
|
|
@@ -1102,7 +1130,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
1102
1130
|
}
|
|
1103
1131
|
// add joined relations after the root entity fields
|
|
1104
1132
|
if (joinedProps.length > 0) {
|
|
1105
|
-
ret.push(...this.getFieldsForJoinedLoad(qb, meta, fields, populate, options, alias));
|
|
1133
|
+
ret.push(...this.getFieldsForJoinedLoad(qb, meta, options.fields, options.exclude, populate, options, alias));
|
|
1106
1134
|
}
|
|
1107
1135
|
return core_1.Utils.unique(ret);
|
|
1108
1136
|
}
|
package/AbstractSqlPlatform.d.ts
CHANGED
|
@@ -13,10 +13,14 @@ export declare abstract class AbstractSqlPlatform extends Platform {
|
|
|
13
13
|
quoteValue(value: any): string;
|
|
14
14
|
formatQuery(sql: string, params: readonly any[]): string;
|
|
15
15
|
getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string;
|
|
16
|
-
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean): string;
|
|
16
|
+
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string;
|
|
17
17
|
getJsonIndexDefinition(index: IndexDef): string[];
|
|
18
18
|
isRaw(value: any): boolean;
|
|
19
19
|
supportsSchemas(): boolean;
|
|
20
20
|
/** @inheritDoc */
|
|
21
21
|
generateCustomOrder(escapedColumn: string, values: unknown[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
getOrderByExpression(column: string, direction: string): string[];
|
|
22
26
|
}
|
package/AbstractSqlPlatform.js
CHANGED
|
@@ -83,7 +83,7 @@ class AbstractSqlPlatform extends core_1.Platform {
|
|
|
83
83
|
getSearchJsonPropertySQL(path, type, aliased) {
|
|
84
84
|
return this.getSearchJsonPropertyKey(path.split('->'), type, aliased);
|
|
85
85
|
}
|
|
86
|
-
getSearchJsonPropertyKey(path, type, aliased) {
|
|
86
|
+
getSearchJsonPropertyKey(path, type, aliased, value) {
|
|
87
87
|
const [a, ...b] = path;
|
|
88
88
|
const quoteKey = (key) => key.match(/^[a-z]\w*$/i) ? key : `"${key}"`;
|
|
89
89
|
if (aliased) {
|
|
@@ -112,5 +112,11 @@ class AbstractSqlPlatform extends core_1.Platform {
|
|
|
112
112
|
});
|
|
113
113
|
return ret + 'else null end)';
|
|
114
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* @internal
|
|
117
|
+
*/
|
|
118
|
+
getOrderByExpression(column, direction) {
|
|
119
|
+
return [`${column} ${direction.toLowerCase()}`];
|
|
120
|
+
}
|
|
115
121
|
}
|
|
116
122
|
exports.AbstractSqlPlatform = AbstractSqlPlatform;
|
package/SqlEntityManager.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
|
-
import { EntityManager, type AnyEntity, type ConnectionType, type EntityData, type EntityName, type EntityRepository, type GetRepository, type QueryResult, type FilterQuery } from '@mikro-orm/core';
|
|
2
|
+
import { EntityManager, type AnyEntity, type ConnectionType, type EntityData, type EntityName, type EntityRepository, type GetRepository, type QueryResult, type FilterQuery, type LoggingOptions } from '@mikro-orm/core';
|
|
3
3
|
import type { AbstractSqlDriver } from './AbstractSqlDriver';
|
|
4
4
|
import { QueryBuilder } from './query';
|
|
5
5
|
import type { SqlEntityRepository } from './SqlEntityRepository';
|
|
@@ -10,11 +10,11 @@ export declare class SqlEntityManager<D extends AbstractSqlDriver = AbstractSqlD
|
|
|
10
10
|
/**
|
|
11
11
|
* Creates a QueryBuilder instance
|
|
12
12
|
*/
|
|
13
|
-
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, alias?: string, type?: ConnectionType): QueryBuilder<T>;
|
|
13
|
+
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, alias?: string, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<T>;
|
|
14
14
|
/**
|
|
15
15
|
* Shortcut for `createQueryBuilder()`
|
|
16
16
|
*/
|
|
17
|
-
qb<T extends object>(entityName: EntityName<T>, alias?: string, type?: ConnectionType): QueryBuilder<T>;
|
|
17
|
+
qb<T extends object>(entityName: EntityName<T>, alias?: string, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<T>;
|
|
18
18
|
/**
|
|
19
19
|
* Returns configured knex instance.
|
|
20
20
|
*/
|
package/SqlEntityManager.js
CHANGED
|
@@ -10,15 +10,15 @@ class SqlEntityManager extends core_1.EntityManager {
|
|
|
10
10
|
/**
|
|
11
11
|
* Creates a QueryBuilder instance
|
|
12
12
|
*/
|
|
13
|
-
createQueryBuilder(entityName, alias, type) {
|
|
13
|
+
createQueryBuilder(entityName, alias, type, loggerContext) {
|
|
14
14
|
const context = this.getContext();
|
|
15
|
-
return new query_1.QueryBuilder(entityName, this.getMetadata(), this.getDriver(), context.getTransactionContext(), alias, type, context);
|
|
15
|
+
return new query_1.QueryBuilder(entityName, this.getMetadata(), this.getDriver(), context.getTransactionContext(), alias, type, context, loggerContext ?? context.loggerContext);
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Shortcut for `createQueryBuilder()`
|
|
19
19
|
*/
|
|
20
|
-
qb(entityName, alias, type) {
|
|
21
|
-
return this.createQueryBuilder(entityName, alias, type);
|
|
20
|
+
qb(entityName, alias, type, loggerContext) {
|
|
21
|
+
return this.createQueryBuilder(entityName, alias, type, loggerContext);
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Returns configured knex instance.
|
package/index.mjs
CHANGED
|
@@ -47,7 +47,7 @@ export const DatabaseObjectExistsException = mod.DatabaseObjectExistsException;
|
|
|
47
47
|
export const DatabaseObjectNotFoundException = mod.DatabaseObjectNotFoundException;
|
|
48
48
|
export const DatabaseSchema = mod.DatabaseSchema;
|
|
49
49
|
export const DatabaseTable = mod.DatabaseTable;
|
|
50
|
-
export const
|
|
50
|
+
export const DataloaderType = mod.DataloaderType;
|
|
51
51
|
export const DataloaderUtils = mod.DataloaderUtils;
|
|
52
52
|
export const DateTimeType = mod.DateTimeType;
|
|
53
53
|
export const DateType = mod.DateType;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/knex",
|
|
3
|
-
"version": "6.0.0-rc.
|
|
3
|
+
"version": "6.0.0-rc.3",
|
|
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",
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"fs-extra": "11.
|
|
62
|
-
"knex": "3.0
|
|
61
|
+
"fs-extra": "11.2.0",
|
|
62
|
+
"knex": "3.1.0",
|
|
63
63
|
"sqlstring": "2.3.3"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@mikro-orm/core": "^5.
|
|
66
|
+
"@mikro-orm/core": "^5.0.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@mikro-orm/core": "6.0.0-rc.
|
|
69
|
+
"@mikro-orm/core": "6.0.0-rc.3"
|
|
70
70
|
}
|
|
71
71
|
}
|
package/query/CriteriaNode.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { inspect } from 'util';
|
|
3
|
-
import { type
|
|
3
|
+
import { type EntityKey, type EntityProperty, type MetadataStorage } from '@mikro-orm/core';
|
|
4
4
|
import type { ICriteriaNode, ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings';
|
|
5
5
|
/**
|
|
6
6
|
* Helper for working with deeply nested where/orderBy/having criteria. Uses composite pattern to build tree from the payload.
|
|
@@ -28,5 +28,4 @@ export declare class CriteriaNode<T extends object> implements ICriteriaNode<T>
|
|
|
28
28
|
aliased(field: string, alias?: string): string;
|
|
29
29
|
/** @ignore */
|
|
30
30
|
[inspect.custom](): string;
|
|
31
|
-
static isCustomExpression(field: string): boolean;
|
|
32
31
|
}
|
package/query/CriteriaNode.js
CHANGED
|
@@ -31,7 +31,7 @@ class CriteriaNode {
|
|
|
31
31
|
this.prop = meta.props.find(prop => prop.name === k || (prop.fieldNames?.length === 1 && prop.fieldNames[0] === k));
|
|
32
32
|
const isProp = this.prop || meta.props.find(prop => (prop.fieldNames || []).includes(k));
|
|
33
33
|
// do not validate if the key is prefixed or type casted (e.g. `k::text`)
|
|
34
|
-
if (validate && !isProp && !k.includes('.') && !k.includes('::') && !core_1.Utils.isOperator(k) && !
|
|
34
|
+
if (validate && !isProp && !k.includes('.') && !k.includes('::') && !core_1.Utils.isOperator(k) && !core_1.RawQueryFragment.isKnownFragment(k)) {
|
|
35
35
|
throw new Error(`Trying to query by not existing property ${entityName}.${k}`);
|
|
36
36
|
}
|
|
37
37
|
});
|
|
@@ -52,7 +52,7 @@ class CriteriaNode {
|
|
|
52
52
|
shouldRename(payload) {
|
|
53
53
|
const type = this.prop ? this.prop.kind : null;
|
|
54
54
|
const composite = this.prop?.joinColumns ? this.prop.joinColumns.length > 1 : false;
|
|
55
|
-
const customExpression =
|
|
55
|
+
const customExpression = core_1.RawQueryFragment.isKnownFragment(this.key);
|
|
56
56
|
const scalar = payload === null || core_1.Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || customExpression;
|
|
57
57
|
const plainObject = core_1.Utils.isPlainObject(payload);
|
|
58
58
|
const keys = plainObject ? Object.keys(payload) : [];
|
|
@@ -98,7 +98,7 @@ class CriteriaNode {
|
|
|
98
98
|
if (!this.key || !this.prop) {
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
|
-
const customExpression =
|
|
101
|
+
const customExpression = core_1.RawQueryFragment.isKnownFragment(this.key);
|
|
102
102
|
const scalar = this.payload === null || core_1.Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || customExpression;
|
|
103
103
|
const operator = core_1.Utils.isObject(this.payload) && Object.keys(this.payload).every(k => core_1.Utils.isOperator(k, false));
|
|
104
104
|
return this.prop.kind === core_1.ReferenceKind.MANY_TO_MANY && (scalar || operator);
|
|
@@ -117,8 +117,5 @@ class CriteriaNode {
|
|
|
117
117
|
.forEach(k => o[k] = this[k]);
|
|
118
118
|
return `${this.constructor.name} ${(0, util_1.inspect)(o)}`;
|
|
119
119
|
}
|
|
120
|
-
static isCustomExpression(field) {
|
|
121
|
-
return !!field.match(/[ ?<>=()]|^\d/);
|
|
122
|
-
}
|
|
123
120
|
}
|
|
124
121
|
exports.CriteriaNode = CriteriaNode;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Dictionary, type
|
|
1
|
+
import { type Dictionary, type EntityKey, type EntityMetadata, type MetadataStorage } from '@mikro-orm/core';
|
|
2
2
|
import type { ICriteriaNode } from '../typings';
|
|
3
3
|
/**
|
|
4
4
|
* @internal
|
|
@@ -5,13 +5,12 @@ const core_1 = require("@mikro-orm/core");
|
|
|
5
5
|
const ObjectCriteriaNode_1 = require("./ObjectCriteriaNode");
|
|
6
6
|
const ArrayCriteriaNode_1 = require("./ArrayCriteriaNode");
|
|
7
7
|
const ScalarCriteriaNode_1 = require("./ScalarCriteriaNode");
|
|
8
|
-
const CriteriaNode_1 = require("./CriteriaNode");
|
|
9
8
|
/**
|
|
10
9
|
* @internal
|
|
11
10
|
*/
|
|
12
11
|
class CriteriaNodeFactory {
|
|
13
12
|
static createNode(metadata, entityName, payload, parent, key) {
|
|
14
|
-
const customExpression =
|
|
13
|
+
const customExpression = core_1.RawQueryFragment.isKnownFragment(key || '');
|
|
15
14
|
const scalar = core_1.Utils.isPrimaryKey(payload) || core_1.Utils.isRawSql(payload) || payload instanceof RegExp || payload instanceof Date || customExpression;
|
|
16
15
|
if (Array.isArray(payload) && !scalar) {
|
|
17
16
|
return this.createArrayNode(metadata, entityName, payload, parent, key);
|
|
@@ -16,7 +16,7 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
16
16
|
if (nestedAlias) {
|
|
17
17
|
alias = nestedAlias;
|
|
18
18
|
}
|
|
19
|
-
if (this.shouldAutoJoin(nestedAlias)) {
|
|
19
|
+
if (this.shouldAutoJoin(qb, nestedAlias)) {
|
|
20
20
|
if (keys.some(k => ['$some', '$none', '$every'].includes(k))) {
|
|
21
21
|
const $and = [];
|
|
22
22
|
const primaryKeys = this.metadata.find(this.entityName).primaryKeys.map(pk => {
|
|
@@ -86,7 +86,7 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
86
86
|
if (nestedAlias) {
|
|
87
87
|
alias = nestedAlias;
|
|
88
88
|
}
|
|
89
|
-
if (this.shouldAutoJoin(nestedAlias)) {
|
|
89
|
+
if (this.shouldAutoJoin(qb, nestedAlias)) {
|
|
90
90
|
return !keys.some(k => ['$some', '$none', '$every'].includes(k));
|
|
91
91
|
}
|
|
92
92
|
return keys.some(field => {
|
|
@@ -95,7 +95,7 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
shouldInline(payload) {
|
|
98
|
-
const customExpression =
|
|
98
|
+
const customExpression = core_1.RawQueryFragment.isKnownFragment(this.key);
|
|
99
99
|
const scalar = core_1.Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || customExpression;
|
|
100
100
|
const operator = core_1.Utils.isObject(payload) && Object.keys(payload).every(k => core_1.Utils.isOperator(k, false));
|
|
101
101
|
return !!this.prop && this.prop.kind !== core_1.ReferenceKind.SCALAR && !scalar && !operator;
|
|
@@ -128,7 +128,7 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
128
128
|
o[key] = payload[k];
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
-
else if (
|
|
131
|
+
else if (core_1.RawQueryFragment.isKnownFragment(k)) {
|
|
132
132
|
o[k] = payload[k];
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
@@ -137,15 +137,19 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
-
shouldAutoJoin(nestedAlias) {
|
|
140
|
+
shouldAutoJoin(qb, nestedAlias) {
|
|
141
141
|
if (!this.prop || !this.parent) {
|
|
142
142
|
return false;
|
|
143
143
|
}
|
|
144
|
+
const keys = Object.keys(this.payload);
|
|
145
|
+
if (keys.every(k => k.includes('.') && k.startsWith(`${qb.alias}.`))) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const meta = this.metadata.find(this.entityName);
|
|
144
149
|
const embeddable = this.prop.kind === core_1.ReferenceKind.EMBEDDED;
|
|
145
150
|
const knownKey = [core_1.ReferenceKind.SCALAR, core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.EMBEDDED].includes(this.prop.kind) || (this.prop.kind === core_1.ReferenceKind.ONE_TO_ONE && this.prop.owner);
|
|
146
|
-
const operatorKeys = knownKey &&
|
|
147
|
-
const primaryKeys = knownKey &&
|
|
148
|
-
const meta = this.metadata.find(this.entityName);
|
|
151
|
+
const operatorKeys = knownKey && keys.every(key => core_1.Utils.isOperator(key, false));
|
|
152
|
+
const primaryKeys = knownKey && keys.every(key => {
|
|
149
153
|
if (!meta.primaryKeys.includes(key)) {
|
|
150
154
|
return false;
|
|
151
155
|
}
|
|
@@ -158,7 +162,7 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
158
162
|
}
|
|
159
163
|
autoJoin(qb, alias) {
|
|
160
164
|
const nestedAlias = qb.getNextAlias(this.prop?.pivotTable ?? this.entityName);
|
|
161
|
-
const customExpression =
|
|
165
|
+
const customExpression = core_1.RawQueryFragment.isKnownFragment(this.key);
|
|
162
166
|
const scalar = core_1.Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || customExpression;
|
|
163
167
|
const operator = core_1.Utils.isPlainObject(this.payload) && Object.keys(this.payload).every(k => core_1.Utils.isOperator(k, false));
|
|
164
168
|
const field = `${alias}.${this.prop.name}`;
|
package/query/QueryBuilder.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export declare class QueryBuilder<T extends object = AnyEntity> {
|
|
|
38
38
|
private readonly context?;
|
|
39
39
|
private connectionType?;
|
|
40
40
|
private readonly em?;
|
|
41
|
-
private readonly
|
|
41
|
+
private readonly loggerContext?;
|
|
42
42
|
get mainAlias(): Alias<T>;
|
|
43
43
|
get alias(): string;
|
|
44
44
|
get helper(): QueryBuilderHelper;
|
|
@@ -87,7 +87,7 @@ export declare class QueryBuilder<T extends object = AnyEntity> {
|
|
|
87
87
|
/**
|
|
88
88
|
* @internal
|
|
89
89
|
*/
|
|
90
|
-
constructor(entityName: EntityName<T> | QueryBuilder<T>, metadata: MetadataStorage, driver: AbstractSqlDriver, context?: Knex.Transaction<any, any[]> | undefined, alias?: string, connectionType?: ConnectionType | undefined, em?: SqlEntityManager<AbstractSqlDriver<import("..").AbstractSqlConnection, AbstractSqlPlatform>> | undefined,
|
|
90
|
+
constructor(entityName: EntityName<T> | QueryBuilder<T>, metadata: MetadataStorage, driver: AbstractSqlDriver, context?: Knex.Transaction<any, any[]> | undefined, alias?: string, connectionType?: ConnectionType | undefined, em?: SqlEntityManager<AbstractSqlDriver<import("..").AbstractSqlConnection, AbstractSqlPlatform>> | undefined, loggerContext?: LoggingOptions | undefined);
|
|
91
91
|
select(fields: Field<T> | Field<T>[], distinct?: boolean): SelectQueryBuilder<T>;
|
|
92
92
|
addSelect(fields: Field<T> | Field<T>[]): SelectQueryBuilder<T>;
|
|
93
93
|
distinct(): SelectQueryBuilder<T>;
|
package/query/QueryBuilder.js
CHANGED
|
@@ -31,7 +31,7 @@ class QueryBuilder {
|
|
|
31
31
|
context;
|
|
32
32
|
connectionType;
|
|
33
33
|
em;
|
|
34
|
-
|
|
34
|
+
loggerContext;
|
|
35
35
|
get mainAlias() {
|
|
36
36
|
this.ensureFromClause();
|
|
37
37
|
return this._mainAlias;
|
|
@@ -88,13 +88,13 @@ class QueryBuilder {
|
|
|
88
88
|
/**
|
|
89
89
|
* @internal
|
|
90
90
|
*/
|
|
91
|
-
constructor(entityName, metadata, driver, context, alias, connectionType, em,
|
|
91
|
+
constructor(entityName, metadata, driver, context, alias, connectionType, em, loggerContext) {
|
|
92
92
|
this.metadata = metadata;
|
|
93
93
|
this.driver = driver;
|
|
94
94
|
this.context = context;
|
|
95
95
|
this.connectionType = connectionType;
|
|
96
96
|
this.em = em;
|
|
97
|
-
this.
|
|
97
|
+
this.loggerContext = loggerContext;
|
|
98
98
|
this.platform = this.driver.getPlatform();
|
|
99
99
|
this.knex = this.driver.getConnection(this.connectionType).getKnex();
|
|
100
100
|
if (alias) {
|
|
@@ -587,7 +587,7 @@ class QueryBuilder {
|
|
|
587
587
|
}
|
|
588
588
|
const write = method === 'run' || !this.platform.getConfig().get('preferReadReplicas');
|
|
589
589
|
const type = this.connectionType || (write ? 'write' : 'read');
|
|
590
|
-
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context, this.
|
|
590
|
+
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context, this.loggerContext);
|
|
591
591
|
const meta = this.mainAlias.metadata;
|
|
592
592
|
if (!options.mapResults || !meta) {
|
|
593
593
|
await this.em?.storeCache(this._cache, cached, res);
|
|
@@ -496,7 +496,7 @@ class QueryBuilderHelper {
|
|
|
496
496
|
order.forEach(part => ret.push(...this.getQueryOrderFromObject(type, part, populate)));
|
|
497
497
|
}
|
|
498
498
|
else {
|
|
499
|
-
ret.push(
|
|
499
|
+
ret.push(...this.platform.getOrderByExpression(colPart, order));
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
}
|
|
@@ -21,6 +21,12 @@ class ScalarCriteriaNode extends CriteriaNode_1.CriteriaNode {
|
|
|
21
21
|
qb.addSelect(field);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
if (this.payload && typeof this.payload === 'object') {
|
|
25
|
+
const keys = Object.keys(this.payload).filter(key => core_1.Utils.isArrayOperator(key) && Array.isArray(this.payload[key]));
|
|
26
|
+
for (const key of keys) {
|
|
27
|
+
this.payload[key] = JSON.stringify(this.payload[key]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
24
30
|
return this.payload;
|
|
25
31
|
}
|
|
26
32
|
willAutoJoin(qb, alias) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Configuration, type Dictionary, type EntityMetadata, type EntityProperty, type
|
|
1
|
+
import { type Configuration, type Dictionary, type EntityMetadata, type EntityProperty, type NamingStrategy } from '@mikro-orm/core';
|
|
2
2
|
import type { SchemaHelper } from './SchemaHelper';
|
|
3
3
|
import type { CheckDef, Column, ForeignKey, IndexDef } from '../typings';
|
|
4
4
|
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
|
|
@@ -25,7 +25,7 @@ export declare class DatabaseTable {
|
|
|
25
25
|
addColumn(column: Column): void;
|
|
26
26
|
addColumnFromProperty(prop: EntityProperty, meta: EntityMetadata, config: Configuration): void;
|
|
27
27
|
private getIndexName;
|
|
28
|
-
getEntityDeclaration(namingStrategy: NamingStrategy, schemaHelper: SchemaHelper, scalarPropertiesForRelations:
|
|
28
|
+
getEntityDeclaration(namingStrategy: NamingStrategy, schemaHelper: SchemaHelper, scalarPropertiesForRelations: 'always' | 'never' | 'smart'): EntityMetadata;
|
|
29
29
|
private foreignKeysToProps;
|
|
30
30
|
private findFkIndex;
|
|
31
31
|
private getIndexProperties;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Dictionary } from '@mikro-orm/core';
|
|
1
2
|
import type { Column, ForeignKey, IndexDef, SchemaDifference, TableDifference } from '../typings';
|
|
2
3
|
import type { DatabaseSchema } from './DatabaseSchema';
|
|
3
4
|
import type { DatabaseTable } from './DatabaseTable';
|
|
@@ -51,6 +52,7 @@ export declare class SchemaComparator {
|
|
|
51
52
|
*/
|
|
52
53
|
isIndexFulfilledBy(index1: IndexDef, index2: IndexDef): boolean;
|
|
53
54
|
diffExpression(expr1: string, expr2: string): boolean;
|
|
55
|
+
parseJsonDefault(defaultValue?: string | null): Dictionary | string | null;
|
|
54
56
|
hasSameDefaultValue(from: Column, to: Column): boolean;
|
|
55
57
|
private mapColumnToProperty;
|
|
56
58
|
private log;
|
|
@@ -449,6 +449,15 @@ class SchemaComparator {
|
|
|
449
449
|
const simplify = (str) => str?.replace(/_\w+\\'(.*?)\\'/g, '$1').replace(/['"`()]|::\w+| +/g, '').toLowerCase();
|
|
450
450
|
return simplify(expr1) !== simplify(expr2);
|
|
451
451
|
}
|
|
452
|
+
parseJsonDefault(defaultValue) {
|
|
453
|
+
if (!defaultValue) {
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
const val = defaultValue
|
|
457
|
+
.replace(/^(_\w+\\)?'(.*?)\\?'$/, '$2')
|
|
458
|
+
.replace(/^\(?'(.*?)'\)?$/, '$1');
|
|
459
|
+
return (0, core_1.parseJsonSafe)(val);
|
|
460
|
+
}
|
|
452
461
|
hasSameDefaultValue(from, to) {
|
|
453
462
|
if (from.default == null || from.default.toString().toLowerCase() === 'null' || from.default.toString().startsWith('nextval(')) {
|
|
454
463
|
return to.default == null || to.default.toLowerCase() === 'null';
|
|
@@ -459,8 +468,8 @@ class SchemaComparator {
|
|
|
459
468
|
return defaultValueFrom === defaultValueTo;
|
|
460
469
|
}
|
|
461
470
|
if (to.mappedType instanceof core_1.JsonType) {
|
|
462
|
-
const defaultValueFrom =
|
|
463
|
-
const defaultValueTo =
|
|
471
|
+
const defaultValueFrom = this.parseJsonDefault(from.default);
|
|
472
|
+
const defaultValueTo = this.parseJsonDefault(to.default);
|
|
464
473
|
return core_1.Utils.equals(defaultValueFrom, defaultValueTo);
|
|
465
474
|
}
|
|
466
475
|
if (to.mappedType instanceof core_1.DateTimeType && from.default && to.default) {
|