enhancer-data-bridge
Version:
A bridge between Enhancer Clould and user business datasource
267 lines (243 loc) • 9.38 kB
JavaScript
;
const BaseServiceClass = require('./service-base');
const mysql = require('mysql');
const async = require('async');
const dmdb = require('dmdb');
var dbTypeMap = {
};
var varTypeMap = {
};
class DmdbService extends BaseServiceClass {
constructor(dbConfig) {
super(dbConfig);
this.dbConfig = dbConfig;
}
// @overridden BaseServiceClass#criteriaQuery
criteriaQuery(criteria, callback) {
var limitReg = /\sLIMIT\s+\d+\s*(\,\s*\d+\s*)?$/i;
var that = this;
var limitClause = criteria.query.match(limitReg);
criteria.query = criteria.query.replace(limitReg, '');
var statement = this.prepareSQLStatement(criteria, '?');
var sql = statement.sql + (limitClause || [''])[0];
var params = statement.params;
var ROWS_LENGTH = 'ROWS_LENGTH';
var countRecords = function(cb) {
if (!criteria.paged || !criteria.countRecords || !statement.isSelect) {
return cb(null, ROWS_LENGTH);
}
var countSql = that.getCountSql(sql, params);
// Create connection and destroy it after use. This is just for preview mode,
// and different from connection using method in bodhi app.
that.getConnection(function(err, conn) {
if (err) {
cb(err);
return;
}
conn.execute(countSql.sql, countSql.params, function(err, result) {
conn && conn.close();
if (err) {
return cb(err);
}
result = result.rows || [];
if (!result.length) {
return cb(null, 0);
}
cb(null, result[0][0]);
});
});
};
var fetchData = function(cb) {
if ( statement.isSelect && criteria.sortBy ) {
sql = sql + " ORDER BY " + criteria.sortBy;
}
if ( statement.isSelect && criteria.paged === true ) {
criteria.rowNum = parseInt(criteria.rowNum) || 1;
sql = sql.replace(limitReg, '');
sql = sql + " LIMIT "
+ ( ( criteria.page - 1 ) * criteria.rowNum )
+ ", " + criteria.rowNum;
}
that.getConnection(function(err, conn) {
if (err) {
cb(err);
return;
}
conn.execute(sql, params, function(err, result) {
conn && conn.close();
if (err) {
return cb(err);
}
var result = that.__handleQueryResult(result);
result.paged = criteria.paged;
result.page = criteria.page;
result.rowNum = criteria.rowNum;
cb(null, result);
});
});
};
async.parallel([countRecords, fetchData], function(err, results) {
if (err) {
return callback(err);
}
var records = results[0];
var finalResult = results[1];
finalResult.records = records === ROWS_LENGTH
? finalResult.rows.length
: records;
if (criteria.format === 'array') {
finalResult.rows = finalResult.rows.map(function(obj) {
var arr = [];
for (var i in obj) {
arr.push(obj[i]);
}
return arr;
});
}
callback(null, finalResult);
});
}
__handleQueryResult(result) {
// for sql procure
if (result.implicitResults && result.implicitResults.length) {
var last = result.implicitResults.length - 1;
result.rows = result.implicitResults[last];
result.metaDatas = result.metaData;
result.metaData = result.metaData[last];
}
var meta = result.metaData;
if (result.rows && result.rows.length) {
result.rows = result.rows.map(function(r) {
var d = {};
r.forEach(function(c, index) {
d[meta[index].name] = c;
});
return d;
});
}
result.affectedRows = result.rowsAffected;
return result;
}
execute(sql, params, callback) {
// Create connection and destroy it after use. This is just for preview mode,
// and different from connection using method in bodhi app.
var that = this;
that.getConnection(function(err, conn) {
if (err) {
callback(err);
return;
}
sql = sql.trim();
var methodName = 'execute';
var firstP = params[0];
if (params.length === 1
&& firstP instanceof Array
&& firstP[0] instanceof Array
&& /^INSERT\sINTO\s/i.test(sql)
) {
methodName = 'executeMany';
params = params[0];
// replace params placeholder;
var placeholder = [];
firstP[0].forEach(function() {
placeholder.push('?');
});
sql = sql.replace('?', placeholder.join(','));
}
conn[methodName](sql, params, function(err, result) {
conn && conn.close();
if (err) {
return callback(err);
}
var result = that.__handleQueryResult(result);
callback(null, result);
});
});
}
beginTransaction(en_cb) {
var that = this;
var dbConfig = this.dbConfig;
dmdb.createPool({
connectString: `dm://${dbConfig.user}:${dbConfig.password}\@${dbConfig.host}:${dbConfig.port}?injectArray=true&autoCommit=false`,
poolMin: 1,
poolMax: 1,
autoCommit: false
}).then(function(pool) {
pool.getConnection(function(err, conn) {
if (err) {
console.log(err);
en_cb(err);
return;
}
var newConn = {
close: function(cb) {
conn.close(cb);
},
release: function(cb) {
conn.release(cb);
},
rollback: function(cb) {
conn.rollback(cb);
},
commit: function(cb) {
conn.commit(cb);
},
execute: function(sql, params, __callback) {
// __callback(null, {rows:[], affectedRows:1});
sql = sql.trim();
var method = 'execute';
var firstP = params[0];
if (params.length === 1
&& firstP instanceof Array
&& firstP[0] instanceof Array
&& /^INSERT\sINTO\s/i.test(sql)
) {
method = 'executeMany';
params = params[0];
// replace params placeholder;
var placeholder = [];
firstP[0].forEach(function() {
placeholder.push('?');
});
sql = sql.replace('?', placeholder.join(','));
}
conn[method](sql, params, function(err, result) {
if (err) {
return __callback(err);
}
var result = that.__handleQueryResult(result);
__callback(null, result);
});
}
};
en_cb(null, newConn);
});
}).catch(function(err) {
en_cb(err);
});
}
getConnection(cb) {
var dbConfig = this.dbConfig;
dmdb.createPool({
connectString: `dm://${dbConfig.user}:${dbConfig.password}\@${dbConfig.host}:${dbConfig.port}?injectArray=true`,
poolMin: 1,
poolMax: 1
}).then(function(pool) {
pool.getConnection(function(err, conn) {
// if (conn) {
// var closeConn = conn.close;
// conn.close = function() {
// closeConn.apply(this, arguments);
// setTimeout(function() {
// pool.close();
// }, 3000);
// }
// }
cb(err, conn);
});
}).catch(function(err) {
cb(err);
});
}
}
module.exports = DmdbService;