const Promise = require('bluebird'); const { chunk } = require('../../utils/objectUtils'); const { isPostgres } = require('../../utils/knexUtils'); const POSTGRES_INSERT_BATCH_SIZE = 100; module.exports = builder => { // Postgres is the only db engine that returns identifiers of all inserted rows. Therefore // we can insert batches only with postgres. const batchSize = isPostgres(builder.knex()) ? POSTGRES_INSERT_BATCH_SIZE : 1; return tableInsertion => { const inputs = []; const others = []; const queries = []; let insertQuery = tableInsertion.modelClass.query().childQueryOf(builder); const items = tableInsertion.items; for (let i = 0, l = items.length; i < l; ++i) { const item = items[i]; const { model, relation } = item; // We need to validate here since at this point the models should no longer contain any special properties. const json = model.$validate(model, { dataPath: item.node.dataPath }); // Set the return value back to model in case defaults were set. model.$set(json); if (relation) { others.push(model); } else { inputs.push(model); } } batchInsert(inputs, insertQuery.clone().copyFrom(builder, /returning/), batchSize, queries); batchInsert(others, insertQuery.clone(), batchSize, queries); return Promise.map(queries, query => query.query, { concurrency: tableInsertion.modelClass.concurrency }); }; }; function batchInsert(models, queryBuilder, batchSize, queries) { const batches = chunk(models, batchSize); for (let i = 0, l = batches.length; i < l; ++i) { queries.push({ query: queryBuilder.clone().insert(batches[i]) }); } }