db-migrate-base
Advanced tools
Comparing version 1.0.1 to 1.2.0
410
index.js
var util = require('util'); | ||
var events = require('events'); | ||
var log = global.mod.log; | ||
var type = global.mod.type; | ||
var Class = global.mod.Class; | ||
var log; | ||
var type; | ||
var Class = require('./class.js'); | ||
var Promise = require('bluebird'); | ||
var internals = {}; | ||
module.exports = Base = Class.extend({ | ||
init: function() { | ||
init: function(intern) { | ||
this._escapeDDL = this._escapeDDL || '"'; | ||
this._escapeString = this._escapeString || '\''; | ||
internals = intern; | ||
this.internals = intern; | ||
log = this.internals.mod.log; | ||
type = this.internals.mod.type; | ||
this.eventEmmiter = new events.EventEmitter(); | ||
@@ -56,2 +68,15 @@ for(var n in events.EventEmitter.prototype) { | ||
truncate: function(tableName, callback) { | ||
return this.runSql('TRUNCATE ' + this._escapeDDL + tableName + this._escapeDDL).nodeify(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() { | ||
@@ -72,8 +97,9 @@ | ||
{ | ||
var self = this; | ||
var self = this, fkFunc, | ||
promises = []; | ||
if (foreignKeys.length > 0) | ||
(foreignKeys.pop())(function() { self.recurseCallbackArray(foreignKeys, callback); } ); | ||
else | ||
callback(); | ||
while((fkFunc = foreignKeys.pop())) | ||
promises.push(Promise.resolve(fkFunc())); | ||
return Promise.all(promises).nodeify(callback); | ||
}, | ||
@@ -90,12 +116,22 @@ | ||
return function (callback) { self.addForeignKey(tableName, fkOptions.table, | ||
fkOptions.name, mapping, fkOptions.rules, callback); }; | ||
return function (callback) { | ||
if (typeof(callback) === 'function') | ||
self.addForeignKey(tableName, fkOptions.table, | ||
fkOptions.name, mapping, fkOptions.rules, callback); | ||
else | ||
return self.addForeignKey(tableName, fkOptions.table, | ||
fkOptions.name, mapping, fkOptions.rules); | ||
}; | ||
}, | ||
createColumnDef: function(name, spec, options) { | ||
name = '"' + name + '"'; | ||
name = this._escapeDDL + name + this._escapeDDL; | ||
var type = this.mapDataType(spec.type); | ||
var len = spec.length ? util.format('(%s)', spec.length) : ''; | ||
var constraint = this.createColumnConstraint(spec, options); | ||
return [name, type, len, constraint].join(' '); | ||
return { foreignKey: null, | ||
constraints: [name, type, len, constraint].join(' ') }; | ||
}, | ||
@@ -112,5 +148,17 @@ | ||
}; | ||
this.createTable(global.migrationTable, options, callback); | ||
this.createTable(this.internals.migrationTable, options, callback); | ||
}, | ||
createSeedsTable: function(callback) { | ||
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 | ||
}; | ||
this.createTable(this.internals.seedTable, options, callback); | ||
}, | ||
createTable: function(tableName, options, callback) { | ||
@@ -147,3 +195,5 @@ log.verbose('creating table:', tableName); | ||
if (primaryKeyColumns.length > 1) { | ||
pkSql = util.format(', PRIMARY KEY (%s)', this.quoteArr(primaryKeyColumns).join(', ')); | ||
pkSql = util.format(', PRIMARY KEY (%s)', | ||
this.quoteDDLArr(primaryKeyColumns).join(', ')); | ||
} else { | ||
@@ -154,9 +204,21 @@ columnDefOptions.emitPrimaryKey = true; | ||
var columnDefs = []; | ||
var foreignKeys = []; | ||
for (var columnName in columnSpecs) { | ||
var columnSpec = columnSpecs[columnName]; | ||
columnDefs.push(this.createColumnDef(columnName, columnSpec, columnDefOptions)); | ||
var constraint = this.createColumnDef(columnName, columnSpec, columnDefOptions, tableName); | ||
columnDefs.push(constraint.constraints); | ||
if (constraint.foreignKey) | ||
foreignKeys.push(constraint.foreignKey); | ||
} | ||
var sql = util.format('CREATE TABLE %s "%s" (%s%s)', ifNotExistsSql, tableName, columnDefs.join(', '), pkSql); | ||
this.runSql(sql, callback); | ||
var sql = util.format('CREATE TABLE %s %s (%s%s)', ifNotExistsSql, | ||
this.escapeDDL(tableName), columnDefs.join(', '), pkSql); | ||
return this.runSql(sql) | ||
.then(function() | ||
{ | ||
return this.recurseCallbackArray(foreignKeys); | ||
}.bind(this)).nodeify(callback); | ||
}, | ||
@@ -175,4 +237,6 @@ | ||
} | ||
var sql = util.format('DROP TABLE %s "%s"', ifExistsSql, tableName); | ||
this.runSql(sql, callback); | ||
var sql = util.format('DROP TABLE %s %s', ifExistsSql, | ||
this.escapeDDL(tableName)); | ||
return this.runSql(sql).nodeify(callback); | ||
}, | ||
@@ -185,5 +249,16 @@ | ||
addColumn: function(tableName, columnName, columnSpec, callback) { | ||
var def = this.createColumnDef(columnName, this.normalizeColumnSpec(columnSpec)); | ||
var sql = util.format('ALTER TABLE "%s" ADD COLUMN %s', tableName, def); | ||
this.runSql(sql, callback); | ||
var def = this.createColumnDef(columnName, | ||
this.normalizeColumnSpec(columnSpec), {}, tableName); | ||
var sql = util.format('ALTER TABLE %s ADD COLUMN %s', | ||
this.escapeDDL(tableName), def.constraints); | ||
return this.runSql(sql) | ||
.then(function() | ||
{ | ||
if(def.foreignKey) | ||
return def.foreignKey(); | ||
else | ||
return Promise.resolve(); | ||
}).nodeify(callback); | ||
}, | ||
@@ -203,6 +278,14 @@ | ||
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) | ||
arr[i] = '"' + arr[i] + '"'; | ||
arr[i] = this._escapeString + arr[i] + this._escapeString; | ||
@@ -222,8 +305,34 @@ return arr; | ||
var sql = util.format('CREATE %s INDEX "%s" ON "%s" (%s)', (unique ? 'UNIQUE' : ''), | ||
indexName, tableName, this.quoteArr(columns).join(', ')); | ||
indexName, tableName, this.quoteDDLArr(columns).join(', ')); | ||
this.runSql(sql, callback); | ||
return this.runSql(sql).nodeify(callback); | ||
}, | ||
insert: function(tableName, columnNameArray, valueArray, callback) { | ||
insert: function(tableName, valueArray, callback) { | ||
var columnNameArray = {}; | ||
if( arguments.length > 3 ) { | ||
log.warn( 'This calling convention of insert is deprecated' ); | ||
columnNameArray = valueArray; | ||
valueArray = callback; | ||
callback = arguments[3]; | ||
} | ||
else { | ||
var names; | ||
if( util.isArray(valueArray) ) { | ||
names = Object.keys(valueArray[0]); | ||
} | ||
else { | ||
names = Object.keys(valueArray); | ||
} | ||
for( var i = 0; i < names.length; ++i ) { | ||
columnNameArray[names[i]] = names[i]; | ||
} | ||
} | ||
if (columnNameArray.length !== valueArray.length) { | ||
@@ -233,25 +342,95 @@ return callback(new Error('The number of columns does not match the number of values.')); | ||
var sql = util.format('INSERT INTO "%s" ', tableName); | ||
var sql = util.format('INSERT INTO %s ', this.escapeDDL(tableName)); | ||
var columnNames = '('; | ||
var values = 'VALUES ('; | ||
var values = 'VALUES '; | ||
var values_part = []; | ||
for (var index in columnNameArray) { | ||
columnNames += columnNameArray[index]; | ||
columnNames += this.escapeDDL(columnNameArray[index]); | ||
if( util.isArray(valueArray) && typeof(valueArray[0]) === 'object') { | ||
for( var i = 0; i < valueArray.length; ++i ) { | ||
values_part[i] = values_part[i] || ''; | ||
if (typeof(valueArray[i][index]) === 'string') { | ||
values_part[i] += this.escapeString(valueArray[i][index]); | ||
} else { | ||
values_part[i] += valueArray[i][index]; | ||
} | ||
} | ||
} | ||
else { | ||
if (typeof(valueArray[index]) === 'string') { | ||
values_part += this.escapeString(valueArray[index]); | ||
} else { | ||
values_part += valueArray[index]; | ||
} | ||
values_part += ","; | ||
} | ||
columnNames += ","; | ||
} | ||
if( util.isArray(valueArray) && typeof(valueArray[0]) === 'object' ) { | ||
for( var i = 0; i < values_part.length; ++i ) { | ||
values += '(' + values_part[i].slice(0, -1) + '),'; | ||
} | ||
values = values.slice(0, -1); | ||
} | ||
else { | ||
values += '(' + values_part.slice(0, -1) + ')'; | ||
} | ||
sql += columnNames.slice(0, -1) + ') ' + | ||
values + ';'; | ||
return this.runSql(sql).nodeify(callback); | ||
}, | ||
update: function(tableName, columnNameArray, valueArray, ids, callback) { | ||
if (columnNameArray.length !== valueArray.length) { | ||
return callback(new Error('The number of columns does not match the number of values.')); | ||
} | ||
var sql = util.format('UPDATE ' + this._escapeDDL + '%s' + this._escapeDDL + ' SET ', tableName ); | ||
for (var index in columnNameArray) { | ||
sql += columnNameArray[index] + '='; | ||
if (typeof(valueArray[index]) === 'string') { | ||
values += "'" + this.escape(valueArray[index]) + "'"; | ||
sql += this._escapeString + this.escape(valueArray[index]) + this._escapeString; | ||
} else { | ||
values += valueArray[index]; | ||
sql += valueArray[index]; | ||
} | ||
if (index != columnNameArray.length - 1) { | ||
columnNames += ","; | ||
values += ","; | ||
sql += ", "; | ||
} | ||
} | ||
sql += columnNames + ') '+ values + ');'; | ||
this.runSql(sql, callback); | ||
sql += ' ' + buildWhereClause(ids); | ||
return this.runSql(sql).nodeify(callback); | ||
}, | ||
lookup: function(tableName, column, id, callback) { | ||
var sql = 'SELECT ' + this.escapeDDL(column) + ' FROM ' + | ||
this.escapeDDL(tableName) + ' ' + buildWhereClause(id); | ||
return this.runSql(sql) | ||
.then(function(row) { | ||
return row[0]; | ||
}); | ||
}, | ||
removeIndex: function(tableName, indexName, callback) { | ||
@@ -266,3 +445,3 @@ if (arguments.length === 2 && typeof(indexName) === 'function') { | ||
var sql = util.format('DROP INDEX "%s"', indexName); | ||
this.runSql(sql, callback); | ||
return this.runSql(sql).nodeify(callback); | ||
}, | ||
@@ -287,7 +466,15 @@ | ||
addMigrationRecord: function (name, callback) { | ||
this.runSql('INSERT INTO "' + global.migrationTable + '" (name, run_on) VALUES (?, ?)', [name, new Date()], callback); | ||
this.runSql('INSERT INTO ' + this.escapeDDL(this.internals.migrationTable) + | ||
' (' + this.escapeDDL('name') + ', ' + this.escapeDDL('run_on') + | ||
') VALUES (?, ?)', [name, new Date()], callback); | ||
}, | ||
startMigration: function(cb){cb();}, | ||
endMigration: function(cb){cb();}, | ||
addSeedRecord: function (name, callback) { | ||
this.runSql('INSERT INTO ' + this.escapeDDL(this.internals.seedTable) + | ||
' (' + this.escapeDDL('name') + ', ' + this.escapeDDL('run_on') + | ||
') VALUES (?, ?)', [name, new Date()], callback); | ||
}, | ||
startMigration: function(cb){ return Promise.resolve().nodeify(cb); }, | ||
endMigration: function(cb){ return Promise.resolve().nodeify(cb); }, | ||
// sql, params, callback | ||
@@ -305,3 +492,3 @@ // sql, callback | ||
allLoadedMigrations: function(callback) { | ||
var sql = 'SELECT * FROM "' + global.migrationTable + '" ORDER BY run_on DESC, name DESC'; | ||
var sql = 'SELECT * FROM ' + this._escapeDDL + this.internals.migrationTable + this._escapeDDL + ' ORDER BY run_on DESC, name DESC'; | ||
return this.all(sql, callback); | ||
@@ -311,2 +498,12 @@ }, | ||
/** | ||
* Queries the seeds table | ||
* | ||
* @param callback | ||
*/ | ||
allLoadedSeeds: function(callback) { | ||
var sql = 'SELECT * FROM ' + this._escapeDDL + this.internals.seedTable + this._escapeDDL + ' ORDER BY run_on DESC, name DESC'; | ||
return this.all(sql, callback); | ||
}, | ||
/** | ||
* Deletes a migration | ||
@@ -317,6 +514,118 @@ * | ||
deleteMigration: function(migrationName, callback) { | ||
var sql = 'DELETE FROM "' + global.migrationTable + '" WHERE name = ?'; | ||
var sql = 'DELETE FROM ' + this._escapeDDL + this.internals.migrationTable + this._escapeDDL + ' WHERE name = ?'; | ||
this.runSql(sql, [migrationName], callback); | ||
}, | ||
/** | ||
* Removes the specified keys from the database | ||
* | ||
* @param table - The table in which the to be deleted values are located | ||
* @param ids - array or object | ||
* id array - arrayof the to be deleted ids | ||
* id object - { table: "name of the table to resolve the ids from", | ||
* column: [ | ||
* { | ||
* name: "name of column", //defaults to id if unset | ||
* operator: ">", //defaults to = if unset | ||
* searchValue: "12", | ||
* searchValue: { table: "source", column: [...] }, | ||
* //recursion with objects possible | ||
* link: "AND" //defaults to AND if unset | ||
* } | ||
* ] | ||
* } | ||
* | ||
* @return Promise(runSql) | ||
*/ | ||
remove: function(table, ids, callback) { | ||
var sql = 'DELETE FROM ' + this._escapeDDL + table + + this._escapeDDL; | ||
var searchClause = ''; | ||
return this.runSql(sql + buildWhereClause(ids)).nodeify(callback); | ||
}, | ||
/** | ||
* Builds a where clause out of column objects. | ||
* | ||
* @param ids - array or object | ||
* id array - arrayof the to be deleted ids | ||
* id object - { table: "name of the table to resolve the ids from", | ||
* column: [ | ||
* { | ||
* name: "name of column", //defaults to id if unset | ||
* operator: ">", //defaults to = if unset | ||
* searchValue: "12", | ||
* searchValue: { table: "source", column: [...] }, | ||
* //recursion with objects possible | ||
* link: "AND" //defaults to AND if unset | ||
* } | ||
* ] | ||
* } | ||
* | ||
* @return string | ||
*/ | ||
buildWhereClause: function(ids) { | ||
var searchClause = ''; | ||
if (util.isArray(ids) && typeof(ids[0]) !== 'object' && ids.length > 1) { | ||
searchClause += 'WHERE id IN (' + ids.join(this._escapeString + ',' + this._escapeString) + ')'; | ||
} | ||
else if(typeof(ids) === 'string' || ids.length === 1) { | ||
var id = (util.isArray(ids)) ? ids[0] : ids; | ||
searchClause += 'WHERE id = ' + id; | ||
} | ||
else if (util.isArray(ids) && typeof(ids[0]) === 'object'){ | ||
var preLink = '' | ||
searchClause = ' WHERE '; | ||
for (var column in ids) { | ||
column.name = column.name || 'id', | ||
column.operator = column.operator || '=', | ||
column.link = column.link || 'AND'; | ||
if (!column.searchValue) { | ||
return Promise.reject('column ' + column.name + ' was entered without a searchValue.'); | ||
} | ||
searchClause += ' ' + preLink + ' ' + this._escapeDDL + | ||
column.name + this._escapeDDL + ' ' + column.operator; | ||
if (typeof(searchValue) === 'object' && | ||
typeof(searchValue.table) === 'string' && | ||
typeof(searchValue.columns) === 'object') { | ||
searchClause += ' (SELECT ' + this._escapeDDL + column.selector + | ||
this._escapeDDL + ' FROM ' + this._escapeDDL + | ||
column.searchValue.table + this._escapeDDL + | ||
buildWhereClause(column.searchValue.column) + ')'; | ||
} | ||
else { | ||
searchClause += ' (' + this._escapeString + column.searchValue + this._escapeString + ')'; | ||
} | ||
preLink = column.link; | ||
} | ||
} | ||
return searchClause; | ||
}, | ||
/** | ||
* Deletes a seed | ||
* | ||
* @param seedName - The name of the seed to be deleted | ||
*/ | ||
deleteSeed: function(seedName, callback) { | ||
var sql = 'DELETE FROM ' + this._escapeDDL + this.internals.seedTable + this._escapeDDL + ' WHERE name = ?'; | ||
this.runSql(sql, [seedName], callback); | ||
}, | ||
all: function(sql, params, callback) { | ||
@@ -327,4 +636,19 @@ throw new Error('not implemented'); | ||
escape: function(str) { | ||
return str.replace(/'/g, "''"); | ||
if(this._escapeString === '\'') | ||
return str.replace(/'/g, "''"); | ||
else | ||
return str.replace(/"/g, '"'); | ||
}, | ||
escapeString: function(str) { | ||
return this._escapeString + this.escape(str) + this._escapeString; | ||
}, | ||
escapeDDL: function(str) { | ||
return this._escapeDDL + str + this._escapeDDL; | ||
} | ||
}); | ||
Promise.promisifyAll(Base); |
{ | ||
"name": "db-migrate-base", | ||
"version": "1.0.1", | ||
"version": "1.2.0", | ||
"description": "db-migrate base driver", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
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
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
22056
6
556