From 1783a665e9fdd74ca2552d8510aee82b0b163452 Mon Sep 17 00:00:00 2001 From: Tobias Gurtzick Date: Wed, 15 May 2019 19:05:01 +0200 Subject: [PATCH] feat(methods): add new migrator methods Signed-off-by: Tobias Gurtzick --- index.js | 250 +++++++++++++++++++++++++++++++++------------- package-lock.json | 13 +++ 2 files changed, 193 insertions(+), 70 deletions(-) create mode 100644 package-lock.json diff --git a/index.js b/index.js index d7efe78..3df6543 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,7 @@ var Promise = require('bluebird'); var internals = {}; var Base = Class.extend({ - init: function(intern) { + init: function (intern) { this._escapeDDL = this._escapeDDL || '"'; this._escapeString = this._escapeString || "'"; @@ -24,11 +24,11 @@ var Base = Class.extend({ } }, - close: function() { + close: function () { throw new Error('not implemented'); }, - _translateSpecialDefaultValues: function( + _translateSpecialDefaultValues: function ( spec, options, tableName, @@ -42,7 +42,7 @@ var Base = Class.extend({ ); }, - _prepareSpec: function(columnName, spec, options, tableName) { + _prepareSpec: function (columnName, spec, options, tableName) { if (spec.defaultValue) { if (spec.defaultValue.raw) { spec.defaultValue.prep = spec.defaultValue.raw; @@ -57,7 +57,7 @@ var Base = Class.extend({ } }, - mapDataType: function(str) { + mapDataType: function (str) { switch (str) { case type.STRING: return 'VARCHAR'; @@ -94,54 +94,55 @@ var Base = Class.extend({ } }, - truncate: function(tableName, callback) { + truncate: function (tableName, callback) { return this.runSql( 'TRUNCATE ' + this._escapeDDL + tableName + this._escapeDDL ).nodeify(callback); }, - checkDBMS: function(dbms, callback) { + checkDBMS: function (dbms, callback) { if (this.dbms === dbms) return Promise.resolve(dbms).nodeify(callback); else return Promise.reject('dbms does not match'); }, - createDatabase: function() { + createDatabase: function () { throw new Error('not implemented'); }, - showDatabase: function() { + showDatabase: function () { throw new Error('not implemented'); }, - switchDatabase: function() { + switchDatabase: function () { throw new Error('not implemented'); }, - dropDatabase: function() { + dropDatabase: function () { throw new Error('not implemented'); }, - recurseCallbackArray: function(foreignKeys, callback) { + recurseCallbackArray: function (foreignKeys, callback) { var self = this, fkFunc, promises = []; - while ((fkFunc = foreignKeys.pop())) + while ((fkFunc = foreignKeys.pop())) { promises.push(Promise.resolve(fkFunc())); + } return Promise.all(promises).nodeify(callback); }, - bindForeignKey: function(tableName, columnName, fkOptions) { + bindForeignKey: function (tableName, columnName, fkOptions) { var self = this, mapping = {}; - if (typeof fkOptions.mapping === 'string') + if (typeof fkOptions.mapping === 'string') { mapping[columnName] = fkOptions.mapping; - else mapping = fkOptions.mapping; + } else mapping = fkOptions.mapping; - return function(callback) { - if (typeof callback === 'function') + return function (callback) { + if (typeof callback === 'function') { self.addForeignKey( tableName, fkOptions.table, @@ -150,7 +151,7 @@ var Base = Class.extend({ fkOptions.rules, callback ); - else + } else { return self.addForeignKey( tableName, fkOptions.table, @@ -158,10 +159,11 @@ var Base = Class.extend({ mapping, fkOptions.rules ); + } }; }, - createColumnDef: function(name, spec, options) { + createColumnDef: function (name, spec, options) { name = this._escapeDDL + name + this._escapeDDL; var type = this.mapDataType(spec.type); var len = spec.length ? util.format('(%s)', spec.length) : ''; @@ -173,7 +175,41 @@ var Base = Class.extend({ }; }, - createMigrationsTable: function(callback) { + _createList: function (table, opt = {}) { + var options = { + columns: { + id: { + type: type.INTEGER, + notNull: true, + primaryKey: true, + autoIncrement: true + }, + name: { type: type.STRING, length: 255, notNull: true }, + run_on: { type: type.DATE_TIME, notNull: true } + }, + ifNotExists: true + }; + return this.createTable(table, options); + }, + + _createKV: function (table, opt = { valueJson: false }) { + var options = { + columns: { + key: { + type: type.STRING, + notNull: true, + primaryKey: true, + unique: true + }, + value: { type: type.TEXT, notNull: true }, + run_on: { type: type.DATE_TIME, notNull: true } + }, + ifNotExists: true + }; + return this.createTable(table, options); + }, + + createMigrationsTable: function (callback) { var options = { columns: { id: { @@ -190,7 +226,7 @@ var Base = Class.extend({ this.createTable(this.internals.migrationTable, options, callback); }, - createSeedsTable: function(callback) { + createSeedsTable: function (callback) { var options = { columns: { id: { @@ -207,18 +243,18 @@ var Base = Class.extend({ this.createTable(this.internals.seedTable, options, callback); }, - _handleMultiPrimaryKeys: function(primaryKeyColumns) { + _handleMultiPrimaryKeys: function (primaryKeyColumns) { return util.format( ', PRIMARY KEY (%s)', this.quoteDDLArr( - primaryKeyColumns.map(function(value) { + primaryKeyColumns.map(function (value) { return value.name; }) ).join(', ') ); }, - createTable: function(tableName, options, callback) { + createTable: function (tableName, options, callback) { log.verbose('creating table:', tableName); var columnSpecs = options; var tableOptions = {}; @@ -300,14 +336,14 @@ var Base = Class.extend({ return this.runSql(sql) .then( - function() { + function () { return this.recurseCallbackArray(callbacks); }.bind(this) ) .nodeify(callback); }, - dropTable: function(tableName, options, callback) { + dropTable: function (tableName, options, callback) { if (arguments.length < 3 && typeof options === 'function') { callback = options; options = {}; @@ -328,11 +364,11 @@ var Base = Class.extend({ return this.runSql(sql).nodeify(callback); }, - renameTable: function(tableName, newTableName, callback) { + renameTable: function (tableName, newTableName, callback) { throw new Error('not implemented'); }, - addColumn: function(tableName, columnName, columnSpec, callback) { + addColumn: function (tableName, columnName, columnSpec, callback) { var columnSpec = this.normalizeColumnSpec(columnSpec); this._prepareSpec(columnName, columnSpec, {}, tableName); var def = this.createColumnDef(columnName, columnSpec, {}, tableName); @@ -351,7 +387,7 @@ var Base = Class.extend({ ); return this.runSql(sql) - .then(function() { + .then(function () { var callbacks = def.callbacks || []; if (def.foreignKey) callbacks.push(def.foreignKey); return self.recurseCallbackArray(callbacks); @@ -359,33 +395,35 @@ var Base = Class.extend({ .nodeify(callback); }, - removeColumn: function(tableName, columnName, callback) { + removeColumn: function (tableName, columnName, callback) { throw new Error('not implemented'); }, - renameColumn: function(tableName, oldColumnName, newColumnName, callback) { + renameColumn: function (tableName, oldColumnName, newColumnName, callback) { throw new Error('not implemented'); }, - changeColumn: function(tableName, columnName, columnSpec, callback) { + changeColumn: function (tableName, columnName, columnSpec, callback) { throw new Error('not implemented'); }, - quoteDDLArr: function(arr) { - for (var i = 0; i < arr.length; ++i) + quoteDDLArr: function (arr) { + for (var i = 0; i < arr.length; ++i) { arr[i] = this._escapeDDL + arr[i] + this._escapeDDL; + } return arr; }, - quoteArr: function(arr) { - for (var i = 0; i < arr.length; ++i) + quoteArr: function (arr) { + for (var i = 0; i < arr.length; ++i) { arr[i] = this._escapeString + arr[i] + this._escapeString; + } return arr; }, - addIndex: function(tableName, indexName, columns, unique, callback) { + addIndex: function (tableName, indexName, columns, unique, callback) { if (typeof unique === 'function') { callback = unique; unique = false; @@ -405,7 +443,7 @@ var Base = Class.extend({ return this.runSql(sql).nodeify(callback); }, - insert: function(tableName, valueArray, callback) { + insert: function (tableName, valueArray, callback) { var columnNameArray = {}; if (arguments.length > 3 || Array.isArray(callback)) { @@ -413,7 +451,7 @@ var Base = Class.extend({ valueArray = callback; } else { var names; - if (util.isArray(valueArray)) { + if (Array.isArray(valueArray)) { names = Object.keys(valueArray[0]); } else { names = Object.keys(valueArray); @@ -438,7 +476,7 @@ var Base = Class.extend({ for (var index in columnNameArray) { columnNames += this.escapeDDL(columnNameArray[index]); - if (util.isArray(valueArray) && typeof valueArray[0] === 'object') { + if (Array.isArray(valueArray) && typeof valueArray[0] === 'object') { for (var i = 0; i < valueArray.length; ++i) { values_part[i] = values_part[i] || ''; @@ -461,7 +499,7 @@ var Base = Class.extend({ columnNames += ','; } - if (util.isArray(valueArray) && typeof valueArray[0] === 'object') { + if (Array.isArray(valueArray) && typeof valueArray[0] === 'object') { for (var i = 0; i < values_part.length; ++i) { values += '(' + values_part[i].slice(0, -1) + '),'; } @@ -476,7 +514,7 @@ var Base = Class.extend({ return this.runSql(sql).nodeify(callback); }, - update: function(tableName, valueArray, ids, callback) { + update: function (tableName, valueArray, ids, callback) { var columnNameArray = {}; if (arguments > 4 && arguments[1].length !== arguments[2].length) { @@ -490,7 +528,7 @@ var Base = Class.extend({ callback = arguments[4]; } else { var names; - if (util.isArray(valueArray)) { + if (Array.isArray(valueArray)) { names = Object.keys(valueArray[0]); } else { names = Object.keys(valueArray); @@ -527,7 +565,7 @@ var Base = Class.extend({ return this.runSql(sql).nodeify(callback); }, - lookup: function(tableName, column, id, callback) { + lookup: function (tableName, column, id, callback) { var sql = 'SELECT ' + this.escapeDDL(column) + @@ -536,12 +574,12 @@ var Base = Class.extend({ ' ' + this.buildWhereClause(id); - return this.runSql(sql).then(function(row) { + return this.runSql(sql).then(function (row) { return row[0]; }); }, - removeIndex: function(tableName, indexName, callback) { + removeIndex: function (tableName, indexName, callback) { if (arguments.length === 2 && typeof indexName === 'function') { callback = indexName; indexName = tableName; @@ -553,15 +591,15 @@ var Base = Class.extend({ return this.runSql(sql).nodeify(callback); }, - addForeignKey: function() { + addForeignKey: function () { throw new Error('not implemented'); }, - removeForeignKey: function() { + removeForeignKey: function () { throw new Error('not implemented'); }, - normalizeColumnSpec: function(obj) { + normalizeColumnSpec: function (obj) { if (typeof obj === 'string') { return { type: obj }; } else { @@ -569,7 +607,39 @@ var Base = Class.extend({ } }, - addMigrationRecord: function(name, callback) { + _insertEntry: function (table, name) { + return this.runSql( + 'INSERT INTO ' + + this.escapeDDL(table) + + ' (' + + this.escapeDDL('name') + + ', ' + + this.escapeDDL('run_on') + + ') VALUES (?, ?)', + [name, new Date()] + ); + }, + + _insertKV: function (table, key, value) { + return this.runSql( + `INSERT INTO ${this.escapeDDL(table)} + (${this.escapeDDL('key')}, ${this.escapeDDL('value')}, ${this.escapeDDL( + 'run_on' +)}) VALUES (?, ?, ?)`, + [key, value, new Date()] + ); + }, + + _updateKV: function (table, key, value) { + return this.runSql( + `UPDATE ${this.escapeDDL(table)} SET ${this.escapeDDL('value')} = ?, + ${this.escapeDDL('run_on')} = ? + WHERE key = ?`, + [value, new Date(), key] + ); + }, + + addMigrationRecord: function (name, callback) { this.runSql( 'INSERT INTO ' + this.escapeDDL(this.internals.migrationTable) + @@ -583,7 +653,7 @@ var Base = Class.extend({ ); }, - addSeedRecord: function(name, callback) { + addSeedRecord: function (name, callback) { this.runSql( 'INSERT INTO ' + this.escapeDDL(this.internals.seedTable) + @@ -597,24 +667,44 @@ var Base = Class.extend({ ); }, - startMigration: function(cb) { + startMigration: function (cb) { return Promise.resolve().nodeify(cb); }, - endMigration: function(cb) { + endMigration: function (cb) { return Promise.resolve().nodeify(cb); }, // sql, params, callback // sql, callback - runSql: function() { + runSql: function () { throw new Error('not implemented'); }, + _getList: function (table) { + var sql = + 'SELECT * FROM ' + + this._escapeDDL + + table + + this._escapeDDL + + ' ORDER BY run_on DESC, name DESC'; + return this.allAsync(sql); + }, + + _getKV: function (table, key) { + var sql = + 'SELECT * FROM ' + + this._escapeDDL + + table + + this._escapeDDL + + ' WHERE key = ?'; + return this.allAsync(sql, [key]).then(([row]) => row); + }, + /** * Queries the migrations table * * @param callback */ - allLoadedMigrations: function(callback) { + allLoadedMigrations: function (callback) { var sql = 'SELECT * FROM ' + this._escapeDDL + @@ -629,7 +719,7 @@ var Base = Class.extend({ * * @param callback */ - allLoadedSeeds: function(callback) { + allLoadedSeeds: function (callback) { var sql = 'SELECT * FROM ' + this._escapeDDL + @@ -639,12 +729,32 @@ var Base = Class.extend({ return this.all(sql, callback); }, + _deleteEntry: function (table, entry) { + var sql = + 'DELETE FROM ' + + this._escapeDDL + + table + + this._escapeDDL + + ' WHERE name = ?'; + return this.runSql(sql, [entry]); + }, + + _deleteKV: function (table, key) { + var sql = + 'DELETE FROM ' + + this._escapeDDL + + table + + this._escapeDDL + + ' WHERE key = ?'; + return this.runSql(sql, [key]); + }, + /** * Deletes a migration * * @param migrationName - The name of the migration to be deleted */ - deleteMigration: function(migrationName, callback) { + deleteMigration: function (migrationName, callback) { var sql = 'DELETE FROM ' + this._escapeDDL + @@ -675,7 +785,7 @@ var Base = Class.extend({ * * @return Promise(runSql) */ - remove: function(table, ids, callback) { + remove: function (table, ids, callback) { var sql = 'DELETE FROM ' + this._escapeDDL + table + +this._escapeDDL; var searchClause = ''; @@ -702,10 +812,10 @@ var Base = Class.extend({ * * @return string */ - buildWhereClause: function(ids) { + buildWhereClause: function (ids) { var searchClause = ''; - if (util.isArray(ids) && typeof ids[0] !== 'object' && ids.length > 1) { + if (Array.isArray(ids) && typeof ids[0] !== 'object' && ids.length > 1) { searchClause += 'WHERE id IN (' + ids.join(this._escapeString + ',' + this._escapeString) + @@ -715,10 +825,10 @@ var Base = Class.extend({ ids.length === 1 || typeof ids === 'number' ) { - var id = util.isArray(ids) ? ids[0] : ids; + var id = Array.isArray(ids) ? ids[0] : ids; searchClause += 'WHERE id = ' + this._escapeString + id + this._escapeString; - } else if (util.isArray(ids) && typeof ids[0] === 'object') { + } else if (Array.isArray(ids) && typeof ids[0] === 'object') { var preLink = ''; searchClause = ' WHERE '; @@ -737,8 +847,8 @@ var Base = Class.extend({ } (column.name = column.name || 'id'), - (column.operator = column.operator || '='), - (column.link = column.link || 'AND'); + (column.operator = column.operator || '='), + (column.link = column.link || 'AND'); if (!column.value) { return Promise.reject( @@ -806,7 +916,7 @@ var Base = Class.extend({ * * @param seedName - The name of the seed to be deleted */ - deleteSeed: function(seedName, callback) { + deleteSeed: function (seedName, callback) { var sql = 'DELETE FROM ' + this._escapeDDL + @@ -816,20 +926,20 @@ var Base = Class.extend({ this.runSql(sql, [seedName], callback); }, - all: function(sql, params, callback) { + all: function (sql, params, callback) { throw new Error('not implemented'); }, - escape: function(str) { + escape: function (str) { if (this._escapeString === "'") return str.replace(/'/g, "''"); else return str.replace(/"/g, '"'); }, - escapeString: function(str) { + escapeString: function (str) { return this._escapeString + this.escape(str) + this._escapeString; }, - escapeDDL: function(str) { + escapeDDL: function (str) { return this._escapeDDL + str + this._escapeDDL; } }); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..db2027d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "db-migrate-base", + "version": "1.6.3", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "bluebird": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", + "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==" + } + } +}