larvitdbmigration
Advanced tools
Comparing version 4.0.3 to 5.0.0
@@ -8,9 +8,19 @@ 'use strict'; | ||
/** | ||
* Initiate driver | ||
* | ||
* @param {object} options - | ||
* @param {object} options.log - | ||
* @param {String} options.indexName - | ||
* @param {String} options.url - ES Url | ||
* @param {String} options.tableName - | ||
* @param {String} options.migrationScriptPath - | ||
*/ | ||
function Driver(options) { | ||
const that = this; | ||
for (const option of ['log', 'indexName', 'url', 'tableName', 'migrationScriptPath']) { | ||
if (!options[option]) { | ||
throw new Error('Missing required option "' + option + '"'); | ||
} | ||
that.options = options || {}; | ||
if (! that.options.indexName) { | ||
throw new Error('Missing required option "indexName"'); | ||
this[option] = options[option]; | ||
} | ||
@@ -20,4 +30,4 @@ } | ||
Driver.prototype.getLock = function getLock(retries, cb) { | ||
const logPrefix = topLogPrefix + 'getLock() - indexName: "' + this.options.indexName + '" - '; | ||
const that = this; | ||
const {indexName, log, url} = this; | ||
const logPrefix = topLogPrefix + 'getLock() - indexName: "' + indexName + '" - '; | ||
@@ -29,13 +39,13 @@ if (typeof retries === 'function') { | ||
that.log.debug(logPrefix + 'Started'); | ||
log.debug(logPrefix + 'Started'); | ||
// Source: https://www.elastic.co/guide/en/elasticsearch/guide/current/concurrency-solutions.html | ||
request({ | ||
'method': 'PUT', | ||
'uri': that.options.url + '/fs/lock/global/_create', | ||
'json': true, | ||
'body': {} | ||
}, function (err, response) { | ||
method: 'PUT', | ||
uri: url + '/fs/lock/global/_create', | ||
json: true, | ||
body: {} | ||
}, (err, response) => { | ||
if (err) { | ||
that.log.error(logPrefix + 'Can not get lock on ' + that.options.url + '/fs/lock/global/_create'); | ||
log.error(logPrefix + 'Can not get lock on ' + url + '/fs/lock/global/_create'); | ||
@@ -47,10 +57,8 @@ return cb(err); | ||
if (retries < 100) { | ||
that.log.info(logPrefix + 'Another process is running the migrations, retry nr: ' + retries + ', wait and try again soon. StatusCode: ' + response.statusCode); | ||
log.info(logPrefix + 'Another process is running the migrations, retry nr: ' + retries + ', wait and try again soon. StatusCode: ' + response.statusCode); | ||
} else { | ||
that.log.warn(logPrefix + 'Another process is running the migrations, retry nr: ' + retries + ', wait and try again soon. StatusCode: ' + response.statusCode); | ||
log.warn(logPrefix + 'Another process is running the migrations, retry nr: ' + retries + ', wait and try again soon. StatusCode: ' + response.statusCode); | ||
} | ||
setTimeout(function () { | ||
that.getLock(retries + 1, cb); | ||
}, 500); | ||
setTimeout(() => this.getLock(retries + 1, cb), 500); | ||
@@ -60,3 +68,3 @@ return; | ||
that.log.verbose(logPrefix + 'Locked!'); | ||
log.verbose(logPrefix + 'Locked!'); | ||
@@ -68,10 +76,10 @@ cb(); | ||
Driver.prototype.rmLock = function rmLock(cb) { | ||
const logPrefix = topLogPrefix + 'rmLock() - indexName: "' + this.options.indexName + '" - '; | ||
const that = this; | ||
const {indexName, log, url} = this; | ||
const logPrefix = topLogPrefix + 'rmLock() - indexName: "' + indexName + '" - '; | ||
that.log.debug(logPrefix + 'Started'); | ||
log.debug(logPrefix + 'Started'); | ||
request.delete(that.options.url + '/fs/lock/global', function (err, response) { | ||
request.delete(url + '/fs/lock/global', (err, response) => { | ||
if (err) { | ||
that.log.error(logPrefix + 'Can not clear lock on ' + that.options.url + '/fs/lock/global'); | ||
log.error(logPrefix + 'Can not clear lock on ' + url + '/fs/lock/global'); | ||
@@ -84,3 +92,3 @@ return cb(err); | ||
that.log.warn(logPrefix + err.message); | ||
log.warn(logPrefix + err.message); | ||
@@ -90,4 +98,3 @@ return cb(err); | ||
that.log.verbose(logPrefix + 'Unlocked!'); | ||
log.verbose(logPrefix + 'Unlocked!'); | ||
cb(); | ||
@@ -97,21 +104,25 @@ }); | ||
Driver.prototype.run = function run(cb) { | ||
const logPrefix = topLogPrefix + 'run() - indexName: "' + this.options.tableName + '" - '; | ||
const indexName = this.options.indexName; | ||
/** | ||
* Run the migrations | ||
* | ||
* @return {promise} - | ||
*/ | ||
Driver.prototype.run = function run() { | ||
const {indexName, tableName, log, url} = this; | ||
const logPrefix = topLogPrefix + 'run() - indexName: "' + tableName + '" - '; | ||
const tasks = []; | ||
const that = this; | ||
let curDoc; | ||
that.log.debug(logPrefix + 'Started'); | ||
log.debug(logPrefix + 'Started'); | ||
function getDoc(cb) { | ||
const subLogPrefix = logPrefix + 'getDoc() - '; | ||
const uri = that.options.url + '/' + indexName + '/' + indexName + '/1'; | ||
const uri = url + '/' + indexName + '/' + indexName + '/1'; | ||
that.log.debug(subLogPrefix + 'Running for ' + uri); | ||
log.debug(subLogPrefix + 'Running for ' + uri); | ||
request(uri, function (err, response, body) { | ||
if (err) { | ||
that.log.error(subLogPrefix + 'GET ' + uri + ' failed, err: ' + err.message); | ||
log.error(subLogPrefix + 'GET ' + uri + ' failed, err: ' + err.message); | ||
@@ -121,3 +132,3 @@ return cb(err); | ||
that.log.debug(subLogPrefix + 'GET ' + uri + ' ' + response.statusCode + ' ' + response.statusMessage); | ||
log.debug(subLogPrefix + 'GET ' + uri + ' ' + response.statusCode + ' ' + response.statusMessage); | ||
@@ -128,3 +139,3 @@ if (response.statusCode === 200) { | ||
} catch (err) { | ||
that.log.error(subLogPrefix + 'GET ' + uri + ' invalid JSON in body, err: ' + err.message + ' string: "' + body + '"'); | ||
log.error(subLogPrefix + 'GET ' + uri + ' invalid JSON in body, err: ' + err.message + ' string: "' + body + '"'); | ||
cb(err); | ||
@@ -141,16 +152,14 @@ } | ||
// Get lock | ||
tasks.push(function (cb) { | ||
that.getLock(cb); | ||
}); | ||
tasks.push(cb => this.getLock(cb)); | ||
// Create index if it does not exist | ||
tasks.push(function (cb) { | ||
const subLogPrefix = logPrefix + 'indexName: "' + indexName + '" - '; | ||
const uri = that.options.url + '/' + indexName; | ||
tasks.push(cb => { | ||
const subLogPrefix = logPrefix + 'indexName: "' + indexName + '" - '; | ||
const uri = url + '/' + indexName; | ||
that.log.debug(subLogPrefix + 'Crating index if it did not exist'); | ||
log.debug(subLogPrefix + 'Crating index if it did not exist'); | ||
request.head(uri, function (err, response) { | ||
request.head(uri, (err, response) => { | ||
if (err) { | ||
that.log.error(subLogPrefix + 'HEAD ' + uri + ' failed, err: ' + err.message); | ||
log.error(subLogPrefix + 'HEAD ' + uri + ' failed, err: ' + err.message); | ||
@@ -161,3 +170,3 @@ return cb(err); | ||
if (response.statusCode === 200) { | ||
that.log.debug(subLogPrefix + 'Index already exists'); | ||
log.debug(subLogPrefix + 'Index already exists'); | ||
@@ -168,3 +177,3 @@ return cb(); | ||
that.log.error(subLogPrefix + err.message); | ||
log.error(subLogPrefix + err.message); | ||
@@ -174,3 +183,3 @@ return cb(err); | ||
that.log.debug(subLogPrefix + 'Index does not exist, create it'); | ||
log.debug(subLogPrefix + 'Index does not exist, create it'); | ||
@@ -180,3 +189,3 @@ // If we arrive here its a 404 - create it! | ||
if (err) { | ||
that.log.error(subLogPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
log.error(subLogPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
@@ -189,3 +198,3 @@ return cb(err); | ||
that.log.error(subLogPrefix + err.message); | ||
log.error(subLogPrefix + err.message); | ||
@@ -195,3 +204,3 @@ return cb(err); | ||
that.log.debug(subLogPrefix + 'Created!'); | ||
log.debug(subLogPrefix + 'Created!'); | ||
@@ -204,14 +213,14 @@ cb(); | ||
// Create document if it does not exist and get current document | ||
tasks.push(function (cb) { | ||
const uri = that.options.url + '/' + indexName + '/' + indexName + '/1'; | ||
tasks.push(cb => { | ||
const uri = url + '/' + indexName + '/' + indexName + '/1'; | ||
getDoc(function (err, response) { | ||
getDoc((err, response) => { | ||
if (err) return cb(err); | ||
if (response.statusCode === 404) { | ||
that.log.debug(logPrefix + 'Create database version document'); | ||
log.debug(logPrefix + 'Create database version document'); | ||
request.put({'url': uri, 'json': {'version': 0, 'status': 'finnished'}}, function (err, response) { | ||
request.put({url: uri, json: {version: 0, status: 'finnished'}}, (err, response) => { | ||
if (err) { | ||
that.log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
@@ -224,3 +233,3 @@ return cb(err); | ||
that.log.error(logPrefix + err.message); | ||
log.error(logPrefix + err.message); | ||
@@ -230,3 +239,3 @@ return cb(err); | ||
that.log.verbose(logPrefix + 'Database version document created'); | ||
log.verbose(logPrefix + 'Database version document created'); | ||
@@ -236,3 +245,3 @@ getDoc(cb); | ||
} else if (response.statusCode === 200) { | ||
that.log.debug(logPrefix + 'Database version document already exists'); | ||
log.debug(logPrefix + 'Database version document already exists'); | ||
cb(); | ||
@@ -242,3 +251,3 @@ } else { | ||
that.log.error(logPrefix + err.message); | ||
log.error(logPrefix + err.message); | ||
@@ -251,7 +260,7 @@ return cb(err); | ||
// Run scripts | ||
tasks.push(function (cb) { | ||
tasks.push(cb => { | ||
try { | ||
that.runScripts(curDoc._source.version + 1, cb); | ||
this.runScripts(curDoc._source.version + 1, cb); | ||
} catch (err) { | ||
that.log.error(logPrefix + 'Error from driver: ' + err.message); | ||
log.error(logPrefix + 'Error from driver: ' + err.message); | ||
cb(err); | ||
@@ -262,31 +271,34 @@ } | ||
// Remove lock | ||
tasks.push(function (cb) { | ||
that.rmLock(cb); | ||
tasks.push(cb => { | ||
this.rmLock(cb); | ||
}); | ||
async.series(tasks, cb); | ||
return new Promise((resolve, reject) => { | ||
async.series(tasks, err => { | ||
if (err) reject(err); | ||
else resolve(); | ||
}); | ||
}); | ||
}; | ||
Driver.prototype.runScripts = function runScripts(startVersion, cb) { | ||
const migrationScriptsPath = this.options.migrationScriptsPath; | ||
const indexName = this.options.indexName; | ||
const logPrefix = topLogPrefix + 'runScripts() - indexName: "' + this.options.indexName + '" - '; | ||
const {migrationScriptPath, log, indexName, url} = this; | ||
const logPrefix = topLogPrefix + 'runScripts() - indexName: "' + indexName + '" - '; | ||
const tasks = []; | ||
const that = this; | ||
const uri = that.options.url + '/' + indexName + '/' + indexName + '/1'; | ||
const uri = url + '/' + indexName + '/' + indexName + '/1'; | ||
let scriptFound = false; | ||
that.log.verbose(logPrefix + 'Started with startVersion: "' + startVersion + '" in path: "' + migrationScriptsPath + '" on options.url: ' + that.options.url); | ||
log.verbose(logPrefix + 'Started with startVersion: "' + startVersion + '" in path: "' + migrationScriptPath + '" on url: ' + url); | ||
// Update db_version status | ||
tasks.push(function (cb) { | ||
if (fs.existsSync(migrationScriptsPath + '/' + startVersion + '.js')) { | ||
that.log.info(logPrefix + 'Found js migration script #' + startVersion + ', running it now.'); | ||
tasks.push(cb => { | ||
if (fs.existsSync(migrationScriptPath + '/' + startVersion + '.js')) { | ||
log.info(logPrefix + 'Found js migration script #' + startVersion + ', running it now.'); | ||
scriptFound = true; | ||
request.put({'url': uri, 'json': {'version': startVersion, 'status': 'started'}}, function (err, response) { | ||
request.put({url: uri, json: {version: startVersion, status: 'started'}}, (err, response) => { | ||
if (err) { | ||
that.log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
@@ -299,3 +311,3 @@ return cb(err); | ||
that.log.error(logPrefix + err.message); | ||
log.error(logPrefix + err.message); | ||
@@ -313,70 +325,72 @@ return cb(err); | ||
// Run the script | ||
tasks.push(function (cb) { | ||
if (scriptFound === true) { | ||
try { | ||
require(migrationScriptsPath + '/' + startVersion + '.js').apply(that, [function (err) { | ||
if (err) { | ||
const scriptErr = err; | ||
tasks.push(async () => { | ||
if (!scriptFound) return; | ||
that.log.error(logPrefix + 'Got error running migration script ' + migrationScriptsPath + '/' + startVersion + '.js' + ': ' + err.message); | ||
const migration = require(migrationScriptPath + '/' + startVersion + '.js'); | ||
try { | ||
await migration(this); | ||
} catch (err) { | ||
const scriptErr = err; | ||
request.put({'url': uri, 'json': {'version': startVersion, 'status': 'failed'}}, function (err, response) { | ||
if (err) { | ||
that.log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
log.error(logPrefix + 'Got error running migration script ' + migrationScriptPath + '/' + startVersion + '.js' + ': ' + err.message); | ||
return cb(err); | ||
} | ||
// Write about the failure in the database | ||
await new Promise((resolve, reject) => { | ||
request.put({url: uri, json: {version: startVersion, status: 'failed'}}, (err, response) => { | ||
if (err) { | ||
log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
if (response.statusCode !== 200) { | ||
const err = new Error('PUT ' + uri + ' statusCode: ' + response.statusCode); | ||
return reject(err); | ||
} | ||
that.log.error(logPrefix + err.message); | ||
if (response.statusCode !== 200) { | ||
const err = new Error('PUT ' + uri + ' statusCode: ' + response.statusCode); | ||
return cb(err); | ||
} | ||
log.error(logPrefix + err.message); | ||
return cb(scriptErr); | ||
}); | ||
return; | ||
return reject(err); | ||
} | ||
that.log.debug(logPrefix + 'Js migration script #' + startVersion + ' ran. Updating database version and moving on.'); | ||
return resolve(scriptErr); | ||
}); | ||
}); | ||
request.put({'url': uri, 'json': {'version': startVersion, 'status': 'finnished'}}, function (err, response) { | ||
if (err) { | ||
that.log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
// Now we've saved the failure in the database, throw back the script error | ||
throw scriptErr; | ||
} | ||
return cb(err); | ||
} | ||
log.debug(logPrefix + 'Js migration script #' + startVersion + ' ran. Updating database version and moving on.'); | ||
if (response.statusCode !== 200) { | ||
const err = new Error('PUT ' + uri + ' statusCode: ' + response.statusCode); | ||
await new Promise((resolve, reject) => { | ||
request.put({url: uri, json: {version: startVersion, status: 'finnished'}}, (err, response) => { | ||
if (err) { | ||
log.error(logPrefix + 'PUT ' + uri + ' failed, err: ' + err.message); | ||
that.log.error(logPrefix + err.message); | ||
return reject(err); | ||
} | ||
return cb(err); | ||
} | ||
if (response.statusCode !== 200) { | ||
const err = new Error('PUT ' + uri + ' statusCode: ' + response.statusCode); | ||
if (fs.existsSync(migrationScriptsPath + '/' + (startVersion + 1) + '.js')) { | ||
that.runScripts(parseInt(startVersion) + 1, cb); | ||
} else { | ||
return cb(); | ||
} | ||
log.error(logPrefix + err.message); | ||
return reject(err); | ||
} | ||
if (fs.existsSync(migrationScriptPath + '/' + (startVersion + 1) + '.js')) { | ||
this.runScripts(parseInt(startVersion) + 1, err => { | ||
if (err) reject(err); | ||
else resolve(); | ||
}); | ||
}]); | ||
} catch (err) { | ||
that.log.error(logPrefix + 'Uncaught error: ' + err.message); | ||
return cb(err); | ||
} | ||
} else { | ||
return cb(); | ||
} | ||
} else { | ||
return resolve(); | ||
} | ||
}); | ||
}); | ||
}); | ||
async.series(tasks, function (err) { | ||
async.series(tasks, err => { | ||
if (err) return cb(err); | ||
that.log.info(logPrefix + 'Database migrated and done. Final version is ' + (startVersion - 1)); | ||
log.info(logPrefix + 'Database migrated and done. Final version is ' + (startVersion - 1)); | ||
@@ -383,0 +397,0 @@ // If we end up here, it means there are no more migration scripts to run |
'use strict'; | ||
const topLogPrefix = 'larvitdbmigration: dbType/mariadb.js: '; | ||
const async = require('async'); | ||
const LUtils = require('larvitutils'); | ||
const mysql = require('mysql2'); | ||
const fs = require('fs'); | ||
/** | ||
* MariaDB driver | ||
* | ||
* @param {object} options - | ||
* @param {String} options.tableName - | ||
* @param {object} options.dbDriver - | ||
* @param {object} options.log - | ||
*/ | ||
function Driver(options) { | ||
const that = this; | ||
if (!options) throw new Error('Options parameter is missing'); | ||
if (!options.tableName) throw new Error('Missing required option "tableName"'); | ||
if (!options.dbDriver) throw new Error('Missing option dbDriver'); | ||
if (!options.log) throw new Error('Missing option log'); | ||
that.options = options || {}; | ||
this.lUtils = new LUtils({log: options.log}); | ||
this.options = options; | ||
} | ||
if (! that.options.tableName) { | ||
throw new Error('Missing required option "tableName"'); | ||
} | ||
Driver.prototype.getLock = async function getLock() { | ||
const {tableName, log, lUtils} = this.options; | ||
const logPrefix = topLogPrefix + 'getLock() - tableName: "' + tableName + '" - '; | ||
const db = this.options.dbDriver; | ||
if (! that.options.dbDriver) { | ||
throw new Error('Missing option dbDriver'); | ||
const dbCon = await db.pool.getConnection(); | ||
await dbCon.query('LOCK TABLES `' + tableName + '` WRITE;'); | ||
const [rows] = await dbCon.query('SELECT running FROM `' + tableName + '`'); | ||
if (rows.length === 0) { | ||
const err = 'No database records'; | ||
log.error(logPrefix + err.message); | ||
throw err; | ||
} else if (rows[0].running !== 0) { | ||
await dbCon.query('UNLOCK TABLES;'); | ||
log.info(logPrefix + 'Another process is running the migrations, wait and try again soon.'); | ||
await lUtils.setTimeout(500); | ||
await this.getLock(); | ||
} | ||
} | ||
Driver.prototype.getLock = function getLock(cb) { | ||
const logPrefix = topLogPrefix + 'getLock() - tableName: "' + this.options.tableName + '" - '; | ||
const tableName = this.options.tableName; | ||
const that = this; | ||
const db = that.options.dbDriver; | ||
await dbCon.query('UPDATE `' + tableName + '` SET running = 1'); | ||
await dbCon.query('UNLOCK TABLES;'); | ||
try { | ||
const tasks = []; | ||
let dbCon; | ||
tasks.push(function (cb) { | ||
db.pool.getConnection(function (err, res) { | ||
if (err) { | ||
that.log.error(logPrefix + 'getConnection() err: ' + err.message); | ||
} | ||
dbCon = res; | ||
cb(err); | ||
}); | ||
}); | ||
tasks.push(function (cb) { | ||
dbCon.query('LOCK TABLES `' + tableName + '` WRITE;', cb); | ||
}); | ||
tasks.push(function (cb) { | ||
dbCon.query('SELECT running FROM `' + tableName + '`', function (err, rows) { | ||
if (err) { | ||
that.log.error(logPrefix + 'SQL err: ' + err.message); | ||
return cb(err); | ||
} | ||
if (rows.length === 0) { | ||
const err = 'No database records'; | ||
that.log.error(logPrefix + err.message); | ||
return cb(err); | ||
} | ||
if (rows[0].running === 0) { | ||
cb(); | ||
} else { | ||
dbCon.query('UNLOCK TABLES;', function (err) { | ||
if (err) { | ||
that.log.error(logPrefix + 'SQL err: ' + err.message); | ||
return cb(err); | ||
} | ||
that.log.info(logPrefix + 'Another process is running the migrations, wait and try again soon.'); | ||
setTimeout(function () { | ||
that.getLock(cb); | ||
}, 500); | ||
}); | ||
} | ||
}); | ||
}); | ||
tasks.push(function (cb) { | ||
dbCon.query('UPDATE `' + tableName + '` SET running = 1', cb); | ||
}); | ||
tasks.push(function (cb) { | ||
dbCon.query('UNLOCK TABLES;', cb); | ||
}); | ||
tasks.push(function (cb) { | ||
dbCon.release(); | ||
cb(); | ||
}); | ||
async.series(tasks, cb); | ||
} catch (err) { | ||
that.log.error(logPrefix + 'Error from driver: ' + err.message); | ||
cb(err); | ||
} | ||
dbCon.release(); | ||
}; | ||
Driver.prototype.run = function run(cb) { | ||
const logPrefix = topLogPrefix + 'run() - tableName: "' + this.options.tableName + '" - '; | ||
const tableName = this.options.tableName; | ||
const tasks = []; | ||
const that = this; | ||
Driver.prototype.run = async function run() { | ||
const {tableName, log} = this.options; | ||
const logPrefix = topLogPrefix + 'run() - tableName: "' + tableName + '" - '; | ||
const db = this.options.dbDriver; | ||
let curVer; | ||
// Create table if it does not exist | ||
tasks.push(function (cb) { | ||
const sql = 'CREATE TABLE IF NOT EXISTS `' + tableName + '` (`id` tinyint(1) unsigned NOT NULL DEFAULT \'1\', `version` int(10) unsigned NOT NULL DEFAULT \'0\', `running` tinyint(3) unsigned NOT NULL DEFAULT \'0\', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=ascii COLLATE=ascii_bin COMMENT=\'Used for automatic database versioning. Do not modify!\';'; | ||
await db.query('CREATE TABLE IF NOT EXISTS `' + tableName + '` (`id` tinyint(1) unsigned NOT NULL DEFAULT \'1\', `version` int(10) unsigned NOT NULL DEFAULT \'0\', `running` tinyint(3) unsigned NOT NULL DEFAULT \'0\', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=ascii COLLATE=ascii_bin COMMENT=\'Used for automatic database versioning. Do not modify!\';'); | ||
db.query(sql, cb); | ||
}); | ||
// Update old version of table (for seamless updating of old versions of this module) | ||
tasks.push(function (cb) { | ||
db.query('DESCRIBE `' + tableName + '`', function (err, rows) { | ||
if (err) return cb(err); | ||
const descRes = await db.query('DESCRIBE `' + tableName + '`'); | ||
if (descRes.rows.length === 2 && descRes.rows[0].Field === 'version' && descRes.rows[1].Field === 'running') { | ||
// Old version detected! Update! | ||
await db.query('ALTER TABLE `' + tableName + '` ADD `id` tinyint(1) unsigned NOT NULL DEFAULT \'1\' FIRST;'); | ||
await db.query('ALTER TABLE `' + tableName + '` ADD PRIMARY KEY `id` (`id`);'); | ||
} | ||
if (rows.length === 2 && rows[0].Field === 'version' && rows[1].Field === 'running') { | ||
// Old version detected! Update! | ||
db.query('ALTER TABLE `' + tableName + '` ADD `id` tinyint(1) unsigned NOT NULL DEFAULT \'1\' FIRST;', function (err) { | ||
if (err) return cb(err); | ||
db.query('ALTER TABLE `' + tableName + '` ADD PRIMARY KEY `id` (`id`);', cb); | ||
}); | ||
} else { | ||
// Nothing to do, continue | ||
cb(); | ||
} | ||
}); | ||
}); | ||
// Insert first record if it does not exist | ||
tasks.push(function (cb) { | ||
db.query('INSERT IGNORE INTO `' + tableName + '` VALUES(1, 0, 0);', cb); | ||
}); | ||
await db.query('INSERT IGNORE INTO `' + tableName + '` VALUES(1, 0, 0);'); | ||
// Lock table by setting the running column to 1 | ||
tasks.push(function (cb) { | ||
that.getLock(cb); | ||
}); | ||
await this.getLock(); | ||
// Get current version | ||
tasks.push(function (cb) { | ||
db.query('SELECT version FROM `' + tableName + '`;', function (err, rows) { | ||
if (err) return cb(err); | ||
const verRes = await db.query('SELECT version FROM `' + tableName + '`;'); | ||
const curVer = verRes.rows[0].version; | ||
curVer = parseInt(rows[0].version); | ||
log.info(logPrefix + 'Current database version is ' + curVer); | ||
that.log.info(logPrefix + 'Current database version is ' + curVer); | ||
cb(); | ||
}); | ||
}); | ||
// Run scripts | ||
tasks.push(function (cb) { | ||
try { | ||
that.runScripts(curVer + 1, cb); | ||
} catch (err) { | ||
that.log.error(logPrefix + 'Error from driver: ' + err.message); | ||
cb(err); | ||
} | ||
}); | ||
await this.runScripts(curVer + 1); | ||
// Unlock table | ||
tasks.push(function (cb) { | ||
db.query('UPDATE `' + tableName + '` SET running = 0;', cb); | ||
}); | ||
async.series(tasks, cb); | ||
await db.query('UPDATE `' + tableName + '` SET running = 0;'); | ||
}; | ||
Driver.prototype.runScripts = function runScripts(startVersion, cb) { | ||
const migrationScriptsPath = this.options.migrationScriptsPath; | ||
const tableName = this.options.tableName; | ||
const logPrefix = topLogPrefix + 'runScripts() - tableName: "' + this.options.tableName + '" - '; | ||
const that = this; | ||
Driver.prototype.runScripts = async function runScripts(startVersion) { | ||
const {tableName, log, migrationScriptPath} = this.options; | ||
const logPrefix = topLogPrefix + 'runScripts() - tableName: "' + tableName + '" - '; | ||
const db = this.options.dbDriver; | ||
that.log.verbose(logPrefix + 'Started with startVersion: "' + startVersion + '" in path: "' + migrationScriptsPath + '"'); | ||
log.verbose(logPrefix + 'Started with startVersion: "' + startVersion + '" in path: "' + migrationScriptPath + '"'); | ||
try { | ||
fs.readdir(migrationScriptsPath, function (err, items) { | ||
const localDbConf = {}; | ||
const sql = 'UPDATE `' + tableName + '` SET version = ' + parseInt(startVersion) + ';'; | ||
// Get items in the migration script path | ||
const items = await new Promise((resolve, reject) => { | ||
fs.readdir(migrationScriptPath, (err, items) => { | ||
if (err) { | ||
that.log.info(logPrefix + 'Could not read migration script path "' + migrationScriptsPath + '"'); | ||
log.info(logPrefix + 'Could not read migration script path "' + migrationScriptPath + '", err: ' + err.message); | ||
reject(err); | ||
} else resolve(items); | ||
}); | ||
}); | ||
return cb(); | ||
} | ||
// Loop through the items and see what kind of migration scripts it is | ||
for (let i = 0; items[i] !== undefined; i++) { | ||
const item = items[i]; | ||
for (let i = 0; items[i] !== undefined; i ++) { | ||
if (items[i] === startVersion + '.js') { | ||
that.log.info(logPrefix + 'Found js migration script #' + startVersion + ', running it now.'); | ||
require(migrationScriptsPath + '/' + startVersion + '.js').apply(that, [function (err) { | ||
if (err) { | ||
that.log.error(logPrefix + 'Got error running migration script ' + migrationScriptsPath + '/' + startVersion + '.js' + ': ' + err.message); | ||
if (item === startVersion + '.js') { | ||
log.info(logPrefix + 'Found js migration script #' + startVersion + ', running it now.'); | ||
return cb(err); | ||
} | ||
const migrationScript = require(migrationScriptPath + '/' + startVersion + '.js'); | ||
that.log.debug(logPrefix + 'Js migration script #' + startVersion + ' ran. Updating database version and moving on.'); | ||
db.query(sql, function (err) { | ||
if (err) return cb(err); | ||
await migrationScript({db, log}); | ||
log.debug(logPrefix + 'Js migration script #' + startVersion + ' ran. Updating database version and moving on.'); | ||
await db.query('UPDATE `' + tableName + '` SET version = ' + parseInt(startVersion) + ';'); | ||
await this.runScripts(parseInt(startVersion) + 1); | ||
} else if (item === startVersion + '.sql') { | ||
log.info(logPrefix + 'Found sql migration script #' + startVersion + ', running it now.'); | ||
that.runScripts(parseInt(startVersion) + 1, cb); | ||
}); | ||
}]); | ||
const localDbConf = {}; | ||
return; | ||
} else if (items[i] === startVersion + '.sql') { | ||
const validDbOptions = []; | ||
const validDbOptions = [ | ||
'host', 'port', 'localAddress', | ||
'socketPath', 'user', 'password', | ||
'database', 'charset', 'timezone', | ||
'connectTimeout', 'stringifyObjects', 'insecureAuth', | ||
'typeCast', 'queryFormat', 'supportBigNumbers', | ||
'bigNumberStrings', 'dateStrings', 'debug', | ||
'trace', 'multipleStatements', 'flags', | ||
'ssl', | ||
let dbCon; | ||
// Valid for pools | ||
'waitForConnections', 'connectionLimit', 'queueLimit' | ||
]; | ||
that.log.info(logPrefix + 'Found sql migration script #' + startVersion + ', running it now.'); | ||
for (const key of Object.keys(db.dbConf)) { | ||
if (validDbOptions.indexOf(key) !== -1) { | ||
localDbConf[key] = db.dbConf[key]; | ||
} | ||
} | ||
localDbConf.multipleStatements = true; | ||
const dbCon = mysql.createConnection(localDbConf); | ||
validDbOptions.push('host'); | ||
validDbOptions.push('port'); | ||
validDbOptions.push('localAddress'); | ||
validDbOptions.push('socketPath'); | ||
validDbOptions.push('user'); | ||
validDbOptions.push('password'); | ||
validDbOptions.push('database'); | ||
validDbOptions.push('charset'); | ||
validDbOptions.push('timezone'); | ||
validDbOptions.push('connectTimeout'); | ||
validDbOptions.push('stringifyObjects'); | ||
validDbOptions.push('insecureAuth'); | ||
validDbOptions.push('typeCast'); | ||
validDbOptions.push('queryFormat'); | ||
validDbOptions.push('supportBigNumbers'); | ||
validDbOptions.push('bigNumberStrings'); | ||
validDbOptions.push('dateStrings'); | ||
validDbOptions.push('debug'); | ||
validDbOptions.push('trace'); | ||
validDbOptions.push('multipleStatements'); | ||
validDbOptions.push('flags'); | ||
validDbOptions.push('ssl'); | ||
await new Promise((resolve, reject) => { | ||
dbCon.query(fs.readFileSync(migrationScriptPath + '/' + items[i]).toString(), err => { | ||
if (err) { | ||
log.error(logPrefix + 'Migration file: ' + item + ' SQL error: ' + err.message); | ||
// Valid for pools | ||
validDbOptions.push('waitForConnections'); | ||
validDbOptions.push('connectionLimit'); | ||
validDbOptions.push('queueLimit'); | ||
for (const key of Object.keys(db.conf)) { | ||
if (validDbOptions.indexOf(key) !== - 1) { | ||
localDbConf[key] = db.conf[key]; | ||
} | ||
return reject(err); | ||
} | ||
localDbConf.multipleStatements = true; | ||
dbCon = mysql.createConnection(localDbConf); | ||
dbCon.query(fs.readFileSync(migrationScriptsPath + '/' + items[i]).toString(), function (err) { | ||
if (err) { | ||
that.log.error(logPrefix + 'Migration file: ' + items[i] + ' SQL error: ' + err.message); | ||
log.info(logPrefix + 'Sql migration script #' + startVersion + ' ran. Updating database version and moving on.'); | ||
resolve(); | ||
}); | ||
}); | ||
return cb(err); | ||
} | ||
await db.query('UPDATE `' + tableName + '` SET version = ' + parseInt(startVersion) + ';'); | ||
that.log.info(logPrefix + 'Sql migration script #' + startVersion + ' ran. Updating database version and moving on.'); | ||
db.query(sql, function (err) { | ||
if (err) return cb(err); | ||
dbCon.end(); | ||
dbCon.end(); | ||
that.runScripts(parseInt(startVersion) + 1, cb); | ||
}); | ||
}); | ||
return; | ||
} | ||
} | ||
that.log.info(logPrefix + 'Database migrated and done. Final version is ' + (startVersion - 1)); | ||
// If we end up here, it means there are no more migration scripts to run | ||
cb(); | ||
}); | ||
} catch (err) { | ||
that.log.error(logPrefix + 'Uncaught error: ' + err.message); | ||
cb(err); | ||
await this.runScripts(parseInt(startVersion) + 1); | ||
} | ||
} | ||
@@ -291,0 +163,0 @@ }; |
60
index.js
'use strict'; | ||
const topLogPrefix = 'larvitdbmigration: index.js - '; | ||
const LUtils = require('larvitutils'); | ||
const lUtils = new LUtils(); | ||
const LUtils = require('larvitutils'); | ||
const lUtils = new LUtils(); | ||
/** | ||
* Module main constructor | ||
* 'dbType': 'mariadb' or 'elasticsearch' | ||
* 'dbDriver': instance of your database driver. For example larvitdb | ||
* | ||
* @param {obj} options - { | ||
* | ||
* **OPTIONAL** | ||
* 'tableName': 'db_version' | ||
* 'indexName': 'db_version' | ||
* 'migrationScriptPath': './dbmigration' | ||
* 'log': new larvitutils.Log() or compatible | ||
* } | ||
* @param {object} options - | ||
* @param {String} options.dbType - "mariadb" or "elasticsearch" | ||
* @param {object} options.dbDriver - instance of your database driver. For example larvitdb | ||
* @param {String} [options.tableName="db_version"] - | ||
* @param {String} [options.indexName="db_version"] - | ||
* @param {String} [options.migrationScriptPath="./dbmigration"] - | ||
* @param {object} [options.log=instance of lutils.Log()] - | ||
*/ | ||
function DbMigration(options) { | ||
const logPrefix = topLogPrefix + 'DbMigration() - '; | ||
const that = this; | ||
const logPrefix = topLogPrefix + 'DbMigration() - '; | ||
if (that === undefined) { | ||
throw new Error('DbMigration must be instantianted'); | ||
} | ||
options = options || {}; | ||
that.options = options = options || {}; | ||
if (! that.options.log) { | ||
that.options.log = new lUtils.Log(); | ||
if (!options.log) { | ||
options.log = new lUtils.Log(); | ||
} | ||
that.log = that.options.log; | ||
const log = options.log; | ||
if (options.tableName === undefined) options.tableName = 'db_version'; | ||
if (options.indexName === undefined) options.indexName = 'db_version'; | ||
if (options.migrationScriptsPath === undefined) options.migrationScriptsPath = './dbmigration'; | ||
if (options.migrationScriptPath === undefined) options.migrationScriptPath = './dbmigration'; | ||
@@ -46,20 +38,18 @@ if (options.dbType !== 'elasticsearch' && options.dbType !== 'mariadb') { | ||
// Resolve ./ paths to be relative to application path | ||
if (that.options.migrationScriptsPath.substring(0, 2) === './') { | ||
that.options.migrationScriptsPath = process.cwd() + '/' + that.options.migrationScriptsPath.substring(2); | ||
if (options.migrationScriptPath.substring(0, 2) === './') { | ||
options.migrationScriptPath = process.cwd() + '/' + options.migrationScriptPath.substring(2); | ||
} | ||
that.dbTypeFile = __dirname + '/dbType/' + options.dbType + '.js'; | ||
that.DbType = require(that.dbTypeFile); | ||
that.dbType = new that.DbType(that.options); | ||
that.dbType.log = that.log; | ||
this.dbTypeFile = __dirname + '/dbType/' + options.dbType + '.js'; | ||
this.DbType = require(this.dbTypeFile); | ||
this.dbType = new this.DbType(options); | ||
that.log.verbose(logPrefix + 'Started with dbType: "' + that.options.dbType + '", tableName/indexName: "' + (that.options.tableName || that.options.indexName) + '", migrationScriptsPath: "' + that.options.migrationScriptsPath + '"'); | ||
log.verbose(logPrefix + 'Started with dbType: "' + options.dbType + '", tableName/indexName: "' + (options.tableName || options.indexName) + '", migrationScriptPath: "' + options.migrationScriptPath + '"'); | ||
// Set functions from the dirver | ||
that.getLock = that.dbType.getLock; | ||
that.rmLock = that.dbType.rmLock; | ||
that.run = that.dbType.run; | ||
that.runScripts = that.dbType.runScripts; | ||
this.options = options; | ||
// Set functions from the driver | ||
this.run = () => this.dbType.run.apply(this.dbType, arguments); | ||
} | ||
exports = module.exports = DbMigration; |
{ | ||
"name": "larvitdbmigration", | ||
"version": "4.0.3", | ||
"version": "5.0.0", | ||
"author": { | ||
@@ -12,5 +12,5 @@ "name": "Mikael 'Lilleman' Göransson", | ||
"dependencies": { | ||
"async": "^2.0.1", | ||
"async": "^3.0.1", | ||
"json-stringify-safe": "^5.0.1", | ||
"larvitutils": "^2.0.0", | ||
"larvitutils": "^2.2.0", | ||
"request": "^2.81.0" | ||
@@ -20,7 +20,10 @@ }, | ||
"devDependencies": { | ||
"larvitdb": "2.1.1", | ||
"eslint": "5.14.1", | ||
"mocha": "6.0.0", | ||
"coveralls": "^3.0.3", | ||
"dotenv": "^8.0.0", | ||
"eslint": "5.16.0", | ||
"larvitdb": "^3.0.2", | ||
"mocha": "^6.1.4", | ||
"mocha-eslint": "5.0.0", | ||
"mysql2": "1.6.5" | ||
"mysql2": "1.6.5", | ||
"nyc": "^14.1.1" | ||
}, | ||
@@ -41,3 +44,4 @@ "keywords": [ | ||
"scripts": { | ||
"test": "mocha --exit" | ||
"test": "nyc mocha --exit", | ||
"coverage": "nyc report --reporter=text-lcov | coveralls" | ||
}, | ||
@@ -44,0 +48,0 @@ "license": "MIT", |
116
README.md
@@ -1,2 +0,2 @@ | ||
[![Build Status](https://travis-ci.org/larvit/larvitdbmigration.svg?branch=master)](https://travis-ci.org/larvit/larvitdbmigration) [![Dependencies](https://david-dm.org/larvit/larvitdbmigration.svg)](https://david-dm.org/larvit/larvitdbmigration.svg) | ||
[![Build Status](https://travis-ci.org/larvit/larvitdbmigration.svg?branch=master)](https://travis-ci.org/larvit/larvitdbmigration) [![Dependencies](https://david-dm.org/larvit/larvitdbmigration.svg)](https://david-dm.org/larvit/larvitdbmigration.svg) [![Coverage Status](https://coveralls.io/repos/github/larvit/larvitdbmigration/badge.svg)](https://coveralls.io/github/larvit/larvitdbmigration) | ||
@@ -20,5 +20,3 @@ # Database migration tool | ||
```bash | ||
npm i --save larvitdbmigration | ||
``` | ||
npm i larvitdbmigration | ||
@@ -37,28 +35,21 @@ ## Usage | ||
const DbMigration = require('larvitdbmigration'); | ||
const options = {}; | ||
const winston = require('winston'); | ||
const log = winston.createLogger({'transports': [new winston.transports.Console()]}); | ||
const db = require('larvitdb'); | ||
let dbMigration; | ||
db.setup({ | ||
'host': '127.0.0.1', | ||
'user': 'foo', | ||
'password': 'bar', | ||
'database': 'baz' | ||
const Db = require('larvitdb'); | ||
const dbDriver = new Db({ | ||
host: '127.0.0.1', | ||
user: 'foo', | ||
password: 'bar', | ||
database: 'baz' | ||
}); | ||
const dbMigration = new DbMigration({ | ||
dbType: 'mariadb', | ||
dbDriver, | ||
tableName: 'db_version', // Optional - used as index name for elasticsearch | ||
migrationScriptPath: './dbmigration', // Optional | ||
log // Optional, will use log.silly(), log.debug(), log.verbose(), log.info(), log.warn() and log.error() if given. | ||
}); | ||
options.dbType = 'mariadb'; | ||
options.dbDriver = db; | ||
options.tableName = 'db_version'; // Optional - used as index name for elasticsearch | ||
options.migrationScriptsPath = './dbmigration'; // Optional | ||
options.log = log; // Optional, will use log.silly(), log.debug(), log.verbose(), log.info(), log.warn() and log.error() if given. | ||
dbMigration = new DbMigration(options); | ||
dbMigration.run(function (err) { | ||
if (err) throw err; | ||
dbMigration.run().then(() => { | ||
// Now database is migrated and ready for use! | ||
}).catch(err => { | ||
throw err; | ||
}); | ||
@@ -73,20 +64,14 @@ ``` | ||
const DbMigration = require('larvitdbmigration'); | ||
const options = {}; | ||
const winston = require('winston'); | ||
const log = winston.createLogger({'transports': [new winston.transports.Console()]}); | ||
const dbMigration = new DbMigration({ | ||
dbType: 'elasticsearch', | ||
url: 'http://127.0.0.1:9200', | ||
indexName: 'db_version', // Optional | ||
migrationScriptPath: './dbmigration', // Optional | ||
log// Optional, will use log.silly(), log.debug(), log.verbose(), log.info(), log.warn() and log.error() if given. | ||
}); | ||
let dbMigration; | ||
options.dbType = 'elasticsearch'; | ||
options.url = 'http://127.0.0.1:9200'; | ||
options.indexName = 'db_version'; // Optional | ||
options.migrationScriptsPath = './dbmigration'; // Optional | ||
options.log = log; // Optional, will use log.silly(), log.debug(), log.verbose(), log.info(), log.warn() and log.error() if given. | ||
dbMigration = new DbMigration(options); | ||
dbMigration.run(function (err) { | ||
if (err) throw err; | ||
dbMigration.run().then(() => { | ||
// Now database is migrated and ready for use! | ||
}).catch(err => { | ||
throw err; | ||
}); | ||
@@ -107,3 +92,3 @@ ``` | ||
Create the file process.cwd()/migrationScriptsPath/1.js with this content: | ||
Create the file process.cwd()/migrationScriptPath/1.js with this content: | ||
@@ -113,6 +98,7 @@ ```javascript | ||
exports = module.exports = function (cb) { | ||
const db = this.options.dbDriver; | ||
// Always make the function async (or explicitly return a promise, see elasticsearch example below) | ||
exports = module.exports = async function (options) { | ||
const {db} = options; | ||
db.query('ALTER TABLE bloj CHANGE nisse hasse int(11);', cb); | ||
await db.query('ALTER TABLE bloj CHANGE nisse hasse int(11);'); | ||
}; | ||
@@ -123,3 +109,3 @@ ``` | ||
Create the file process.cwd()/migrationScriptsPath/1.js with this content: | ||
Create the file process.cwd()/migrationScriptPath/1.js with this content: | ||
@@ -131,18 +117,24 @@ ```javascript | ||
exports = module.exports = function (cb) { | ||
const that = this; | ||
exports = module.exports = function (options) { | ||
const {url} = options; | ||
request({ | ||
'url': that.options.url + '/some_index/_mapping/some_type', | ||
'json': true, | ||
'method': 'PUT', | ||
'body': { | ||
'properties': { | ||
'names': { | ||
'type': 'string', | ||
'position_increment_gap': 100 | ||
// Return a promise instead of having the function async, see async example above | ||
return new Promise((resolve, reject) => { | ||
request({ | ||
url: url + '/some_index/_mapping/some_type', | ||
json: true, | ||
method: 'PUT', | ||
body: { | ||
properties: { | ||
names: { | ||
type: 'string', | ||
position_increment_gap: 100 | ||
} | ||
} | ||
} | ||
} | ||
}, cb); | ||
}, err => { | ||
if (err) reject(err); | ||
else resolve(); | ||
}); | ||
}); | ||
}; | ||
@@ -155,3 +147,3 @@ ``` | ||
Create the file process.cwd()/migrationScriptsPath/1.sql with this content: | ||
Create the file process.cwd()/migrationScriptPath/1.sql with this content: | ||
@@ -158,0 +150,0 @@ ```SQL |
{ | ||
"extends": [ | ||
"config:base" | ||
] | ||
], | ||
"automerge": true, | ||
"major": { | ||
"automerge": false | ||
} | ||
} |
'use strict'; | ||
require('dotenv').config(); | ||
const DbMigration = require(__dirname + '/../index.js'); | ||
@@ -8,160 +10,72 @@ const request = require('request'); | ||
const lutils = new Lutils(); | ||
const async = require('async'); | ||
const path = require('path'); | ||
const log = new lutils.Log('silence!!!'); | ||
const db = require('larvitdb'); | ||
const fs = require('fs'); | ||
const log = new lutils.Log('error'); | ||
const Db = require('larvitdb'); | ||
const esConf = { | ||
host: process.env.ES_HOST !== undefined ? process.env.ES_HOST : '127.0.0.1:9200' | ||
}; | ||
let db; | ||
let mariaDbConf; | ||
let esConf; | ||
before(async () => { | ||
// Setup MariaDB | ||
const mariaConf = { | ||
host: process.env.DB_HOST !== undefined ? process.env.DB_HOST : '127.0.0.1', | ||
user: process.env.DB_USER !== undefined ? process.env.DB_USER : 'root', | ||
port: process.env.DB_PORT !== undefined ? process.env.DB_PORT : '3306', | ||
password: process.env.DB_PASSWORD !== undefined ? process.env.DB_PASSWORD : 'toor', | ||
database: process.env.DB_DATABASE !== undefined ? process.env.DB_DATABASE : 'test' | ||
}; | ||
log.debug('mariaConf: ' + JSON.stringify(mariaConf)); | ||
db = new Db(mariaConf); | ||
const {rows} = await db.query('SHOW TABLES'); | ||
before(function (done) { | ||
const tasks = []; | ||
if (rows.length) { | ||
log.error('Database is not empty. To make a test, you must supply an empty database!'); | ||
process.exit(1); | ||
} | ||
let mariaDbConfFile; | ||
let esConfFile; | ||
// Setup ES | ||
log.debug('esConf: ' + JSON.stringify(esConf)); | ||
// Set conf file paths | ||
tasks.push(function (cb) { | ||
if (process.env.ESCONFFILE === undefined) { | ||
esConfFile = __dirname + '/../config/es_test.json'; | ||
} else { | ||
esConfFile = process.env.ESCONFFILE; | ||
} | ||
function checkEmptyEs() { | ||
const reqOptions = {}; | ||
if (process.env.DBCONFFILE === undefined) { | ||
mariaDbConfFile = __dirname + '/../config/db_test.json'; | ||
} else { | ||
mariaDbConfFile = process.env.DBCONFFILE; | ||
} | ||
reqOptions.url = 'http://' + esConf.host + '/_cat/indices?format=json'; | ||
reqOptions.json = true; | ||
log.verbose('MariaDB config file: "' + mariaDbConfFile + '"'); | ||
log.verbose('Elasticsearch config file: "' + esConfFile + '"'); | ||
cb(); | ||
}); | ||
// MariaDb | ||
tasks.push(function (cb) { | ||
function checkEmptyMariaDb() { | ||
db.query('SHOW TABLES', function (err, rows) { | ||
return new Promise((resolve, reject) => { | ||
request(reqOptions, function (err, response, body) { | ||
if (err) { | ||
log.error(err); | ||
process.exit(1); | ||
} | ||
log.error('Error talking to Elasticsearch, err: ' + err.message); | ||
if (rows.length) { | ||
log.error('Database is not empty. To make a test, you must supply an empty database!'); | ||
process.exit(1); | ||
return reject(err); | ||
} | ||
cb(); | ||
}); | ||
} | ||
function runMariaDbSetup(mariaDbConfFile) { | ||
let conf; | ||
log.verbose('DB config: ' + JSON.stringify(require(mariaDbConfFile))); | ||
conf = require(mariaDbConfFile); | ||
conf.log = log; | ||
db.setup(conf, function (err) { | ||
if (err) { | ||
log.error('Database setup problem: ' + err.message); | ||
process.exit(1); | ||
if (!Array.isArray(body) || body.length !== 0) { | ||
return reject(new Error('Elasticsearch is not empty. To make a test, you must supply an empty database!')); | ||
} | ||
checkEmptyMariaDb(); | ||
resolve(); | ||
}); | ||
} | ||
fs.stat(mariaDbConfFile, function (err) { | ||
const altMariaDbConfFile = __dirname + '/../config/' + mariaDbConfFile; | ||
if (err) { | ||
log.info('Failed to find config file "' + mariaDbConfFile + '", retrying with "' + altMariaDbConfFile + '"'); | ||
fs.stat(altMariaDbConfFile, function (err) { | ||
if (err) { | ||
log.error('MariaDb config file does not exist'); | ||
process.exit(1); | ||
} | ||
mariaDbConf = require(altMariaDbConfFile); | ||
runMariaDbSetup(altMariaDbConfFile); | ||
}); | ||
} else { | ||
mariaDbConf = require(mariaDbConfFile); | ||
runMariaDbSetup(mariaDbConfFile); | ||
} | ||
}); | ||
}); | ||
// Elasticsearch | ||
tasks.push(function (cb) { | ||
function checkEmptyEs() { | ||
const reqOptions = {}; | ||
reqOptions.url = 'http://' + esConf.clientOptions.host + '/_cat/indices?format=json'; | ||
reqOptions.json = true; | ||
request(reqOptions, function (err, response, body) { | ||
if (err) throw err; | ||
if (! Array.isArray(body) || body.length !== 0) { | ||
throw new Error('Database is not empty. To make a test, you must supply an empty database!'); | ||
} | ||
cb(err); | ||
}); | ||
} | ||
fs.stat(esConfFile, function (err) { | ||
const altEsConfFile = __dirname + '/../config/' + esConfFile; | ||
if (err) { | ||
log.info('Failed to find config file "' + esConfFile + '", retrying with "' + altEsConfFile + '"'); | ||
fs.stat(altEsConfFile, function (err) { | ||
if (err) { | ||
log.error('ES config file does not exist'); | ||
process.exit(1); | ||
} | ||
esConf = require(altEsConfFile); | ||
checkEmptyEs(altEsConfFile); | ||
}); | ||
} else { | ||
esConf = require(esConfFile); | ||
checkEmptyEs(esConfFile); | ||
} | ||
}); | ||
}); | ||
async.parallel(tasks, done); | ||
} | ||
await checkEmptyEs(); | ||
}); | ||
after(function (done) { | ||
const tasks = []; | ||
after(async () => { | ||
await db.removeAllTables(); | ||
await db.pool.end(); | ||
tasks.push(function (cb) { | ||
db.removeAllTables(cb); | ||
}); | ||
tasks.push(function (cb) { | ||
await new Promise((resolve, reject) => { | ||
const reqOptions = {}; | ||
reqOptions.url = 'http://' + esConf.clientOptions.host + '/_all'; | ||
reqOptions.url = 'http://' + esConf.host + '/_all'; | ||
reqOptions.json = true; | ||
reqOptions.method = 'DELETE'; | ||
request(reqOptions, cb); | ||
request(reqOptions, err => { | ||
if (err) reject(err); | ||
else resolve(); | ||
}); | ||
}); | ||
async.parallel(tasks, function (err) { | ||
if (err) throw err; | ||
done(); | ||
}); | ||
}); | ||
@@ -173,73 +87,53 @@ | ||
it('Run them', function (done) { | ||
let dbMigrations; | ||
it('Run them', async () => { | ||
const dbMigrations = new DbMigration({ | ||
migrationScriptPath: path.join(__dirname, '../testmigrations_mariadb'), | ||
dbType: 'mariadb', | ||
dbDriver: db, | ||
log | ||
}); | ||
mariaDbConf.migrationScriptsPath = path.join(__dirname, '../testmigrations_mariadb'); | ||
mariaDbConf.dbType = 'mariadb'; | ||
mariaDbConf.dbDriver = db; | ||
mariaDbConf.log = log; | ||
dbMigrations = new DbMigration(mariaDbConf); | ||
dbMigrations.run(function (err) { | ||
if (err) throw err; | ||
done(); | ||
}); | ||
await dbMigrations.run(); | ||
}); | ||
it('Should fetch some data form a migrated table', function (done) { | ||
db.query('SELECT * FROM bloj', function (err, rows) { | ||
if (err) throw err; | ||
it('Should fetch some data form a migrated table', async () => { | ||
const {rows} = await db.query('SELECT * FROM bloj'); | ||
assert.deepStrictEqual(rows.length, 1); | ||
assert.deepStrictEqual(rows[0].hasse, 42); | ||
done(); | ||
}); | ||
assert.deepStrictEqual(rows.length, 1); | ||
assert.deepStrictEqual(rows[0].hasse, 42); | ||
}); | ||
it('Make sure function works', function (done) { | ||
db.query('SELECT multi_two(4) AS foo', function (err, rows) { | ||
if (err) throw err; | ||
it('Make sure function works', async () => { | ||
const {rows} = await db.query('SELECT multi_two(4) AS foo'); | ||
assert.deepStrictEqual(rows[0].foo, 8); | ||
done(); | ||
}); | ||
assert.deepStrictEqual(rows[0].foo, 8); | ||
}); | ||
it('Make sure function nr 2 works', function (done) { | ||
db.query('SELECT multi_three(4) AS foo', function (err, rows) { | ||
if (err) throw err; | ||
it('Make sure function nr 2 works', async () => { | ||
const {rows} = await db.query('SELECT multi_three(4) AS foo'); | ||
assert.deepStrictEqual(rows[0].foo, 12); | ||
done(); | ||
}); | ||
assert.deepStrictEqual(rows[0].foo, 12); | ||
}); | ||
it('Should fail when migration returns error', function (done) { | ||
const tasks = []; | ||
it('Should fail when migration returns error', async () => { | ||
await db.removeAllTables(); | ||
// Clean out database | ||
tasks.push(function (cb) { | ||
db.removeAllTables(cb); | ||
// Run failing migrations | ||
const dbMigrations = new DbMigration({ | ||
migrationScriptPath: path.join(__dirname, '../testmigrations_mariadb_failing'), | ||
dbType: 'mariadb', | ||
dbDriver: db, | ||
log | ||
}); | ||
// Run failing migrations | ||
tasks.push(function (cb) { | ||
let dbMigrations; | ||
let thrownErr; | ||
mariaDbConf.migrationScriptsPath = path.join(__dirname, '../testmigrations_mariadb_failing'); | ||
mariaDbConf.dbType = 'mariadb'; | ||
mariaDbConf.dbDriver = db; | ||
mariaDbConf.log = log; | ||
try { | ||
await dbMigrations.run(); | ||
} catch (err) { | ||
thrownErr = err; | ||
} | ||
dbMigrations = new DbMigration(mariaDbConf); | ||
dbMigrations.run(function (err) { | ||
assert(err instanceof Error, 'err should be an instance of Error'); | ||
cb(); | ||
}); | ||
}); | ||
async.series(tasks, done); | ||
assert(thrownErr instanceof Error, 'err should be an instance of Error'); | ||
assert.strictEqual(thrownErr.message, 'some error'); | ||
}); | ||
@@ -251,20 +145,16 @@ }); | ||
it('Run them', function (done) { | ||
let dbMigrations; | ||
it('Run them', async () => { | ||
let dbMigrations; | ||
esConf.dbType = 'elasticsearch'; | ||
esConf.url = 'http://' + esConf.clientOptions.host; | ||
esConf.migrationScriptsPath = path.join(__dirname, '../testmigrations_elasticsearch'); | ||
esConf.url = 'http://' + esConf.host; | ||
esConf.migrationScriptPath = path.join(__dirname, '../testmigrations_elasticsearch'); | ||
esConf.log = log; | ||
dbMigrations = new DbMigration(esConf); | ||
dbMigrations.run(function (err) { | ||
if (err) throw err; | ||
done(); | ||
}); | ||
await dbMigrations.run(); | ||
}); | ||
it('should check the db_versions index', function (done) { | ||
request('http://' + esConf.clientOptions.host + '/db_version/db_version/1', function (err, response, body) { | ||
request('http://' + esConf.host + '/db_version/db_version/1', function (err, response, body) { | ||
const jsonBody = JSON.parse(body); | ||
@@ -282,3 +172,3 @@ | ||
it('should check the foo index', function (done) { | ||
request('http://' + esConf.clientOptions.host + '/foo/bar/666', function (err, response, body) { | ||
request('http://' + esConf.host + '/foo/bar/666', function (err, response, body) { | ||
const jsonBody = JSON.parse(body); | ||
@@ -288,3 +178,3 @@ | ||
assert.strictEqual(jsonBody._source.blubb, 7); | ||
assert.strictEqual(jsonBody._source.blubb, 7); | ||
@@ -295,17 +185,11 @@ done(); | ||
it('run them again', function (done) { | ||
let dbMigrations; | ||
it('run them again', async () => { | ||
esConf.dbType = 'elasticsearch'; | ||
esConf.url = 'http://' + esConf.clientOptions.host; | ||
esConf.migrationScriptsPath = path.join(__dirname, '../testmigrations_elasticsearch'); | ||
esConf.url = 'http://' + esConf.host; | ||
esConf.migrationScriptPath = path.join(__dirname, '../testmigrations_elasticsearch'); | ||
esConf.log = log; | ||
dbMigrations = new DbMigration(esConf); | ||
dbMigrations.run(function (err) { | ||
if (err) throw err; | ||
done(); | ||
}); | ||
const dbMigrations = new DbMigration(esConf); | ||
await dbMigrations.run(); | ||
}); | ||
}); |
'use strict'; | ||
require('mocha-eslint')([__dirname + '/..'], { | ||
// Increase the timeout of the test if linting takes to long | ||
'timeout': 5000, // Defaults to the global mocha `timeout` option | ||
require('mocha-eslint')( | ||
[__dirname + '/..'], | ||
{ | ||
// Increase the timeout of the test if linting takes to long | ||
timeout: 5000, // Defaults to the global mocha `timeout` option | ||
// Increase the time until a test is marked as slow | ||
'slow': 1000 // Defaults to the global mocha `slow` option | ||
}); | ||
// Increase the time until a test is marked as slow | ||
slow: 1000 // Defaults to the global mocha `slow` option | ||
} | ||
); |
@@ -6,14 +6,16 @@ 'use strict'; | ||
// Create index | ||
exports = module.exports = function (cb) { | ||
const esUri = this.options.url; | ||
exports = module.exports = function (options) { | ||
const esUri = options.url; | ||
request.put(esUri + '/foo', function (err, response) { | ||
if (err) throw err; | ||
return new Promise((resolve, reject) => { | ||
request.put(esUri + '/foo', (err, response) => { | ||
if (err) return reject(err); | ||
if (response.statusCode !== 200) { | ||
throw new Error('non-200 statusCode: ' + response.statusCode); | ||
} | ||
if (response.statusCode !== 200) { | ||
return reject(new Error('non-200 statusCode: ' + response.statusCode)); | ||
} | ||
cb(); | ||
resolve(); | ||
}); | ||
}); | ||
}; |
@@ -6,14 +6,16 @@ 'use strict'; | ||
// Create document | ||
exports = module.exports = function (cb) { | ||
const esUri = this.options.url; | ||
exports = module.exports = async function (options) { | ||
const esUri = options.url; | ||
request.put({'url': esUri + '/foo/bar/666', 'json': {'blubb': 7}}, function (err, response) { | ||
if (err) throw err; | ||
await new Promise((resolve, reject) => { | ||
request.put({url: esUri + '/foo/bar/666', json: {blubb: 7}}, (err, response) => { | ||
if (err) return reject(err); | ||
if (response.statusCode !== 201) { | ||
throw new Error('non-201 statusCode: ' + response.statusCode); | ||
} | ||
if (response.statusCode !== 201) { | ||
return reject(new Error('non-201 statusCode: ' + response.statusCode)); | ||
} | ||
cb(); | ||
resolve(); | ||
}); | ||
}); | ||
}; |
'use strict'; | ||
exports = module.exports = function (cb) { | ||
cb(new Error('some error')); | ||
exports = module.exports = function () { | ||
throw new Error('some error'); | ||
}; |
'use strict'; | ||
const async = require('async'); | ||
exports = module.exports = async options => { | ||
const {db} = options; | ||
exports = module.exports = function (cb) { | ||
const tasks = []; | ||
const db = this.options.dbDriver; | ||
tasks.push(function (cb) { | ||
db.query('ALTER TABLE bloj CHANGE nisse hasse int(11);', cb); | ||
}); | ||
tasks.push(function (cb) { | ||
db.query('INSERT INTO bloj (hasse) VALUES(42);', cb); | ||
}); | ||
async.series(tasks, cb); | ||
await db.query('ALTER TABLE bloj CHANGE nisse hasse int(11);'); | ||
await db.query('INSERT INTO bloj (hasse) VALUES(42);'); | ||
}; |
'use strict'; | ||
const async = require('async'); | ||
exports = module.exports = async function (options) { | ||
const db = options.db; | ||
exports = module.exports = function (cb) { | ||
const tasks = []; | ||
const db = this.options.dbDriver; | ||
tasks.push(function (cb) { | ||
db.query('DROP FUNCTION IF EXISTS multi_three;', cb); | ||
}); | ||
tasks.push(function (cb) { | ||
db.query(`CREATE FUNCTION multi_three (x INT) RETURNS INT | ||
await db.query('DROP FUNCTION IF EXISTS multi_three;'); | ||
await db.query(`CREATE FUNCTION multi_three (x INT) RETURNS INT | ||
DETERMINISTIC | ||
@@ -21,6 +14,3 @@ BEGIN | ||
END | ||
`, cb); | ||
}); | ||
async.series(tasks, cb); | ||
`); | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 6 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
35279
8
20
684
149
18
1
4
54
+ Addedasync@3.2.6(transitive)
- Removedasync@2.6.4(transitive)
- Removedlodash@4.17.21(transitive)
Updatedasync@^3.0.1
Updatedlarvitutils@^2.2.0