sequelize-msnodesqlv8
Version:
A sequelize dialect driver for the msnodesqlv8 module.
194 lines (172 loc) • 5.07 kB
JavaScript
;
const EventEmitter = require('events').EventEmitter;
const debug = require('debug')('sequelize-msnodesqlv8');
const mssql = require('msnodesqlv8');
const uuid = require('uuid');
const Request = require('./request.js');
function detectDriver() {
const drivers = [
'SQL Server Native Client 12.0',
'SQL Server Native Client 11.0',
'SQL Server Native Client 10.0',
'SQL Native Client',
'SQL Server'
];
let detectedDriver = null;
return drivers.reduce((prev, driver) => {
return prev.then(() => {
if (detectedDriver !== null) {
return;
}
return new Promise((resolve) => {
mssql.open(`Driver=${ driver };`, (err, conn) => {
if (err) {
if (err.message.indexOf('Neither DSN nor SERVER keyword supplied') !== -1 && detectedDriver === null) {
detectedDriver = driver;
}
} else {
// Should not be possible because nothing but driver is specified.
conn.close(() => {});
}
resolve();
});
});
});
}, Promise.resolve()).then(() => {
if (detectedDriver) {
return detectedDriver;
}
throw new Error('driver was not specified and no driver was detected');
});
}
class Connection extends EventEmitter {
constructor(config) {
super();
config = Object.assign({}, config, config.options);
delete config.options;
if (!config.connectionString) {
if (typeof config.instanceName !== 'string' || config.instanceName.match(/^MSSQLSERVER$/i)) {
config.instanceName = '';
}
config.connectionString = (config.driver ? `Driver={${ config.driver }};` : '') +
`Server=${ config.server ? config.server : 'localhost' }\\${ config.instanceName };` +
(config.database ? `Database=${ config.database };` : '') +
(config.trustedConnection ? 'Trusted_Connection=yes;' : `Uid=${ config.userName || '' };Pwd=${ config.password || '' };`);
}
this.uuid = uuid.v4();
this.config = config;
this.connection = null;
this.connectionCloseFunc = null;
this.timer = null;
this.requests = [];
Promise.resolve().then(() => {
let match = this.config.connectionString.match(/(?:^\s*Driver\s*=)|(?:;\s*Driver\s*=)/i);
if (!match) {
return detectDriver().then((driver) => {
this.config.driver = driver;
this.config.connectionString = `Driver={${ driver }};${ this.config.connectionString }`;
});
}
}).then(() => {
this.connect();
}).catch((err) => {
this.emit('connect', err);
});
}
get closed() {
return this.connection === null || this.connection.close !== this.connectionCloseFunc;
}
get loggedIn() {
return !this.closed;
}
connect() {
mssql.open(this.config.connectionString, (err, conn) => {
if (!err) {
debug(`connection (${ this.uuid }): opened`);
this.connection = conn;
this.connectionCloseFunc = conn.close;
// Poll connection to make sure it is still open.
this.timer = setInterval(() => {
if (this.closed) {
this.reset();
}
}, 5000);
}
this.emit('connect', err);
});
}
reset() {
debug(`connection (${ this.uuid }): reset by peer`);
let error = new Error('connection reset by peer');
error.code = 'ECONNRESET';
this.emit('error', error);
}
close() {
clearInterval(this.timer);
this.timer = null;
if (this.connection !== null) {
this.connection.close((err) => {
this.connection = null;
this.emit('end', err);
});
} else {
this.emit('end', new Error('connection already closed'));
}
this.requests.slice().forEach((request) => this.removeRequest(request, new Error('connection closed')));
debug(`connection (${ this.uuid }): closed`);
}
beginTransaction(callback, name) {
name = name ? `[${ name }]` : '';
let request = new Request(`BEGIN TRANSACTION ${ name };`, (err) => {
if (typeof callback === 'function') {
callback(err);
}
});
request.execute(this);
}
commitTransaction(callback, name) {
name = name ? `[${ name }]` : '';
let request = new Request(`COMMIT TRANSACTION ${ name };`, (err) => {
if (typeof callback === 'function') {
callback(err);
}
});
request.execute(this);
}
rollbackTransaction(callback, name) {
name = name ? `[${ name }]` : '';
let request = new Request(`ROLLBACK TRANSACTION ${ name };`, (err) => {
if (typeof callback === 'function') {
callback(err);
}
});
request.execute(this);
}
saveTransaction(callback, name) {
if (!name) {
callback(new Error('name required for transaction savepoint'));
return;
}
name = `[${ name }]`;
let request = new Request(`SAVE TRANSACTION ${ name };`, (err) => {
if (typeof callback === 'function') {
callback(err);
}
});
request.execute(this);
}
execSql(request) {
request.execute(this);
}
removeRequest(request, error) {
debug(`connection (${ this.uuid }): removing request (${ request.uuid })`);
let index = this.requests.indexOf(request);
if (index !== -1) {
this.requests.splice(index, 1);
if (error && typeof request.callback === 'function') {
request.callback(error);
}
}
}
}
module.exports = Connection;