salix/loopback/server/connectors/vn-mysql.js

223 lines
6.7 KiB
JavaScript

const mysql = require('mysql');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const MySQL = require('loopback-connector-mysql').MySQL;
const EnumFactory = require('loopback-connector-mysql').EnumFactory;
const fs = require('fs');
class VnMySQL extends MySQL {
/**
* Promisified version of execute().
*
* @param {String} query The SQL query string
* @param {Array} params The query parameters
* @param {Object} options The loopback options
* @param {Function} cb The callback
* @return {Promise} The operation promise
*/
executeP(query, params, options = {}, cb) {
return new Promise((resolve, reject) => {
this.execute(query, params, options, (error, response) => {
if (cb)
cb(error, response);
if (error)
reject(error);
else
resolve(response);
});
});
}
/**
* Executes an SQL query from an Stmt.
*
* @param {ParameterizedSql} stmt - Stmt object
* @param {Object} options Query options (Ex: {transaction})
* @return {Object} Connector promise
*/
executeStmt(stmt, options) {
return this.executeP(stmt.sql, stmt.params, options);
}
/**
* Executes a query from an SQL script.
*
* @param {String} sqlScript The sql script file
* @param {Array} params The query parameters
* @param {Object} options Query options (Ex: {transaction})
* @return {Object} Connector promise
*/
executeScript(sqlScript, params, options) {
return new Promise((resolve, reject) => {
fs.readFile(sqlScript, 'utf8', (err, contents) => {
if (err) return reject(err);
this.execute(contents, params, options)
.then(resolve, reject);
});
});
}
/**
* Build the SQL WHERE clause for the where object without checking that
* properties exists in the model.
*
* @param {object} where An object for the where conditions
* @return {ParameterizedSQL} The SQL WHERE clause
*/
makeWhere(where) {
let wrappedConnector = Object.create(this);
Object.assign(wrappedConnector, {
getModelDefinition() {
return {
properties: new Proxy({}, {
get: () => true
})
};
},
toColumnValue(_, val) {
return val;
},
columnEscaped(_, property) {
return this.escapeName(property);
}
});
return wrappedConnector.buildWhere(null, where);
}
/**
* Constructs SQL order clause from Loopback filter.
*
* @param {Object} order The order definition
* @return {String} Built SQL order
*/
makeOrderBy(order) {
if (!order)
return '';
if (typeof order === 'string')
order = [order];
let clauses = [];
for (let clause of order) {
let sqlOrder = '';
let t = clause.split(/[\s,]+/);
sqlOrder += this.escapeName(t[0]);
if (t.length > 1)
sqlOrder += ' ' + (t[1].toUpperCase() == 'ASC' ? 'ASC' : 'DESC');
clauses.push(sqlOrder);
}
return `ORDER BY ${clauses.join(', ')}`;
}
/**
* Constructs SQL limit clause from Loopback filter.
*
* @param {Object} filter The loopback filter
* @return {String} Built SQL limit
*/
makeLimit(filter) {
let limit = parseInt(filter.limit);
let offset = parseInt(filter.offset || filter.skip);
return this._buildLimit(null, limit, offset);
}
/**
* Constructs SQL pagination from Loopback filter.
*
* @param {Object} filter The loopback filter
* @return {String} Built SQL pagination
*/
makePagination(filter) {
return ParameterizedSQL.join([
this.makeOrderBy(filter.order),
this.makeLimit(filter)
]);
}
/**
* Constructs SQL filter including where, order and limit
* clauses from Loopback filter.
*
* @param {Object} filter The loopback filter
* @return {String} Built SQL filter
*/
makeSuffix(filter) {
return ParameterizedSQL.join([
this.makeWhere(filter.where),
this.makePagination(filter)
]);
}
/**
* Constructs SQL where clause from Loopback filter discarding
* properties that not pertain to the model. If defined, appends
* the table alias to each field.
*
* @param {String} model The model name
* @param {Object} where The loopback where filter
* @param {String} tableAlias Query main table alias
* @return {String} Built SQL where
*/
buildModelWhere(model, where, tableAlias) {
let parent = this;
let wrappedConnector = Object.create(this);
Object.assign(wrappedConnector, {
columnEscaped(model, property) {
let sql = tableAlias
? this.escapeName(tableAlias) + '.'
: '';
return sql + parent.columnEscaped(model, property);
}
});
return wrappedConnector.buildWhere(model, where);
}
/**
* Constructs SQL where clause from Loopback filter discarding
* properties that not pertain to the model. If defined, appends
* the table alias to each field.
*
* @param {String} model The model name
* @param {Object} filter The loopback filter
* @param {String} tableAlias Query main table alias
* @return {String} Built SQL suffix
*/
buildModelSuffix(model, filter, tableAlias) {
return ParameterizedSQL.join([
this.buildModelWhere(model, filter.where, tableAlias),
this.makePagination(filter)
]);
}
}
exports.VnMySQL = VnMySQL;
exports.initialize = function initialize(dataSource, callback) {
dataSource.driver = mysql;
dataSource.connector = new VnMySQL(dataSource.settings);
dataSource.connector.dataSource = dataSource;
const modelBuilder = dataSource.modelBuilder;
const 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);
}
};