Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

node-pg-migrate

Package Overview
Dependencies
Maintainers
3
Versions
180
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-pg-migrate - npm Package Compare versions

Comparing version 0.0.12 to 0.0.13

.eslintignore

62

lib/db.js
/*
This file just manages the database connection and provides a query method
*/
This file just manages the database connection and provides a query method
*/
var pg = require('pg');
//or native libpq bindings
//var pg = require('pg').native
// or native libpq bindings
// var pg = require('pg').native

@@ -12,28 +12,6 @@ var client;

module.exports.init = function(connection_string){
client = new pg.Client(connection_string || process.env.DATABASE_URL);
}
function createConnection(callback) {
if (client_active) return callback();
module.exports.query = function(query, callback){
createConnection(function(err){
if (err) return callback(err);
// console.log('sql>> ' + query);
client.query(query, function(err, result){
if (err) return callback(err);
return callback(null, result);
});
});
}
module.exports.close = function(){
client.end();
}
function createConnection(callback){
if (client_active) return callback();
client.connect(function(err){
client.connect(function(err) {
if (err) {

@@ -47,1 +25,27 @@ console.error('could not connect to postgres', err);

}
module.exports.init = function(connection_string) {
if (!client) {
client = new pg.Client(connection_string || process.env.DATABASE_URL);
}
};
module.exports.query = function(query, callback) {
createConnection(function(connErr) {
if (connErr) return callback(connErr);
// console.log('sql>> ' + query);
client.query(query, function(queryErr, result) {
if (queryErr) return callback(queryErr);
return callback(null, result);
});
});
};
module.exports.close = function() {
client_active = false;
if (client) {
client.end();
client = null;
}
};
/*
The migration builder is used to actually create a migration from instructions
The migration builder is used to actually create a migration from instructions
A new instance of MigrationBuilder is instantiated and passed to the up or down block
of each migration when it is being run.
A new instance of MigrationBuilder is instantiated and passed to the up or down block
of each migration when it is being run.
It makes the methods available via the pgm variable and stores up the sql commands.
This is what makes it possible to do this without making everything async
and it makes inferrence of down migrations possible.
It makes the methods available via the pgm variable and stores up the sql commands.
This is what makes it possible to do this without making everything async
and it makes inferrence of down migrations possible.
*/
*/
var _ = require('lodash');
var utils = require('./utils');

@@ -21,6 +20,6 @@

tables: require('./operations/tables'),
other: require('./operations/other')
}
other: require('./operations/other'),
};
var MigrationBuilder = function(){
var MigrationBuilder = function() {
var self = this;

@@ -33,20 +32,16 @@ var steps = [];

this.enableReverseMode = function(){
this.enableReverseMode = function() {
REVERSE_MODE = true;
}
this.noTransaction = function(){
};
this.noTransaction = function() {
self.use_transaction = false;
}
};
this.getSql = function(){
this.getSql = function() {
return this.getSqlSteps().join('\n') + '\n';
};
this.getSqlSteps = function() {
// in reverse mode, we flip the order of the statements
if (REVERSE_MODE){
steps = steps.reverse();
}
return steps.join("\n")+"\n";
}
this.getSqlSteps = function(){
// in reverse mode, we flip the order of the statements
return REVERSE_MODE ? steps.reverse() : steps;
}
return REVERSE_MODE ? steps.slice().reverse() : steps;
};

@@ -56,13 +51,13 @@ // this function wraps each operation within a function that either

// to the steps array
function wrap(operation){
return function(){
function wrap(operation) {
return function() {
if (REVERSE_MODE) {
if ( typeof operation.reverse !== 'function' ){
if (typeof operation.reverse !== 'function') {
throw new Error('Impossible to automatically infer down migration');
}
steps = steps.concat( operation.reverse.apply( self, arguments ) );
steps = steps.concat(operation.reverse.apply(self, arguments));
} else {
steps = steps.concat( operation.apply( self, arguments ) );
steps = steps.concat(operation.apply(self, arguments));
}
}
};
}

@@ -73,31 +68,31 @@

// there are some convenience aliases to make usage easier
this.createExtension = wrap( ops.extensions.create );
this.dropExtension = wrap( ops.extensions.drop );
this.createExtension = wrap(ops.extensions.create);
this.dropExtension = wrap(ops.extensions.drop);
this.addExtension = this.createExtension;
this.createTable = wrap( ops.tables.create );
this.dropTable = wrap( ops.tables.drop );
this.renameTable = wrap( ops.tables.renameTable );
this.createTable = wrap(ops.tables.create);
this.dropTable = wrap(ops.tables.drop);
this.renameTable = wrap(ops.tables.renameTable);
this.addColumns = wrap( ops.tables.addColumns );
this.dropColumns = wrap( ops.tables.dropColumns );
this.renameColumn = wrap( ops.tables.renameColumn );
this.alterColumn = wrap( ops.tables.alterColumn );
this.addColumns = wrap(ops.tables.addColumns);
this.dropColumns = wrap(ops.tables.dropColumns);
this.renameColumn = wrap(ops.tables.renameColumn);
this.alterColumn = wrap(ops.tables.alterColumn);
this.addColumn = this.addColumns;
this.dropColumn = this.dropColumns;
this.addConstraint = wrap( ops.tables.addConstraint );
this.dropConstraint = wrap( ops.tables.dropConstraint );
this.addConstraint = wrap(ops.tables.addConstraint);
this.dropConstraint = wrap(ops.tables.dropConstraint);
this.createConstraint = this.addConstraint;
this.createType = wrap( ops.tables.createType );
this.dropType = wrap( ops.tables.dropType );
this.alterType = wrap( ops.tables.alterType );
this.createType = wrap(ops.tables.createType);
this.dropType = wrap(ops.tables.dropType);
this.alterType = wrap(ops.tables.alterType);
this.addType = this.createType;
this.createIndex = wrap( ops.indexes.create );
this.dropIndex = wrap( ops.indexes.drop );
this.createIndex = wrap(ops.indexes.create);
this.dropIndex = wrap(ops.indexes.drop);
this.addIndex = this.createIndex;
this.sql = wrap( ops.other.sql );
this.sql = wrap(ops.other.sql);

@@ -109,4 +104,4 @@

this.func = utils.PgLiteral.create;
}
};
module.exports = MigrationBuilder;
module.exports = MigrationBuilder;
/*
A new Migration is instantiated for each migration file.
A new Migration is instantiated for each migration file.
It is responsible for storing the name of the file and knowing how to execute
the up and down migrations defined in the file.
It is responsible for storing the name of the file and knowing how to execute
the up and down migrations defined in the file.
*/
*/
var fs = require('fs');
var fs = require('fs');
var mkdirp = require('mkdirp');
var path = require('path');
var util = require('util');
var async = require('async');
var _ = require('lodash');
var path = require('path');
var util = require('util');
var async = require('async');
var utils = require('./utils');
var utils = require('./utils');
var MigrationBuilder = require('./migration-builder');
var db = require('./db');
var Migration = function(path, actions, options){
var Migration = function(migrationPath, actions, options) {
var self = this;
this.path = path;
this.name = path.split('/').pop().replace(/\.js$/, '');
actions = actions || {};
this.path = migrationPath;
this.name = migrationPath.split('/').pop().replace(/\.js$/, '');
actions = actions || {}; // eslint-disable-line no-param-reassign
this.up = actions.up;
this.down = actions.down;
self.applyUp = function(done){
self.applyUp = function(done) {
var pgm = new MigrationBuilder();
function upComplete(){
console.log('### MIGRATION '+self.name+' (up) ###')
function upComplete() {
console.log('### MIGRATION ' + self.name + ' (up) ###');
var sql_steps = pgm.getSqlSteps();
sql_steps.push( utils.t("INSERT INTO "+options.migrations_table+" (name, run_on) VALUES ('{name}', NOW());", { name: self.name }) );
sql_steps.push(utils.t('INSERT INTO "{table}" (name, run_on) VALUES (\'{name}\', NOW());', { table: options.migrations_table, name: self.name }));
if (pgm.use_transaction){
if (pgm.use_transaction) {
// wrap in a transaction, combine into one sql statement

@@ -43,9 +42,9 @@ sql_steps.unshift('BEGIN;');

} else {
console.log('#> WARNING: This migration is not wrapped in a transaction! <')
console.log('#> WARNING: This migration is not wrapped in a transaction! <');
}
console.log( sql_steps.join("\n")+"\n\n" );
console.log(sql_steps.join('\n') + '\n\n');
if (!global.dryRun) {
async.eachSeries(sql_steps, function(sql, next_step){
async.eachSeries(sql_steps, function(sql, next_step) {
db.query(sql, next_step);

@@ -58,15 +57,15 @@ }, done);

if (self.up.length == 2) {
if (self.up.length === 2) {
self.up(pgm, upComplete);
} else {
self.up(pgm);
upComplete()
upComplete();
}
}
self.applyDown = function(done){
};
self.applyDown = function(done) {
var pgm = new MigrationBuilder();
if (self.down === false){
return done('User has disabled down migration on file: '+self.name);
} else if (self.down === undefined){
if (self.down === false) {
return done('User has disabled down migration on file: ' + self.name);
} else if (self.down === undefined) {
// automatically infer the down migration by running the up migration in reverse mode...

@@ -77,10 +76,9 @@ pgm.enableReverseMode();

function downComplete(){
function downComplete() {
console.log('### MIGRATION ' + self.name + ' (down) ###');
console.log('### MIGRATION '+self.name+' (down) ###')
var sql_steps = pgm.getSqlSteps();
sql_steps.push( utils.t("DELETE FROM "+options.migrations_table+" WHERE name='{name}';", { name: self.name }) );
sql_steps.push(utils.t('DELETE FROM "{table}" WHERE name=\'{name}\';', { table: options.migrations_table, name: self.name }));
if (pgm.use_transaction){
if (pgm.use_transaction) {
// wrap in a transaction, combine into one sql statement

@@ -90,9 +88,9 @@ sql_steps.unshift('BEGIN;');

} else {
console.log('#> WARNING: This migration is not wrapped in a transaction! <')
console.log('#> WARNING: This migration is not wrapped in a transaction! <');
}
console.log( sql_steps.join("\n")+"\n\n" );
console.log(sql_steps.join('\n') + '\n\n');
if (!global.dryRun) {
async.eachSeries(sql_steps, function(sql, next_step){
async.eachSeries(sql_steps, function(sql, next_step) {
db.query(sql, next_step);

@@ -105,14 +103,13 @@ }, done);

if (self.down.length == 2) {
if (self.down.length === 2) {
self.down(pgm, downComplete);
} else {
self.down(pgm);
downComplete()
downComplete();
}
}
}
};
};
// class method that creates a new migration file by cloning the migration template
Migration.create = function(name, directory){
Migration.create = function(name, directory) {
// ensure the migrations directory exists

@@ -125,7 +122,7 @@ mkdirp.sync(directory);

// copy the default migration template to the new file location
fs.createReadStream( path.resolve(__dirname, './migration-template.js'))
.pipe(fs.createWriteStream( new_file ));
fs.createReadStream(path.resolve(__dirname, './migration-template.js'))
.pipe(fs.createWriteStream(new_file));
return new Migration( new_file );
}
return new Migration(new_file);
};

@@ -132,0 +129,0 @@ module.exports = Migration;

@@ -5,7 +5,7 @@ var utils = require('../utils');

var ops = module.exports = {
create: function( extensions ) {
if ( !_.isArray(extensions) ) extensions = [extensions];
return _.map(extensions, function(extension){
return utils.t('CREATE EXTENSION \"{extension}\";', {
extension: extension
create: function(extensions) {
if (!_.isArray(extensions)) extensions = [ extensions ]; // eslint-disable-line no-param-reassign
return _.map(extensions, function(extension) {
return utils.t('CREATE EXTENSION "{extension}";', {
extension: extension,
});

@@ -15,13 +15,13 @@ });

drop: function( extensions ) {
if ( !_.isArray(extensions) ) extensions = [extensions];
return _.map(extensions, function(extension){
return utils.t('DROP EXTENSION \"{extension}\";', {
extension: extension
drop: function(extensions) {
if (!_.isArray(extensions)) extensions = [ extensions ]; // eslint-disable-line no-param-reassign
return _.map(extensions, function(extension) {
return utils.t('DROP EXTENSION "{extension}";', {
extension: extension,
});
});
},
}
};
// setup reverse functions
ops.create.reverse = ops.drop;
var utils = require('../utils');
var _ = require('lodash');
function generateIndexName(table_name, columns, options) {
if (options.name) return options.name;
var name = table_name;
if (_.isArray(columns)) name += '_' + columns.join('_');
else name += '_' + columns;
if (options.unique) name += '_unique';
name += '_index';
return name;
// if (options.unique)
}
function generateColumnsString(columns) {
if (_.isArray(columns)) return columns.map(function(name) {
return '"' + name + '"';
}).join(', ');
if (/.+\(.*\)/.test(columns)) return columns; // expression
return '"' + columns + '"'; // single column
}
var ops = module.exports = {
create: function( table_name, columns, options ) {
create: function(table_name, columns, options) {
/*
columns - the column, columns, or expression to create the index on
columns - the column, columns, or expression to create the index on
Options
name - explicitly specify the name for the index
unique - is this a unique index
where - where clause
concurrently -
options.method - [ btree | hash | gist | spgist | gin ]
*/
options = options || {};
Options
name - explicitly specify the name for the index
unique - is this a unique index
where - where clause
concurrently -
options.method - [ btree | hash | gist | spgist | gin ]
*/
options = options || {}; // eslint-disable-line no-param-reassign
var sql = utils.t('CREATE {unique} INDEX {concurrently}{index_name} ON \"{table_name}\"{method} ({columns}){where};', {
table_name : table_name,
index_name : generateIndexName( table_name, columns, options ),
columns : generateColumnsString(columns),
unique : options.unique ? ' UNIQUE ' : '',
concurrently : options.concurrently ? ' CONCURRENTLY ' : '',
method : options.method ? ' USING '+options.method : '',
where : options.where ? ' WHERE '+options.where : '',
}
var sql = utils.t('CREATE {unique} INDEX {concurrently} "{index_name}" ON "{table_name}"{method} ({columns}){where};', {
table_name: table_name,
index_name: generateIndexName(table_name, columns, options),
columns: generateColumnsString(columns),
unique: options.unique ? ' UNIQUE ' : '',
concurrently: options.concurrently ? ' CONCURRENTLY ' : '',
method: options.method ? ' USING ' + options.method : '',
where: options.where ? ' WHERE ' + options.where : '',
}
);

@@ -32,29 +51,11 @@ return sql;

drop: function ( table_name, columns, options ) {
options = options || {};
drop: function(table_name, columns, options) {
options = options || {}; // eslint-disable-line no-param-reassign
var index_name = generateIndexName( table_name, columns, options );
return utils.t('DROP INDEX {index};', { index: index_name } );
}
}
var index_name = generateIndexName(table_name, columns, options);
return utils.t('DROP INDEX "{index}";', { index: index_name });
},
};
// setup reverse functions
ops.create.reverse = ops.drop;
function generateIndexName( table_name, columns, options ){
if (options.name) return options.name;
var name = table_name;
if ( _.isArray(columns) ) name += '_' + columns.join('_');
else name += '_' + columns;
if (options.unique) name += '_unique';
name += '_index';
return name;
// if (options.unique)
}
function generateColumnsString(columns){
if ( _.isArray(columns) ) return columns = columns.map(function(name){return '"' + name + '"';}).join(', ');
if (/.+\(.*\)/.test(columns)) return columns; //expression
return columns = '"' + columns + '"'; //single column
}
var utils = require('../utils');
module.exports = {
sql: function(sql, args){
sql: function(sql, args) {
// applies some very basic templating using the utils.p
var s = utils.t(sql, args);
// add trailing ; if not present
if (s.lastIndexOf(';') != (s.length - 1)){
if (s.lastIndexOf(';') !== (s.length - 1)) {
s += ';';
}
return s;
}
}
},
};
var utils = require('../utils');
var _ = require('lodash');
var type_adapters = {
int: 'integer',
string: 'text',
float: 'real',
double: 'double precision',
datetime: 'timestamp',
bool: 'boolean',
};
function applyTypeAdapters(type) {
// some convenience adapters -- see above
return type_adapters[type] ? type_adapters[type] : type;
}
function parseColumns(columns) {
return _.map(columns, function(options, column_name) {
options = options || {}; // eslint-disable-line no-param-reassign
var type = applyTypeAdapters(options.type);
var constraints = [];
if (typeof options === 'string') {
// convenience type for serial primary keys
if (options === 'id') {
type = 'serial';
options = { primaryKey: true }; // eslint-disable-line no-param-reassign
} else {
type = options;
}
}
if (options.unique) {
constraints.push('UNIQUE');
}
if (options.primaryKey) {
constraints.push('PRIMARY KEY');
}
if (options.notNull) {
constraints.push('NOT NULL');
}
if (options.check) {
constraints.push('CHECK (' + options.check + ')');
}
if (options.references) {
constraints.push('REFERENCES ' + options.references);
if (options.onDelete) {
constraints.push('ON DELETE ' + options.onDelete);
}
if (options.onUpdate) {
constraints.push('ON UPDATE ' + options.onUpdate);
}
}
return utils.t('"{column_name}" {type}{default}{constraints}', {
column_name: column_name,
type: type,
default: options.default !== undefined ? ' DEFAULT ' + utils.escapeValue(options.default) : '',
constraints: constraints.length ? ' ' + constraints.join(' ') : '',
});
}).join(', \n');
}
var ops = module.exports = {
create: function( table_name, columns, options ) {
create: function(table_name, columns, options) {
/*
columns - hash of columns
columns - hash of columns
Options
table_name - the name of the table
columns - see column options
options.inherits - table to inherit from (optional)
*/
options = options || {};
var sql = utils.t("CREATE TABLE \"{table_name}\" (\n{columns}\n){inherits};", {
table_name : table_name,
columns : parseColumns( columns ).replace(/^/gm, ' '),
inherits : options.inherits ? ' INHERITS '+options.inherits : '',
Options
table_name - the name of the table
columns - see column options
options.inherits - table to inherit from (optional)
*/
options = options || {}; // eslint-disable-line no-param-reassign
var sql = utils.t('CREATE TABLE "{table_name}" (\n{columns}\n){inherits};', {
table_name: table_name,
columns: parseColumns(columns).replace(/^/gm, ' '),
inherits: options.inherits ? ' INHERITS ' + options.inherits : '',
});

@@ -23,78 +84,77 @@ return sql;

drop: function ( table_name ) {
return utils.t('DROP TABLE \"{table_name}\";', { table_name: table_name } );
drop: function(table_name) {
return utils.t('DROP TABLE "{table_name}";', { table_name: table_name });
},
addColumns: function ( table_name, columns ) {
return utils.t("ALTER TABLE \"{table_name}\" \n{actions};", {
addColumns: function(table_name, columns) {
return utils.t('ALTER TABLE "{table_name}" \n{actions};', {
table_name: table_name,
actions: parseColumns( columns ).replace(/^/gm, ' ADD '),
actions: parseColumns(columns).replace(/^/gm, ' ADD '),
});
},
dropColumns: function ( table_name, columns ) {
if ( typeof columns === 'string' ) {
columns = [columns];
} else if ( !_.isArray(columns) && typeof columns === 'object' ){
columns = _.keys(columns);
dropColumns: function(table_name, columns) {
if (typeof columns === 'string') {
columns = [ columns ]; // eslint-disable-line no-param-reassign
} else if (!_.isArray(columns) && typeof columns === 'object') {
columns = _.keys(columns); // eslint-disable-line no-param-reassign
}
return utils.t("ALTER TABLE \"{table_name}\" \n{actions};", {
return utils.t('ALTER TABLE "{table_name}" \n{actions};', {
table_name: table_name,
actions: columns.join(",\n").replace(/^/gm, ' DROP '),
actions: columns.join(',\n').replace(/^/gm, ' DROP '),
});
},
alterColumn: function ( table_name, column_name, options ) {
alterColumn: function(table_name, column_name, options) {
var actions = [];
if ( options.default === null ){
if (options.default === null) {
actions.push('DROP DEFAULT');
} else if ( options.default !== undefined ){
actions.push('SET DEFAULT '+utils.escapeValue(options.default));
} else if (options.default !== undefined) {
actions.push('SET DEFAULT ' + utils.escapeValue(options.default));
}
if ( options.type ){
actions.push('SET DATA TYPE '+applyTypeAdapters(options.type));
if (options.type) {
actions.push('SET DATA TYPE ' + applyTypeAdapters(options.type));
}
if ( options.notNull ){
if (options.notNull) {
actions.push('SET NOT NULL');
} else if ( options.notNull === false || options.allowNull ){
} else if (options.notNull === false || options.allowNull) {
actions.push('DROP NOT NULL');
}
return utils.t("ALTER TABLE \"{table_name}\" \n{actions};", {
return utils.t('ALTER TABLE "{table_name}" \n{actions};', {
table_name: table_name,
actions: actions.join(",\n").replace(/^/gm, ' ALTER '+column_name+' '),
actions: actions.join(',\n').replace(/^/gm, ' ALTER ' + column_name + ' '),
});
},
// RENAME
renameTable: function( table_name, new_name ){
return utils.t("ALTER TABLE \"{table_name}\" RENAME TO {new_name};", {
renameTable: function(table_name, new_name) {
return utils.t('ALTER TABLE "{table_name}" RENAME TO "{new_name}";', {
table_name: table_name,
new_name: new_name
new_name: new_name,
});
},
undoRenameTable: function( table_name, new_name ){
module.exports.renameTable( new_name, table_name );
undoRenameTable: function(table_name, new_name) {
module.exports.renameTable(new_name, table_name);
},
renameColumn: function( table_name, column_name, new_name ){
return utils.t("ALTER TABLE \"{table_name}\" RENAME {column} TO {new_name};", {
renameColumn: function(table_name, column_name, new_name) {
return utils.t('ALTER TABLE "{table_name}" RENAME "{column}" TO "{new_name}";', {
table_name: table_name,
column: column_name,
new_name: new_name
new_name: new_name,
});
},
undoRenameColumn: function( table_name, column_name, new_name ){
module.exports.renameColumn( table_name, new_name, column_name );
undoRenameColumn: function(table_name, column_name, new_name) {
module.exports.renameColumn(table_name, new_name, column_name);
},
// CONSTRAINTS -- only supports named check constraints
addConstraint: function( table_name, constraint_name, expression ){
return utils.t("ALTER TABLE \"{table_name}\" ADD{constraint_name} {constraint};", {
addConstraint: function(table_name, constraint_name, expression) {
return utils.t('ALTER TABLE "{table_name}" ADD{constraint_name} {constraint};', {
table_name: table_name,
constraint_name: constraint_name ? ' CONSTRAINT '+constraint_name : '',
constraint: expression
constraint_name: constraint_name ? ' CONSTRAINT "' + constraint_name + '"' : '',
constraint: expression,
});
},
dropConstraint: function( table_name, constraint_name, expression ){
return utils.t("ALTER TABLE \"{table_name}\" DROP CONSTRAINT {constraint_name};", {
dropConstraint: function(table_name, constraint_name) {
return utils.t('ALTER TABLE "{table_name}" DROP CONSTRAINT "{constraint_name}";', {
table_name: table_name,

@@ -106,17 +166,15 @@ constraint_name: constraint_name,

createType: function( type_name, options ){
return utils.t("CREATE TYPE {type_name} AS ENUM ('{opts}');", {
createType: function(type_name, options) {
return utils.t('CREATE TYPE "{type_name}" AS ENUM (\'{opts}\');', {
type_name: type_name,
opts: options.join("', '")
opts: options.join('\', \''),
});
},
dropType: function( type_name ){
return utils.t("DROP TYPE {type_name};", { type_name: type_name });
dropType: function(type_name) {
return utils.t('DROP TYPE "{type_name}";', { type_name: type_name });
},
alterType: function( type_name, options ){
alterType: function() {
},
};
}
}
// setup reverse functions

@@ -129,64 +187,1 @@ ops.create.reverse = ops.drop;

ops.renameTable.reverse = ops.undoRenameTable;
var type_adapters = {
'int': 'integer',
'string': 'text',
'float': 'real',
'double': 'double precision',
'datetime': 'timestamp',
'bool': 'boolean',
}
function applyTypeAdapters ( type ){
// some convenience adapters -- see above
return type_adapters[type] ? type_adapters[type] : type;
}
function parseColumns ( columns ){
return _.map(columns, function( options, column_name ){
options = options || {};
var type = applyTypeAdapters(options.type);
var constraints = [];
if (typeof options === 'string'){
// convenience type for serial primary keys
if (options == 'id'){
type = 'serial';
options = { primaryKey: true };
} else {
type = options;
}
}
if (options.unique){
constraints.push('UNIQUE');
}
if (options.primaryKey){
constraints.push('PRIMARY KEY');
}
if (options.notNull){
constraints.push('NOT NULL');
}
if (options.check){
constraints.push('CHECK ('+options.check+')');
}
if (options.references){
constraints.push('REFERENCES '+options.references);
if (options.onDelete){
constraints.push('ON DELETE '+options.onDelete);
}
if (options.onUpdate){
constraints.push('ON UPDATE '+options.onUpdate);
}
}
return utils.t('\"{column_name}\" {type}{default}{constraints}', {
column_name: column_name,
type: type,
default: options.default !== undefined ? ' DEFAULT '+utils.escapeValue(options.default) : '',
constraints: constraints.length ? ' '+constraints.join(' ') : ''
});
}).join(", \n");
}

@@ -9,24 +9,59 @@ var async = require('async');

module.exports = function MigrationRunner(options){
function loadMigrationFiles(options) {
var migrations = [];
fs.readdirSync(options.dir + '/').forEach(function(file) {
if (file.match(/.+\.js$/g) !== null && file !== 'index.js') {
var file_path = options.dir + '/' + file;
var actions = require(path.relative(__dirname, file_path));
var migration = new Migration(file_path, actions, options);
migrations.push(migration);
}
});
return _.sortBy(migrations, 'name');
}
function ensureMigrationTableExists(options, callback) {
Step(
function checkIfTableExists() {
db.query('SELECT table_name FROM information_schema.tables WHERE table_schema = \'public\' AND table_name = \'' + options.migrations_table + '\'', this);
},
function createTableIfNecessary(err, result) {
if (err) return callback(err);
if (result && result.rows && result.rows.length === 1) return callback();
db.query('CREATE TABLE "' + options.migrations_table + '" ( id SERIAL, name varchar(255) NOT NULL, run_on timestamp NOT NULL)', this);
},
function finish(err) {
if (err) return callback(err);
return callback();
}
);
}
module.exports = function MigrationRunner(options) {
var self = this;
var migrations = [];
loadMigrationFiles();
var migrations = loadMigrationFiles(options);
db.init(options.database_url);
self.run = function(callback) {
function exitCallback(arg) {
db.close();
callback(arg);
}
self.run = function(callback){
var current_index, migrate_to_index;
Step(
function(){
ensureMigrationTableExists(this);
function() {
db.init(options.database_url);
this();
},
function fetchCompletedMigrations(err){
db.query("SELECT * FROM "+options.migrations_table+" ORDER BY run_on", this)
function() {
ensureMigrationTableExists(options, this);
},
function fetchCompletedMigrations() {
db.query('SELECT * FROM "' + options.migrations_table + '" ORDER BY run_on', this);
},
function determineMigrationsToRun(err, result) {
if(err) return callback(err);
if(!result || !result.rows) return callback(new Error('Unable to fetch migrations from pgmigrations table'));
if (err) return exitCallback(err);
if (!result || !result.rows) return exitCallback(new Error('Unable to fetch migrations from ' + options.migrations_table + ' table'));
//store done migration names
// store done migration names
var runNames = result.rows.map(function(row) {

@@ -39,9 +74,8 @@ return row.name;

//filter out undone and done migrations from list of files
for(var i = 0; i < migrations.length; i++) {
if(runNames.indexOf(migrations[i].name) < 0) {
//if specific migration file is requested
if(options.file && options.file == migrations[i].name) {
runMigrations = [migrations[i]];
// filter out undone and done migrations from list of files
for (var i = 0; i < migrations.length; i++) {
if (runNames.indexOf(migrations[i].name) < 0) {
// if specific migration file is requested
if (options.file && options.file === migrations[i].name) {
runMigrations = [ migrations[i] ];
break;

@@ -51,14 +85,13 @@ }

} else {
doneMigrations.push(migrations[i])
doneMigrations.push(migrations[i]);
}
}
//final selection will go here
// final selection will go here
var to_run;
//down gets by default one migration at the time, if not set otherwise
if(options.direction == 'down') {
// down gets by default one migration at the time, if not set otherwise
if (options.direction === 'down') {
to_run = doneMigrations.slice(-1);
//up gets all undone migrations by default
// up gets all undone migrations by default
} else {

@@ -68,7 +101,7 @@ to_run = runMigrations;

//if specific count of migrations is requested
if(options.count) {
// if specific count of migrations is requested
if (options.count) {
// infinity is set in the bin file
if(options.count !== Infinity) {
if(options.direction == 'up') {
if (options.count !== Infinity) {
if (options.direction === 'up') {
to_run = runMigrations.slice(0, options.count);

@@ -81,5 +114,5 @@ } else {

if(!to_run.length) {
if (!to_run.length) {
console.log('No migrations to run!');
return callback();
return exitCallback();
}

@@ -89,60 +122,26 @@

console.log('> Migrating files:');
for(var i in to_run) {
console.log('> - ' + to_run[i].name);
}
to_run.forEach(function(m) {
console.log('> - ' + m.name);
});
this(null, to_run);
},
function runMigrations(err, migrations_to_run){
if (err) return callback(err);
async.eachSeries(migrations_to_run, function(m, next){
if (options.direction == 'up') m.applyUp(next);
function runMigrations(err, migrations_to_run) {
if (err) return exitCallback(err);
async.eachSeries(migrations_to_run, function(m, next) {
if (options.direction === 'up') m.applyUp(next);
else m.applyDown(next);
}, this);
},
function finish(err){
function finish(err) {
if (err) {
console.log('> Rolling back attempted migration ...')
return callback(err);
console.log('> Rolling back attempted migration ...');
return exitCallback(err);
}
callback();
exitCallback();
}
)
}
);
};
};
function loadMigrationFiles(){
fs.readdirSync( options.dir + '/' ).forEach(function(file) {
if (file.match(/.+\.js$/g) !== null && file !== 'index.js') {
var name = file.replace('.js', '');
// console.log( '> loading migration: '+name)
var file_path = options.dir +'/'+ file;
var actions = require( path.relative(__dirname, file_path) );
var migration = new Migration( file_path, actions, options );
migrations.push(migration);
}
});
migrations = _.sortBy(migrations, 'name');
}
function ensureMigrationTableExists(callback){
Step(
function checkIfTableExists(){
db.query("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '"+options.migrations_table+"'", this);
},
function createTableIfNecessary(err, result){
if (err) return callback(err);
if (result && result.rows && result.rows.length == 1) return callback();
db.query('CREATE TABLE '+options.migrations_table+' ( id SERIAL, name varchar(255) NOT NULL, run_on timestamp NOT NULL)', this);
},
function finish(err){
if (err) return callback(err);
return callback();
}
)
}
}

@@ -0,29 +1,37 @@

// This is used to create unescaped strings
// exposed in the migrations via pgm.func
function PgLiteral(str) {
this.toString = function() {
return str;
};
}
PgLiteral.create = function(str) {
return new PgLiteral(str);
};
module.exports = {
// teeny templating function
// http://mir.aculo.us/2011/03/09/little-helpers-a-tweet-sized-javascript-templating-engine/
t: function(s,d){
for(var p in d)
s=s.replace(new RegExp('{'+p+'}','g'), d[p]);
return s;
t: function(s, d) {
return Object
.keys(d || {})
.reduce(function(str, p) {
var newSubstr = d[p];
if (typeof d[p] === 'object') {
var schema = d[p].schema;
var name = d[p].name;
newSubstr = (schema ? schema + '"."' : '') + name;
}
return str.replace(new RegExp('{' + p + '}', 'g'), newSubstr);
}, s);
},
escapeValue: function ( val ){
escapeValue: function(val) {
// TODO: figure out a solution for unescaping functions -- ex: NOW()
if ( val === null ) return 'NULL';
if ( typeof val === 'boolean' ) return val.toString();
if ( typeof val === 'string' ) return "'"+escape(val)+"'";
if ( typeof val === 'number' ) return val;
if ( val instanceof PgLiteral ) return val.toString();
if (val === null) return 'NULL';
if (typeof val === 'boolean') return val.toString();
if (typeof val === 'string') return '\'' + escape(val) + '\'';
if (typeof val === 'number') return val;
if (val instanceof PgLiteral) return val.toString();
},
PgLiteral: PgLiteral
}
// This is used to create unescaped strings
// exposed in the migrations via pgm.func
function PgLiteral(str){
this.toString = function(){
return str;
}
}
PgLiteral.create = function(str){
return new PgLiteral(str);
}
PgLiteral: PgLiteral,
};

@@ -18,3 +18,3 @@ {

],
"version": "0.0.12",
"version": "0.0.13",
"engines": {

@@ -37,6 +37,7 @@ "node": ">=0.6.0"

"optimist": "~0.6.1",
"pkginfo": "~0.3.0",
"step": "0.0.5"
},
"devDependencies": {
"eslint": "^3.11.1",
"eslint-plugin-import": "^2.2.0",
"mocha": "^2.2.5",

@@ -51,4 +52,6 @@ "pg": "^6.1.2",

"scripts": {
"test": "./node_modules/.bin/mocha test"
"test": "./node_modules/.bin/mocha test",
"lint": "eslint -c .eslintrc . bin/pg-migrate",
"lintfix": "npm run lint -- --fix"
}
}

@@ -300,6 +300,17 @@ # pg-migrate

### Using schemas
Instead of passing string as name to `pgm` functions, you can pass an object with keys `schema` and `name`. E.g.
`pgm.createTable( {schema: 'my_schema', name: 'my_table_name'}, {id: 'serial'});`
will generate
```sql
CREATE TABLE "my_schema"."my_table_name" (
"id" serial
);
```
## Explanation & Goals

@@ -306,0 +317,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc