@mikro-orm/knex 6.0.0-dev.8 → 6.0.0-dev.80
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 +5 -2
- package/AbstractSqlConnection.js +25 -17
- package/AbstractSqlDriver.d.ts +18 -18
- package/AbstractSqlDriver.js +117 -48
- package/AbstractSqlPlatform.d.ts +1 -0
- package/AbstractSqlPlatform.js +20 -5
- package/MonkeyPatchable.d.ts +1 -0
- package/MonkeyPatchable.js +3 -0
- package/README.md +64 -107
- package/SqlEntityManager.d.ts +2 -5
- package/SqlEntityManager.js +5 -9
- package/SqlEntityRepository.d.ts +6 -4
- package/SqlEntityRepository.js +10 -8
- package/index.mjs +19 -6
- package/package.json +7 -7
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +9 -9
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +10 -13
- package/query/ObjectCriteriaNode.d.ts +3 -3
- package/query/ObjectCriteriaNode.js +12 -8
- package/query/QueryBuilder.d.ts +25 -7
- package/query/QueryBuilder.js +237 -61
- package/query/QueryBuilderHelper.d.ts +3 -5
- package/query/QueryBuilderHelper.js +96 -74
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/schema/DatabaseSchema.d.ts +4 -1
- package/schema/DatabaseSchema.js +22 -6
- package/schema/DatabaseTable.d.ts +2 -1
- package/schema/DatabaseTable.js +25 -24
- package/schema/SchemaComparator.js +9 -2
- package/schema/SchemaHelper.d.ts +5 -3
- package/schema/SchemaHelper.js +10 -4
- package/schema/SqlSchemaGenerator.d.ts +3 -5
- package/schema/SqlSchemaGenerator.js +41 -20
- package/typings.d.ts +8 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
|
-
import type { AnyEntity, Configuration, ConnectionOptions, EntityData, IsolationLevel, QueryResult, Transaction, TransactionEventBroadcaster } from '@mikro-orm/core';
|
|
2
|
+
import type { AnyEntity, Configuration, ConnectionOptions, EntityData, IsolationLevel, LoggingOptions, QueryResult, Transaction, TransactionEventBroadcaster } from '@mikro-orm/core';
|
|
3
3
|
import { Connection } from '@mikro-orm/core';
|
|
4
4
|
import type { AbstractSqlPlatform } from './AbstractSqlPlatform';
|
|
5
5
|
export declare abstract class AbstractSqlConnection extends Connection {
|
|
@@ -7,6 +7,9 @@ export declare abstract class AbstractSqlConnection extends Connection {
|
|
|
7
7
|
protected platform: AbstractSqlPlatform;
|
|
8
8
|
protected client: Knex;
|
|
9
9
|
constructor(config: Configuration, options?: ConnectionOptions, type?: 'read' | 'write');
|
|
10
|
+
abstract createKnex(): void;
|
|
11
|
+
/** @inheritDoc */
|
|
12
|
+
connect(): void | Promise<void>;
|
|
10
13
|
getKnex(): Knex;
|
|
11
14
|
close(force?: boolean): Promise<void>;
|
|
12
15
|
isConnected(): Promise<boolean>;
|
|
@@ -22,7 +25,7 @@ export declare abstract class AbstractSqlConnection extends Connection {
|
|
|
22
25
|
}): Promise<Knex.Transaction>;
|
|
23
26
|
commit(ctx: Knex.Transaction, eventBroadcaster?: TransactionEventBroadcaster): Promise<void>;
|
|
24
27
|
rollback(ctx: Knex.Transaction, eventBroadcaster?: TransactionEventBroadcaster): Promise<void>;
|
|
25
|
-
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(queryOrKnex: string | Knex.QueryBuilder | Knex.Raw, params?: unknown[], method?: 'all' | 'get' | 'run', ctx?: Transaction): Promise<T>;
|
|
28
|
+
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(queryOrKnex: string | Knex.QueryBuilder | Knex.Raw, params?: unknown[], method?: 'all' | 'get' | 'run', ctx?: Transaction, logging?: LoggingOptions): Promise<T>;
|
|
26
29
|
/**
|
|
27
30
|
* Execute raw SQL queries from file
|
|
28
31
|
*/
|
package/AbstractSqlConnection.js
CHANGED
|
@@ -14,16 +14,23 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
14
14
|
super(config, options, type);
|
|
15
15
|
this.patchKnexClient();
|
|
16
16
|
}
|
|
17
|
+
/** @inheritDoc */
|
|
18
|
+
connect() {
|
|
19
|
+
this.createKnex();
|
|
20
|
+
}
|
|
17
21
|
getKnex() {
|
|
22
|
+
if (!this.client) {
|
|
23
|
+
this.createKnex();
|
|
24
|
+
}
|
|
18
25
|
return this.client;
|
|
19
26
|
}
|
|
20
27
|
async close(force) {
|
|
21
28
|
await super.close(force);
|
|
22
|
-
await this.
|
|
29
|
+
await this.getKnex().destroy();
|
|
23
30
|
}
|
|
24
31
|
async isConnected() {
|
|
25
32
|
try {
|
|
26
|
-
await this.
|
|
33
|
+
await this.getKnex().raw('select 1');
|
|
27
34
|
return true;
|
|
28
35
|
}
|
|
29
36
|
catch {
|
|
@@ -46,7 +53,7 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
46
53
|
if (!options.ctx) {
|
|
47
54
|
await options.eventBroadcaster?.dispatchEvent(core_1.EventType.beforeTransactionStart);
|
|
48
55
|
}
|
|
49
|
-
const trx = await (options.ctx || this.
|
|
56
|
+
const trx = await (options.ctx || this.getKnex()).transaction(null, { isolationLevel: options.isolationLevel });
|
|
50
57
|
if (!options.ctx) {
|
|
51
58
|
await options.eventBroadcaster?.dispatchEvent(core_1.EventType.afterTransactionStart, trx);
|
|
52
59
|
}
|
|
@@ -76,30 +83,31 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
76
83
|
await eventBroadcaster?.dispatchEvent(core_1.EventType.afterTransactionRollback, ctx);
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
|
-
async execute(queryOrKnex, params = [], method = 'all', ctx) {
|
|
86
|
+
async execute(queryOrKnex, params = [], method = 'all', ctx, logging) {
|
|
87
|
+
await this.ensureConnection();
|
|
80
88
|
if (core_1.Utils.isObject(queryOrKnex)) {
|
|
81
|
-
ctx
|
|
89
|
+
ctx ??= (queryOrKnex.client.transacting ? queryOrKnex : null);
|
|
82
90
|
const q = queryOrKnex.toSQL();
|
|
83
91
|
queryOrKnex = q.sql;
|
|
84
92
|
params = q.bindings;
|
|
85
93
|
}
|
|
86
94
|
const formatted = this.platform.formatQuery(queryOrKnex, params);
|
|
87
|
-
const sql = this.getSql(queryOrKnex, formatted);
|
|
88
|
-
|
|
89
|
-
const query = this.
|
|
95
|
+
const sql = this.getSql(queryOrKnex, formatted, logging);
|
|
96
|
+
return this.executeQuery(sql, async () => {
|
|
97
|
+
const query = this.getKnex().raw(formatted);
|
|
90
98
|
if (ctx) {
|
|
91
99
|
query.transacting(ctx);
|
|
92
100
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
const res = await query;
|
|
102
|
+
return this.transformRawResult(res, method);
|
|
103
|
+
}, { query: queryOrKnex, params, ...logging });
|
|
96
104
|
}
|
|
97
105
|
/**
|
|
98
106
|
* Execute raw SQL queries from file
|
|
99
107
|
*/
|
|
100
108
|
async loadFile(path) {
|
|
101
109
|
const buf = await (0, fs_extra_1.readFile)(path);
|
|
102
|
-
await this.
|
|
110
|
+
await this.getKnex().raw(buf.toString());
|
|
103
111
|
}
|
|
104
112
|
createKnexClient(type) {
|
|
105
113
|
const driverOptions = this.config.get('driverOptions');
|
|
@@ -138,15 +146,15 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
138
146
|
};
|
|
139
147
|
return config;
|
|
140
148
|
}
|
|
141
|
-
getSql(query, formatted) {
|
|
149
|
+
getSql(query, formatted, context) {
|
|
142
150
|
const logger = this.config.getLogger();
|
|
143
|
-
if (!logger.isEnabled('query')) {
|
|
151
|
+
if (!logger.isEnabled('query', context)) {
|
|
144
152
|
return query;
|
|
145
153
|
}
|
|
146
|
-
if (logger.isEnabled('query-params')) {
|
|
154
|
+
if (logger.isEnabled('query-params', context)) {
|
|
147
155
|
return formatted;
|
|
148
156
|
}
|
|
149
|
-
return this.
|
|
157
|
+
return this.getKnex().client.positionBindings(query);
|
|
150
158
|
}
|
|
151
159
|
/**
|
|
152
160
|
* do not call `positionBindings` when there are no bindings - it was messing up with
|
|
@@ -177,5 +185,5 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
177
185
|
};
|
|
178
186
|
}
|
|
179
187
|
}
|
|
180
|
-
exports.AbstractSqlConnection = AbstractSqlConnection;
|
|
181
188
|
AbstractSqlConnection.__patched = false;
|
|
189
|
+
exports.AbstractSqlConnection = AbstractSqlConnection;
|
package/AbstractSqlDriver.d.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
|
-
import type { AnyEntity, Collection, ConnectionType, Configuration, Constructor, CountOptions, DeleteOptions, Dictionary, DriverMethodOptions, EntityData, EntityDictionary, EntityField, EntityMetadata, EntityName, EntityProperty, FilterQuery, FindOneOptions, FindOptions, IDatabaseDriver, LockOptions, NativeInsertUpdateManyOptions, NativeInsertUpdateOptions, PopulateOptions, Primary, QueryOrderMap, QueryResult, Transaction } from '@mikro-orm/core';
|
|
2
|
+
import type { AnyEntity, Collection, ConnectionType, Configuration, Constructor, CountOptions, DeleteOptions, Dictionary, DriverMethodOptions, EntityData, EntityDictionary, EntityField, EntityMetadata, EntityName, EntityProperty, FilterQuery, FindOneOptions, FindOptions, IDatabaseDriver, LockOptions, NativeInsertUpdateManyOptions, NativeInsertUpdateOptions, PopulateOptions, Primary, QueryOrderMap, QueryResult, Transaction, OrderDefinition, LoggingOptions } from '@mikro-orm/core';
|
|
3
3
|
import { DatabaseDriver, EntityManagerType } from '@mikro-orm/core';
|
|
4
4
|
import type { AbstractSqlConnection } from './AbstractSqlConnection';
|
|
5
5
|
import type { AbstractSqlPlatform } from './AbstractSqlPlatform';
|
|
6
6
|
import { QueryBuilder, QueryType } from './query';
|
|
7
7
|
import { SqlEntityManager } from './SqlEntityManager';
|
|
8
8
|
import type { Field } from './typings';
|
|
9
|
-
export declare abstract class AbstractSqlDriver<
|
|
9
|
+
export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection = AbstractSqlConnection, Platform extends AbstractSqlPlatform = AbstractSqlPlatform> extends DatabaseDriver<Connection> {
|
|
10
10
|
[EntityManagerType]: SqlEntityManager<this>;
|
|
11
|
-
protected readonly connection:
|
|
12
|
-
protected readonly replicas:
|
|
13
|
-
protected readonly platform:
|
|
14
|
-
protected constructor(config: Configuration, platform:
|
|
15
|
-
getPlatform():
|
|
11
|
+
protected readonly connection: Connection;
|
|
12
|
+
protected readonly replicas: Connection[];
|
|
13
|
+
protected readonly platform: Platform;
|
|
14
|
+
protected constructor(config: Configuration, platform: Platform, connection: Constructor<Connection>, connector: string[]);
|
|
15
|
+
getPlatform(): Platform;
|
|
16
16
|
createEntityManager<D extends IDatabaseDriver = IDatabaseDriver>(useContext?: boolean): D[typeof EntityManagerType];
|
|
17
|
-
find<T extends object, P extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOptions<T, P>): Promise<EntityData<T>[]>;
|
|
18
|
-
findOne<T extends object, P extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOneOptions<T, P>): Promise<EntityData<T> | null>;
|
|
19
|
-
findVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any>): Promise<EntityData<T>[]>;
|
|
17
|
+
find<T extends object, P extends string = never, F extends string = '*'>(entityName: string, where: FilterQuery<T>, options?: FindOptions<T, P, F>): Promise<EntityData<T>[]>;
|
|
18
|
+
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>;
|
|
19
|
+
findVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: FindOptions<T, any, any>): Promise<EntityData<T>[]>;
|
|
20
20
|
countVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: CountOptions<T>): Promise<number>;
|
|
21
|
-
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any>, type: QueryType.COUNT): Promise<number>;
|
|
22
|
-
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any>, type: QueryType.SELECT): Promise<T[]>;
|
|
23
|
-
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any>): Promise<T[]>;
|
|
21
|
+
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any, any>, type: QueryType.COUNT): Promise<number>;
|
|
22
|
+
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any, any>, type: QueryType.SELECT): Promise<T[]>;
|
|
23
|
+
protected wrapVirtualExpressionInSubquery<T extends object>(meta: EntityMetadata<T>, expression: string, where: FilterQuery<T>, options: FindOptions<T, any, any>): Promise<T[]>;
|
|
24
24
|
mapResult<T extends object>(result: EntityData<T>, meta: EntityMetadata<T>, populate?: PopulateOptions<T>[], qb?: QueryBuilder<T>, map?: Dictionary): EntityData<T> | null;
|
|
25
25
|
private mapJoinedProps;
|
|
26
26
|
private appendToCollection;
|
|
@@ -31,12 +31,12 @@ export declare abstract class AbstractSqlDriver<C extends AbstractSqlConnection
|
|
|
31
31
|
nativeUpdateMany<T extends object>(entityName: string, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
|
|
32
32
|
nativeDelete<T extends object>(entityName: string, where: FilterQuery<T> | string | any, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
|
|
33
33
|
syncCollection<T extends object, O extends object>(coll: Collection<T, O>, options?: DriverMethodOptions): Promise<void>;
|
|
34
|
-
loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?:
|
|
34
|
+
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>): Promise<Dictionary<T[]>>;
|
|
35
35
|
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>;
|
|
36
36
|
/**
|
|
37
37
|
* 1:1 owner side needs to be marked for population so QB auto-joins the owner id
|
|
38
38
|
*/
|
|
39
|
-
protected autoJoinOneToOneOwner<T extends object, P extends string = never>(meta: EntityMetadata
|
|
39
|
+
protected autoJoinOneToOneOwner<T extends object, P extends string = never>(meta: EntityMetadata<T>, populate: PopulateOptions<T>[], fields?: readonly EntityField<T, P>[]): PopulateOptions<T>[];
|
|
40
40
|
protected joinedProps<T>(meta: EntityMetadata, populate: PopulateOptions<T>[]): PopulateOptions<T>[];
|
|
41
41
|
/**
|
|
42
42
|
* @internal
|
|
@@ -48,17 +48,17 @@ export declare abstract class AbstractSqlDriver<C extends AbstractSqlConnection
|
|
|
48
48
|
*/
|
|
49
49
|
mapPropToFieldNames<T extends object>(qb: QueryBuilder<T>, prop: EntityProperty<T>, tableAlias?: string): Field<T>[];
|
|
50
50
|
/** @internal */
|
|
51
|
-
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, ctx?: Transaction<Knex.Transaction>, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean): QueryBuilder<T>;
|
|
51
|
+
createQueryBuilder<T extends object>(entityName: EntityName<T> | QueryBuilder<T>, ctx?: Transaction<Knex.Transaction>, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean, logging?: LoggingOptions): QueryBuilder<T>;
|
|
52
52
|
protected resolveConnectionType(args: {
|
|
53
53
|
ctx?: Transaction<Knex.Transaction>;
|
|
54
54
|
connectionType?: ConnectionType;
|
|
55
55
|
}): ConnectionType;
|
|
56
56
|
protected extractManyToMany<T>(entityName: string, data: EntityDictionary<T>): EntityData<T>;
|
|
57
57
|
protected processManyToMany<T extends object>(meta: EntityMetadata<T> | undefined, pks: Primary<T>[], collections: EntityData<T>, clear: boolean, options?: DriverMethodOptions): Promise<void>;
|
|
58
|
-
protected updateCollectionDiff<T extends object, O extends object>(meta: EntityMetadata<O>, prop: EntityProperty<
|
|
58
|
+
protected updateCollectionDiff<T extends object, O extends object>(meta: EntityMetadata<O>, prop: EntityProperty<O>, pks: Primary<O>[], deleteDiff: Primary<T>[][] | boolean, insertDiff: Primary<T>[][], options?: DriverMethodOptions & {
|
|
59
59
|
ownerSchema?: string;
|
|
60
60
|
}): Promise<void>;
|
|
61
|
-
lockPessimistic<T>(entity: T, options: LockOptions): Promise<void>;
|
|
61
|
+
lockPessimistic<T extends object>(entity: T, options: LockOptions): Promise<void>;
|
|
62
62
|
protected buildJoinedPropsOrderBy<T extends object>(entityName: string, qb: QueryBuilder<T>, meta: EntityMetadata<T>, populate: PopulateOptions<T>[], parentPath?: string): QueryOrderMap<T>[];
|
|
63
63
|
protected normalizeFields<T extends object>(fields: Field<T>[], prefix?: string): string[];
|
|
64
64
|
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;
|
package/AbstractSqlDriver.js
CHANGED
|
@@ -26,19 +26,28 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
26
26
|
}
|
|
27
27
|
const populate = this.autoJoinOneToOneOwner(meta, options.populate, options.fields);
|
|
28
28
|
const joinedProps = this.joinedProps(meta, populate);
|
|
29
|
-
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false);
|
|
29
|
+
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false, options.logging);
|
|
30
30
|
const fields = this.buildFields(meta, populate, joinedProps, qb, options.fields);
|
|
31
31
|
const joinedPropsOrderBy = this.buildJoinedPropsOrderBy(entityName, qb, meta, joinedProps);
|
|
32
|
+
const orderBy = [...core_1.Utils.asArray(options.orderBy), ...joinedPropsOrderBy];
|
|
32
33
|
if (core_1.Utils.isPrimaryKey(where, meta.compositePK)) {
|
|
33
34
|
where = { [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: where };
|
|
34
35
|
}
|
|
36
|
+
const { first, last, before, after } = options;
|
|
37
|
+
const isCursorPagination = [first, last, before, after].some(v => v != null);
|
|
35
38
|
qb.select(fields)
|
|
36
39
|
.populate(populate, joinedProps.length > 0 ? options.populateWhere : undefined)
|
|
37
40
|
.where(where)
|
|
38
|
-
.orderBy([...core_1.Utils.asArray(options.orderBy), ...joinedPropsOrderBy])
|
|
39
41
|
.groupBy(options.groupBy)
|
|
40
42
|
.having(options.having)
|
|
41
43
|
.withSchema(this.getSchemaName(meta, options));
|
|
44
|
+
if (isCursorPagination) {
|
|
45
|
+
const { orderBy: newOrderBy, where } = this.processCursorOptions(meta, options, orderBy);
|
|
46
|
+
qb.andWhere(where).orderBy(newOrderBy);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
qb.orderBy(orderBy);
|
|
50
|
+
}
|
|
42
51
|
if (options.limit !== undefined) {
|
|
43
52
|
qb.limit(options.limit, options.offset);
|
|
44
53
|
}
|
|
@@ -47,6 +56,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
47
56
|
}
|
|
48
57
|
core_1.Utils.asArray(options.flags).forEach(flag => qb.setFlag(flag));
|
|
49
58
|
const result = await this.rethrow(qb.execute('all'));
|
|
59
|
+
if (isCursorPagination && !first && !!last) {
|
|
60
|
+
result.reverse();
|
|
61
|
+
}
|
|
50
62
|
if (joinedProps.length > 0) {
|
|
51
63
|
return this.mergeJoinedResult(result, meta);
|
|
52
64
|
}
|
|
@@ -61,7 +73,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
61
73
|
opts.limit = 1;
|
|
62
74
|
}
|
|
63
75
|
if (opts.limit > 0 && !opts.flags?.includes(core_1.QueryFlag.DISABLE_PAGINATE)) {
|
|
64
|
-
opts.flags
|
|
76
|
+
opts.flags ??= [];
|
|
65
77
|
opts.flags.push(core_1.QueryFlag.DISABLE_PAGINATE);
|
|
66
78
|
}
|
|
67
79
|
const res = await this.find(entityName, where, opts);
|
|
@@ -112,7 +124,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
112
124
|
qb.where(where);
|
|
113
125
|
const kqb = qb.getKnexQuery().clear('select');
|
|
114
126
|
if (type === query_1.QueryType.COUNT) {
|
|
115
|
-
kqb.select(
|
|
127
|
+
kqb.select(this.connection.getKnex().raw('count(*) as count'));
|
|
116
128
|
}
|
|
117
129
|
else { // select
|
|
118
130
|
kqb.select('*');
|
|
@@ -154,8 +166,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
154
166
|
}));
|
|
155
167
|
if (!hasPK) {
|
|
156
168
|
// initialize empty collections
|
|
157
|
-
if ([core_1.
|
|
158
|
-
result[relation.name]
|
|
169
|
+
if ([core_1.ReferenceKind.MANY_TO_MANY, core_1.ReferenceKind.ONE_TO_MANY].includes(relation.kind)) {
|
|
170
|
+
result[relation.name] ??= [];
|
|
159
171
|
}
|
|
160
172
|
return;
|
|
161
173
|
}
|
|
@@ -179,8 +191,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
179
191
|
else {
|
|
180
192
|
map[key] = result;
|
|
181
193
|
}
|
|
182
|
-
if ([core_1.
|
|
183
|
-
result[relation.name]
|
|
194
|
+
if ([core_1.ReferenceKind.MANY_TO_MANY, core_1.ReferenceKind.ONE_TO_MANY].includes(relation.kind)) {
|
|
195
|
+
result[relation.name] ??= [];
|
|
184
196
|
this.appendToCollection(meta2, result[relation.name], relationPojo);
|
|
185
197
|
}
|
|
186
198
|
else {
|
|
@@ -215,7 +227,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
215
227
|
return this.rethrow(qb.getCount());
|
|
216
228
|
}
|
|
217
229
|
async nativeInsert(entityName, data, options = {}) {
|
|
218
|
-
options.convertCustomTypes
|
|
230
|
+
options.convertCustomTypes ??= true;
|
|
219
231
|
const meta = this.metadata.find(entityName);
|
|
220
232
|
const collections = this.extractManyToMany(entityName, data);
|
|
221
233
|
const pks = meta?.primaryKeys ?? [this.config.getNamingStrategy().referenceColumnName()];
|
|
@@ -235,16 +247,20 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
235
247
|
return res;
|
|
236
248
|
}
|
|
237
249
|
async nativeInsertMany(entityName, data, options = {}) {
|
|
238
|
-
options.processCollections
|
|
239
|
-
options.convertCustomTypes
|
|
250
|
+
options.processCollections ??= true;
|
|
251
|
+
options.convertCustomTypes ??= true;
|
|
240
252
|
const meta = this.metadata.find(entityName);
|
|
241
253
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
242
254
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
243
255
|
const set = new Set();
|
|
244
|
-
data.forEach(row =>
|
|
256
|
+
data.forEach(row => core_1.Utils.keys(row).forEach(k => set.add(k)));
|
|
245
257
|
const props = [...set].map(name => meta?.properties[name] ?? { name, fieldNames: [name] });
|
|
246
|
-
|
|
258
|
+
let fields = core_1.Utils.flatten(props.map(prop => prop.fieldNames));
|
|
259
|
+
const duplicates = core_1.Utils.findDuplicates(fields);
|
|
247
260
|
const params = [];
|
|
261
|
+
if (duplicates.length) {
|
|
262
|
+
fields = core_1.Utils.unique(fields);
|
|
263
|
+
}
|
|
248
264
|
/* istanbul ignore next */
|
|
249
265
|
const tableName = meta ? this.getTableName(meta, options) : this.platform.quoteIdentifier(entityName);
|
|
250
266
|
let sql = `insert into ${tableName} `;
|
|
@@ -255,29 +271,45 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
255
271
|
else {
|
|
256
272
|
sql += ' ' + data.map(() => `select null as ${this.platform.quoteIdentifier(pks[0])}`).join(' union all ');
|
|
257
273
|
}
|
|
274
|
+
const addParams = (prop, row) => {
|
|
275
|
+
if (options.convertCustomTypes && prop.customType) {
|
|
276
|
+
params.push(prop.customType.convertToDatabaseValue(row[prop.name], this.platform, { key: prop.name, mode: 'query-data' }));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
params.push(row[prop.name]);
|
|
280
|
+
};
|
|
258
281
|
if (fields.length > 0 || this.platform.usesDefaultKeyword()) {
|
|
259
282
|
sql += data.map(row => {
|
|
260
283
|
const keys = [];
|
|
261
284
|
props.forEach(prop => {
|
|
262
285
|
if (prop.fieldNames.length > 1) {
|
|
263
|
-
|
|
264
|
-
|
|
286
|
+
const param = row[prop.name] ?? prop.fieldNames.map(() => null);
|
|
287
|
+
const key = (row[prop.name] ?? prop.fieldNames).map(() => '?');
|
|
288
|
+
prop.fieldNames.forEach((field, idx) => {
|
|
289
|
+
if (duplicates.includes(field)) {
|
|
290
|
+
param.splice(idx, 1);
|
|
291
|
+
key.splice(idx, 1);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
params.push(...param);
|
|
295
|
+
keys.push(...key);
|
|
265
296
|
}
|
|
266
297
|
else if (prop.customType && 'convertToDatabaseValueSQL' in prop.customType && !this.platform.isRaw(row[prop.name])) {
|
|
267
298
|
keys.push(prop.customType.convertToDatabaseValueSQL('?', this.platform));
|
|
268
|
-
|
|
299
|
+
addParams(prop, row);
|
|
269
300
|
}
|
|
270
301
|
else {
|
|
271
|
-
|
|
302
|
+
addParams(prop, row);
|
|
272
303
|
keys.push('?');
|
|
273
304
|
}
|
|
274
305
|
});
|
|
275
306
|
return '(' + (keys.join(', ') || 'default') + ')';
|
|
276
307
|
}).join(', ');
|
|
277
308
|
}
|
|
278
|
-
if (this.platform.usesReturningStatement()) {
|
|
279
|
-
|
|
280
|
-
|
|
309
|
+
if (meta && this.platform.usesReturningStatement()) {
|
|
310
|
+
const returningProps = meta.props
|
|
311
|
+
.filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw))
|
|
312
|
+
.filter(prop => !(prop.name in data[0]) || core_1.Utils.isRawSql(data[0][prop.name]));
|
|
281
313
|
const returningFields = core_1.Utils.flatten(returningProps.map(prop => prop.fieldNames));
|
|
282
314
|
/* istanbul ignore next */
|
|
283
315
|
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
@@ -289,8 +321,8 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
289
321
|
pk = data.map(d => core_1.Utils.getPrimaryKeyCond(d, pks));
|
|
290
322
|
}
|
|
291
323
|
else {
|
|
292
|
-
res.row
|
|
293
|
-
res.rows
|
|
324
|
+
res.row ??= {};
|
|
325
|
+
res.rows ??= [];
|
|
294
326
|
pk = data.map((d, i) => d[pks[0]] ?? res.rows[i]?.[pks[0]]).map(d => [d]);
|
|
295
327
|
res.insertId = res.insertId || res.row[pks[0]];
|
|
296
328
|
}
|
|
@@ -300,7 +332,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
300
332
|
return res;
|
|
301
333
|
}
|
|
302
334
|
async nativeUpdate(entityName, where, data, options = {}) {
|
|
303
|
-
options.convertCustomTypes
|
|
335
|
+
options.convertCustomTypes ??= true;
|
|
304
336
|
const meta = this.metadata.find(entityName);
|
|
305
337
|
const pks = this.getPrimaryKeyFields(entityName);
|
|
306
338
|
const collections = this.extractManyToMany(entityName, data);
|
|
@@ -314,11 +346,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
314
346
|
.withSchema(this.getSchemaName(meta, options));
|
|
315
347
|
if (options.upsert) {
|
|
316
348
|
/* istanbul ignore next */
|
|
317
|
-
const uniqueFields = core_1.Utils.isPlainObject(where) ?
|
|
349
|
+
const uniqueFields = core_1.Utils.isPlainObject(where) ? core_1.Utils.keys(where) : meta.primaryKeys;
|
|
318
350
|
/* istanbul ignore next */
|
|
319
351
|
qb.insert(data)
|
|
320
352
|
.onConflict(uniqueFields.map(p => meta?.properties[p]?.fieldNames[0] ?? p))
|
|
321
|
-
.merge(
|
|
353
|
+
.merge(core_1.Utils.keys(data).filter(f => !uniqueFields.includes(f)))
|
|
354
|
+
.returning(meta?.comparableProps.filter(p => !p.lazy && !(p.name in data)).map(p => p.name) ?? '*');
|
|
322
355
|
}
|
|
323
356
|
else {
|
|
324
357
|
qb.update(data).where(where);
|
|
@@ -331,12 +364,29 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
331
364
|
return res;
|
|
332
365
|
}
|
|
333
366
|
async nativeUpdateMany(entityName, where, data, options = {}) {
|
|
334
|
-
options.processCollections
|
|
335
|
-
options.convertCustomTypes
|
|
367
|
+
options.processCollections ??= true;
|
|
368
|
+
options.convertCustomTypes ??= true;
|
|
336
369
|
const meta = this.metadata.get(entityName);
|
|
370
|
+
if (options.upsert) {
|
|
371
|
+
const uniqueFields = core_1.Utils.isPlainObject(where[0]) ? Object.keys(where[0]) : meta.primaryKeys;
|
|
372
|
+
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes).withSchema(this.getSchemaName(meta, options));
|
|
373
|
+
qb.insert(data)
|
|
374
|
+
.onConflict(uniqueFields.map(p => meta.properties[p]?.fieldNames[0] ?? p))
|
|
375
|
+
.merge(Object.keys(data[0]).filter(f => !uniqueFields.includes(f)))
|
|
376
|
+
.returning(meta.comparableProps.filter(p => !p.lazy && !(p.name in data[0])).map(p => p.name) ?? '*');
|
|
377
|
+
return qb.execute('run', false);
|
|
378
|
+
}
|
|
337
379
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
338
380
|
const keys = new Set();
|
|
339
|
-
|
|
381
|
+
const returning = new Set();
|
|
382
|
+
data.forEach(row => {
|
|
383
|
+
core_1.Utils.keys(row).forEach(k => {
|
|
384
|
+
keys.add(k);
|
|
385
|
+
if (core_1.Utils.isRawSql(row[k])) {
|
|
386
|
+
returning.add(k);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
});
|
|
340
390
|
const pkCond = core_1.Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
|
|
341
391
|
const params = [];
|
|
342
392
|
let sql = `update ${this.getTableName(meta, options)} set `;
|
|
@@ -396,6 +446,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
396
446
|
return '?';
|
|
397
447
|
});
|
|
398
448
|
sql += ` in (${conds.join(', ')})`;
|
|
449
|
+
if (this.platform.usesReturningStatement() && returning.size > 0) {
|
|
450
|
+
const returningFields = core_1.Utils.flatten([...returning].map(prop => meta.properties[prop].fieldNames));
|
|
451
|
+
/* istanbul ignore next */
|
|
452
|
+
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
453
|
+
}
|
|
399
454
|
const res = await this.rethrow(this.execute(sql, params, 'run', options.ctx));
|
|
400
455
|
for (let i = 0; i < collections.length; i++) {
|
|
401
456
|
await this.processManyToMany(meta, where[i], collections[i], false, options);
|
|
@@ -430,7 +485,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
430
485
|
deleteDiff.push(...snapshot);
|
|
431
486
|
insertDiff.push(...current);
|
|
432
487
|
}
|
|
433
|
-
if (coll.property.
|
|
488
|
+
if (coll.property.kind === core_1.ReferenceKind.ONE_TO_MANY) {
|
|
434
489
|
const cols = coll.property.referencedColumnNames;
|
|
435
490
|
const qb = this.createQueryBuilder(coll.property.type, ctx, 'write')
|
|
436
491
|
.withSchema(this.getSchemaName(meta, options))
|
|
@@ -444,7 +499,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
444
499
|
const pivotMeta = this.metadata.find(coll.property.pivotEntity);
|
|
445
500
|
if (pivotMeta.schema === '*') {
|
|
446
501
|
/* istanbul ignore next */
|
|
447
|
-
options
|
|
502
|
+
options ??= {};
|
|
448
503
|
options.schema = ownerSchema;
|
|
449
504
|
}
|
|
450
505
|
return this.rethrow(this.updateCollectionDiff(meta, coll.property, pks, deleteDiff, insertDiff, options));
|
|
@@ -512,7 +567,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
512
567
|
}
|
|
513
568
|
const relationsToPopulate = populate.map(({ field }) => field);
|
|
514
569
|
const toPopulate = meta.relations
|
|
515
|
-
.filter(prop => prop.
|
|
570
|
+
.filter(prop => prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name))
|
|
516
571
|
.filter(prop => fields.length === 0 || fields.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
517
572
|
.map(prop => ({ field: prop.name, strategy: prop.strategy }));
|
|
518
573
|
return [...populate, ...toPopulate];
|
|
@@ -520,7 +575,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
520
575
|
joinedProps(meta, populate) {
|
|
521
576
|
return populate.filter(p => {
|
|
522
577
|
const prop = meta.properties[p.field] || {};
|
|
523
|
-
return (p.strategy || prop.strategy || this.config.get('loadStrategy')) === core_1.LoadStrategy.JOINED && prop.
|
|
578
|
+
return (p.strategy || prop.strategy || this.config.get('loadStrategy')) === core_1.LoadStrategy.JOINED && prop.kind !== core_1.ReferenceKind.SCALAR;
|
|
524
579
|
});
|
|
525
580
|
}
|
|
526
581
|
/**
|
|
@@ -545,14 +600,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
545
600
|
getFieldsForJoinedLoad(qb, meta, explicitFields, populate = [], parentTableAlias, parentJoinPath) {
|
|
546
601
|
const fields = [];
|
|
547
602
|
const joinedProps = this.joinedProps(meta, populate);
|
|
603
|
+
if (explicitFields?.includes('*')) {
|
|
604
|
+
fields.push('*');
|
|
605
|
+
}
|
|
548
606
|
const shouldHaveColumn = (prop, populate, fields) => {
|
|
549
607
|
if (!this.platform.shouldHaveColumn(prop, populate)) {
|
|
550
608
|
return false;
|
|
551
609
|
}
|
|
552
610
|
if (!fields || prop.primary) {
|
|
553
|
-
return
|
|
611
|
+
return !fields?.includes('*');
|
|
554
612
|
}
|
|
555
|
-
return fields.
|
|
613
|
+
return fields.some(f => f === prop.name || f.toString().startsWith(prop.name + '.'));
|
|
556
614
|
};
|
|
557
615
|
// alias all fields in the primary table
|
|
558
616
|
meta.props
|
|
@@ -582,11 +640,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
582
640
|
const aliased = qb.ref(tableAlias ? `${tableAlias}__${prop.fieldNames[0]}` : prop.fieldNames[0]).toString();
|
|
583
641
|
if (prop.customType?.convertToJSValueSQL && tableAlias) {
|
|
584
642
|
const prefixed = qb.ref(prop.fieldNames[0]).withSchema(tableAlias).toString();
|
|
585
|
-
return [
|
|
643
|
+
return [(0, core_1.raw)(`${prop.customType.convertToJSValueSQL(prefixed, this.platform)} as ${aliased}`)];
|
|
586
644
|
}
|
|
587
645
|
if (prop.formula) {
|
|
588
646
|
const alias = qb.ref(tableAlias ?? qb.alias).toString();
|
|
589
|
-
return [`${prop.formula(alias)} as ${aliased}`];
|
|
647
|
+
return [(0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`)];
|
|
590
648
|
}
|
|
591
649
|
if (tableAlias) {
|
|
592
650
|
return prop.fieldNames.map(fieldName => qb.ref(fieldName).withSchema(tableAlias).as(`${tableAlias}__${fieldName}`));
|
|
@@ -594,9 +652,9 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
594
652
|
return prop.fieldNames;
|
|
595
653
|
}
|
|
596
654
|
/** @internal */
|
|
597
|
-
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes) {
|
|
655
|
+
createQueryBuilder(entityName, ctx, preferredConnectionType, convertCustomTypes, logging) {
|
|
598
656
|
const connectionType = this.resolveConnectionType({ ctx, connectionType: preferredConnectionType });
|
|
599
|
-
const qb = new query_1.QueryBuilder(entityName, this.metadata, this, ctx, undefined, connectionType);
|
|
657
|
+
const qb = new query_1.QueryBuilder(entityName, this.metadata, this, ctx, undefined, connectionType, undefined, logging);
|
|
600
658
|
if (!convertCustomTypes) {
|
|
601
659
|
qb.unsetFlag(core_1.QueryFlag.CONVERT_CUSTOM_TYPES);
|
|
602
660
|
}
|
|
@@ -620,7 +678,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
620
678
|
}
|
|
621
679
|
const ret = {};
|
|
622
680
|
this.metadata.find(entityName).relations.forEach(prop => {
|
|
623
|
-
if (prop.
|
|
681
|
+
if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY && data[prop.name]) {
|
|
624
682
|
ret[prop.name] = data[prop.name].map((item) => core_1.Utils.asArray(item));
|
|
625
683
|
delete data[prop.name];
|
|
626
684
|
}
|
|
@@ -663,7 +721,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
663
721
|
});
|
|
664
722
|
/* istanbul ignore else */
|
|
665
723
|
if (this.platform.allowsMultiInsert()) {
|
|
666
|
-
await this.nativeInsertMany(prop.pivotEntity, items, {
|
|
724
|
+
await this.nativeInsertMany(prop.pivotEntity, items, {
|
|
725
|
+
...options,
|
|
726
|
+
convertCustomTypes: false,
|
|
727
|
+
processCollections: false,
|
|
728
|
+
});
|
|
667
729
|
}
|
|
668
730
|
else {
|
|
669
731
|
await core_1.Utils.runSerial(items, item => {
|
|
@@ -679,7 +741,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
679
741
|
const meta = (0, core_1.helper)(entity).__meta;
|
|
680
742
|
const qb = this.createQueryBuilder(entity.constructor.name, options.ctx).unsetFlag(core_1.QueryFlag.CONVERT_CUSTOM_TYPES).withSchema(options.schema ?? meta.schema);
|
|
681
743
|
const cond = core_1.Utils.getPrimaryKeyCond(entity, meta.primaryKeys);
|
|
682
|
-
qb.select('1').where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
744
|
+
qb.select((0, core_1.raw)('1')).where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
683
745
|
await this.rethrow(qb.execute());
|
|
684
746
|
}
|
|
685
747
|
buildJoinedPropsOrderBy(entityName, qb, meta, populate, parentPath) {
|
|
@@ -691,7 +753,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
691
753
|
const path = `${parentPath ? parentPath : entityName}.${relation.field}`;
|
|
692
754
|
const propAlias = qb.getAliasForJoinPath(path);
|
|
693
755
|
if (propOrderBy) {
|
|
694
|
-
|
|
756
|
+
core_1.Utils.keys(propOrderBy).forEach(field => {
|
|
695
757
|
orderBy.push({ [`${propAlias}.${field}`]: propOrderBy[field] });
|
|
696
758
|
});
|
|
697
759
|
}
|
|
@@ -718,10 +780,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
718
780
|
return ret;
|
|
719
781
|
}
|
|
720
782
|
processField(meta, prop, field, ret, populate, joinedProps, qb) {
|
|
721
|
-
if (!prop || (prop.
|
|
783
|
+
if (!prop || (prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner)) {
|
|
722
784
|
return;
|
|
723
785
|
}
|
|
724
|
-
if (prop.
|
|
786
|
+
if (prop.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
725
787
|
if (prop.object) {
|
|
726
788
|
ret.push(prop.fieldNames[0]);
|
|
727
789
|
return;
|
|
@@ -735,8 +797,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
735
797
|
}
|
|
736
798
|
return;
|
|
737
799
|
}
|
|
800
|
+
if (prop.formula) {
|
|
801
|
+
ret.push(prop.name);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
738
804
|
if (prop.fieldNames) {
|
|
739
|
-
ret.push(prop.fieldNames
|
|
805
|
+
ret.push(...prop.fieldNames);
|
|
740
806
|
}
|
|
741
807
|
}
|
|
742
808
|
buildFields(meta, populate, joinedProps, qb, fields) {
|
|
@@ -745,6 +811,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
745
811
|
const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL);
|
|
746
812
|
const hasExplicitFields = !!fields;
|
|
747
813
|
const ret = [];
|
|
814
|
+
let addFormulas = false;
|
|
748
815
|
if (joinedProps.length > 0) {
|
|
749
816
|
ret.push(...this.getFieldsForJoinedLoad(qb, meta, fields, populate));
|
|
750
817
|
}
|
|
@@ -770,20 +837,22 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
770
837
|
else if (lazyProps.filter(p => !p.formula).length > 0) {
|
|
771
838
|
const props = meta.props.filter(prop => this.platform.shouldHaveColumn(prop, populate, false));
|
|
772
839
|
ret.push(...core_1.Utils.flatten(props.filter(p => !lazyProps.includes(p)).map(p => p.fieldNames)));
|
|
840
|
+
addFormulas = true;
|
|
773
841
|
}
|
|
774
842
|
else if (hasLazyFormulas || requiresSQLConversion) {
|
|
775
843
|
ret.push('*');
|
|
844
|
+
addFormulas = true;
|
|
776
845
|
}
|
|
777
|
-
if (ret.length > 0 && !hasExplicitFields) {
|
|
846
|
+
if (ret.length > 0 && !hasExplicitFields && addFormulas) {
|
|
778
847
|
meta.props
|
|
779
848
|
.filter(prop => prop.formula && !lazyProps.includes(prop))
|
|
780
849
|
.forEach(prop => {
|
|
781
850
|
const alias = qb.ref(qb.alias).toString();
|
|
782
851
|
const aliased = qb.ref(prop.fieldNames[0]).toString();
|
|
783
|
-
ret.push(`${prop.formula(alias)} as ${aliased}`);
|
|
852
|
+
ret.push((0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`));
|
|
784
853
|
});
|
|
785
854
|
meta.props
|
|
786
|
-
.filter(prop => prop.
|
|
855
|
+
.filter(prop => prop.hasConvertToDatabaseValueSQL || prop.hasConvertToJSValueSQL)
|
|
787
856
|
.forEach(prop => ret.push(prop.name));
|
|
788
857
|
}
|
|
789
858
|
return ret.length > 0 ? core_1.Utils.unique(ret) : ['*'];
|
package/AbstractSqlPlatform.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare abstract class AbstractSqlPlatform extends Platform {
|
|
|
14
14
|
quoteValue(value: any): string;
|
|
15
15
|
formatQuery(sql: string, params: readonly any[]): string;
|
|
16
16
|
getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string;
|
|
17
|
+
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean): string;
|
|
17
18
|
isRaw(value: any): boolean;
|
|
18
19
|
supportsSchemas(): boolean;
|
|
19
20
|
/** @inheritDoc */
|