@mikro-orm/knex 6.0.0-dev.6 → 6.0.0-dev.60
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 +3 -0
- package/AbstractSqlConnection.js +16 -8
- package/AbstractSqlDriver.d.ts +16 -16
- package/AbstractSqlDriver.js +107 -44
- package/AbstractSqlPlatform.d.ts +2 -2
- package/AbstractSqlPlatform.js +14 -7
- package/MonkeyPatchable.d.ts +1 -0
- package/MonkeyPatchable.js +3 -0
- package/README.md +64 -107
- package/SqlEntityManager.d.ts +0 -4
- package/SqlEntityManager.js +1 -9
- package/SqlEntityRepository.d.ts +0 -1
- package/SqlEntityRepository.js +0 -1
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.mjs +176 -0
- package/package.json +5 -5
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +8 -8
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +11 -11
- package/query/ObjectCriteriaNode.d.ts +3 -3
- package/query/ObjectCriteriaNode.js +12 -8
- package/query/QueryBuilder.d.ts +17 -4
- package/query/QueryBuilder.js +188 -45
- package/query/QueryBuilderHelper.d.ts +3 -5
- package/query/QueryBuilderHelper.js +85 -71
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/schema/DatabaseSchema.js +3 -3
- package/schema/DatabaseTable.d.ts +9 -9
- package/schema/DatabaseTable.js +21 -22
- package/schema/SchemaComparator.d.ts +4 -4
- package/schema/SchemaComparator.js +4 -2
- package/schema/SchemaHelper.d.ts +11 -11
- package/schema/SchemaHelper.js +3 -3
- package/schema/{SchemaGenerator.d.ts → SqlSchemaGenerator.d.ts} +3 -7
- package/schema/{SchemaGenerator.js → SqlSchemaGenerator.js} +17 -24
- package/schema/index.d.ts +1 -1
- package/schema/index.js +1 -1
- package/typings.d.ts +14 -13
|
@@ -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>;
|
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
|
}
|
|
@@ -77,8 +84,9 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
86
|
async execute(queryOrKnex, params = [], method = 'all', ctx) {
|
|
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;
|
|
@@ -86,7 +94,7 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
86
94
|
const formatted = this.platform.formatQuery(queryOrKnex, params);
|
|
87
95
|
const sql = this.getSql(queryOrKnex, formatted);
|
|
88
96
|
const res = await this.executeQuery(sql, () => {
|
|
89
|
-
const query = this.
|
|
97
|
+
const query = this.getKnex().raw(formatted);
|
|
90
98
|
if (ctx) {
|
|
91
99
|
query.transacting(ctx);
|
|
92
100
|
}
|
|
@@ -99,7 +107,7 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
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');
|
|
@@ -146,7 +154,7 @@ class AbstractSqlConnection extends core_1.Connection {
|
|
|
146
154
|
if (logger.isEnabled('query-params')) {
|
|
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 } 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
|
|
@@ -58,7 +58,7 @@ export declare abstract class AbstractSqlDriver<C extends AbstractSqlConnection
|
|
|
58
58
|
protected updateCollectionDiff<T extends object, O extends object>(meta: EntityMetadata<O>, prop: EntityProperty<T>, 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
|
@@ -29,16 +29,25 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
29
29
|
const qb = this.createQueryBuilder(entityName, options.ctx, options.connectionType, false);
|
|
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.hydrateProps
|
|
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,11 @@ 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)));
|
|
322
354
|
}
|
|
323
355
|
else {
|
|
324
356
|
qb.update(data).where(where);
|
|
@@ -331,12 +363,28 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
331
363
|
return res;
|
|
332
364
|
}
|
|
333
365
|
async nativeUpdateMany(entityName, where, data, options = {}) {
|
|
334
|
-
options.processCollections
|
|
335
|
-
options.convertCustomTypes
|
|
366
|
+
options.processCollections ??= true;
|
|
367
|
+
options.convertCustomTypes ??= true;
|
|
336
368
|
const meta = this.metadata.get(entityName);
|
|
369
|
+
if (options.upsert) {
|
|
370
|
+
const uniqueFields = core_1.Utils.isPlainObject(where[0]) ? Object.keys(where[0]) : meta.primaryKeys;
|
|
371
|
+
const qb = this.createQueryBuilder(entityName, options.ctx, 'write', options.convertCustomTypes).withSchema(this.getSchemaName(meta, options));
|
|
372
|
+
qb.insert(data)
|
|
373
|
+
.onConflict(uniqueFields.map(p => meta?.properties[p]?.fieldNames[0] ?? p))
|
|
374
|
+
.merge(Object.keys(data[0]).filter(f => !uniqueFields.includes(f)));
|
|
375
|
+
return qb.execute('run', false);
|
|
376
|
+
}
|
|
337
377
|
const collections = options.processCollections ? data.map(d => this.extractManyToMany(entityName, d)) : [];
|
|
338
378
|
const keys = new Set();
|
|
339
|
-
|
|
379
|
+
const returning = new Set();
|
|
380
|
+
data.forEach(row => {
|
|
381
|
+
core_1.Utils.keys(row).forEach(k => {
|
|
382
|
+
keys.add(k);
|
|
383
|
+
if (core_1.Utils.isRawSql(row[k])) {
|
|
384
|
+
returning.add(k);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
});
|
|
340
388
|
const pkCond = core_1.Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
|
|
341
389
|
const params = [];
|
|
342
390
|
let sql = `update ${this.getTableName(meta, options)} set `;
|
|
@@ -396,6 +444,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
396
444
|
return '?';
|
|
397
445
|
});
|
|
398
446
|
sql += ` in (${conds.join(', ')})`;
|
|
447
|
+
if (this.platform.usesReturningStatement() && returning.size > 0) {
|
|
448
|
+
const returningFields = core_1.Utils.flatten([...returning].map(prop => meta.properties[prop].fieldNames));
|
|
449
|
+
/* istanbul ignore next */
|
|
450
|
+
sql += returningFields.length > 0 ? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}` : '';
|
|
451
|
+
}
|
|
399
452
|
const res = await this.rethrow(this.execute(sql, params, 'run', options.ctx));
|
|
400
453
|
for (let i = 0; i < collections.length; i++) {
|
|
401
454
|
await this.processManyToMany(meta, where[i], collections[i], false, options);
|
|
@@ -430,7 +483,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
430
483
|
deleteDiff.push(...snapshot);
|
|
431
484
|
insertDiff.push(...current);
|
|
432
485
|
}
|
|
433
|
-
if (coll.property.
|
|
486
|
+
if (coll.property.kind === core_1.ReferenceKind.ONE_TO_MANY) {
|
|
434
487
|
const cols = coll.property.referencedColumnNames;
|
|
435
488
|
const qb = this.createQueryBuilder(coll.property.type, ctx, 'write')
|
|
436
489
|
.withSchema(this.getSchemaName(meta, options))
|
|
@@ -444,7 +497,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
444
497
|
const pivotMeta = this.metadata.find(coll.property.pivotEntity);
|
|
445
498
|
if (pivotMeta.schema === '*') {
|
|
446
499
|
/* istanbul ignore next */
|
|
447
|
-
options
|
|
500
|
+
options ??= {};
|
|
448
501
|
options.schema = ownerSchema;
|
|
449
502
|
}
|
|
450
503
|
return this.rethrow(this.updateCollectionDiff(meta, coll.property, pks, deleteDiff, insertDiff, options));
|
|
@@ -512,7 +565,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
512
565
|
}
|
|
513
566
|
const relationsToPopulate = populate.map(({ field }) => field);
|
|
514
567
|
const toPopulate = meta.relations
|
|
515
|
-
.filter(prop => prop.
|
|
568
|
+
.filter(prop => prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name))
|
|
516
569
|
.filter(prop => fields.length === 0 || fields.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
517
570
|
.map(prop => ({ field: prop.name, strategy: prop.strategy }));
|
|
518
571
|
return [...populate, ...toPopulate];
|
|
@@ -520,7 +573,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
520
573
|
joinedProps(meta, populate) {
|
|
521
574
|
return populate.filter(p => {
|
|
522
575
|
const prop = meta.properties[p.field] || {};
|
|
523
|
-
return (p.strategy || prop.strategy || this.config.get('loadStrategy')) === core_1.LoadStrategy.JOINED && prop.
|
|
576
|
+
return (p.strategy || prop.strategy || this.config.get('loadStrategy')) === core_1.LoadStrategy.JOINED && prop.kind !== core_1.ReferenceKind.SCALAR;
|
|
524
577
|
});
|
|
525
578
|
}
|
|
526
579
|
/**
|
|
@@ -545,14 +598,17 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
545
598
|
getFieldsForJoinedLoad(qb, meta, explicitFields, populate = [], parentTableAlias, parentJoinPath) {
|
|
546
599
|
const fields = [];
|
|
547
600
|
const joinedProps = this.joinedProps(meta, populate);
|
|
601
|
+
if (explicitFields?.includes('*')) {
|
|
602
|
+
fields.push('*');
|
|
603
|
+
}
|
|
548
604
|
const shouldHaveColumn = (prop, populate, fields) => {
|
|
549
605
|
if (!this.platform.shouldHaveColumn(prop, populate)) {
|
|
550
606
|
return false;
|
|
551
607
|
}
|
|
552
608
|
if (!fields || prop.primary) {
|
|
553
|
-
return
|
|
609
|
+
return !fields?.includes('*');
|
|
554
610
|
}
|
|
555
|
-
return fields.
|
|
611
|
+
return fields.some(f => f === prop.name || f.toString().startsWith(prop.name + '.'));
|
|
556
612
|
};
|
|
557
613
|
// alias all fields in the primary table
|
|
558
614
|
meta.props
|
|
@@ -582,11 +638,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
582
638
|
const aliased = qb.ref(tableAlias ? `${tableAlias}__${prop.fieldNames[0]}` : prop.fieldNames[0]).toString();
|
|
583
639
|
if (prop.customType?.convertToJSValueSQL && tableAlias) {
|
|
584
640
|
const prefixed = qb.ref(prop.fieldNames[0]).withSchema(tableAlias).toString();
|
|
585
|
-
return [
|
|
641
|
+
return [(0, core_1.raw)(`${prop.customType.convertToJSValueSQL(prefixed, this.platform)} as ${aliased}`)];
|
|
586
642
|
}
|
|
587
643
|
if (prop.formula) {
|
|
588
644
|
const alias = qb.ref(tableAlias ?? qb.alias).toString();
|
|
589
|
-
return [`${prop.formula(alias)} as ${aliased}`];
|
|
645
|
+
return [(0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`)];
|
|
590
646
|
}
|
|
591
647
|
if (tableAlias) {
|
|
592
648
|
return prop.fieldNames.map(fieldName => qb.ref(fieldName).withSchema(tableAlias).as(`${tableAlias}__${fieldName}`));
|
|
@@ -620,7 +676,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
620
676
|
}
|
|
621
677
|
const ret = {};
|
|
622
678
|
this.metadata.find(entityName).relations.forEach(prop => {
|
|
623
|
-
if (prop.
|
|
679
|
+
if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY && data[prop.name]) {
|
|
624
680
|
ret[prop.name] = data[prop.name].map((item) => core_1.Utils.asArray(item));
|
|
625
681
|
delete data[prop.name];
|
|
626
682
|
}
|
|
@@ -663,7 +719,11 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
663
719
|
});
|
|
664
720
|
/* istanbul ignore else */
|
|
665
721
|
if (this.platform.allowsMultiInsert()) {
|
|
666
|
-
await this.nativeInsertMany(prop.pivotEntity, items, {
|
|
722
|
+
await this.nativeInsertMany(prop.pivotEntity, items, {
|
|
723
|
+
...options,
|
|
724
|
+
convertCustomTypes: false,
|
|
725
|
+
processCollections: false,
|
|
726
|
+
});
|
|
667
727
|
}
|
|
668
728
|
else {
|
|
669
729
|
await core_1.Utils.runSerial(items, item => {
|
|
@@ -679,7 +739,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
679
739
|
const meta = (0, core_1.helper)(entity).__meta;
|
|
680
740
|
const qb = this.createQueryBuilder(entity.constructor.name, options.ctx).unsetFlag(core_1.QueryFlag.CONVERT_CUSTOM_TYPES).withSchema(options.schema ?? meta.schema);
|
|
681
741
|
const cond = core_1.Utils.getPrimaryKeyCond(entity, meta.primaryKeys);
|
|
682
|
-
qb.select('1').where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
742
|
+
qb.select((0, core_1.raw)('1')).where(cond).setLockMode(options.lockMode, options.lockTableAliases);
|
|
683
743
|
await this.rethrow(qb.execute());
|
|
684
744
|
}
|
|
685
745
|
buildJoinedPropsOrderBy(entityName, qb, meta, populate, parentPath) {
|
|
@@ -691,7 +751,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
691
751
|
const path = `${parentPath ? parentPath : entityName}.${relation.field}`;
|
|
692
752
|
const propAlias = qb.getAliasForJoinPath(path);
|
|
693
753
|
if (propOrderBy) {
|
|
694
|
-
|
|
754
|
+
core_1.Utils.keys(propOrderBy).forEach(field => {
|
|
695
755
|
orderBy.push({ [`${propAlias}.${field}`]: propOrderBy[field] });
|
|
696
756
|
});
|
|
697
757
|
}
|
|
@@ -718,10 +778,10 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
718
778
|
return ret;
|
|
719
779
|
}
|
|
720
780
|
processField(meta, prop, field, ret, populate, joinedProps, qb) {
|
|
721
|
-
if (!prop || (prop.
|
|
781
|
+
if (!prop || (prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner)) {
|
|
722
782
|
return;
|
|
723
783
|
}
|
|
724
|
-
if (prop.
|
|
784
|
+
if (prop.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
725
785
|
if (prop.object) {
|
|
726
786
|
ret.push(prop.fieldNames[0]);
|
|
727
787
|
return;
|
|
@@ -736,7 +796,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
736
796
|
return;
|
|
737
797
|
}
|
|
738
798
|
if (prop.fieldNames) {
|
|
739
|
-
ret.push(prop.fieldNames
|
|
799
|
+
ret.push(...prop.fieldNames);
|
|
740
800
|
}
|
|
741
801
|
}
|
|
742
802
|
buildFields(meta, populate, joinedProps, qb, fields) {
|
|
@@ -745,6 +805,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
745
805
|
const requiresSQLConversion = meta.props.some(p => p.customType?.convertToJSValueSQL);
|
|
746
806
|
const hasExplicitFields = !!fields;
|
|
747
807
|
const ret = [];
|
|
808
|
+
let addFormulas = false;
|
|
748
809
|
if (joinedProps.length > 0) {
|
|
749
810
|
ret.push(...this.getFieldsForJoinedLoad(qb, meta, fields, populate));
|
|
750
811
|
}
|
|
@@ -770,17 +831,19 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
|
|
|
770
831
|
else if (lazyProps.filter(p => !p.formula).length > 0) {
|
|
771
832
|
const props = meta.props.filter(prop => this.platform.shouldHaveColumn(prop, populate, false));
|
|
772
833
|
ret.push(...core_1.Utils.flatten(props.filter(p => !lazyProps.includes(p)).map(p => p.fieldNames)));
|
|
834
|
+
addFormulas = true;
|
|
773
835
|
}
|
|
774
836
|
else if (hasLazyFormulas || requiresSQLConversion) {
|
|
775
837
|
ret.push('*');
|
|
838
|
+
addFormulas = true;
|
|
776
839
|
}
|
|
777
|
-
if (ret.length > 0 && !hasExplicitFields) {
|
|
840
|
+
if (ret.length > 0 && !hasExplicitFields && addFormulas) {
|
|
778
841
|
meta.props
|
|
779
842
|
.filter(prop => prop.formula && !lazyProps.includes(prop))
|
|
780
843
|
.forEach(prop => {
|
|
781
844
|
const alias = qb.ref(qb.alias).toString();
|
|
782
845
|
const aliased = qb.ref(prop.fieldNames[0]).toString();
|
|
783
|
-
ret.push(`${prop.formula(alias)} as ${aliased}`);
|
|
846
|
+
ret.push((0, core_1.raw)(`${prop.formula(alias)} as ${aliased}`));
|
|
784
847
|
});
|
|
785
848
|
meta.props
|
|
786
849
|
.filter(prop => prop.customType?.convertToDatabaseValueSQL || prop.customType?.convertToJSValueSQL)
|
package/AbstractSqlPlatform.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Constructor, EntityManager, EntityRepository, IDatabaseDriver, MikroORM } from '@mikro-orm/core';
|
|
2
2
|
import { Platform } from '@mikro-orm/core';
|
|
3
3
|
import type { SchemaHelper } from './schema';
|
|
4
|
-
import {
|
|
4
|
+
import { SqlSchemaGenerator } from './schema';
|
|
5
5
|
export declare abstract class AbstractSqlPlatform extends Platform {
|
|
6
6
|
protected readonly schemaHelper?: SchemaHelper;
|
|
7
7
|
usesPivotTable(): boolean;
|
|
@@ -10,7 +10,7 @@ export declare abstract class AbstractSqlPlatform extends Platform {
|
|
|
10
10
|
getSchemaHelper(): SchemaHelper | undefined;
|
|
11
11
|
/** @inheritDoc */
|
|
12
12
|
lookupExtensions(orm: MikroORM): void;
|
|
13
|
-
getSchemaGenerator(driver: IDatabaseDriver, em?: EntityManager):
|
|
13
|
+
getSchemaGenerator(driver: IDatabaseDriver, em?: EntityManager): SqlSchemaGenerator;
|
|
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;
|
package/AbstractSqlPlatform.js
CHANGED
|
@@ -20,13 +20,16 @@ class AbstractSqlPlatform extends core_1.Platform {
|
|
|
20
20
|
}
|
|
21
21
|
/** @inheritDoc */
|
|
22
22
|
lookupExtensions(orm) {
|
|
23
|
-
schema_1.
|
|
23
|
+
schema_1.SqlSchemaGenerator.register(orm);
|
|
24
24
|
}
|
|
25
25
|
/* istanbul ignore next: kept for type inference only */
|
|
26
26
|
getSchemaGenerator(driver, em) {
|
|
27
|
-
return new schema_1.
|
|
27
|
+
return new schema_1.SqlSchemaGenerator(em ?? driver);
|
|
28
28
|
}
|
|
29
29
|
quoteValue(value) {
|
|
30
|
+
if (core_1.Utils.isRawSql(value)) {
|
|
31
|
+
return this.formatQuery(value.sql, value.params ?? []);
|
|
32
|
+
}
|
|
30
33
|
if (this.isRaw(value)) {
|
|
31
34
|
return value;
|
|
32
35
|
}
|
|
@@ -45,22 +48,26 @@ class AbstractSqlPlatform extends core_1.Platform {
|
|
|
45
48
|
let j = 0;
|
|
46
49
|
let pos = 0;
|
|
47
50
|
let ret = '';
|
|
51
|
+
if (sql[0] === '?' && sql[1] !== '?') {
|
|
52
|
+
ret += this.quoteValue(params[j++]);
|
|
53
|
+
pos = 1;
|
|
54
|
+
}
|
|
48
55
|
while (pos < sql.length) {
|
|
49
56
|
const idx = sql.indexOf('?', pos + 1);
|
|
50
57
|
if (idx === -1) {
|
|
51
58
|
ret += sql.substring(pos, sql.length);
|
|
52
59
|
break;
|
|
53
60
|
}
|
|
54
|
-
if (sql.
|
|
55
|
-
ret += sql.
|
|
61
|
+
if (sql.substring(idx - 1, idx + 1) === '\\?') {
|
|
62
|
+
ret += sql.substring(pos, idx - 1) + '?';
|
|
56
63
|
pos = idx + 1;
|
|
57
64
|
}
|
|
58
|
-
else if (sql.
|
|
59
|
-
ret += sql.
|
|
65
|
+
else if (sql.substring(idx, idx + 2) === '??') {
|
|
66
|
+
ret += sql.substring(pos, idx) + this.quoteIdentifier(params[j++]);
|
|
60
67
|
pos = idx + 2;
|
|
61
68
|
}
|
|
62
69
|
else {
|
|
63
|
-
ret += sql.
|
|
70
|
+
ret += sql.substring(pos, idx) + this.quoteValue(params[j++]);
|
|
64
71
|
pos = idx + 1;
|
|
65
72
|
}
|
|
66
73
|
}
|
package/MonkeyPatchable.d.ts
CHANGED