digi-dump
Version:
Create a DUMP from MySQL
252 lines (221 loc) • 6.79 kB
JavaScript
var async = require('async');
var mqNode = require('mq-node');
var _ = require('lodash');
var fs = require('fs');
var mysql;
var extend = function(obj) {
for (var i = 1; i < arguments.length; i++) for (var key in arguments[i]) obj[key] = arguments[i][key];
return obj;
}
var typeCastOptions = { typeCast: function (field, next) {
if (field.type === "GEOMETRY") {
var offset = field.parser._offset;
var buffer = field.buffer();
field.parser._offset = offset;
var result = field.geometry();
annotateWkbTypes(result, buffer, 4);
return result;
}
return next();
}}
var annotateWkbTypes = function(geometry, buffer, offset) {
if (!buffer) return offset;
var byteOrder = buffer.readUInt8(offset); offset += 1;
var ignorePoints = function(count) { offset += count * 16; }
var readInt = function() {
var result = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset);
offset += 4;
return result;
}
geometry._wkbType = readInt();
if (geometry._wkbType === 1) {
ignorePoints(1);
} else if (geometry._wkbType === 2) {
ignorePoints(readInt());
} else if (geometry._wkbType === 3) {
var rings = readInt();
for (var i=0; i<rings; i++) {
ignorePoints(readInt());
}
} else if (geometry._wkbType === 7) {
var elements = readInt();
for (var i=0; i<elements; i++) {
offset = annotateWkbTypes(geometry[i], buffer, offset);
}
}
return offset
}
var escapeGeometryType = function(val) {
var constructors = {1: "POINT", 2: "LINESTRING", 3: "POLYGON", 4: "MULTIPOINT", 5: "MULTILINESTRING", 6: "MULTIPOLYGON", 7: "GEOMETRYCOLLECTION" };
var isPointType = function(val) { return val && typeof val.x === 'number' && typeof val.y === 'number'; }
var close = function(str) { return str.length && str[0] === '(' ? str : '(' + str + ')'; }
function escape(val) {
var result = isPointType(val) ? (val.x + " " + val.y) :
"(" + val.map(escape).join(',') + ")";
if (val._wkbType) {
result = constructors[val._wkbType] + close(result);
}
return result;
}
return "GeomFromText('" + escape(val) + "')";
}
var isset = function(){
var a = arguments;
var l = a.length;
var i = 0;
var undef;
if (l === 0) throw new Error('Empty isset');
while (i!==l) {
if(a[i]===undef || a[i]===null) return false;
++i;
}
return true;
}
var buildInsert = function(rows,table,options){
var cols = _.keys(rows[0]);
var sql = [];
if(cols.constructor===Array) {
var filteredCols = [];
if(
options.colsToIgnore &&
(options.colsToIgnore).constructor==Array &&
(options.colsToIgnore).length > 0
) {
cols.forEach((item) => {
if((options.colsToIgnore).indexOf(item) == -1) {
filteredCols.push(item);
}
});
} else {
filteredCols = cols;
}
for(var i in rows){
var values=[];
for(var k in rows[i]){
if(typeof rows[i][k]==='function') continue;
if(!isset(rows[i][k])){
if(rows[i][k]==null){
values.push("NULL");
} else {
values.push(" ");
}
} else if (rows[i][k]!=='') {
if (rows[i][k]._wkbType) {
var geometry = escapeGeometryType(rows[i][k]);
values.push(geometry);
} else if(typeof rows[i][k] === 'number'){
values.push(rows[i][k]);
} else {
values.push(mysql.escape(rows[i][k]));
}
} else {
values.push("''");
}
}
sql.push("INSERT INTO `"+table+"` (`"+filteredCols.join("`,`")+"`) VALUES ("+values.join()+");");
}
return sql.join('\n');
}
}
module.exports = function(options,done){
var defaultConnection = {
host: 'localhost',
user: 'root',
password: '',
database: 'test'
};
var defaultOptions = {
tables:null,
schema:true,
data:true,
ifNotExist:true,
autoIncrement:true,
dropTable:false,
getDump:false,
dest:'./data.sql',
where: null
}
mysql = mqNode(extend({},defaultConnection,{
host:options.host,
user:options.user,
password:options.password,
database:options.database,
port:options.port,
socketPath:options.socketPath,
}));
options = extend({},defaultConnection,defaultOptions,options);
if(!options.database) throw new Error('Database not specified');
async.auto({
getTables:function(callback){
if(!options.tables || !options.tables.length){ // if not especifed, get all
mysql.query("SHOW TABLES FROM `"+options.database+"`",function(err,data){
if(err) return callback(err);
var resp = [];
for(var i=0;i<data.length;i++) resp.push(data[i]['Tables_in_'+options.database]);
callback(err,resp);
});
} else {
callback(null,options.tables);
}
},
createSchemaDump:['getTables',function(callback,results){
if(!options.schema) {
callback();
return;
}
var run = [];
results.getTables.forEach(function(table){
run.push(function(callback){
mysql.query("SHOW CREATE TABLE `"+table+"`",callback);
})
})
async.parallel(run,function(err,data){
if (err) return callback(err);
var resp = [];
for(var i in data){
var r = data[i][0]['Create Table']+";";
if(options.dropTable) r = r.replace(/CREATE TABLE `/, 'DROP TABLE IF EXISTS `' + data[i][0]['Table'] + '`;\nCREATE TABLE `');
if(options.ifNotExist) r = r.replace(/CREATE TABLE `/,'CREATE TABLE IF NOT EXISTS `');
if(!options.autoIncrement) r = r.replace(/AUTO_INCREMENT=\d+ /g,'');
resp.push(r)
}
callback(err,resp);
});
}],
createDataDump:['createSchemaDump',function(callback,results){
var tbls = [];
if (options.data) {
tbls = results.getTables; // get data for all tables
} else if (options.where) {
tbls = Object.keys(options.where); // get data for tables with a where specified
} else {
callback();
return;
}
var run = [];
_.each(tbls,function(table){
run.push(function(callback){
var opts = {cols:'*', from:"`"+table+"`"};
if ((options.where != null) && (typeof options.where[table] != 'undefined')) {
opts.where = options.where[table];
}
mysql.select(opts,function(err,data){
if (err) return callback(err);
callback(err,buildInsert(data,table,options));
}, typeCastOptions);
});
});
async.parallel(run,callback)
}],
getDataDump:['createSchemaDump','createDataDump',function(callback,results){
if(!results.createSchemaDump || !results.createSchemaDump.length) results.createSchemaDump=[];
if(!results.createDataDump || !results.createDataDump.length) results.createDataDump=[];
callback(null,results.createSchemaDump.concat(results.createDataDump).join("\n\n"));
}]
},function(err,results){
if(err) return done(err);
mysql.connection.end();
if(options.getDump) return done(err, results.getDataDump);
fs.writeFile(options.dest, results.getDataDump, done);
});
}