不要怂,就是干,撸起袖子干!

Commit 7275c7c6 by Felix Becker Committed by Jan Aagaard Meier

ES6 refactor: dialects / MSSQL (#6049)

* ES6 refactor of MSSQL ConnectionManager

classes, let, const, arrow functions, export default

* Make Mssql Query an ES6 class

* ES6 refactor of Mssql Query

let, const, arrow functions, property shorthands, for of, export default
1 parent 3ff27d10
'use strict'; 'use strict';
var AbstractConnectionManager = require('../abstract/connection-manager') const AbstractConnectionManager = require('../abstract/connection-manager');
, ConnectionManager const ResourceLock = require('./resource-lock');
, ResourceLock = require('./resource-lock') const Promise = require('../../promise');
, Utils = require('../../utils') const sequelizeErrors = require('../../errors');
, Promise = require('../../promise') const parserStore = require('../parserStore')('mssql');
, sequelizeErrors = require('../../errors') const _ = require('lodash');
, parserStore = require('../parserStore')('mssql')
, _ = require('lodash'); class ConnectionManager extends AbstractConnectionManager {
constructor(dialect, sequelize) {
ConnectionManager = function(dialect, sequelize) { super(dialect, sequelize);
AbstractConnectionManager.call(this, dialect, sequelize);
this.sequelize = sequelize; this.sequelize = sequelize;
this.sequelize.config.port = this.sequelize.config.port || 1433; this.sequelize.config.port = this.sequelize.config.port || 1433;
...@@ -22,24 +21,20 @@ ConnectionManager = function(dialect, sequelize) { ...@@ -22,24 +21,20 @@ ConnectionManager = function(dialect, sequelize) {
} }
throw err; throw err;
} }
}; }
Utils._.extend(ConnectionManager.prototype, AbstractConnectionManager.prototype);
// Expose this as a method so that the parsing may be updated when the user has added additional, custom types // Expose this as a method so that the parsing may be updated when the user has added additional, custom types
ConnectionManager.prototype.$refreshTypeParser = function (dataType) { $refreshTypeParser(dataType) {
parserStore.refresh(dataType); parserStore.refresh(dataType);
}; }
ConnectionManager.prototype.$clearTypeParser = function () { $clearTypeParser() {
parserStore.clear(); parserStore.clear();
}; }
ConnectionManager.prototype.connect = function(config) { connect(config) {
var self = this; return new Promise((resolve, reject) => {
return new Promise(function (resolve, reject) { const connectionConfig = {
var connectionConfig = {
userName: config.username, userName: config.username,
password: config.password, password: config.password,
server: config.host, server: config.host,
...@@ -60,16 +55,16 @@ ConnectionManager.prototype.connect = function(config) { ...@@ -60,16 +55,16 @@ ConnectionManager.prototype.connect = function(config) {
connectionConfig.domain = config.dialectOptions.domain; connectionConfig.domain = config.dialectOptions.domain;
} }
Object.keys(config.dialectOptions).forEach(function(key) { for (const key of Object.keys(config.dialectOptions)) {
connectionConfig.options[key] = config.dialectOptions[key]; connectionConfig.options[key] = config.dialectOptions[key];
}); }
} }
var connection = new self.lib.Connection(connectionConfig) const connection = new this.lib.Connection(connectionConfig);
, connectionLock = new ResourceLock(connection); const connectionLock = new ResourceLock(connection);
connection.lib = self.lib; connection.lib = this.lib;
connection.on('connect', function(err) { connection.on('connect', err => {
if (!err) { if (!err) {
resolve(connectionLock); resolve(connectionLock);
return; return;
...@@ -112,36 +107,39 @@ ConnectionManager.prototype.connect = function(config) { ...@@ -112,36 +107,39 @@ ConnectionManager.prototype.connect = function(config) {
}); });
if (config.pool.handleDisconnects) { if (config.pool.handleDisconnects) {
connection.on('error', function (err) { connection.on('error', err => {
switch (err.code) { switch (err.code) {
case 'ESOCKET': case 'ESOCKET':
case 'ECONNRESET': case 'ECONNRESET':
self.pool.destroy(connectionLock); this.pool.destroy(connectionLock);
} }
}); });
} }
}); });
}; }
ConnectionManager.prototype.disconnect = function(connectionLock) { disconnect(connectionLock) {
var connection = connectionLock.unwrap(); const connection = connectionLock.unwrap();
// Dont disconnect a connection that is already disconnected // Dont disconnect a connection that is already disconnected
if (!!connection.closed) { if (!!connection.closed) {
return Promise.resolve(); return Promise.resolve();
} }
return new Promise(function (resolve, reject) { return new Promise(resolve => {
connection.on('end', resolve); connection.on('end', resolve);
connection.close(); connection.close();
}); });
}; }
ConnectionManager.prototype.validate = function(connectionLock) { validate(connectionLock) {
var connection = connectionLock.unwrap(); const connection = connectionLock.unwrap();
return connection && connection.loggedIn; return connection && connection.loggedIn;
}; }
}
module.exports = ConnectionManager; module.exports = ConnectionManager;
module.exports.ConnectionManager = ConnectionManager;
module.exports.default = ConnectionManager;
'use strict'; 'use strict';
var Utils = require('../../utils') const Utils = require('../../utils');
, Promise = require('../../promise') const Promise = require('../../promise');
, AbstractQuery = require('../abstract/query') const AbstractQuery = require('../abstract/query');
, sequelizeErrors = require('../../errors.js') const sequelizeErrors = require('../../errors.js');
, parserStore = require('../parserStore')('mssql'), const parserStore = require('../parserStore')('mssql');
_ = require('lodash'); const _ = require('lodash');
var Query = function(connection, sequelize, options) { class Query extends AbstractQuery {
constructor(connection, sequelize, options) {
super();
this.connection = connection; this.connection = connection;
this.instance = options.instance; this.instance = options.instance;
this.model = options.model; this.model = options.model;
...@@ -19,84 +21,80 @@ var Query = function(connection, sequelize, options) { ...@@ -19,84 +21,80 @@ var Query = function(connection, sequelize, options) {
}, options || {}); }, options || {});
this.checkLoggingOption(); this.checkLoggingOption();
}; }
Utils.inherit(Query, AbstractQuery);
Query.prototype.getInsertIdField = function() { getInsertIdField() {
return 'id'; return 'id';
}; }
Query.formatBindParameters = AbstractQuery.formatBindParameters; _run(connection, sql, parameters) {
Query.prototype._run = function(connection, sql, parameters) {
var self = this;
this.sql = sql; this.sql = sql;
//do we need benchmark for this query execution //do we need benchmark for this query execution
var benchmark = this.sequelize.options.benchmark || this.options.benchmark; const benchmark = this.sequelize.options.benchmark || this.options.benchmark;
let queryBegin;
if (benchmark) { if (benchmark) {
var queryBegin = Date.now(); queryBegin = Date.now();
} else { } else {
this.sequelize.log('Executing (' + (connection.uuid || 'default') + '): ' + this.sql, this.options); this.sequelize.log('Executing (' + (connection.uuid || 'default') + '): ' + this.sql, this.options);
} }
var promise = new Utils.Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
// TRANSACTION SUPPORT // TRANSACTION SUPPORT
if (_.includes(self.sql, 'BEGIN TRANSACTION')) { if (_.includes(this.sql, 'BEGIN TRANSACTION')) {
connection.beginTransaction(function(err) { connection.beginTransaction(err => {
if (!!err) { if (!!err) {
reject(self.formatError(err)); reject(this.formatError(err));
} else { } else {
resolve(self.formatResults()); resolve(this.formatResults());
} }
} /* name, isolation_level */); } /* name, isolation_level */);
} else if (_.includes(self.sql, 'COMMIT TRANSACTION')) { } else if (_.includes(this.sql, 'COMMIT TRANSACTION')) {
connection.commitTransaction(function(err) { connection.commitTransaction(err => {
if (!!err) { if (!!err) {
reject(self.formatError(err)); reject(this.formatError(err));
} else { } else {
resolve(self.formatResults()); resolve(this.formatResults());
} }
}); });
} else if (_.includes(self.sql, 'ROLLBACK TRANSACTION')) { } else if (_.includes(this.sql, 'ROLLBACK TRANSACTION')) {
connection.rollbackTransaction(function(err) { connection.rollbackTransaction(err => {
if (!!err) { if (!!err) {
reject(self.formatError(err)); reject(this.formatError(err));
} else { } else {
resolve(self.formatResults()); resolve(this.formatResults());
} }
}); });
} else { } else {
// QUERY SUPPORT // QUERY SUPPORT
var results = []; const results = [];
var request = new connection.lib.Request(self.sql, function(err) { const request = new connection.lib.Request(this.sql, err => {
if (benchmark) { if (benchmark) {
self.sequelize.log('Executed (' + (connection.uuid || 'default') + '): ' + self.sql, (Date.now() - queryBegin), self.options); this.sequelize.log('Executed (' + (connection.uuid || 'default') + '): ' + this.sql, (Date.now() - queryBegin), this.options);
} }
if (err) { if (err) {
err.sql = sql; err.sql = sql;
reject(self.formatError(err)); reject(this.formatError(err));
} else { } else {
resolve(self.formatResults(results)); resolve(this.formatResults(results));
} }
}); });
request.on('row', function(columns) { request.on('row', columns => {
var row = {}; const row = {};
columns.forEach(function(column) { for (const column of columns) {
var typeid = column.metadata.type.id const typeid = column.metadata.type.id;
, value = column.value const parse = parserStore.get(typeid);
, parse = parserStore.get(typeid); let value = column.value;
if (value !== null & !!parse) { if (value !== null & !!parse) {
value = parse(value); value = parse(value);
} }
row[column.metadata.colName] = value; row[column.metadata.colName] = value;
}); }
results.push(row); results.push(row);
}); });
...@@ -104,19 +102,13 @@ Query.prototype._run = function(connection, sql, parameters) { ...@@ -104,19 +102,13 @@ Query.prototype._run = function(connection, sql, parameters) {
connection.execSql(request); connection.execSql(request);
} }
}); });
}
return promise; run(sql, parameters) {
}; return Promise.using(this.connection.lock(), connection => this._run(connection, sql, parameters));
}
Query.prototype.run = function(sql, parameters) {
var self = this;
return Promise.using(this.connection.lock(), function (connection) {
return self._run(connection, sql, parameters);
});
};
/** /**
* High level function that handles the results of a query execution. * High level function that handles the results of a query execution.
* *
* *
...@@ -132,8 +124,8 @@ Query.prototype.run = function(sql, parameters) { ...@@ -132,8 +124,8 @@ Query.prototype.run = function(sql, parameters) {
* *
* @param {Array} data - The result of the query execution. * @param {Array} data - The result of the query execution.
*/ */
Query.prototype.formatResults = function(data) { formatResults(data) {
var result = this.instance; let result = this.instance;
if (this.isInsertQuery(data)) { if (this.isInsertQuery(data)) {
this.handleInsertQuery(data); this.handleInsertQuery(data);
...@@ -143,7 +135,7 @@ Query.prototype.formatResults = function(data) { ...@@ -143,7 +135,7 @@ Query.prototype.formatResults = function(data) {
// test returning only the PK. There isn't a way in MSSQL to identify // test returning only the PK. There isn't a way in MSSQL to identify
// that a given return value is the PK, and we have no schema information // that a given return value is the PK, and we have no schema information
// because there was no calling Model. // because there was no calling Model.
var record = data[0]; const record = data[0];
result = record[Object.keys(record)[0]]; result = record[Object.keys(record)[0]];
} else { } else {
result = data; result = data;
...@@ -155,7 +147,7 @@ Query.prototype.formatResults = function(data) { ...@@ -155,7 +147,7 @@ Query.prototype.formatResults = function(data) {
result = this.handleShowTablesQuery(data); result = this.handleShowTablesQuery(data);
} else if (this.isDescribeQuery()) { } else if (this.isDescribeQuery()) {
result = {}; result = {};
data.forEach(function(_result) { for (const _result of data) {
if (_result.Default) { if (_result.Default) {
_result.Default = _result.Default.replace("('",'').replace("')",'').replace(/'/g,''); /* jshint ignore: line */ _result.Default = _result.Default.replace("('",'').replace("')",'').replace(/'/g,''); /* jshint ignore: line */
} }
...@@ -166,7 +158,7 @@ Query.prototype.formatResults = function(data) { ...@@ -166,7 +158,7 @@ Query.prototype.formatResults = function(data) {
defaultValue: _result.Default, defaultValue: _result.Default,
primaryKey: _result.Constraint === 'PRIMARY KEY' primaryKey: _result.Constraint === 'PRIMARY KEY'
}; };
}); }
} else if (this.isShowIndexesQuery()) { } else if (this.isShowIndexesQuery()) {
result = this.handleShowIndexesQuery(data); result = this.handleShowIndexesQuery(data);
} else if (this.isSelectQuery()) { } else if (this.isSelectQuery()) {
...@@ -187,32 +179,31 @@ Query.prototype.formatResults = function(data) { ...@@ -187,32 +179,31 @@ Query.prototype.formatResults = function(data) {
} }
return result; return result;
}; }
Query.prototype.handleShowTablesQuery = function(results) { handleShowTablesQuery(results) {
return results.map(function(resultSet) { return results.map(resultSet => {
return { return {
tableName: resultSet.TABLE_NAME, tableName: resultSet.TABLE_NAME,
schema: resultSet.TABLE_SCHEMA schema: resultSet.TABLE_SCHEMA
}; };
}); });
}; }
Query.prototype.formatError = function (err) {
var match;
formatError(err) {
let match;
match = err.message.match(/Violation of UNIQUE KEY constraint '((.|\s)*)'. Cannot insert duplicate key in object '.*'.(:? The duplicate key value is \((.*)\).)?/); match = err.message.match(/Violation of UNIQUE KEY constraint '((.|\s)*)'. Cannot insert duplicate key in object '.*'.(:? The duplicate key value is \((.*)\).)?/);
match = match || err.message.match(/Cannot insert duplicate key row in object .* with unique index '(.*)'/); match = match || err.message.match(/Cannot insert duplicate key row in object .* with unique index '(.*)'/);
if (match && match.length > 1) { if (match && match.length > 1) {
var fields = {} let fields = {};
, message = 'Validation error' const uniqueKey = this.model && this.model.uniqueKeys[match[1]];
, uniqueKey = this.model && this.model.uniqueKeys[match[1]]; let message = 'Validation error';
if (uniqueKey && !!uniqueKey.msg) { if (uniqueKey && !!uniqueKey.msg) {
message = uniqueKey.msg; message = uniqueKey.msg;
} }
if (!!match[4]) { if (!!match[4]) {
var values = match[4].split(',').map(Function.prototype.call, String.prototype.trim); const values = match[4].split(',').map(part => part.trim());
if (!!uniqueKey) { if (!!uniqueKey) {
fields = Utils._.zipObject(uniqueKey.fields, values); fields = Utils._.zipObject(uniqueKey.fields, values);
} else { } else {
...@@ -220,20 +211,15 @@ Query.prototype.formatError = function (err) { ...@@ -220,20 +211,15 @@ Query.prototype.formatError = function (err) {
} }
} }
var errors = []; const errors = [];
var self = this; Utils._.forOwn(fields, (value, field) => {
Utils._.forOwn(fields, function(value, field) {
errors.push(new sequelizeErrors.ValidationErrorItem( errors.push(new sequelizeErrors.ValidationErrorItem(
self.getUniqueConstraintErrorMessage(field), this.getUniqueConstraintErrorMessage(field),
'unique violation', field, value)); 'unique violation', field, value
));
}); });
return new sequelizeErrors.UniqueConstraintError({ return new sequelizeErrors.UniqueConstraintError({message, errors, parent: err, fields});
message: message,
errors: errors,
parent: err,
fields: fields
});
} }
match = err.message.match(/Failed on step '(.*)'.Could not create constraint. See previous errors./) || match = err.message.match(/Failed on step '(.*)'.Could not create constraint. See previous errors./) ||
...@@ -249,32 +235,32 @@ Query.prototype.formatError = function (err) { ...@@ -249,32 +235,32 @@ Query.prototype.formatError = function (err) {
} }
return new sequelizeErrors.DatabaseError(err); return new sequelizeErrors.DatabaseError(err);
}; }
Query.prototype.isShowOrDescribeQuery = function() { isShowOrDescribeQuery() {
var result = false; let result = false;
result = result || (this.sql.toLowerCase().indexOf("select c.column_name as 'name', c.data_type as 'type', c.is_nullable as 'isnull'") === 0); /* jshint ignore: line */ result = result || (this.sql.toLowerCase().indexOf("select c.column_name as 'name', c.data_type as 'type', c.is_nullable as 'isnull'") === 0); /* jshint ignore: line */
result = result || (this.sql.toLowerCase().indexOf('select tablename = t.name, name = ind.name,') === 0); result = result || (this.sql.toLowerCase().indexOf('select tablename = t.name, name = ind.name,') === 0);
result = result || (this.sql.toLowerCase().indexOf('exec sys.sp_helpindex @objname') === 0); result = result || (this.sql.toLowerCase().indexOf('exec sys.sp_helpindex @objname') === 0);
return result; return result;
}; }
Query.prototype.isShowIndexesQuery = function () { isShowIndexesQuery() {
return this.sql.toLowerCase().indexOf('exec sys.sp_helpindex @objname') === 0; return this.sql.toLowerCase().indexOf('exec sys.sp_helpindex @objname') === 0;
}; }
Query.prototype.handleShowIndexesQuery = function (data) { handleShowIndexesQuery(data) {
// Group by index name, and collect all fields // Group by index name, and collect all fields
data = _.reduce(data, function (acc, item) { data = _.reduce(data, (acc, item) => {
if (!(item.index_name in acc)) { if (!(item.index_name in acc)) {
acc[item.index_name] = item; acc[item.index_name] = item;
item.fields = []; item.fields = [];
} }
Utils._.forEach(item.index_keys.split(','), function(column) { Utils._.forEach(item.index_keys.split(','), column => {
var columnName = column.trim(); let columnName = column.trim();
if (columnName.indexOf('(-)') !== -1) { if (columnName.indexOf('(-)') !== -1) {
columnName = columnName.replace('(-)',''); columnName = columnName.replace('(-)','');
} }
...@@ -290,24 +276,22 @@ Query.prototype.handleShowIndexesQuery = function (data) { ...@@ -290,24 +276,22 @@ Query.prototype.handleShowIndexesQuery = function (data) {
return acc; return acc;
}, {}); }, {});
return Utils._.map(data, function(item) { return Utils._.map(data, item => ({
return {
primary: (item.index_name.toLowerCase().indexOf('pk') === 0), primary: (item.index_name.toLowerCase().indexOf('pk') === 0),
fields: item.fields, fields: item.fields,
name: item.index_name, name: item.index_name,
tableName: undefined, tableName: undefined,
unique: (item.index_description.toLowerCase().indexOf('unique') !== -1), unique: (item.index_description.toLowerCase().indexOf('unique') !== -1),
type: undefined, type: undefined
}; }));
}); }
};
Query.prototype.handleInsertQuery = function(results, metaData) { handleInsertQuery(results, metaData) {
if (this.instance) { if (this.instance) {
// add the inserted row id to the instance // add the inserted row id to the instance
var autoIncrementField = this.model.autoIncrementField const autoIncrementField = this.model.autoIncrementField;
, autoIncrementFieldAlias = null let id = null;
, id = null; let autoIncrementFieldAlias = null;
if (this.model.rawAttributes.hasOwnProperty(autoIncrementField) && if (this.model.rawAttributes.hasOwnProperty(autoIncrementField) &&
this.model.rawAttributes[autoIncrementField].field !== undefined) this.model.rawAttributes[autoIncrementField].field !== undefined)
...@@ -320,6 +304,9 @@ Query.prototype.handleInsertQuery = function(results, metaData) { ...@@ -320,6 +304,9 @@ Query.prototype.handleInsertQuery = function(results, metaData) {
this.instance[autoIncrementField] = id; this.instance[autoIncrementField] = id;
} }
}; }
}
module.exports = Query; module.exports = Query;
module.exports.Query = Query;
module.exports.default = Query;
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!