Skip to content
This repository was archived by the owner on Sep 2, 2025. It is now read-only.

Commit 4c3b529

Browse files
authored
Batch insert support (#127)
* Batch insert support. Closes #125 * don't use .returning() with redshift dialect * add a test case: create with $noSelect and without allowedInsert * fix: Objection.js hooks don't work with '.toKnexQuery()' method
1 parent db29655 commit 4c3b529

File tree

1 file changed

+92
-43
lines changed

1 file changed

+92
-43
lines changed

src/index.js

Lines changed: 92 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -616,58 +616,107 @@ class Service extends AdapterService {
616616
});
617617
}
618618

619-
/**
620-
* `create` service function for Objection.
621-
* @param {object} data
622-
* @param {object} params
623-
*/
624-
async _create (data, params) {
625-
const transaction = await this._createTransaction(params);
626-
const create = (data, params) => {
627-
const q = this._createQuery(params);
628-
const allowedUpsert = this.mergeRelations(this.allowedUpsert, params.mergeAllowUpsert);
629-
const allowedInsert = this.mergeRelations(this.allowedInsert, params.mergeAllowInsert);
630-
631-
if (this.createUseUpsertGraph) {
632-
if (allowedUpsert) {
633-
q.allowGraph(allowedUpsert);
634-
}
635-
q.upsertGraphAndFetch(data, this.upsertGraphOptions);
636-
} else if (allowedInsert) {
637-
q.allowGraph(allowedInsert);
638-
q.insertGraph(data, this.insertGraphOptions);
639-
} else {
640-
q.insert(data, this.id);
641-
}
642-
643-
return q
644-
.then(row => {
645-
if (params.query && params.query.$noSelect) { return data; }
646-
647-
let id;
619+
_getCreatedRecords (insertResults, inputData, params) {
620+
if (params.query && params.query.$noSelect) {
621+
return inputData;
622+
}
623+
if (!Array.isArray(insertResults)) {
624+
insertResults = [insertResults];
625+
}
648626

649-
if (Array.isArray(this.id)) {
650-
id = [];
627+
const findQuery = Object.assign({ $and: [] }, params.query);
628+
const idsQueries = [];
651629

652-
for (const idKey of this.id) {
653-
id.push(row && row[idKey] ? row[idKey] : data[idKey]);
654-
}
630+
if (Array.isArray(this.id)) {
631+
for (const insertResult of insertResults) {
632+
const ids = [];
633+
for (const idKey of this.id) {
634+
if (idKey in insertResult) {
635+
ids.push(insertResult[idKey]);
655636
} else {
656-
id = row && row[this.id] ? row[this.id] : data[this.id];
637+
return inputData;
657638
}
639+
}
640+
idsQueries.push(this.getIdsQuery(ids));
641+
}
642+
} else {
643+
const ids = [];
644+
for (const insertResult of insertResults) {
645+
if (this.id in insertResult) {
646+
ids.push(insertResult[this.id]);
647+
} else {
648+
return inputData;
649+
}
650+
}
651+
idsQueries.push(this.getIdsQuery(null, ids));
652+
}
658653

659-
if (!id || (Array.isArray(id) && !id.length)) { return data; }
654+
if (idsQueries.length > 1) {
655+
findQuery.$and.push({ $or: idsQueries });
656+
} else {
657+
findQuery.$and = findQuery.$and.concat(idsQueries);
658+
}
660659

661-
return this._get(id, params);
662-
})
663-
.catch(errorHandler);
664-
};
660+
return this._find(Object.assign({}, params, { query: findQuery }))
661+
.then(page => {
662+
const records = page.data || page;
663+
if (Array.isArray(inputData)) {
664+
return records;
665+
}
666+
return records[0];
667+
});
668+
}
665669

666-
if (Array.isArray(data)) {
667-
return Promise.all(data.map(current => create(current, params))).then(this._commitTransaction(transaction), this._rollbackTransaction(transaction));
670+
/**
671+
* @param data
672+
* @param params
673+
* @returns {Promise<Object|Object[]>}
674+
* @private
675+
*/
676+
_batchInsert (data, params) {
677+
const { dialect } = this.Model.knex().client;
678+
// batch insert only works with Postgresql and SQL Server
679+
if (dialect === 'postgresql' || dialect === 'mssql') {
680+
return this._createQuery(params)
681+
.insert(data)
682+
.returning(this.id);
683+
}
684+
if (!Array.isArray(data)) {
685+
return this._createQuery(params).insert(data);
668686
}
687+
const promises = data.map(dataItem => {
688+
return this._createQuery(params).insert(dataItem);
689+
});
690+
return Promise.all(promises);
691+
}
669692

670-
return create(data, params).then(this._commitTransaction(transaction), this._rollbackTransaction(transaction));
693+
/**
694+
* `create` service function for Objection.
695+
* @param {object} data
696+
* @param {object} params
697+
*/
698+
async _create (data, params) {
699+
const transaction = await this._createTransaction(params);
700+
const q = this._createQuery(params);
701+
let promise = q;
702+
const allowedUpsert = this.mergeRelations(this.allowedUpsert, params.mergeAllowUpsert);
703+
const allowedInsert = this.mergeRelations(this.allowedInsert, params.mergeAllowInsert);
704+
705+
if (this.createUseUpsertGraph) {
706+
if (allowedUpsert) {
707+
q.allowGraph(allowedUpsert);
708+
}
709+
q.upsertGraph(data, this.upsertGraphOptions);
710+
} else if (allowedInsert) {
711+
q.allowGraph(allowedInsert);
712+
q.insertGraph(data, this.insertGraphOptions);
713+
} else {
714+
promise = this._batchInsert(data, params);
715+
}
716+
return promise
717+
.then(insertResults => this._getCreatedRecords(insertResults, data, params))
718+
.then(this._commitTransaction(transaction), this._rollbackTransaction(transaction))
719+
.catch(errorHandler);
671720
}
672721

673722
/**

0 commit comments

Comments
 (0)