Skip to content

Commit

Permalink
perf(core): use raw sql for batch updates
Browse files Browse the repository at this point in the history
Related: #732
  • Loading branch information
B4nan committed Oct 12, 2020
1 parent 3cafbf3 commit 1089c57
Showing 1 changed file with 21 additions and 11 deletions.
32 changes: 21 additions & 11 deletions packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,35 +289,45 @@ export abstract class AbstractSqlDriver<C extends AbstractSqlConnection = Abstra
const keys = new Set<string>();
data.forEach(row => Object.keys(row).forEach(k => keys.add(k)));
const pkCond = Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames)).map(pk => `${this.platform.quoteIdentifier(pk)} = ?`).join(' and ');
const params: any[] = [];
let sql = `update ${this.platform.quoteIdentifier(meta.collection)} set `;

keys.forEach(key => {
const prop = meta.properties[key];
prop.fieldNames.forEach((fieldName: string, fieldNameIdx: number) => {
let sql = `case`;
const params: any[] = [];
sql += `${this.platform.quoteIdentifier(fieldName)} = case`;
where.forEach((cond, idx) => {
if (key in data[idx]) {
const pks = Utils.getOrderedPrimaryKeys(cond as Dictionary, meta);
sql += ` when (${pkCond}) then ?`;
params.push(...pks, prop.fieldNames.length > 1 ? data[idx][key][fieldNameIdx] : data[idx][key]);
}
});
sql += ` else ${this.platform.quoteIdentifier(fieldName)} end`;
values[fieldName] = knex.raw(sql, params);
sql += ` else ${this.platform.quoteIdentifier(fieldName)} end, `;

return sql;
});
});

const qb = this.createQueryBuilder<T>(entityName, ctx, true)
.unsetFlag(QueryFlag.CONVERT_CUSTOM_TYPES)
.update(values)
.where({ [Utils.getPrimaryKeyHash(meta.primaryKeys)]: where });
sql = sql.substr(0, sql.length - 2) + ' where ';
const pks = Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames));
sql += pks.length > 1 ? `(${pks.map(pk => `${this.platform.quoteIdentifier(pk)}`).join(', ')})` : this.platform.quoteIdentifier(pks[0]);

const res = await this.rethrow(qb.execute('run', false));
const conds = where.map(cond => {
if (pks.length > 1) {
meta.primaryKeys.forEach(pk => params.push(cond[pk as string]));
return `(${new Array(pks.length).fill('?').join(', ')})`;
}

const pkConds = data.map((_, idx) => Utils.extractPK<T>(where[idx], meta)!) as Primary<T>[][];
params.push(cond);
return '?';
});
const values = pks.length > 1 && this.platform.requiresValuesKeyword() ? 'values ' : '';
sql += ` in (${values}${conds.join(', ')})`;
const res = await this.rethrow(this.execute<QueryResult>(sql, params, 'run', ctx));

for (let i = 0; i < collections.length; i++) {
await this.processManyToMany<T>(meta, pkConds[i], collections[i], false, ctx);
await this.processManyToMany<T>(meta, where[i] as Primary<T>[], collections[i], false, ctx);
}

return res;
Expand Down

0 comments on commit 1089c57

Please sign in to comment.