@mikro-orm/sql 7.0.0-rc.0 → 7.0.0-rc.2
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 +7 -0
- package/AbstractSqlDriver.js +58 -25
- package/AbstractSqlPlatform.d.ts +8 -1
- package/AbstractSqlPlatform.js +18 -1
- package/SqlEntityManager.d.ts +3 -2
- package/dialects/mysql/BaseMySqlPlatform.d.ts +1 -1
- package/dialects/mysql/BaseMySqlPlatform.js +4 -3
- package/dialects/sqlite/BaseSqliteConnection.d.ts +4 -1
- package/dialects/sqlite/BaseSqliteConnection.js +4 -0
- package/dialects/sqlite/NodeSqliteDialect.d.ts +21 -0
- package/dialects/sqlite/NodeSqliteDialect.js +41 -0
- package/dialects/sqlite/SqliteDriver.d.ts +12 -0
- package/dialects/sqlite/SqliteDriver.js +14 -0
- package/dialects/sqlite/{BaseSqlitePlatform.d.ts → SqlitePlatform.d.ts} +5 -2
- package/dialects/sqlite/{BaseSqlitePlatform.js → SqlitePlatform.js} +27 -4
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +5 -0
- package/dialects/sqlite/SqliteSchemaHelper.js +20 -1
- package/dialects/sqlite/index.d.ts +3 -1
- package/dialects/sqlite/index.js +3 -1
- package/package.json +2 -2
- package/query/ObjectCriteriaNode.js +1 -1
- package/query/QueryBuilder.d.ts +67 -20
- package/query/QueryBuilder.js +80 -15
- package/query/QueryBuilderHelper.d.ts +2 -2
- package/query/QueryBuilderHelper.js +9 -9
- package/schema/SchemaComparator.js +1 -0
- package/schema/SqlSchemaGenerator.d.ts +2 -1
- package/schema/SqlSchemaGenerator.js +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/typings.d.ts +14 -3
package/query/QueryBuilder.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AnyEntity, type AutoPath, type ConnectionType, type Dictionary, type EntityData, type EntityKey, type EntityManager, type EntityMetadata, type EntityName, type EntityProperty, type ExpandProperty, type FilterObject, type FilterOptions, type FilterValue, type FlushMode, type GroupOperator, type Loaded, LockMode, type LoggingOptions, type MetadataStorage, type ObjectQuery, PopulateHint, type PopulateOptions, type PopulatePath, QueryFlag, type QueryOrderKeysFlat, type QueryOrderMap, type QueryResult, RawQueryFragment, type Raw, type RequiredEntityData, type Scalar, type Subquery, type Transaction } from '@mikro-orm/core';
|
|
1
|
+
import { type AnyEntity, type AutoPath, type Collection, type ConnectionType, type Dictionary, type EntityData, type EntityDTOFlat, type EntityDTOProp, type EntityKey, type EntityManager, type EntityMetadata, type EntityName, type EntityProperty, type ExpandProperty, type FilterObject, type FilterOptions, type FilterValue, type FlushMode, type GroupOperator, type Loaded, LockMode, type LoggingOptions, type MetadataStorage, type PrimaryProperty, type ObjectQuery, PopulateHint, type PopulateOptions, type PopulatePath, QueryFlag, type QueryOrderKeysFlat, type QueryOrderMap, type QueryResult, RawQueryFragment, type Raw, type RequiredEntityData, type Scalar, type SerializeDTO, type Subquery, type Transaction } from '@mikro-orm/core';
|
|
2
2
|
import { JoinType, QueryType } from './enums.js';
|
|
3
3
|
import type { AbstractSqlDriver } from '../AbstractSqlDriver.js';
|
|
4
4
|
import { type Alias, type OnConflictClause, QueryBuilderHelper } from './QueryBuilderHelper.js';
|
|
@@ -52,14 +52,16 @@ type AddToContext<Type extends object, Context, Field extends string, Alias exte
|
|
|
52
52
|
[K in Alias]: [GetPath<Context, Field>, K, ExpandProperty<Type[GetPropName<Field> & keyof Type]>, Select];
|
|
53
53
|
};
|
|
54
54
|
type GetPath<Context, Field extends string> = GetAlias<Field> extends infer Alias ? IsNever<Alias> extends true ? GetPropName<Field> : Alias extends keyof Context ? Context[Alias] extends [infer Path, ...any[]] ? AppendToHint<Path & string, GetPropName<Field>> : GetPropName<Field> : GetPropName<Field> : GetPropName<Field>;
|
|
55
|
-
type GetType<Type extends object, Context, Field extends string> = GetAlias<Field> extends infer Alias ? IsNever<Alias> extends true ? Type : Alias extends keyof Context ? Context[Alias] extends [string, string, infer PropType, any] ? PropType & object : Type : Type : Type;
|
|
55
|
+
type GetType<Type extends object, Context, Field extends string> = GetAlias<Field> extends infer Alias ? IsNever<Alias> extends true ? Type : [Context] extends [never] ? Type : Alias extends keyof Context ? Context[Alias] extends [string, string, infer PropType, any] ? PropType & object : Type : Type : Type;
|
|
56
56
|
type AddToHint<RootAlias, Context, Field extends string, Select extends boolean = false> = Select extends true ? GetAlias<Field> extends infer Alias ? IsNever<Alias> extends true ? GetPropName<Field> : Alias extends RootAlias ? GetPropName<Field> : Alias extends keyof Context ? Context[Alias] extends [infer Path, ...any[]] ? AppendToHint<Path & string, GetPropName<Field>> : GetPropName<Field> : GetPropName<Field> : GetPropName<Field> : never;
|
|
57
57
|
export type ModifyHint<RootAlias, Context, Hint extends string, Field extends string, Select extends boolean = false> = Hint | AddToHint<RootAlias, Context, Field, Select>;
|
|
58
58
|
export type ModifyContext<Entity extends object, Context, Field extends string, Alias extends string, Select extends boolean = false> = IsNever<Context> extends true ? AddToContext<GetType<Entity, object, Field>, object, Field, Alias, Select> : Context & AddToContext<GetType<Entity, Context, Field>, Context, Field, Alias, Select>;
|
|
59
59
|
type StripRootAlias<F extends string, RootAlias extends string, Context = never> = F extends `${RootAlias}.${infer Field}` ? Field : F extends `${infer Alias}.${string}` ? Alias extends AliasNames<Context> ? never : F : F;
|
|
60
|
-
type
|
|
60
|
+
type StripFieldAlias<F extends string> = F extends `${infer Path} as ${string}` ? Path : F;
|
|
61
|
+
type ExtractRootFields<Fields, RootAlias extends string, Context = never> = [Fields] extends ['*'] ? '*' : Fields extends `${RootAlias}.*` ? '*' : Fields extends string ? StripRootAlias<StripFieldAlias<Fields>, RootAlias, Context> : never;
|
|
61
62
|
type PrefixWithPath<Path extends string, Field extends string> = `${Path}.${Field}`;
|
|
62
63
|
type StripJoinAlias<F extends string, Alias extends string> = F extends `${Alias}.${infer Field}` ? Field : F;
|
|
64
|
+
export type JoinSelectField<JoinedEntity, Alias extends string> = (keyof JoinedEntity & string) | `${Alias}.${keyof JoinedEntity & string}`;
|
|
63
65
|
type AddJoinFields<RootAlias, Context, Field extends string, Alias extends string, JoinFields extends readonly string[]> = JoinFields extends readonly (infer F)[] ? F extends string ? PrefixWithPath<AddToHint<RootAlias, Context, Field, true> & string, StripJoinAlias<F, Alias>> : never : never;
|
|
64
66
|
export type ModifyFields<CurrentFields extends string, RootAlias, Context, Field extends string, Alias extends string, JoinFields extends readonly string[] | undefined> = JoinFields extends readonly string[] ? CurrentFields | AddJoinFields<RootAlias, Context, Field, Alias, JoinFields> : CurrentFields;
|
|
65
67
|
type EntityRelations<T> = EntityKey<T, true>;
|
|
@@ -68,25 +70,33 @@ type AliasNames<Context> = Context[keyof Context] extends infer Join ? Join exte
|
|
|
68
70
|
type ContextRelationKeys<Context> = Context[keyof Context] extends infer Join ? Join extends any ? Join extends [string, infer Alias, infer Type, any] ? `${Alias & string}.${EntityRelations<Type & object>}` : never : never : never;
|
|
69
71
|
export type QBField<Entity, RootAlias extends string, Context> = EntityRelations<Entity> | `${RootAlias}.${EntityRelations<Entity>}` | ([Context] extends [never] ? never : ContextRelationKeys<Context>);
|
|
70
72
|
type ContextFieldKeys<Context> = Context[keyof Context] extends infer Join ? Join extends any ? Join extends [string, infer Alias, infer Type, any] ? `${Alias & string}.${keyof Type & string}` : never : never : never;
|
|
71
|
-
|
|
73
|
+
type WithAlias<T extends string> = T | `${T} as ${string}`;
|
|
74
|
+
export type Field<Entity, RootAlias extends string = never, Context = never> = WithAlias<EntityKey<Entity>> | (IsNever<RootAlias> extends true ? never : WithAlias<`${RootAlias}.${EntityKey<Entity>}`> | `${RootAlias}.*`) | ([Context] extends [never] ? never : WithAlias<ContextFieldKeys<Context>> | `${AliasNames<Context>}.*`) | '*' | QueryBuilder<any> | NativeQueryBuilder | RawQueryFragment<any> | (RawQueryFragment & symbol);
|
|
72
75
|
type RootAliasOrderKeys<RootAlias extends string, Entity> = {
|
|
73
76
|
[K in `${RootAlias}.${EntityKey<Entity>}`]?: QueryOrderKeysFlat;
|
|
74
77
|
};
|
|
75
78
|
type ContextOrderKeys<Context> = {
|
|
76
79
|
[K in ContextFieldKeys<Context>]?: QueryOrderKeysFlat;
|
|
77
80
|
};
|
|
78
|
-
|
|
81
|
+
type RawOrderKeys<RawAliases extends string> = {
|
|
82
|
+
[K in RawAliases]?: QueryOrderKeysFlat;
|
|
83
|
+
};
|
|
84
|
+
export type ContextOrderByMap<Entity, RootAlias extends string = never, Context = never, RawAliases extends string = never> = QueryOrderMap<Entity> | ((IsNever<RootAlias> extends true ? {} : RootAliasOrderKeys<RootAlias, Entity>) & ([Context] extends [never] ? {} : ContextOrderKeys<Context>) & (IsNever<RawAliases> extends true ? {} : string extends RawAliases ? {} : RawOrderKeys<RawAliases>));
|
|
79
85
|
type AliasedPath<Alias extends string, Type, P extends string> = P extends `${Alias}.*` ? P : P extends `${Alias}.${infer Rest}` ? `${Alias}.${AutoPath<Type & object, Rest, `${PopulatePath.ALL}`>}` : never;
|
|
80
86
|
type ContextAliasedPath<Context, P extends string> = Context[keyof Context] extends infer Join ? Join extends any ? Join extends [string, infer Alias, infer Type, any] ? AliasedPath<Alias & string, Type, P> : never : never : never;
|
|
81
|
-
type NestedAutoPath<Entity, RootAlias extends string, Context, P extends string> = P extends `${string}:ref` ? never : AliasedPath<RootAlias, Entity, P> | ContextAliasedPath<Context, P> | AutoPath<Entity, P, `${PopulatePath.ALL}`>;
|
|
87
|
+
type NestedAutoPath<Entity, RootAlias extends string, Context, P extends string> = P extends `${string}:ref` ? never : P extends `${infer Path} as ${string}` ? (AliasedPath<RootAlias, Entity, Path> | ContextAliasedPath<Context, Path> | AutoPath<Entity, Path, `${PopulatePath.ALL}`>) extends never ? never : P : AliasedPath<RootAlias, Entity, P> | ContextAliasedPath<Context, P> | AutoPath<Entity, P, `${PopulatePath.ALL}`>;
|
|
82
88
|
type AliasedObjectQuery<Entity extends object, Alias extends string> = {
|
|
83
89
|
[K in EntityKey<Entity> as `${Alias}.${K}`]?: ObjectQuery<Entity>[K];
|
|
84
90
|
};
|
|
85
|
-
type JoinCondition<JoinedEntity extends object, Alias extends string> = ObjectQuery<JoinedEntity> | AliasedObjectQuery<JoinedEntity, Alias
|
|
91
|
+
type JoinCondition<JoinedEntity extends object, Alias extends string> = (ObjectQuery<JoinedEntity> | AliasedObjectQuery<JoinedEntity, Alias>) & {
|
|
92
|
+
$not?: JoinCondition<JoinedEntity, Alias>;
|
|
93
|
+
$or?: JoinCondition<JoinedEntity, Alias>[];
|
|
94
|
+
$and?: JoinCondition<JoinedEntity, Alias>[];
|
|
95
|
+
};
|
|
86
96
|
type RawJoinCondition = {
|
|
87
97
|
[key: string]: FilterValue<Scalar> | RawQueryFragment;
|
|
88
98
|
};
|
|
89
|
-
type ExtractRawAliasFromField<F> = F extends RawQueryFragment<infer A> ? (A extends string ? A : never) : never;
|
|
99
|
+
type ExtractRawAliasFromField<F> = F extends RawQueryFragment<infer A> ? (A extends string ? A : never) : F extends `${string} as ${infer A}` ? A : never;
|
|
90
100
|
type ExtractRawAliasesFromTuple<T extends readonly unknown[]> = T extends readonly [infer Head, ...infer Tail] ? ExtractRawAliasFromField<Head> | ExtractRawAliasesFromTuple<Tail> : never;
|
|
91
101
|
type ExtractRawAliases<Fields> = Fields extends readonly unknown[] ? ExtractRawAliasesFromTuple<Fields> : ExtractRawAliasFromField<Fields>;
|
|
92
102
|
type FlatOperatorMap = {
|
|
@@ -194,6 +204,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
194
204
|
protected _joinedProps: Map<string, PopulateOptions<any>>;
|
|
195
205
|
protected _cache?: boolean | number | [string, number];
|
|
196
206
|
protected _indexHint?: string;
|
|
207
|
+
protected _collation?: string;
|
|
197
208
|
protected _comments: string[];
|
|
198
209
|
protected _hintComments: string[];
|
|
199
210
|
protected flushMode?: FlushMode;
|
|
@@ -228,6 +239,10 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
228
239
|
* // Select with raw expressions
|
|
229
240
|
* qb.select([raw('count(*) as total')]);
|
|
230
241
|
*
|
|
242
|
+
* // Select with aliases (works for regular and formula properties)
|
|
243
|
+
* qb.select(['id', 'fullName as displayName']);
|
|
244
|
+
* qb.select(['id', sql.ref('fullName').as('displayName')]);
|
|
245
|
+
*
|
|
231
246
|
* // Select with distinct
|
|
232
247
|
* qb.select('*', true);
|
|
233
248
|
* ```
|
|
@@ -396,11 +411,11 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
396
411
|
* .where({ 'a.name': 'John' });
|
|
397
412
|
* ```
|
|
398
413
|
*/
|
|
399
|
-
joinAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly string[] | undefined = undefined>(field: Field | [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, type?: JoinType, path?: string, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
400
|
-
leftJoinAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly string[] | undefined = undefined>(field: Field | [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
401
|
-
leftJoinLateralAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly string[] | undefined = undefined>(field: [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
402
|
-
innerJoinAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly string[] | undefined = undefined>(field: Field | [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
403
|
-
innerJoinLateralAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly string[] | undefined = undefined>(field: [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
414
|
+
joinAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly [JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>, ...JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>[]] | undefined = undefined>(field: Field | [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, type?: JoinType, path?: string, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
415
|
+
leftJoinAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly [JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>, ...JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>[]] | undefined = undefined>(field: Field | [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
416
|
+
leftJoinLateralAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly [JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>, ...JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>[]] | undefined = undefined>(field: [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
417
|
+
innerJoinAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly [JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>, ...JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>[]] | undefined = undefined>(field: Field | [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
418
|
+
innerJoinLateralAndSelect<Field extends QBField<Entity, RootAlias, Context>, Alias extends string, const JoinFields extends readonly [JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>, ...JoinSelectField<JoinedEntityType<Entity, Context, Field & string>, Alias>[]] | undefined = undefined>(field: [Field, RawQueryFragment | QueryBuilder<any>], alias: Alias, cond?: JoinCondition<JoinedEntityType<Entity, Context, Field & string>, Alias>, fields?: JoinFields, schema?: string): SelectQueryBuilder<Entity, RootAlias, ModifyHint<RootAlias, Context, Hint, Field, true> & {}, ModifyContext<Entity, Context, Field, Alias, true>, RawAliases, ModifyFields<Fields, RootAlias, Context, Field, Alias, JoinFields>>;
|
|
404
419
|
protected getFieldsForJoinedLoad(prop: EntityProperty<Entity>, alias: string, explicitFields?: readonly string[]): InternalField<Entity>[];
|
|
405
420
|
/**
|
|
406
421
|
* Apply filters to the QB where condition.
|
|
@@ -503,7 +518,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
503
518
|
* qb.orderBy({ 'profile.bio': 'asc' }); // nested via dot notation
|
|
504
519
|
* ```
|
|
505
520
|
*/
|
|
506
|
-
orderBy(orderBy: ContextOrderByMap<Entity, RootAlias, Context> | ContextOrderByMap<Entity, RootAlias, Context>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context, RawAliases, Fields>;
|
|
521
|
+
orderBy(orderBy: ContextOrderByMap<Entity, RootAlias, Context, RawAliases> | ContextOrderByMap<Entity, RootAlias, Context, RawAliases>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context, RawAliases, Fields>;
|
|
507
522
|
/**
|
|
508
523
|
* Adds an ORDER BY clause to the query, replacing any existing order.
|
|
509
524
|
*
|
|
@@ -516,19 +531,21 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
516
531
|
* ```
|
|
517
532
|
*/
|
|
518
533
|
orderBy<const T extends Record<string, QueryOrderKeysFlat>>(orderBy: T & {
|
|
519
|
-
[K in keyof T]: K extends NestedAutoPath<Entity, RootAlias, Context, K & string> ? T[K] : never;
|
|
534
|
+
[K in keyof T]: K extends NestedAutoPath<Entity, RootAlias, Context, K & string> ? T[K] : (K extends RawAliases ? T[K] : never);
|
|
520
535
|
}): SelectQueryBuilder<Entity, RootAlias, Hint, Context, RawAliases, Fields>;
|
|
521
536
|
/**
|
|
522
537
|
* Adds additional ORDER BY clause without replacing existing order.
|
|
523
538
|
*/
|
|
524
|
-
andOrderBy(orderBy: ContextOrderByMap<Entity, RootAlias, Context> | ContextOrderByMap<Entity, RootAlias, Context>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context, RawAliases, Fields>;
|
|
539
|
+
andOrderBy(orderBy: ContextOrderByMap<Entity, RootAlias, Context, RawAliases> | ContextOrderByMap<Entity, RootAlias, Context, RawAliases>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context, RawAliases, Fields>;
|
|
525
540
|
/**
|
|
526
541
|
* Adds additional ORDER BY clause without replacing existing order.
|
|
527
542
|
*/
|
|
528
543
|
andOrderBy<const T extends Record<string, QueryOrderKeysFlat>>(orderBy: T & {
|
|
529
|
-
[K in keyof T]: K extends NestedAutoPath<Entity, RootAlias, Context, K & string> ? T[K] : never;
|
|
544
|
+
[K in keyof T]: K extends NestedAutoPath<Entity, RootAlias, Context, K & string> ? T[K] : (K extends RawAliases ? T[K] : never);
|
|
530
545
|
}): SelectQueryBuilder<Entity, RootAlias, Hint, Context, RawAliases, Fields>;
|
|
531
546
|
private processOrderBy;
|
|
547
|
+
/** Collect custom aliases from select fields (stored as 'resolved as alias' strings by select()). */
|
|
548
|
+
private getSelectAliases;
|
|
532
549
|
/**
|
|
533
550
|
* Adds a GROUP BY clause to the query.
|
|
534
551
|
*
|
|
@@ -611,6 +628,10 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
|
|
|
611
628
|
* Adds index hint to the FROM clause.
|
|
612
629
|
*/
|
|
613
630
|
indexHint(sql: string | undefined): this;
|
|
631
|
+
/**
|
|
632
|
+
* Adds COLLATE clause to ORDER BY expressions.
|
|
633
|
+
*/
|
|
634
|
+
collation(collation: string | undefined): this;
|
|
614
635
|
/**
|
|
615
636
|
* Prepend comment to the sql query using the syntax `/* ... *‍/`. Some characters are forbidden such as `/*, *‍/` and `?`.
|
|
616
637
|
*/
|
|
@@ -827,10 +848,36 @@ export interface RunQueryBuilder<Entity extends object, RootAlias extends string
|
|
|
827
848
|
where(cond: QBFilterQuery<Entity, RootAlias, Context, RawAliases> | string, params?: keyof typeof GroupOperator | any[], operator?: keyof typeof GroupOperator): this;
|
|
828
849
|
execute<Result = QueryResult<Entity>>(method?: 'all' | 'get' | 'run', mapResults?: boolean): Promise<Result>;
|
|
829
850
|
}
|
|
851
|
+
/**
|
|
852
|
+
* @internal Optimized DTO type for execute().
|
|
853
|
+
* Bypasses the double mapped type of EntityDTO<Loaded<T, H, F>> by using DirectDTO
|
|
854
|
+
* which only iterates selected keys instead of all entity keys.
|
|
855
|
+
*
|
|
856
|
+
* - Wildcard, no joins: EntityDTO<T>
|
|
857
|
+
* - Selected fields, no joins: DirectDTO<T, F> (~132x faster than Pick<EntityDTO<T>, F>)
|
|
858
|
+
* - Wildcard + single-level join: Omit<EntityDTO<T>> + override populated relations
|
|
859
|
+
* - Selected fields + single-level join: DirectDTO for root + DirectDTO for joined (~60x faster)
|
|
860
|
+
* - Wildcard + nested joins: uses SerializeDTO<T, H> (~40x faster than EntityDTO<Loaded<T, H>>)
|
|
861
|
+
* - Fields + nested joins: falls back to EntityDTO<Loaded<T, H, F>>
|
|
862
|
+
*/
|
|
863
|
+
type DirectDTO<T, F extends keyof T> = {
|
|
864
|
+
[K in F]: EntityDTOProp<T, NonNullable<T[K]>> | Extract<T[K], null | undefined>;
|
|
865
|
+
};
|
|
866
|
+
type PopulatedDTO<T, K extends keyof T> = NonNullable<T[K]> extends Collection<infer U> ? EntityDTOFlat<U & object>[] : EntityDTOFlat<ExpandProperty<T[K]>>;
|
|
867
|
+
type SubFields<F extends string, Rel extends string> = F extends `${Rel}.${infer Sub}` ? Sub : never;
|
|
868
|
+
type RootFields<F extends string, H extends string> = F extends `${string}.${string}` ? F extends `${H}.${string}` ? never : F : F;
|
|
869
|
+
type JoinDTO<T, K extends keyof T, F extends string> = NonNullable<T[K]> extends Collection<infer U> ? SubFields<F, K & string> extends never ? EntityDTOProp<T, Collection<U>> : DirectDTO<U, (SubFields<F, K & string> | PrimaryProperty<U>) & keyof U>[] : SubFields<F, K & string> extends never ? EntityDTOProp<T, T[K]> : DirectDTO<NonNullable<T[K]>, (SubFields<F, K & string> | PrimaryProperty<NonNullable<T[K]>>) & keyof NonNullable<T[K]>> | Extract<T[K], null | undefined>;
|
|
870
|
+
type ExecuteDTO<T, H extends string, F extends string> = [
|
|
871
|
+
H
|
|
872
|
+
] extends [never] ? [F] extends ['*'] ? EntityDTOFlat<T> : DirectDTO<T, F & keyof T> : [F] extends ['*'] ? true extends (H extends `${string}.${string}` ? true : false) ? SerializeDTO<T, H> : Omit<EntityDTOFlat<T>, H & keyof EntityDTOFlat<T>> & {
|
|
873
|
+
[K in H & keyof T as K & keyof EntityDTOFlat<T>]: PopulatedDTO<T, K> | Extract<T[K], null | undefined>;
|
|
874
|
+
} : true extends (H extends `${string}.${string}` ? true : false) ? EntityDTOFlat<Loaded<T, H, F>> : DirectDTO<T, (RootFields<F, H> | PrimaryProperty<T>) & keyof T> & {
|
|
875
|
+
[K in H & keyof T]: JoinDTO<T, K, F>;
|
|
876
|
+
};
|
|
830
877
|
export interface SelectQueryBuilder<Entity extends object = AnyEntity, RootAlias extends string = never, Hint extends string = never, Context extends object = never, RawAliases extends string = never, Fields extends string = '*'> extends QueryBuilder<Entity, RootAlias, Hint, Context, RawAliases, Fields> {
|
|
831
|
-
execute<Result = Entity[]>(method?: 'all' | 'get' | 'run', mapResults?: boolean): Promise<Result>;
|
|
832
|
-
execute<Result = Entity[]>(method: 'all', mapResults?: boolean): Promise<Result>;
|
|
833
|
-
execute<Result = Entity
|
|
878
|
+
execute<Result = ExecuteDTO<Entity, Hint, Fields>[]>(method?: 'all' | 'get' | 'run', mapResults?: boolean): Promise<Result>;
|
|
879
|
+
execute<Result = ExecuteDTO<Entity, Hint, Fields>[]>(method: 'all', mapResults?: boolean): Promise<Result>;
|
|
880
|
+
execute<Result = ExecuteDTO<Entity, Hint, Fields>>(method: 'get', mapResults?: boolean): Promise<Result>;
|
|
834
881
|
execute<Result = QueryResult<Entity>>(method: 'run', mapResults?: boolean): Promise<Result>;
|
|
835
882
|
}
|
|
836
883
|
export interface CountQueryBuilder<Entity extends object> extends QueryBuilder<Entity, any, any> {
|
package/query/QueryBuilder.js
CHANGED
|
@@ -3,6 +3,8 @@ import { JoinType, QueryType } from './enums.js';
|
|
|
3
3
|
import { QueryBuilderHelper } from './QueryBuilderHelper.js';
|
|
4
4
|
import { CriteriaNodeFactory } from './CriteriaNodeFactory.js';
|
|
5
5
|
import { NativeQueryBuilder } from './NativeQueryBuilder.js';
|
|
6
|
+
/** Matches 'path as alias' — safe because ORM property names are JS identifiers (no spaces). */
|
|
7
|
+
const FIELD_ALIAS_RE = /^(.+?)\s+as\s+(\w+)$/i;
|
|
6
8
|
/**
|
|
7
9
|
* SQL query builder with fluent interface.
|
|
8
10
|
*
|
|
@@ -67,6 +69,7 @@ export class QueryBuilder {
|
|
|
67
69
|
_joinedProps = new Map();
|
|
68
70
|
_cache;
|
|
69
71
|
_indexHint;
|
|
72
|
+
_collation;
|
|
70
73
|
_comments = [];
|
|
71
74
|
_hintComments = [];
|
|
72
75
|
flushMode;
|
|
@@ -103,8 +106,19 @@ export class QueryBuilder {
|
|
|
103
106
|
this.ensureNotFinalized();
|
|
104
107
|
this._fields = Utils.asArray(fields).flatMap(f => {
|
|
105
108
|
if (typeof f !== 'string') {
|
|
109
|
+
// Normalize sql.ref('prop') and sql.ref('prop').as('alias') to string form
|
|
110
|
+
if (isRaw(f) && f.sql === '??' && f.params.length === 1) {
|
|
111
|
+
return this.resolveNestedPath(String(f.params[0]));
|
|
112
|
+
}
|
|
113
|
+
if (isRaw(f) && f.sql === '?? as ??' && f.params.length === 2) {
|
|
114
|
+
return `${this.resolveNestedPath(String(f.params[0]))} as ${String(f.params[1])}`;
|
|
115
|
+
}
|
|
106
116
|
return f;
|
|
107
117
|
}
|
|
118
|
+
const asMatch = f.match(FIELD_ALIAS_RE);
|
|
119
|
+
if (asMatch) {
|
|
120
|
+
return `${this.resolveNestedPath(asMatch[1].trim())} as ${asMatch[2]}`;
|
|
121
|
+
}
|
|
108
122
|
return this.resolveNestedPath(f);
|
|
109
123
|
});
|
|
110
124
|
if (distinct) {
|
|
@@ -307,7 +321,7 @@ export class QueryBuilder {
|
|
|
307
321
|
for (const p of targetMeta.getPrimaryProps()) {
|
|
308
322
|
fields.push(...this.driver.mapPropToFieldNames(this, p, alias, targetMeta, schema));
|
|
309
323
|
}
|
|
310
|
-
if (explicitFields) {
|
|
324
|
+
if (explicitFields && explicitFields.length > 0) {
|
|
311
325
|
for (const field of explicitFields) {
|
|
312
326
|
const [a, f] = this.helper.splitField(field);
|
|
313
327
|
const p = targetMeta.properties[f];
|
|
@@ -321,7 +335,7 @@ export class QueryBuilder {
|
|
|
321
335
|
}
|
|
322
336
|
targetMeta.props
|
|
323
337
|
.filter(prop => {
|
|
324
|
-
if (!explicitFields) {
|
|
338
|
+
if (!explicitFields || explicitFields.length === 0) {
|
|
325
339
|
return this.platform.shouldHaveColumn(prop, populate);
|
|
326
340
|
}
|
|
327
341
|
return prop.primary && !explicitFields.includes(prop.name) && !explicitFields.includes(`${alias}.${prop.name}`);
|
|
@@ -457,7 +471,18 @@ export class QueryBuilder {
|
|
|
457
471
|
if (reset) {
|
|
458
472
|
this._orderBy = [];
|
|
459
473
|
}
|
|
460
|
-
|
|
474
|
+
const selectAliases = this.getSelectAliases();
|
|
475
|
+
Utils.asArray(orderBy).forEach(orig => {
|
|
476
|
+
// Shallow clone to avoid mutating the caller's object — safe because the clone
|
|
477
|
+
// is only used within this loop iteration and `orig` is not referenced afterward.
|
|
478
|
+
const o = { ...orig };
|
|
479
|
+
// Wrap known select aliases in raw() so they bypass property validation and alias prefixing
|
|
480
|
+
for (const key of Object.keys(o)) {
|
|
481
|
+
if (selectAliases.has(key)) {
|
|
482
|
+
o[raw('??', [key])] = o[key];
|
|
483
|
+
delete o[key];
|
|
484
|
+
}
|
|
485
|
+
}
|
|
461
486
|
this.helper.validateQueryOrder(o);
|
|
462
487
|
const processed = QueryHelper.processWhere({
|
|
463
488
|
where: o,
|
|
@@ -476,10 +501,27 @@ export class QueryBuilder {
|
|
|
476
501
|
});
|
|
477
502
|
return this;
|
|
478
503
|
}
|
|
504
|
+
/** Collect custom aliases from select fields (stored as 'resolved as alias' strings by select()). */
|
|
505
|
+
getSelectAliases() {
|
|
506
|
+
const aliases = new Set();
|
|
507
|
+
for (const field of this._fields ?? []) {
|
|
508
|
+
if (typeof field === 'string') {
|
|
509
|
+
const m = field.match(FIELD_ALIAS_RE);
|
|
510
|
+
if (m) {
|
|
511
|
+
aliases.add(m[2]);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return aliases;
|
|
516
|
+
}
|
|
479
517
|
groupBy(fields) {
|
|
480
518
|
this.ensureNotFinalized();
|
|
481
519
|
this._groupBy = Utils.asArray(fields).flatMap(f => {
|
|
482
520
|
if (typeof f !== 'string') {
|
|
521
|
+
// Normalize sql.ref('prop') to string for proper formula resolution
|
|
522
|
+
if (isRaw(f) && f.sql === '??' && f.params.length === 1) {
|
|
523
|
+
return this.resolveNestedPath(String(f.params[0]));
|
|
524
|
+
}
|
|
483
525
|
return f;
|
|
484
526
|
}
|
|
485
527
|
return this.resolveNestedPath(f);
|
|
@@ -501,7 +543,7 @@ export class QueryBuilder {
|
|
|
501
543
|
if (typeof cond === 'string') {
|
|
502
544
|
cond = { [raw(`(${cond})`, params)]: [] };
|
|
503
545
|
}
|
|
504
|
-
const processed = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond, undefined, undefined, false).process(this);
|
|
546
|
+
const processed = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond, undefined, undefined, false).process(this, { type: 'having' });
|
|
505
547
|
if (!this._having || !operator) {
|
|
506
548
|
this._having = processed;
|
|
507
549
|
}
|
|
@@ -638,6 +680,14 @@ export class QueryBuilder {
|
|
|
638
680
|
this._indexHint = sql;
|
|
639
681
|
return this;
|
|
640
682
|
}
|
|
683
|
+
/**
|
|
684
|
+
* Adds COLLATE clause to ORDER BY expressions.
|
|
685
|
+
*/
|
|
686
|
+
collation(collation) {
|
|
687
|
+
this.ensureNotFinalized();
|
|
688
|
+
this._collation = collation;
|
|
689
|
+
return this;
|
|
690
|
+
}
|
|
641
691
|
/**
|
|
642
692
|
* Prepend comment to the sql query using the syntax `/* ... *‍/`. Some characters are forbidden such as `/*, *‍/` and `?`.
|
|
643
693
|
*/
|
|
@@ -682,7 +732,7 @@ export class QueryBuilder {
|
|
|
682
732
|
Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy', schema)), isNotEmptyObject(this._groupBy));
|
|
683
733
|
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), isNotEmptyObject(this._having));
|
|
684
734
|
Utils.runIfNotEmpty(() => {
|
|
685
|
-
const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
|
|
735
|
+
const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap, this._collation);
|
|
686
736
|
if (queryOrder.length > 0) {
|
|
687
737
|
const sql = Utils.unique(queryOrder).join(', ');
|
|
688
738
|
qb.orderBy(sql);
|
|
@@ -1015,7 +1065,7 @@ export class QueryBuilder {
|
|
|
1015
1065
|
// clone array/object properties
|
|
1016
1066
|
const properties = [
|
|
1017
1067
|
'flags', '_populate', '_populateWhere', '_populateFilter', '__populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
|
|
1018
|
-
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
|
|
1068
|
+
'_schema', '_indexHint', '_collation', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
|
|
1019
1069
|
'_comments', '_hintComments', 'aliasCounter',
|
|
1020
1070
|
];
|
|
1021
1071
|
for (const prop of Object.keys(this)) {
|
|
@@ -1167,14 +1217,23 @@ export class QueryBuilder {
|
|
|
1167
1217
|
}
|
|
1168
1218
|
prepareFields(fields, type = 'where', schema) {
|
|
1169
1219
|
const ret = [];
|
|
1170
|
-
const getFieldName = (name) => {
|
|
1171
|
-
|
|
1220
|
+
const getFieldName = (name, customAlias) => {
|
|
1221
|
+
const alias = customAlias ?? (type === 'groupBy' ? null : undefined);
|
|
1222
|
+
return this.helper.mapper(name, this.type, undefined, alias, schema);
|
|
1172
1223
|
};
|
|
1173
|
-
fields.forEach(
|
|
1174
|
-
if (typeof
|
|
1175
|
-
ret.push(
|
|
1224
|
+
fields.forEach(originalField => {
|
|
1225
|
+
if (typeof originalField !== 'string') {
|
|
1226
|
+
ret.push(originalField);
|
|
1176
1227
|
return;
|
|
1177
1228
|
}
|
|
1229
|
+
// Strip 'as alias' suffix if present — the alias is passed to mapper at the end
|
|
1230
|
+
let field = originalField;
|
|
1231
|
+
let customAlias;
|
|
1232
|
+
const asMatch = originalField.match(FIELD_ALIAS_RE);
|
|
1233
|
+
if (asMatch) {
|
|
1234
|
+
field = asMatch[1].trim();
|
|
1235
|
+
customAlias = asMatch[2];
|
|
1236
|
+
}
|
|
1178
1237
|
const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
|
|
1179
1238
|
if (join && type === 'where') {
|
|
1180
1239
|
ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
|
|
@@ -1192,10 +1251,13 @@ export class QueryBuilder {
|
|
|
1192
1251
|
if (prop?.embedded || (prop?.kind === ReferenceKind.EMBEDDED && prop.object)) {
|
|
1193
1252
|
const name = prop.embeddedPath?.join('.') ?? prop.fieldNames[0];
|
|
1194
1253
|
const aliased = this._aliases[a] ? `${a}.${name}` : name;
|
|
1195
|
-
ret.push(getFieldName(aliased));
|
|
1254
|
+
ret.push(getFieldName(aliased, customAlias));
|
|
1196
1255
|
return;
|
|
1197
1256
|
}
|
|
1198
1257
|
if (prop?.kind === ReferenceKind.EMBEDDED) {
|
|
1258
|
+
if (customAlias) {
|
|
1259
|
+
throw new Error(`Cannot use 'as ${customAlias}' alias on embedded property '${field}' because it expands to multiple columns. Alias individual fields instead (e.g. '${field}.propertyName as ${customAlias}').`);
|
|
1260
|
+
}
|
|
1199
1261
|
const nest = (prop) => {
|
|
1200
1262
|
for (const childProp of Object.values(prop.embeddedProps)) {
|
|
1201
1263
|
if (childProp.fieldNames && (childProp.kind !== ReferenceKind.EMBEDDED || childProp.object) && childProp.persist !== false) {
|
|
@@ -1209,11 +1271,14 @@ export class QueryBuilder {
|
|
|
1209
1271
|
nest(prop);
|
|
1210
1272
|
return;
|
|
1211
1273
|
}
|
|
1212
|
-
if (prop && prop.fieldNames.length > 1) {
|
|
1274
|
+
if (prop && prop.fieldNames.length > 1 && !prop.fieldNames.includes(f)) {
|
|
1275
|
+
if (customAlias) {
|
|
1276
|
+
throw new Error(`Cannot use 'as ${customAlias}' alias on '${field}' because it expands to multiple columns (${prop.fieldNames.join(', ')}).`);
|
|
1277
|
+
}
|
|
1213
1278
|
ret.push(...prop.fieldNames.map(f => getFieldName(f)));
|
|
1214
1279
|
return;
|
|
1215
1280
|
}
|
|
1216
|
-
ret.push(getFieldName(field));
|
|
1281
|
+
ret.push(getFieldName(field, customAlias));
|
|
1217
1282
|
});
|
|
1218
1283
|
const requiresSQLConversion = this.mainAlias.meta.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false);
|
|
1219
1284
|
if (this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) &&
|
|
@@ -1528,7 +1593,7 @@ export class QueryBuilder {
|
|
|
1528
1593
|
if (!this.flags.has(QueryFlag.DISABLE_PAGINATE) && this._groupBy.length === 0 && this.hasToManyJoins()) {
|
|
1529
1594
|
this.flags.add(QueryFlag.PAGINATE);
|
|
1530
1595
|
}
|
|
1531
|
-
if (meta && this.flags.has(QueryFlag.PAGINATE) && !this.flags.has(QueryFlag.DISABLE_PAGINATE) && (this._limit > 0 || this._offset > 0)) {
|
|
1596
|
+
if (meta && !meta.virtual && this.flags.has(QueryFlag.PAGINATE) && !this.flags.has(QueryFlag.DISABLE_PAGINATE) && (this._limit > 0 || this._offset > 0)) {
|
|
1532
1597
|
this.wrapPaginateSubQuery(meta);
|
|
1533
1598
|
}
|
|
1534
1599
|
if (meta && (this.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(QueryFlag.DELETE_SUB_QUERY))) {
|
|
@@ -52,8 +52,8 @@ export declare class QueryBuilderHelper {
|
|
|
52
52
|
private getValueReplacement;
|
|
53
53
|
private getOperatorReplacement;
|
|
54
54
|
validateQueryOrder<T>(orderBy: QueryOrderMap<T>): void;
|
|
55
|
-
getQueryOrder(type: QueryType, orderBy: FlatQueryOrderMap | FlatQueryOrderMap[], populate: Dictionary<string
|
|
56
|
-
getQueryOrderFromObject(type: QueryType, orderBy: FlatQueryOrderMap, populate: Dictionary<string
|
|
55
|
+
getQueryOrder(type: QueryType, orderBy: FlatQueryOrderMap | FlatQueryOrderMap[], populate: Dictionary<string>, collation?: string): string[];
|
|
56
|
+
getQueryOrderFromObject(type: QueryType, orderBy: FlatQueryOrderMap, populate: Dictionary<string>, collation?: string): string[];
|
|
57
57
|
finalize(type: QueryType, qb: NativeQueryBuilder, meta?: EntityMetadata, data?: Dictionary, returning?: InternalField<any>[]): void;
|
|
58
58
|
splitField<T>(field: EntityKey<T>, greedyAlias?: boolean): [string, EntityKey<T>, string | undefined];
|
|
59
59
|
getLockSQL(qb: NativeQueryBuilder, lockMode: LockMode, lockTables?: string[], joinsMap?: Dictionary<JoinOptions>): void;
|
|
@@ -110,8 +110,8 @@ export class QueryBuilderHelper {
|
|
|
110
110
|
}
|
|
111
111
|
if (prop?.formula) {
|
|
112
112
|
const alias2 = this.platform.quoteIdentifier(a).toString();
|
|
113
|
-
const
|
|
114
|
-
const as =
|
|
113
|
+
const aliasName = alias === undefined ? prop.fieldNames[0] : alias;
|
|
114
|
+
const as = aliasName === null ? '' : ` as ${this.platform.quoteIdentifier(aliasName)}`;
|
|
115
115
|
const meta = this.aliasMap[a]?.meta ?? this.metadata.get(this.entityName);
|
|
116
116
|
const table = this.createFormulaTable(alias2, meta, schema);
|
|
117
117
|
const columns = meta.createColumnMappingObject(p => this.getTPTAliasForProperty(p.name, a), alias2);
|
|
@@ -605,20 +605,20 @@ export class QueryBuilderHelper {
|
|
|
605
605
|
].join('\n'));
|
|
606
606
|
}
|
|
607
607
|
}
|
|
608
|
-
getQueryOrder(type, orderBy, populate) {
|
|
608
|
+
getQueryOrder(type, orderBy, populate, collation) {
|
|
609
609
|
if (Array.isArray(orderBy)) {
|
|
610
|
-
return orderBy.flatMap(o => this.getQueryOrder(type, o, populate));
|
|
610
|
+
return orderBy.flatMap(o => this.getQueryOrder(type, o, populate, collation));
|
|
611
611
|
}
|
|
612
|
-
return this.getQueryOrderFromObject(type, orderBy, populate);
|
|
612
|
+
return this.getQueryOrderFromObject(type, orderBy, populate, collation);
|
|
613
613
|
}
|
|
614
|
-
getQueryOrderFromObject(type, orderBy, populate) {
|
|
614
|
+
getQueryOrderFromObject(type, orderBy, populate, collation) {
|
|
615
615
|
const ret = [];
|
|
616
616
|
for (const key of Utils.getObjectQueryKeys(orderBy)) {
|
|
617
617
|
const direction = orderBy[key];
|
|
618
618
|
const order = typeof direction === 'number' ? QueryOrderNumeric[direction] : direction;
|
|
619
619
|
if (Raw.isKnownFragmentSymbol(key)) {
|
|
620
620
|
const raw = Raw.getKnownFragment(key);
|
|
621
|
-
ret.push(...this.platform.getOrderByExpression(this.platform.formatQuery(raw.sql, raw.params), order));
|
|
621
|
+
ret.push(...this.platform.getOrderByExpression(this.platform.formatQuery(raw.sql, raw.params), order, collation));
|
|
622
622
|
continue;
|
|
623
623
|
}
|
|
624
624
|
for (const f of Utils.splitPrimaryKeys(key)) {
|
|
@@ -638,10 +638,10 @@ export class QueryBuilderHelper {
|
|
|
638
638
|
colPart = this.platform.formatQuery(colPart.sql, colPart.params);
|
|
639
639
|
}
|
|
640
640
|
if (Array.isArray(order)) {
|
|
641
|
-
order.forEach(part => ret.push(...this.getQueryOrderFromObject(type, part, populate)));
|
|
641
|
+
order.forEach(part => ret.push(...this.getQueryOrderFromObject(type, part, populate, collation)));
|
|
642
642
|
}
|
|
643
643
|
else {
|
|
644
|
-
ret.push(...this.platform.getOrderByExpression(colPart, order));
|
|
644
|
+
ret.push(...this.platform.getOrderByExpression(colPart, order, collation));
|
|
645
645
|
}
|
|
646
646
|
}
|
|
647
647
|
}
|
|
@@ -165,6 +165,7 @@ export class SchemaComparator {
|
|
|
165
165
|
if (this.diffComment(fromTable.comment, toTable.comment)) {
|
|
166
166
|
tableDifferences.changedComment = toTable.comment;
|
|
167
167
|
this.log(`table comment changed for ${tableDifferences.name}`, { fromTableComment: fromTable.comment, toTableComment: toTable.comment });
|
|
168
|
+
changes++;
|
|
168
169
|
}
|
|
169
170
|
const fromTableColumns = fromTable.getColumns();
|
|
170
171
|
const toTableColumns = toTable.getColumns();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type ClearDatabaseOptions, type CreateSchemaOptions, type Dictionary, type DropSchemaOptions, type EnsureDatabaseOptions, type EntityMetadata, type ISchemaGenerator, type MikroORM, type Transaction, type UpdateSchemaOptions } from '@mikro-orm/core';
|
|
2
|
+
import { AbstractSchemaGenerator } from '@mikro-orm/core/schema';
|
|
2
3
|
import type { SchemaDifference } from '../typings.js';
|
|
3
4
|
import { DatabaseSchema } from './DatabaseSchema.js';
|
|
4
5
|
import type { AbstractSqlDriver } from '../AbstractSqlDriver.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommitOrderCalculator, Utils, } from '@mikro-orm/core';
|
|
2
|
+
import { AbstractSchemaGenerator } from '@mikro-orm/core/schema';
|
|
2
3
|
import { DatabaseSchema } from './DatabaseSchema.js';
|
|
3
4
|
import { SchemaComparator } from './SchemaComparator.js';
|
|
4
5
|
export class SqlSchemaGenerator extends AbstractSchemaGenerator {
|