196 lines
6.8 KiB
JavaScript
196 lines
6.8 KiB
JavaScript
|
|
var mysql = require('mysql');
|
|
const loopbackConnector = require('loopback-connector');
|
|
const SqlConnector = loopbackConnector.SqlConnector;
|
|
const ParameterizedSQL = loopbackConnector.ParameterizedSQL;
|
|
var MySQL = require('loopback-connector-mysql').MySQL;
|
|
var EnumFactory = require('loopback-connector-mysql').EnumFactory;
|
|
var debug = require('debug')('loopback-connector-sql');
|
|
|
|
exports.initialize = function(dataSource, callback) {
|
|
dataSource.driver = mysql;
|
|
dataSource.connector = new VnMySQL(dataSource.settings);
|
|
dataSource.connector.dataSource = dataSource;
|
|
|
|
var modelBuilder = dataSource.modelBuilder;
|
|
var defineType = modelBuilder.defineValueType ?
|
|
modelBuilder.defineValueType.bind(modelBuilder) :
|
|
modelBuilder.constructor.registerType.bind(modelBuilder.constructor);
|
|
|
|
defineType(function Point() {});
|
|
|
|
dataSource.EnumFactory = EnumFactory;
|
|
|
|
if (callback) {
|
|
if (dataSource.settings.lazyConnect) {
|
|
process.nextTick(function() {
|
|
callback();
|
|
});
|
|
} else {
|
|
dataSource.connector.connect(callback);
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.VnMySQL = VnMySQL;
|
|
|
|
function VnMySQL(settings) {
|
|
SqlConnector.call(this, 'mysql', settings);
|
|
}
|
|
|
|
VnMySQL.prototype = Object.create(MySQL.prototype);
|
|
VnMySQL.constructor = VnMySQL;
|
|
|
|
VnMySQL.prototype.toColumnValue = function(prop, val) {
|
|
if (val == null || !prop || prop.type !== Date)
|
|
return MySQL.prototype.toColumnValue.call(this, prop, val);
|
|
|
|
val = new Date(val);
|
|
|
|
return val.getFullYear() + '-' +
|
|
fillZeros(val.getMonth() + 1) + '-' +
|
|
fillZeros(val.getDate()) + ' ' +
|
|
fillZeros(val.getHours()) + ':' +
|
|
fillZeros(val.getMinutes()) + ':' +
|
|
fillZeros(val.getSeconds());
|
|
|
|
function fillZeros(v) {
|
|
return v < 10 ? '0' + v : v;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Private make method
|
|
* @param {Object} model Model instance
|
|
* @param {Object} where Where filter
|
|
* @return {ParameterizedSQL} Parametized object
|
|
*/
|
|
VnMySQL.prototype._makeWhere = function(model, where) {
|
|
let columnValue;
|
|
let sqlExp;
|
|
|
|
if (!where) {
|
|
return new ParameterizedSQL('');
|
|
}
|
|
if (typeof where !== 'object' || Array.isArray(where)) {
|
|
debug('Invalid value for where: %j', where);
|
|
return new ParameterizedSQL('');
|
|
}
|
|
var self = this;
|
|
var props = self.getModelDefinition(model).properties;
|
|
|
|
var whereStmts = [];
|
|
for (var key in where) {
|
|
var stmt = new ParameterizedSQL('', []);
|
|
// Handle and/or operators
|
|
if (key === 'and' || key === 'or') {
|
|
var branches = [];
|
|
var branchParams = [];
|
|
var clauses = where[key];
|
|
if (Array.isArray(clauses)) {
|
|
for (var i = 0, n = clauses.length; i < n; i++) {
|
|
var stmtForClause = self._makeWhere(model, clauses[i]);
|
|
if (stmtForClause.sql) {
|
|
stmtForClause.sql = '(' + stmtForClause.sql + ')';
|
|
branchParams = branchParams.concat(stmtForClause.params);
|
|
branches.push(stmtForClause.sql);
|
|
}
|
|
}
|
|
stmt.merge({
|
|
sql: branches.join(' ' + key.toUpperCase() + ' '),
|
|
params: branchParams
|
|
});
|
|
whereStmts.push(stmt);
|
|
continue;
|
|
}
|
|
// The value is not an array, fall back to regular fields
|
|
}
|
|
var p = props[key];
|
|
|
|
// eslint-disable one-var
|
|
var expression = where[key];
|
|
var columnName = self.columnEscaped(model, key);
|
|
// eslint-enable one-var
|
|
if (expression === null || expression === undefined) {
|
|
stmt.merge(columnName + ' IS NULL');
|
|
} else if (expression && expression.constructor === Object) {
|
|
var operator = Object.keys(expression)[0];
|
|
// Get the expression without the operator
|
|
expression = expression[operator];
|
|
if (operator === 'inq' || operator === 'nin' || operator === 'between') {
|
|
columnValue = [];
|
|
if (Array.isArray(expression)) {
|
|
// Column value is a list
|
|
for (var j = 0, m = expression.length; j < m; j++) {
|
|
columnValue.push(this.toColumnValue(p, expression[j]));
|
|
}
|
|
} else {
|
|
columnValue.push(this.toColumnValue(p, expression));
|
|
}
|
|
if (operator === 'between') {
|
|
// BETWEEN v1 AND v2
|
|
var v1 = columnValue[0] === undefined ? null : columnValue[0];
|
|
var v2 = columnValue[1] === undefined ? null : columnValue[1];
|
|
columnValue = [v1, v2];
|
|
} else {
|
|
// IN (v1,v2,v3) or NOT IN (v1,v2,v3)
|
|
if (columnValue.length === 0) {
|
|
if (operator === 'inq') {
|
|
columnValue = [null];
|
|
} else {
|
|
// nin () is true
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
} else if (operator === 'regexp' && expression instanceof RegExp) {
|
|
// do not coerce RegExp based on property definitions
|
|
columnValue = expression;
|
|
} else {
|
|
columnValue = this.toColumnValue(p, expression);
|
|
}
|
|
sqlExp = self.buildExpression(columnName, operator, columnValue, p);
|
|
stmt.merge(sqlExp);
|
|
} else {
|
|
// The expression is the field value, not a condition
|
|
columnValue = self.toColumnValue(p, expression);
|
|
if (columnValue === null) {
|
|
stmt.merge(columnName + ' IS NULL');
|
|
} else if (columnValue instanceof ParameterizedSQL) {
|
|
stmt.merge(columnName + '=').merge(columnValue);
|
|
} else {
|
|
stmt.merge({
|
|
sql: columnName + '=?',
|
|
params: [columnValue]
|
|
});
|
|
}
|
|
}
|
|
whereStmts.push(stmt);
|
|
}
|
|
var params = [];
|
|
var sqls = [];
|
|
for (var k = 0, s = whereStmts.length; k < s; k++) {
|
|
sqls.push(whereStmts[k].sql);
|
|
params = params.concat(whereStmts[k].params);
|
|
}
|
|
var whereStmt = new ParameterizedSQL({
|
|
sql: sqls.join(' AND '),
|
|
params: params
|
|
});
|
|
return whereStmt;
|
|
};
|
|
|
|
/**
|
|
* Build the SQL WHERE clause for the where object
|
|
* @param {string} model Model name
|
|
* @param {object} where An object for the where conditions
|
|
* @return {ParameterizedSQL} The SQL WHERE clause
|
|
*/
|
|
VnMySQL.prototype.makeWhere = function(model, where) {
|
|
var whereClause = this._makeWhere(model, where);
|
|
if (whereClause.sql) {
|
|
whereClause.sql = 'WHERE ' + whereClause.sql;
|
|
}
|
|
return whereClause;
|
|
};
|