Skip to content

Commit

Permalink
Merge pull request #1090 from BclEx/master
Browse files Browse the repository at this point in the history
mssql provider
  • Loading branch information
tgriesser committed Dec 15, 2015
2 parents c22a51e + fbbda07 commit c7a659a
Show file tree
Hide file tree
Showing 56 changed files with 3,494 additions and 147 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Expand Up @@ -31,6 +31,7 @@ You can optionally specify which dialects to test using the `DB` environment var
* sqlite3
* maria
* oracle
* mssql

```bash
$ DB='postgres mysql' npm test
Expand Down
11 changes: 11 additions & 0 deletions lib/client.js
@@ -1,5 +1,6 @@
'use strict';

var _ = require('lodash');
var Promise = require('./promise');
var helpers = require('./helpers');

Expand Down Expand Up @@ -42,6 +43,10 @@ function Client() {
this.initializePool(config);
}
}
this.valueForUndefined = this.raw('DEFAULT');
if (config.useNullAsDefault) {
this.valueForUndefined = null;
}
}
inherits(Client, EventEmitter);

Expand Down Expand Up @@ -139,6 +144,12 @@ assign(Client.prototype, {
return this._stream.call(this, connection, obj, _stream, options);
},

prepBindings: function prepBindings(bindings) {
return _.map(bindings, function (binding) {
return binding === undefined ? this.valueForUndefined : binding;
}, this);
},

wrapIdentifier: function wrapIdentifier(value) {
return value !== '*' ? '"' + value.replace(/"/g, '""') + '"' : '*';
},
Expand Down
19 changes: 5 additions & 14 deletions lib/connection/index.js
@@ -1,12 +1,6 @@
'use strict';

Object.defineProperty(exports, '__esModule', {
value: true
});

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
exports.__esModule = true;

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

Expand All @@ -20,20 +14,17 @@ var Connection = (function (_EventEmitter) {
function Connection(connection) {
_classCallCheck(this, Connection);

_get(Object.getPrototypeOf(Connection.prototype), 'constructor', this).call(this);
_EventEmitter.call(this);
this.connection = connection;

// Flag indicating whether the connection is "managed",
// and should be released to the pool upon completion
this.managed = false;
}

_createClass(Connection, [{
key: 'execute',
value: function execute() {
return this._execute();
}
}]);
Connection.prototype.execute = function execute() {
return this._execute();
};

return Connection;
})(_events.EventEmitter);
Expand Down
2 changes: 0 additions & 2 deletions lib/dialects/maria/index.js
Expand Up @@ -23,8 +23,6 @@ assign(Client_MariaSQL.prototype, {

driverName: 'mariasql',

SqlString: require('../../query/string'),

Transaction: Transaction,

_driver: function _driver() {
Expand Down
28 changes: 28 additions & 0 deletions lib/dialects/mssql/formatter.js
@@ -0,0 +1,28 @@
'use strict';

var inherits = require('inherits');
var assign = require('lodash/object/assign');
var Formatter = require('../../formatter');

function MSSQL_Formatter(client) {
Formatter.call(this, client);
}
inherits(MSSQL_Formatter, Formatter);

assign(MSSQL_Formatter.prototype, {

// Accepts a string or array of columns to wrap as appropriate.
columnizeWithPrefix: function columnizeWithPrefix(prefix, target) {
var columns = typeof target === 'string' ? [target] : target;
var str = '',
i = -1;
while (++i < columns.length) {
if (i > 0) str += ', ';
str += prefix + this.wrap(columns[i]);
}
return str;
}

});

module.exports = MSSQL_Formatter;
196 changes: 196 additions & 0 deletions lib/dialects/mssql/index.js
@@ -0,0 +1,196 @@

// MSSQL Client
// -------
'use strict';

var _ = require('lodash');
var inherits = require('inherits');
var assign = require('lodash/object/assign');

var Formatter = require('./formatter');
var Client = require('../../client');
var Promise = require('../../promise');
var helpers = require('../../helpers');

var Transaction = require('./transaction');
var QueryCompiler = require('./query/compiler');
var JoinClause = require('./query/joinclause');
var SchemaCompiler = require('./schema/compiler');
var TableCompiler = require('./schema/tablecompiler');
var ColumnCompiler = require('./schema/columncompiler');

// Always initialize with the "QueryBuilder" and "QueryCompiler"
// objects, which extend the base 'lib/query/builder' and
// 'lib/query/compiler', respectively.
function Client_MSSQL(config) {
Client.call(this, config);
}
inherits(Client_MSSQL, Client);

assign(Client_MSSQL.prototype, {

dialect: 'mssql',

driverName: 'mssql',

_driver: function _driver() {
return require('mssql');
},

Transaction: Transaction,

Formatter: Formatter,

QueryCompiler: QueryCompiler,

JoinClause: JoinClause,

SchemaCompiler: SchemaCompiler,

TableCompiler: TableCompiler,

ColumnCompiler: ColumnCompiler,

wrapIdentifier: function wrapIdentifier(value) {
return value !== '*' ? '[' + value.replace(/\[/g, '\[') + ']' : '*';
},

// Get a raw connection, called by the `pool` whenever a new
// connection needs to be added to the pool.
acquireRawConnection: function acquireRawConnection() {
var client = this;
var connection = new this.driver.Connection(this.connectionSettings);
return new Promise(function (resolver, rejecter) {
connection.connect(function (err) {
if (err) return rejecter(err);
connection.on('error', connectionErrorHandler.bind(null, client, connection));
connection.on('end', connectionErrorHandler.bind(null, client, connection));
resolver(connection);
});
});
},

// Used to explicitly close a connection, called internally by the pool
// when a connection times out or the pool is shutdown.
destroyRawConnection: function destroyRawConnection(connection, cb) {
connection.close(cb);
},

// Position the bindings for the query.
positionBindings: function positionBindings(sql) {
var questionCount = -1;
return sql.replace(/\?/g, function () {
questionCount += 1;
return '@p' + questionCount;
});
},

prepBindings: function prepBindings(bindings) {
return _.map(bindings, function (value) {
if (value === undefined) {
return this.valueForUndefined;
}
return value;
}, this);
},

// Grab a connection, run the query via the MSSQL streaming interface,
// and pass that through to the stream we've sent back to the client.
_stream: function _stream(connection, obj, stream, options) {
options = options || {};
if (!obj || typeof obj === 'string') obj = { sql: obj };
// convert ? params into positional bindings (@p1)
obj.sql = this.positionBindings(obj.sql);
obj.bindings = this.prepBindings(obj.bindings) || [];
return new Promise(function (resolver, rejecter) {
stream.on('error', rejecter);
stream.on('end', resolver);
var sql = obj.sql;
if (!sql) return resolver();
if (obj.options) sql = assign({ sql: sql }, obj.options).sql;
var req = (connection.tx_ || connection).request();
//req.verbose = true;
req.multiple = true;
req.stream = true;
if (obj.bindings) {
for (var i = 0; i < obj.bindings.length; i++) {
req.input('p' + i, obj.bindings[i]);
}
}
req.pipe(stream);
req.query(sql);
});
},

// Runs the query on the specified connection, providing the bindings
// and any other necessary prep work.
_query: function _query(connection, obj) {
if (!obj || typeof obj === 'string') obj = { sql: obj };
// convert ? params into positional bindings (@p1)
obj.sql = this.positionBindings(obj.sql);
obj.bindings = this.prepBindings(obj.bindings) || [];
return new Promise(function (resolver, rejecter) {
var sql = obj.sql;
if (!sql) return resolver();
if (obj.options) sql = assign({ sql: sql }, obj.options).sql;
var req = (connection.tx_ || connection).request();
// req.verbose = true;
req.multiple = true;
if (obj.bindings) {
for (var i = 0; i < obj.bindings.length; i++) {
req.input('p' + i, obj.bindings[i]);
}
}
req.query(sql, function (err, recordset) {
if (err) return rejecter(err);
obj.response = recordset[0];
resolver(obj);
});
});
},

// Process the response as returned from the query.
processResponse: function processResponse(obj, runner) {
if (obj == null) return;
var response = obj.response;
var method = obj.method;
if (obj.output) return obj.output.call(runner, response);
switch (method) {
case 'select':
case 'pluck':
case 'first':
response = helpers.skim(response);
if (method === 'pluck') return _.pluck(response, obj.pluck);
return method === 'first' ? response[0] : response;
case 'insert':
case 'del':
case 'update':
case 'counter':
if (obj.returning) {
if (obj.returning === '@@rowcount') {
return response[0][''];
}
if (Array.isArray(obj.returning) && obj.returning.length > 1 || obj.returning[0] === '*') {
return response;
}
// return an array with values if only one returning value was specified
return _.flatten(_.map(response, _.values));
}
return response;
default:
return response;
}
}

});

// MSSQL Specific error handler
function connectionErrorHandler(client, connection, err) {
if (connection && err && err.fatal) {
if (connection.__knex__disposed) return;
connection.__knex__disposed = true;
client.pool.destroy(connection);
}
}

module.exports = Client_MSSQL;
21 changes: 21 additions & 0 deletions lib/dialects/mssql/query/builder.js
@@ -0,0 +1,21 @@
"use strict";

//
// // MSSQL Query Builder
// // ------
// var inherits = require('inherits')
// var QueryBuilder = require('../../../query/bulder')
// var assign = require('lodash/object/assign');
//
// function QueryBuilder_MSSQL(client) {
// QueryBuilder.call(this, client)
// }
// inherits(QueryBuilder_MSSQL, QueryBuilder)
//
// assign(QueryBuilder_MSSQL.prototype, {
//
// })
//
// // Set the QueryBuilder & QueryCompiler on the client object,
// // incase anyone wants to modify things to suit their own purposes.
// module.exports = QueryBuilder_MSSQL;

0 comments on commit c7a659a

Please sign in to comment.