UNPKG

sql-fixtures

Version:

Populate a SQL database with fixture data

192 lines (165 loc) 4.87 kB
var _ = require("lodash"); var knex = require("knex"); var bluebird = require("bluebird"); var util = require("./util"); var executeFkQueries = require("./execute-fk-queries"); var generateSpecIds = require("./generate-spec-ids"); var prioritize = require("./prioritize"); var insertRecords = require("./insert-records"); var resolveDependencies = require("./resolve-dependencies"); var unescape = require("./unescape"); function addToFinalResult(finalResult, levelResults, originalConfig) { levelResults.forEach(function (levelResult) { _.forIn(levelResult, function (records, table, levelResult) { finalResult[table] = finalResult[table] || []; _.each(records, function (record) { var index = _.findIndex(util.asArray(originalConfig[table]), { specId: record.specId, }); finalResult[table][index] = record; }); }); }); return finalResult; } function fail(error, callback) { return bluebird.reject(error).nodeify(callback); } function stripSpecIds(result) { _.forIn(result, function (records, table) { _.each(records, function (record) { delete record.specId; }); }); return result; } function clone(object) { return _.mapValues(object, function (value) { if (_.isArray(value)) { return _.map(value, _.clone); } return _.clone(value); }); } function isKnexInstance(obj) { return ( obj && _.isFunction(obj.where) && _.isFunction(obj.andWhere) && _.isFunction(obj.insert) ); } function isAllTablesEmpty(dataConfig) { return _.every(Object.keys(dataConfig), function (key) { return dataConfig[key].length === 0; }); } function FixtureGenerator(knexInstanceOrConnectionConfig) { if (isKnexInstance(knexInstanceOrConnectionConfig)) { this.knex = knexInstanceOrConnectionConfig; } else { this._connectionConfig = knexInstanceOrConnectionConfig; this.knex = knex(knexInstanceOrConnectionConfig); } } FixtureGenerator.prototype.create = function resolveQueriesAndCreateRecords( dataConfig, options, callback ) { dataConfig = clone(dataConfig); if (_.isFunction(options)) { callback = options; } options = options || {}; if (isAllTablesEmpty(dataConfig)) { // user is asking us to insert no rows. Which is a strange, but valid, request. // Rather than talk to the db at all, we can immediately return in this scenario. return bluebird.resolve(dataConfig).nodeify(callback); } var withSpecIds = generateSpecIds(dataConfig); var prioritized = prioritize(withSpecIds); if (prioritized instanceof Error) { return fail(prioritized, callback); } var knexInst = (this.knex = this.knex || knex(this._connectionConfig)); var fkQueries = executeFkQueries(dataConfig, knexInst); var mainPromise = bluebird.all(fkQueries).then(function createRecords() { return bluebird .reduce( prioritized, function (buildingFinalResult, priorityLevel) { priorityLevel = resolveDependencies( buildingFinalResult, priorityLevel ); priorityLevel = unescape(priorityLevel); var priorityLevelPromises = insertRecords( knexInst, priorityLevel, options.unique, options.showWarning ); return bluebird .all(priorityLevelPromises) .then(function (levelResults) { return addToFinalResult( buildingFinalResult, levelResults, withSpecIds ); }); }, {} ) .then(function (finalResult) { return stripSpecIds(finalResult); }); }); return mainPromise.nodeify(callback); }; FixtureGenerator.prototype.destroy = function destroy(callback) { if (this.knex) { return bluebird .resolve() .bind(this) .then(function () { return this.knex.destroy(); }) .tap(function () { this.knex = null; }) .nodeify(callback); } else { return bluebird.resolve().nodeify(callback); } }; var singleton; FixtureGenerator.create = function staticCreateRecords( connectionConfig, dataConfig, options, callback ) { if (!singleton) { singleton = new FixtureGenerator(connectionConfig); } return singleton.create(dataConfig, options, callback); }; FixtureGenerator.destroy = function staticDestroy(callback) { if (!singleton) { return bluebird.resolve().nodeify(callback); } // TODO: look into using bluebird's disposer pattern return bluebird .resolve() .then(function () { return singleton.destroy(); }) .nodeify(callback) .finally(function () { singleton = null; }); }; FixtureGenerator.disconnect = FixtureGenerator.destroy; module.exports = FixtureGenerator;