UNPKG

flexgres

Version:

Flexibly change your Postgres schemas with Flexgres.

310 lines (273 loc) 8.89 kB
/* Getting Started ** Before you test this script make sure you run two commands in PSQL ** 1) `CREATE USER chris WITH PASSWORD '12345'` ** 2) `CREATE DATABASE flexgres` ** You should now be able to test flexgres schemas */ var async = require("async"); module.exports = function(config, cb) { //These are mandatory if (!config.driver) throw "Must supply driver."; if (!config.tables) throw "Must supply table structure."; var client = config.driver; var tables = config.tables; //Optional features var logging = config.logging || false; //This is for the diffing computation var diffs = []; var diffsTbl = []; //Run the query client.connect(function(err) { if (err) throw err; async.series([ //Find diffs in existing tables function(callback) { async.eachSeries(config.tables, function(table,callbackEach) { var q = ` SELECT * FROM information_schema.columns WHERE table_name = '`+ table.tableName +`' `; if (logging == true) console.log(q); client.query(q, function(err, result) { if (err) throw err result.rows.map(function(row) { diffs.push({ "table": row.table_name, "column": row.column_name, "null": row.is_nullable, "dtype": row.data_type }) }) callbackEach(); }) }, function() { callback(); }) }, //Add columns based on if it's not found in diffs function(callback) { async.eachSeries(tables, function(table, callbackEach) { var c = table.columns; var t = c.filter(function(t) { var truthy = true; diffs.map(function(diff) { if (t.name.toUpperCase() == diff.column.toUpperCase()) { truthy = false; } }) return truthy; }); if (t.length > 0) { c = t[0]; } else { return callbackEach(); } console.log(c); var d = c.type.toUpperCase(); var n = c.null; if (n == false) { n = "NOT NULL"; } else { n = ""; } q = ` ALTER TABLE `+table.tableName+` ADD `+c.name+` `+d+` `+n+` ` if (logging == true) console.log(q); client.query(q, function(err, result) { if (err) throw err; return callbackEach(); }) }, function() { return callback(); }) }, //Change diffs based on existing schemas function(callback) { async.eachSeries(diffs, function(diff, callbackEach) { var structure = ""; var q1, q2, flag = false; var t = tables.filter(function(t) { return t.tableName.toUpperCase() == diff.table.toUpperCase() }); if (t.length == 0) { return callbackEach(); } var c = t[0].columns.filter(function(co) { return co.name.toUpperCase() == diff.column.toUpperCase(); }); if (c.length == 0) { q1 = ` ALTER TABLE `+diff.table+` DROP COLUMN `+diff.column+` ` if (logging == true) console.log("s1", q1); flag = true; client.query(q1, function(err, result) { if (err) throw err; }) } else if (c.length == 1 && diff) { var dt = diff.dtype.toUpperCase(); var ct = c[0].type.toUpperCase(); var nt = ct; ct = ct .replace("INT", "INTEGER") .replace("INT8", "BIGINT") .replace("SERIAL8", "BIGSERIAL") .replace("VARBIT", "BIT VARYING") .replace("BOOL", "BOOLEAN") .replace("CHAR", "CHARACTER") .replace("VARCHAR", "CHARACTER VARYING") .replace("FLOAT8", "DOUBLE PRECISION") .replace("INT4", "INTEGER") .replace("DECIMAL", "NUMERIC") .replace("FLOAT4", "REAL") .replace("INT2", "SMALLINT") .replace("SERIAL2", "SMALLSERIAL") .replace("SERIAL4", "SERIAL") .replace("TIMETZ", "TIME") .replace("TIMESTAMPTZ", "TIMESTAMP") dt = dt .replace("INT", "INTEGER") .replace("INT8", "BIGINT") .replace("SERIAL8", "BIGSERIAL") .replace("VARBIT", "BIT VARYING") .replace("BOOL", "BOOLEAN") .replace("CHAR", "CHARACTER") .replace("VARCHAR", "CHARACTER VARYING") .replace("FLOAT8", "DOUBLE PRECISION") .replace("INT4", "INTEGER") .replace("DECIMAL", "NUMERIC") .replace("FLOAT4", "REAL") .replace("INT2", "SMALLINT") .replace("SERIAL2", "SMALLSERIAL") .replace("SERIAL4", "SERIAL") .replace("TIMETZ", "TIME") .replace("TIMESTAMPTZ", "TIMESTAMP") if ( diff.null == "NO" && c[0].null == false && dt == ct ) { return callbackEach(); } if (diff.null == "NO") { var n = "NOT NULL"; } else { var n = ""; } var d = nt; q1 = ` ALTER TABLE `+diff.table+` DROP `+diff.column+` ` q2 = ` ALTER TABLE `+diff.table+` ADD `+diff.column+` `+d+` `+n+` ` } else { return callbackEach(); } async.series([ function(callback2) { if (flag == true) return callbackEach(); if (logging == true) console.log("s2", q1); client.query(q1, function(err, result) { if (err) throw err; return callback2(); }) }, function(callback2) { if (logging == true) console.log(q2); client.query(q2, function(err, result) { if (err) throw err; return callbackEach(); }) } ]) }, function() { return callback(); }) }, //Find diffs in schema function(callback) { var q = ` SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ` if (logging == true) console.log(q); client.query(q, function(err, result) { if (err) throw err; result.rows.map(function(t) { diffsTbl.push(t.table_name); }) callback(); }) }, //Drop tables if they exist function (callback) { async.eachSeries(diffsTbl, function(dTbl, callbackEach) { var m = tables.filter(function(t) { return t.tableName.toLowerCase() == dTbl.toLowerCase(); }) if (m.length == 0) { var q = "\ DROP TABLE IF EXISTS "+dTbl+" \ "; if (logging == true) console.log(q); client.query(q, function(err, result) { if (err) throw err; callbackEach(); }) } else { callbackEach(); } }, function() { callback(); }) }, //Create new tables if they don't exist already function(callback) { async.eachSeries(tables, function(table, callbackEach) { var m = false; table.tableName = table.tableName.toLowerCase(); diffsTbl.map(function(d) { if (d == table.tableName) m = true; }) if (m == true) return callbackEach(); var structure = ""; table.columns.map(function(c, index) { var p = ""; if (c["primary"] == true) p = "PRIMARY KEY"; var n = ""; if (c["null"] == false) n = "NOT NULL"; structure = structure + c["name"] + " " + c["type"] + " " + p + " " + n if (index < table.columns.length - 1) { structure = structure + ","; } }) var q = "\ CREATE TABLE "+table.tableName+"(\ "+structure+"\ );\ "; if (logging == true) console.log(q); client.query(q, function(err, result) { if (err) throw err; callbackEach(); }) }, function() { callback(); }) } ], function() { client.end(); cb(); }) }) }