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

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