pimatic
Version:
A home automation server and framework for the Raspberry PI running on node.js
242 lines (202 loc) • 7.78 kB
JavaScript
'use strict';
exports.__esModule = true;
var _omit2 = require('lodash/omit');
var _omit3 = _interopRequireDefault(_omit2);
var _map2 = require('lodash/map');
var _map3 = _interopRequireDefault(_map2);
var _identity2 = require('lodash/identity');
var _identity3 = _interopRequireDefault(_identity2);
var _find2 = require('lodash/find');
var _find3 = _interopRequireDefault(_find2);
var _uniqueId2 = require('lodash/uniqueId');
var _uniqueId3 = _interopRequireDefault(_uniqueId2);
var _assign2 = require('lodash/assign');
var _assign3 = _interopRequireDefault(_assign2);
var _bluebird = require('bluebird');
var _bluebird2 = _interopRequireDefault(_bluebird);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// So altering the schema in SQLite3 is a major pain.
// We have our own object to deal with the renaming and altering the types
// for sqlite3 things.
function SQLite3_DDL(client, tableCompiler, pragma, connection) {
this.client = client;
this.tableCompiler = tableCompiler;
this.pragma = pragma;
this.tableName = this.tableCompiler.tableNameRaw;
this.alteredName = (0, _uniqueId3.default)('_knex_temp_alter');
this.connection = connection;
}
// SQLite3_DDL
//
// All of the SQLite3 specific DDL helpers for renaming/dropping
// columns and changing datatypes.
// -------
(0, _assign3.default)(SQLite3_DDL.prototype, {
getColumn: _bluebird2.default.method(function (column) {
var currentCol = (0, _find3.default)(this.pragma, { name: column });
if (!currentCol) throw new Error('The column ' + column + ' is not in the ' + this.tableName + ' table');
return currentCol;
}),
getTableSql: function getTableSql() {
return this.trx.raw('SELECT name, sql FROM sqlite_master WHERE type="table" AND name="' + this.tableName + '"');
},
renameTable: _bluebird2.default.method(function () {
return this.trx.raw('ALTER TABLE "' + this.tableName + '" RENAME TO "' + this.alteredName + '"');
}),
dropOriginal: function dropOriginal() {
return this.trx.raw('DROP TABLE "' + this.tableName + '"');
},
dropTempTable: function dropTempTable() {
return this.trx.raw('DROP TABLE "' + this.alteredName + '"');
},
copyData: function copyData() {
return this.trx.raw('SELECT * FROM "' + this.tableName + '"').bind(this).then(this.insertChunked(20, this.alteredName));
},
reinsertData: function reinsertData(iterator) {
return function () {
return this.trx.raw('SELECT * FROM "' + this.alteredName + '"').bind(this).then(this.insertChunked(20, this.tableName, iterator));
};
},
insertChunked: function insertChunked(amount, target, iterator) {
iterator = iterator || _identity3.default;
return function (result) {
var batch = [];
var ddl = this;
return _bluebird2.default.reduce(result, function (memo, row) {
memo++;
batch.push(row);
if (memo % 20 === 0 || memo === result.length) {
return ddl.trx.queryBuilder().table(target).insert((0, _map3.default)(batch, iterator)).then(function () {
batch = [];
}).thenReturn(memo);
}
return memo;
}, 0);
};
},
createTempTable: function createTempTable(createTable) {
return function () {
return this.trx.raw(createTable.sql.replace(this.tableName, this.alteredName));
};
},
_doReplace: function _doReplace(sql, from, to) {
var matched = sql.match(/^CREATE TABLE (\S+) \((.*)\)/);
var tableName = matched[1];
var defs = matched[2];
if (!defs) {
throw new Error('No column definitions in this statement!');
}
var parens = 0,
args = [],
ptr = 0;
var i = 0;
var x = defs.length;
for (i = 0; i < x; i++) {
switch (defs[i]) {
case '(':
parens++;
break;
case ')':
parens--;
break;
case ',':
if (parens === 0) {
args.push(defs.slice(ptr, i));
ptr = i + 1;
}
break;
case ' ':
if (ptr === i) {
ptr = i + 1;
}
break;
}
}
args.push(defs.slice(ptr, i));
args = args.map(function (item) {
var split = item.split(' ');
if (split[0] === from) {
// column definition
if (to) {
split[0] = to;
return split.join(' ');
}
return ''; // for deletions
}
// skip constraint name
var idx = /constraint/i.test(split[0]) ? 2 : 0;
// primary key and unique constraints have one or more
// columns from this table listed between (); replace
// one if it matches
if (/primary|unique/i.test(split[idx])) {
return item.replace(/\(.*\)/, function (columns) {
return columns.replace(from, to);
});
}
// foreign keys have one or more columns from this table
// listed between (); replace one if it matches
// foreign keys also have a 'references' clause
// which may reference THIS table; if it does, replace
// column references in that too!
if (/foreign/.test(split[idx])) {
split = item.split(/ references /i);
// the quoted column names save us from having to do anything
// other than a straight replace here
split[0] = split[0].replace(from, to);
if (split[1].slice(0, tableName.length) === tableName) {
split[1] = split[1].replace(/\(.*\)/, function (columns) {
return columns.replace(from, to);
});
}
return split.join(' references ');
}
return item;
});
return sql.replace(/\(.*\)/, function () {
return '(' + args.join(', ') + ')';
}).replace(/,\s*([,)])/, '$1');
},
// Boy, this is quite a method.
renameColumn: _bluebird2.default.method(function (from, to) {
var _this = this;
return this.client.transaction(function (trx) {
_this.trx = trx;
return _this.getColumn(from).bind(_this).then(_this.getTableSql).then(function (sql) {
var a = this.client.wrapIdentifier(from);
var b = this.client.wrapIdentifier(to);
var createTable = sql[0];
var newSql = this._doReplace(createTable.sql, a, b);
if (sql === newSql) {
throw new Error('Unable to find the column to change');
}
return _bluebird2.default.bind(this).then(this.createTempTable(createTable)).then(this.copyData).then(this.dropOriginal).then(function () {
return this.trx.raw(newSql);
}).then(this.reinsertData(function (row) {
row[to] = row[from];
return (0, _omit3.default)(row, from);
})).then(this.dropTempTable);
});
}, { connection: this.connection });
}),
dropColumn: _bluebird2.default.method(function (column) {
var _this2 = this;
return this.client.transaction(function (trx) {
_this2.trx = trx;
return _this2.getColumn(column).bind(_this2).then(_this2.getTableSql).then(function (sql) {
var createTable = sql[0];
var a = this.client.wrapIdentifier(column);
var newSql = this._doReplace(createTable.sql, a, '');
if (sql === newSql) {
throw new Error('Unable to find the column to change');
}
return _bluebird2.default.bind(this).then(this.createTempTable(createTable)).then(this.copyData).then(this.dropOriginal).then(function () {
return this.trx.raw(newSql);
}).then(this.reinsertData(function (row) {
return (0, _omit3.default)(row, column);
})).then(this.dropTempTable);
});
}, { connection: this.connection });
})
});
exports.default = SQLite3_DDL;
module.exports = exports['default'];