From cabfc6a53618a999746040c76f6572c8bdf5acb2 Mon Sep 17 00:00:00 2001 From: maxeljkin Date: Sat, 12 Oct 2019 04:43:22 +0300 Subject: [PATCH 1/4] refactor(bluebird): remove Bluebird.bind --- lib/dialects/sqlite3/schema/ddl.js | 123 ++++++++++++----------------- lib/migrate/Migrator.js | 3 +- lib/runner.js | 21 +++-- lib/seed/Seeder.js | 68 +++++++--------- 4 files changed, 91 insertions(+), 124 deletions(-) diff --git a/lib/dialects/sqlite3/schema/ddl.js b/lib/dialects/sqlite3/schema/ddl.js index 67d52ea76d..c1c81317a9 100644 --- a/lib/dialects/sqlite3/schema/ddl.js +++ b/lib/dialects/sqlite3/schema/ddl.js @@ -4,7 +4,6 @@ // columns and changing datatypes. // ------- -const Bluebird = require('bluebird'); const { assign, uniqueId, @@ -16,7 +15,8 @@ const { fromPairs, some, negate, - isEmpty + isEmpty, + chunk, } = require('lodash'); // So altering the schema in SQLite3 is a major pain. @@ -83,52 +83,34 @@ assign(SQLite3_DDL.prototype, { copyData() { return this.trx .raw(`SELECT * FROM "${this.tableName()}"`) - .bind(this) - .then(this.insertChunked(20, this.alteredName)); + .then((result) => + this.insertChunked(20, this.alteredName, identity, result) + ); }, reinsertData(iterator) { - return function() { - return this.trx - .raw(`SELECT * FROM "${this.alteredName}"`) - .bind(this) - .then(this.insertChunked(20, this.tableName(), iterator)); - }; + return this.trx + .raw(`SELECT * FROM "${this.alteredName}"`) + .then((result) => + this.insertChunked(20, this.tableName(), iterator, result) + ); }, - insertChunked(amount, target, iterator) { + async insertChunked(chunkSize, target, iterator, result) { iterator = iterator || identity; - return function(result) { - let batch = []; - const ddl = this; - return Bluebird.reduce( - result, - function(memo, row) { - memo++; - batch.push(row); - if (memo % 20 === 0 || memo === result.length) { - return ddl.trx - .queryBuilder() - .table(target) - .insert(map(batch, iterator)) - .then(function() { - batch = []; - }) - .then(() => memo); - } - return memo; - }, - 0 - ); - }; + const chunked = chunk(result, chunkSize); + for (const batch of chunked) { + await this.trx + .queryBuilder() + .table(target) + .insert(map(batch, iterator)); + } }, createTempTable(createTable) { - return function() { - return this.trx.raw( - createTable.sql.replace(this.tableName(), this.alteredName) - ); - }; + return this.trx.raw( + createTable.sql.replace(this.tableName(), this.alteredName) + ); }, _doReplace(sql, from, to) { @@ -172,7 +154,7 @@ assign(SQLite3_DDL.prototype, { const fromIdentifier = from.replace(/[`"'[\]]/g, ''); - args = args.map(function(item) { + args = args.map((item) => { let split = item.trim().split(' '); // SQLite supports all quoting mechanisms prevalent in all major dialects of SQL @@ -185,7 +167,7 @@ assign(SQLite3_DDL.prototype, { new RegExp(`\`${fromIdentifier}\``, 'i'), new RegExp(`"${fromIdentifier}"`, 'i'), new RegExp(`'${fromIdentifier}'`, 'i'), - new RegExp(`\\[${fromIdentifier}\\]`, 'i') + new RegExp(`\\[${fromIdentifier}\\]`, 'i'), ]; if (fromIdentifier.match(/^\S+$/)) { fromMatchCandidates.push(new RegExp(`\\b${fromIdentifier}\\b`, 'i')); @@ -195,7 +177,10 @@ assign(SQLite3_DDL.prototype, { some(fromMatchCandidates, (c) => target.match(c)); const replaceFromIdentifier = (target) => - fromMatchCandidates.reduce((result, candidate) => result.replace(candidate, to), target); + fromMatchCandidates.reduce( + (result, candidate) => result.replace(candidate, to), + target + ); if (doesMatchFromIdentifier(split[0])) { // column definition @@ -213,7 +198,7 @@ assign(SQLite3_DDL.prototype, { // columns from this table listed between (); replace // one if it matches if (/primary|unique/i.test(split[idx])) { - const ret = item.replace(/\(.*\)/, replaceFromIdentifier); + const ret = item.replace(/\(.*\)/, replaceFromIdentifier); // If any member columns are dropped then uniqueness/pk constraint // can not be retained if (ret !== item && isEmpty(to)) return ''; @@ -240,7 +225,10 @@ assign(SQLite3_DDL.prototype, { if (split[1].slice(0, tableName.length) === tableName) { // self-referential foreign key - const replacedKeyTargetSpec = split[1].replace(/\(.*\)/, replaceFromIdentifier); + const replacedKeyTargetSpec = split[1].replace( + /\(.*\)/, + replaceFromIdentifier + ); if (split[1] !== replacedKeyTargetSpec) { // If we are removing one or more columns of a foreign // key, then we should not retain the key at all @@ -289,20 +277,10 @@ assign(SQLite3_DDL.prototype, { ) ); - return Bluebird.bind(this) - .then(this.createTempTable(createTable)) - .then(this.copyData) - .then(this.dropOriginal) - .then(function() { - return this.trx.raw(newSql); - }) - .then( - this.reinsertData(function(row) { - row[mappedTo] = row[mappedFrom]; - return omit(row, mappedFrom); - }) - ) - .then(this.dropTempTable); + return this.reinsertMapped(createTable, newSql, (row) => { + row[mappedTo] = row[mappedFrom]; + return omit(row, mappedFrom); + }); }, { connection: this.connection } ); @@ -312,10 +290,9 @@ assign(SQLite3_DDL.prototype, { return this.client.transaction( (trx) => { this.trx = trx; - return Bluebird.all(columns.map((column) => this.getColumn(column))) - .bind(this) - .then(this.getTableSql) - .then(function(sql) { + return Promise.all(columns.map((column) => this.getColumn(column))) + .then(() => this.getTableSql()) + .then((sql) => { const createTable = sql[0]; let newSql = createTable.sql; columns.forEach((column) => { @@ -330,20 +307,24 @@ assign(SQLite3_DDL.prototype, { fromPairs(columns.map((column) => [column, column])) ) ); - return Bluebird.bind(this) - .then(this.createTempTable(createTable)) - .then(this.copyData) - .then(this.dropOriginal) - .then(function() { - return this.trx.raw(newSql); - }) - .then(this.reinsertData((row) => omit(row, ...mappedColumns))) - .then(this.dropTempTable); + return this.reinsertMapped(createTable, newSql, (row) => + omit(row, ...mappedColumns) + ); }); }, { connection: this.connection } ); }, + + reinsertMapped(createTable, newSql, mapRow) { + return Promise.resolve() + .then(() => this.createTempTable(createTable)) + .then(() => this.copyData()) + .then(() => this.dropOriginal()) + .then(() => this.trx.raw(newSql)) + .then(() => this.reinsertData(mapRow)) + .then(() => this.dropTempTable()); + }, }); module.exports = SQLite3_DDL; diff --git a/lib/migrate/Migrator.js b/lib/migrate/Migrator.js index d6a7bb31cb..9624bfc82d 100644 --- a/lib/migrate/Migrator.js +++ b/lib/migrate/Migrator.js @@ -1,6 +1,5 @@ // Migrator // ------- -const Bluebird = require('bluebird'); const { differenceWith, each, @@ -486,7 +485,7 @@ class Migrator { _waterfallBatch(batchNo, migrations, direction, trx) { const trxOrKnex = trx || this.knex; const { tableName, schemaName, disableTransactions } = this.config; - let current = Bluebird.bind({ failed: false, failedOn: 0 }); + let current = Promise.resolve(); const log = []; each(migrations, (migration) => { const name = this.config.migrationSource.getMigrationName(migration); diff --git a/lib/runner.js b/lib/runner.js index 1b9e4f30bd..8b14b82038 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -219,17 +219,16 @@ Object.assign(Runner.prototype, { // In the case of the "schema builder" we call `queryArray`, which runs each // of the queries in sequence. - queryArray(queries) { - return queries.length === 1 - ? this.query(queries[0]) - : Bluebird.bind(this) - .return(queries) - .reduce(function(memo, query) { - return this.query(query).then(function(resp) { - memo.push(resp); - return memo; - }); - }, []); + async queryArray(queries) { + if (queries.length === 1) { + return this.query(queries[0]); + } + + const results = []; + for (const query of queries) { + results.push(await this.query(query)); + } + return results; }, // Check whether there's a transaction flag, and that it has a connection. diff --git a/lib/seed/Seeder.js b/lib/seed/Seeder.js index b4cda7fbe5..e3cc5e52fa 100644 --- a/lib/seed/Seeder.js +++ b/lib/seed/Seeder.js @@ -29,7 +29,7 @@ class Seeder { // Runs seed files for the given environment. async run(config) { this.config = this.setConfig(config); - const [all] = await this._seedData(); + const [all] = await this._listAll(); const files = config && config.specific ? all.filter((file) => file === config.specific) @@ -78,15 +78,10 @@ class Seeder { } } - // Run seed files, in sequence. +// Run seed files, in sequence. _runSeeds(seeds) { - return Bluebird.all(map(seeds, bind(this._validateSeedStructure, this))) - .bind(this) - .then(function(seeds) { - return Bluebird.bind(this).then(function() { - return this._waterfallBatch(seeds); - }); - }); + seeds.forEach((seed) => this._validateSeedStructure(seed)); + return this._waterfallBatch(seeds); } // Validates seed files by requiring and checking for a `seed` function. @@ -135,40 +130,33 @@ class Seeder { return seedPath; } - // Runs a batch of seed files. - _waterfallBatch(seeds) { +// Runs a batch of seed files. + async _waterfallBatch(seeds) { const { knex } = this; const seedDirectory = this._absoluteConfigDir(); - let current = Bluebird.bind({ failed: false, failedOn: 0 }); const log = []; - each(seeds, (seed) => { - const name = path.join(seedDirectory, seed); - seed = require(name); - - // Run each seed file. - current = current.then(() => - // Nesting promise to prevent bubbling up of error on catch - Promise.resolve() - .then(() => seed.seed(knex)) - .then(() => log.push(name)) - .catch((originalError) => { - const error = new Error( - `Error while executing "${name}" seed: ${originalError.message}` - ); - error.original = originalError; - error.stack = - error.stack - .split('\n') - .slice(0, 2) - .join('\n') + - '\n' + - originalError.stack; - throw error; - }) - ); - }); - - return current.then(() => [log]); + for (const seedName of seeds) { + const seedPath = path.join(seedDirectory, seedName); + const seed = require(seedPath); + try { + await seed.seed(knex); + log.push(seedPath); + } catch (originalError) { + const error = new Error( + `Error while executing "${seedPath}" seed: ${originalError.message}` + ); + error.original = originalError; + error.stack = + error.stack + .split('\n') + .slice(0, 2) + .join('\n') + + '\n' + + originalError.stack; + throw error; + } + } + return [log]; } _absoluteConfigDir() { From 2d979e579cc3f5b9035024962f91339220d720c0 Mon Sep 17 00:00:00 2001 From: maxeljkin Date: Mon, 14 Oct 2019 23:38:15 +0300 Subject: [PATCH 2/4] chore(seeder): remove unused imports --- lib/seed/Seeder.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/seed/Seeder.js b/lib/seed/Seeder.js index e3cc5e52fa..946277cbdb 100644 --- a/lib/seed/Seeder.js +++ b/lib/seed/Seeder.js @@ -6,15 +6,7 @@ const path = require('path'); const { promisify } = require('util'); const mkdirp = require('mkdirp'); const Bluebird = require('bluebird'); -const { - filter, - includes, - map, - bind, - template, - each, - extend, -} = require('lodash'); +const { filter, includes, template, extend } = require('lodash'); const { writeJsFileUsingTemplate } = require('../util/template'); // The new seeds we're performing, typically called from the `knex.seed` @@ -78,7 +70,7 @@ class Seeder { } } -// Run seed files, in sequence. + // Run seed files, in sequence. _runSeeds(seeds) { seeds.forEach((seed) => this._validateSeedStructure(seed)); return this._waterfallBatch(seeds); @@ -130,7 +122,7 @@ class Seeder { return seedPath; } -// Runs a batch of seed files. + // Runs a batch of seed files. async _waterfallBatch(seeds) { const { knex } = this; const seedDirectory = this._absoluteConfigDir(); From 27203a7c1e9f1cafb169b65d58d0fcd3c4d89187 Mon Sep 17 00:00:00 2001 From: maxeljkin Date: Mon, 14 Oct 2019 23:38:40 +0300 Subject: [PATCH 3/4] chore(seeder): delete unused method --- lib/seed/Seeder.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/seed/Seeder.js b/lib/seed/Seeder.js index 946277cbdb..b134157d38 100644 --- a/lib/seed/Seeder.js +++ b/lib/seed/Seeder.js @@ -54,11 +54,6 @@ class Seeder { ); } - // Gets the seed file list from the specified seed directory. - _seedData() { - return Bluebird.join(this._listAll()); - } - // Ensures a folder for the seeds exist, dependent on the // seed config settings. async _ensureFolder() { From 5e9343ee9add67de41b52d93c1722c4c7271df65 Mon Sep 17 00:00:00 2001 From: maxeljkin Date: Tue, 15 Oct 2019 01:06:29 +0300 Subject: [PATCH 4/4] fix(seeder): fix method usage --- lib/seed/Seeder.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/seed/Seeder.js b/lib/seed/Seeder.js index b134157d38..1d29ded33d 100644 --- a/lib/seed/Seeder.js +++ b/lib/seed/Seeder.js @@ -5,8 +5,7 @@ const fs = require('fs'); const path = require('path'); const { promisify } = require('util'); const mkdirp = require('mkdirp'); -const Bluebird = require('bluebird'); -const { filter, includes, template, extend } = require('lodash'); +const { filter, includes, extend } = require('lodash'); const { writeJsFileUsingTemplate } = require('../util/template'); // The new seeds we're performing, typically called from the `knex.seed` @@ -21,7 +20,7 @@ class Seeder { // Runs seed files for the given environment. async run(config) { this.config = this.setConfig(config); - const [all] = await this._listAll(); + const all = await this._listAll(); const files = config && config.specific ? all.filter((file) => file === config.specific) @@ -87,14 +86,6 @@ class Seeder { ); } - // Generates the stub template for the current seed file, returning a compiled template. - _generateStubTemplate() { - const stubPath = this._getStubPath(); - return promisify(fs.readFile)(stubPath).then( - (stub) => template(stub.toString(), { variable: 'd' }) - ); - } - _getNewStubFileName(name) { if (name[0] === '-') name = name.slice(1); return name + '.' + this.config.extension;