From 1d875c4b6452d42360fc91ffb216d3a00966d1d5 Mon Sep 17 00:00:00 2001 From: Gil Ferreira Date: Mon, 22 Jan 2018 13:54:26 -0500 Subject: [PATCH] Update dependancies --- lib/adapter.js | 229 +++++++++++++++++++++++++++++++------------------ lib/sql.js | 212 +++++++++++++++++++++++++++++---------------- lib/utils.js | 50 +++++++---- package.json | 19 ++-- 4 files changed, 325 insertions(+), 185 deletions(-) diff --git a/lib/adapter.js b/lib/adapter.js index df14bb9..29dd4ee 100644 --- a/lib/adapter.js +++ b/lib/adapter.js @@ -32,10 +32,10 @@ var debugging = false * submodules and load them at the top of the file with other dependencies. * e.g. var update = `require('./lib/update')` */ -module.exports = (function () { +module.exports = (function() { // You'll want to maintain a reference to each connection // that gets registered with this adapter. - var connections = { } + var connections = {} // You may also want to store additional, private data // per-connection (esp. if your data store uses persistent @@ -54,7 +54,6 @@ module.exports = (function () { // var adapter = { - // Set to true if this adapter supports (or requires) things like data // types, validations, keys, etc. If true, the schema for models using this // adapter will be automatically synced when the server starts. Not @@ -102,9 +101,11 @@ module.exports = (function () { * @param {Function} cb [description] * @return {[type]} [description] */ - registerConnection: function (connection, collections, cb) { - if (!connection.identity) return cb(new Error('Connection is missing an identity.')) - if (connections[connection.identity]) return cb(new Error('Connection is already registered.')) + registerConnection: function(connection, collections, cb) { + if (!connection.identity) + return cb(new Error('Connection is missing an identity.')) + if (connections[connection.identity]) + return cb(new Error('Connection is already registered.')) // Add in logic here to initialize connection // e.g. connections[connection.identity] = new Database(connection, @@ -123,7 +124,7 @@ module.exports = (function () { * @param {String} connection * @param {Function} cb */ - connectConnection: function (conn, cb) { + connectConnection: function(conn, cb) { var uniqId = _.uniqueId() var connection = connections[conn] var persistent = !!connection.config.persistent @@ -133,19 +134,28 @@ module.exports = (function () { if (persistent) { connected = assigned && !!connection.mssqlConnection.connected } else { - connected = assigned && connection.mssqlConnection[uniqId] && connection.mssqlConnection[uniqId].connected + connected = + assigned && + connection.mssqlConnection[uniqId] && + connection.mssqlConnection[uniqId].connected } if (persistent && !connected) { - connection.mssqlConnection = new mssql.Connection(marshalConfig(connection.config), cb) + connection.mssqlConnection = new mssql.Connection( + marshalConfig(connection.config), + cb + ) } else if (!persistent && !connected) { if (!assigned) { connection.mssqlConnection = [] } - connection.mssqlConnection[uniqId] = new mssql.Connection(marshalConfig(connection.config), function (err) { - cb(err, uniqId) - }) + connection.mssqlConnection[uniqId] = new mssql.Connection( + marshalConfig(connection.config), + function(err) { + cb(err, uniqId) + } + ) } else { _.defer(cb) } @@ -160,7 +170,7 @@ module.exports = (function () { * @return {[type]} [description] */ // Teardown a Connection - teardown: function (conn, cb) { + teardown: function(conn, cb) { if (debugging) { console.log('Inside teardown') } @@ -169,16 +179,16 @@ module.exports = (function () { conn = null } if (!conn) { - _.each(connections, function (c) { + _.each(connections, function(c) { if (c.persistent) { c.mssqlConnection && c.mssqlConnection.close() } else { - _.each(c.mssqlConnection, function (handle) { + _.each(c.mssqlConnection, function(handle) { handle && handle.close() }) } }) - connections = { } + connections = {} return cb() } if (!connections[conn]) return cb() @@ -186,7 +196,7 @@ module.exports = (function () { if (connections[conn].persistent) { connections[conn].mssqlConnection.close() } else { - _.each(connections[conn], function (handle) { + _.each(connections[conn], function(handle) { handle.mssqlConnection && handle.mssqlConnection.close() }) } @@ -195,11 +205,16 @@ module.exports = (function () { cb() }, // Return attributes - describe: function (connection, collection, cb) { + describe: function(connection, collection, cb) { // Add in logic here to describe a collection (e.g. DESCRIBE TABLE logic) var schemaName = getSchemaName(connection, collection) - var statement = "SELECT c.name AS ColumnName,TYPE_NAME(c.user_type_id) AS TypeName,c.is_nullable AS Nullable,c.is_identity AS AutoIncrement,ISNULL((SELECT is_unique FROM sys.indexes i LEFT OUTER JOIN sys.index_columns ic ON i.index_id=ic.index_id WHERE i.object_id=t.object_id AND ic.object_id=t.object_id AND ic.column_id=c.column_id),0) AS [Unique],ISNULL((SELECT is_primary_key FROM sys.indexes i LEFT OUTER JOIN sys.index_columns ic ON i.index_id=ic.index_id WHERE i.object_id=t.object_id AND ic.object_id=t.object_id AND ic.column_id=c.column_id),0) AS PrimaryKey,ISNULL((SELECT COUNT(*) FROM sys.indexes i LEFT OUTER JOIN sys.index_columns ic ON i.index_id=ic.index_id WHERE i.object_id=t.object_id AND ic.object_id=t.object_id AND ic.column_id=c.column_id),0) AS Indexed FROM sys.tables t INNER JOIN sys.columns c ON c.object_id=t.object_id LEFT OUTER JOIN sys.index_columns ic ON ic.object_id=t.object_id WHERE t.name='" + collection + "' AND OBJECT_SCHEMA_NAME(t.object_id) = '" + schemaName + "'" - adapter.connectConnection(connection, function __DESCRIBE__ (err, uniqId) { + var statement = + "SELECT c.name AS ColumnName,TYPE_NAME(c.user_type_id) AS TypeName,c.is_nullable AS Nullable,c.is_identity AS AutoIncrement,ISNULL((SELECT is_unique FROM sys.indexes i LEFT OUTER JOIN sys.index_columns ic ON i.index_id=ic.index_id WHERE i.object_id=t.object_id AND ic.object_id=t.object_id AND ic.column_id=c.column_id),0) AS [Unique],ISNULL((SELECT is_primary_key FROM sys.indexes i LEFT OUTER JOIN sys.index_columns ic ON i.index_id=ic.index_id WHERE i.object_id=t.object_id AND ic.object_id=t.object_id AND ic.column_id=c.column_id),0) AS PrimaryKey,ISNULL((SELECT COUNT(*) FROM sys.indexes i LEFT OUTER JOIN sys.index_columns ic ON i.index_id=ic.index_id WHERE i.object_id=t.object_id AND ic.object_id=t.object_id AND ic.column_id=c.column_id),0) AS Indexed FROM sys.tables t INNER JOIN sys.columns c ON c.object_id=t.object_id LEFT OUTER JOIN sys.index_columns ic ON ic.object_id=t.object_id WHERE t.name='" + + collection + + "' AND OBJECT_SCHEMA_NAME(t.object_id) = '" + + schemaName + + "'" + adapter.connectConnection(connection, function __DESCRIBE__(err, uniqId) { if (err) { console.error('Error during describe', err) return cb(err) @@ -214,7 +229,7 @@ module.exports = (function () { } var request = new mssql.Request(mssqlConnect) - request.query(statement, function (err, recordset) { + request.query(statement, function(err, recordset) { if (err) { console.log('Error in describe query', err) return cb(err) @@ -236,9 +251,9 @@ module.exports = (function () { * (SQL-ish) database. * */ - define: function (connection, collection, definition, cb) { + define: function(connection, collection, definition, cb) { // Add in logic here to create a collection (e.g. CREATE TABLE logic) - adapter.connectConnection(connection, function __DEFINE__ (err, uniqId) { + adapter.connectConnection(connection, function __DEFINE__(err, uniqId) { if (err) { console.error('Error during define connect', err) return cb(err) @@ -257,7 +272,7 @@ module.exports = (function () { } var request = new mssql.Request(mssqlConnect) - request.query(statement, function (err, recordset) { + request.query(statement, function(err, recordset) { if (err) { console.error('Error during query', err) return cb(err) @@ -276,12 +291,16 @@ module.exports = (function () { * (SQL-ish) database. * */ - drop: function (connection, collection, relations, cb) { + drop: function(connection, collection, relations, cb) { // Add in logic here to delete a collection (e.g. DROP TABLE logic) var schemaName = getSchemaName(connection, collection) var tableName = '[' + schemaName + ']' + '.[' + collection + ']' - var statement = "IF OBJECT_ID('" + tableName + "', 'U') IS NOT NULL DROP TABLE " + tableName - adapter.connectConnection(connection, function __DROP__ (err, uniqId) { + var statement = + "IF OBJECT_ID('" + + tableName + + "', 'U') IS NOT NULL DROP TABLE " + + tableName + adapter.connectConnection(connection, function __DROP__(err, uniqId) { if (err) { console.error(err) return cb(err) @@ -296,7 +315,7 @@ module.exports = (function () { } var request = new mssql.Request(mssqlConnect) - request.query(statement, function (err) { + request.query(statement, function(err) { if (err) return cb(err) if (!connections[connection].persistent) { mssqlConnect && mssqlConnect.close() @@ -316,9 +335,15 @@ module.exports = (function () { * find methods/usages. * */ - find: function (connection, collection, options, cb) { + find: function(connection, collection, options, cb) { // Check if this is an aggregate query and that there is something to return - if (options.groupBy || options.sum || options.average || options.min || options.max) { + if ( + options.groupBy || + options.sum || + options.average || + options.min || + options.max + ) { if (!options.sum && !options.average && !options.min && !options.max) { return cb(new Error('Cannot groupBy without a calculation')) } @@ -329,7 +354,7 @@ module.exports = (function () { var tableName = '[' + schemaName + ']' + '.[' + collection + ']' var statement = sql.selectQuery(tableName, options) - adapter.connectConnection(connection, function __FIND__ (err, uniqId) { + adapter.connectConnection(connection, function __FIND__(err, uniqId) { if (err) { log.info('Error in __FIND__:', err) return cb(err) @@ -345,7 +370,7 @@ module.exports = (function () { var request = new mssql.Request(mssqlConnect) - request.query(statement, function (err, recordset) { + request.query(statement, function(err, recordset) { if (err) return cb(err) if (!connections[connection].persistent) { mssqlConnect && mssqlConnect.close() @@ -355,13 +380,19 @@ module.exports = (function () { }) }, - stream: function (connection, collection, options, stream) { - var shutDownStreams = function () { + stream: function(connection, collection, options, stream) { + var shutDownStreams = function() { stream.end() connection.close() } - if (options.groupBy || options.sum || options.average || options.min || options.max) { + if ( + options.groupBy || + options.sum || + options.average || + options.min || + options.max + ) { if (!options.sum && !options.average && !options.min && !options.max) { shutDownStreams() } @@ -370,7 +401,7 @@ module.exports = (function () { options.__primaryKey__ = adapter.getPrimaryKey(connection, collection) var statement = sql.selectQuery(collection, options) - adapter.connectConnection(connection, function __FIND__ (err, uniqId) { + adapter.connectConnection(connection, function __FIND__(err, uniqId) { if (err) { console.error('error', err) shutDownStreams() @@ -388,25 +419,25 @@ module.exports = (function () { request.stream = true request.query(statement) - request.on('row', function (row) { + request.on('row', function(row) { stream.write(row) }) - request.on('error', function (err) { + request.on('error', function(err) { if (err) { console.log('Error detected:', err) } shutDownStreams() }) - request.on('done', function (affected) { + request.on('done', function(affected) { shutDownStreams() }) }) }, // Raw Query Interface - query: function (connection, collection, query, data, cb) { + query: function(connection, collection, query, data, cb) { if (_.isFunction(data)) { if (debugging) { console.log('Data is function. A cb was passed back') @@ -415,7 +446,7 @@ module.exports = (function () { data = null } - adapter.connectConnection(connection, function __FIND__ (err, uniqId) { + adapter.connectConnection(connection, function __FIND__(err, uniqId) { if (err) { console.error('Error inside query __FIND__', err) return cb(err) @@ -430,7 +461,7 @@ module.exports = (function () { } var request = new mssql.Request(mssqlConnect) - request.query(query, function (err, recordset) { + request.query(query, function(err, recordset) { if (err) return cb(err) if (connections[connection] && !connections[connection].persistent) { mssqlConnect && mssqlConnect.close() @@ -440,29 +471,34 @@ module.exports = (function () { }) }, - create: function (connection, collection, values, cb) { + create: function(connection, collection, values, cb) { var identityInsert = false var pk = adapter.getPrimaryKey(connection, collection) // console.log('pk=', pk) - Object.keys(values).forEach(function (key) { + Object.keys(values).forEach(function(key) { values[key] = utils.prepareValue(values[key]) if (pk === key && pk === 'id') { identityInsert = true - // console.log(pk, '==', key) + // console.log(pk, '==', key) } }) var schemaName = getSchemaName(connection, collection) var tableName = '[' + schemaName + ']' + '.[' + collection + ']' var statement = sql.insertQuery(tableName, values) if (identityInsert) { - statement = 'SET IDENTITY_INSERT ' + tableName + ' ON; ' + + statement = + 'SET IDENTITY_INSERT ' + + tableName + + ' ON; ' + statement + - 'SET IDENTITY_INSERT ' + tableName + ' OFF;' + 'SET IDENTITY_INSERT ' + + tableName + + ' OFF;' } // console.log('create statement:', statement) - adapter.connectConnection(connection, function __CREATE__ (err, uniqId) { + adapter.connectConnection(connection, function __CREATE__(err, uniqId) { if (err) { console.error('Error in connect', err) return cb(err) @@ -477,7 +513,7 @@ module.exports = (function () { } var request = new mssql.Request(mssqlConnect) - request.query(statement, function (err, recordsets) { + request.query(statement, function(err, recordsets) { if (err) { console.error('Error during query', err) return cb(err) @@ -490,7 +526,9 @@ module.exports = (function () { }) } - var _query = new Query(connections[connection].collections[collection].definition) + var _query = new Query( + connections[connection].collections[collection].definition + ) var castValues = _query.cast(model) // console.log('castValues', castValues) @@ -502,16 +540,23 @@ module.exports = (function () { }) }, - getPrimaryKey: function (connection, collection) { + getPrimaryKey: function(connection, collection) { var pk = 'id' - Object.keys(connections[connection].collections[collection].definition).forEach(function (key) { - if (!connections[connection].collections[collection].definition[key].hasOwnProperty('primaryKey')) return + Object.keys( + connections[connection].collections[collection].definition + ).forEach(function(key) { + if ( + !connections[connection].collections[collection].definition[ + key + ].hasOwnProperty('primaryKey') + ) + return pk = key }) return pk }, - update: function (connection, collection, options, values, cb) { + update: function(connection, collection, options, values, cb) { var schemaName = getSchemaName(connection, collection) var tableName = '[' + schemaName + ']' + '.[' + collection + ']' @@ -520,7 +565,7 @@ module.exports = (function () { var pk = adapter.getPrimaryKey(connection, collection) var statement = 'SELECT [' + pk + '] FROM ' + tableName + ' ' + criteria - adapter.connectConnection(connection, function __UPDATE__ (err, uniqId) { + adapter.connectConnection(connection, function __UPDATE__(err, uniqId) { if (err) { console.error(err) return cb(err) @@ -535,7 +580,7 @@ module.exports = (function () { } var request = new mssql.Request(mssqlConnect) - request.query(statement, function (err, recordset) { + request.query(statement, function(err, recordset) { if (err) { console.log('Error during query', err) return cb(err) @@ -546,20 +591,25 @@ module.exports = (function () { } var pks = [] - recordset.forEach(function (row) { + recordset.forEach(function(row) { pks.push(row[pk]) }) - Object.keys(values).forEach(function (key) { + Object.keys(values).forEach(function(key) { values[key] = utils.prepareValue(values[key]) }) delete values[pk] - statement = 'UPDATE ' + tableName + ' SET ' + sql.updateCriteria(collection, values) + ' ' + statement = + 'UPDATE ' + + tableName + + ' SET ' + + sql.updateCriteria(collection, values) + + ' ' statement += sql.serializeOptions(collection, options) - request.query(statement, function (err, _recordset) { + request.query(statement, function(err, _recordset) { if (err) return cb(err) var criteria @@ -568,7 +618,7 @@ module.exports = (function () { criteria = { where: {}, limit: 1 } criteria.where[pk] = pks[0] } else { - criteria = {where: {}} + criteria = { where: {} } criteria.where[pk] = pks } @@ -581,18 +631,18 @@ module.exports = (function () { }) }, - destroy: function (connection, collection, options, cb) { + destroy: function(connection, collection, options, cb) { var schemaName = getSchemaName(connection, collection) var tableName = '[' + schemaName + ']' + '.[' + collection + ']' var statement = 'DELETE FROM ' + tableName statement += sql.serializeOptions(collection, options) - adapter.connectConnection(connection, function __DELETE__ (err, uniqId) { + adapter.connectConnection(connection, function __DELETE__(err, uniqId) { if (err) { console.error(err) return cb(err) } - adapter.find(connection, collection, options, function (err, records) { + adapter.find(connection, collection, options, function(err, records) { if (err) return cb(err) uniqId = uniqId || false @@ -604,7 +654,7 @@ module.exports = (function () { } var request = new mssql.Request(mssqlConnect) - request.query(statement, function (err, emptyDeleteRecordSet) { + request.query(statement, function(err, emptyDeleteRecordSet) { if (err) return cb(err) if (!connections[connection].persistent) { mssqlConnect && mssqlConnect.close() @@ -615,32 +665,39 @@ module.exports = (function () { }) }, - join: function (connectionName, collectionName, criteria, cb) { + join: function(connectionName, collectionName, criteria, cb) { if (_.isObject(criteria)) { delete criteria.select } - CursorJoin({ - instructions: criteria, - parentCollection: collectionName, - // nativeJoins: true, - - $find: function (collectionIdentity, criteria, cb) { - return adapter.find(connectionName, collectionIdentity, criteria, cb) + CursorJoin( + { + instructions: criteria, + parentCollection: collectionName, + // nativeJoins: true, + + $find: function(collectionIdentity, criteria, cb) { + return adapter.find( + connectionName, + collectionIdentity, + criteria, + cb + ) + }, + + $getPK: function(collectionIdentity) { + if (!collectionIdentity) return + var connectionObject = connections[connectionName] + var collection = connectionObject.collections[collectionIdentity] + return collection.getPrimaryKey() + } }, - - $getPK: function (collectionIdentity) { - if (!collectionIdentity) return - var connectionObject = connections[connectionName] - var collection = connectionObject.collections[collectionIdentity] - return collection.getPrimaryKey() - } - }, cb) + cb + ) } - } - function marshalConfig (_config) { + function marshalConfig(_config) { var config = _.defaults(_config, { server: _config.host, pool: { @@ -653,9 +710,11 @@ module.exports = (function () { return config } - function getSchemaName (connection, collection) { + function getSchemaName(connection, collection) { var collectionObject = connections[connection].collections[collection] - return collectionObject.meta && collectionObject.meta.schemaName ? collectionObject.meta.schemaName : 'dbo' + return collectionObject.meta && collectionObject.meta.schemaName + ? collectionObject.meta.schemaName + : 'dbo' } return adapter diff --git a/lib/sql.js b/lib/sql.js index 4805f03..08b491d 100644 --- a/lib/sql.js +++ b/lib/sql.js @@ -3,19 +3,18 @@ _.str = require('underscore.string') var utils = require('./utils') var sql = { - - escapeId: function (val) { + escapeId: function(val) { return '[' + val.replace(/'/g, "''") + ']' }, - escape: function (val, stringifyObjects, timeZone) { + escape: function(val, stringifyObjects, timeZone) { if (val === undefined || val === null) { return 'NULL' } switch (typeof val) { case 'boolean': - return (val) ? '1' : '0' + return val ? '1' : '0' case 'number': return val + '' } @@ -24,7 +23,7 @@ var sql = { val = val.toString() } - val = val.replace(/[']/g, function (s) { + val = val.replace(/[']/g, function(s) { switch (s) { case "'": return "''" @@ -38,41 +37,45 @@ var sql = { return "'" + val + "'" }, - normalizeSchema: function (schema) { - return _.reduce(schema, function (memo, field) { - // Marshal mssql DESCRIBE to waterline collection semantics - var attrName = field.ColumnName - var type = field.TypeName + normalizeSchema: function(schema) { + return _.reduce( + schema, + function(memo, field) { + // Marshal mssql DESCRIBE to waterline collection semantics + var attrName = field.ColumnName + var type = field.TypeName - memo[attrName] = { - type: type + memo[attrName] = { + type: type // defaultsTo: field.Default - } + } - memo[attrName].autoIncrement = field.AutoIncrement - memo[attrName].primaryKey = field.PrimaryKey - memo[attrName].unique = field.Unique - memo[attrName].indexed = field.Indexed - memo[attrName].nullable = field.Nullable + memo[attrName].autoIncrement = field.AutoIncrement + memo[attrName].primaryKey = field.PrimaryKey + memo[attrName].unique = field.Unique + memo[attrName].indexed = field.Indexed + memo[attrName].nullable = field.Nullable - return memo - }, {}) + return memo + }, + {} + ) }, // @returns ALTER query for adding a column - addColumn: function (collectionName, attrName, attrDef) { + addColumn: function(collectionName, attrName, attrDef) { var tableName = collectionName var columnDefinition = sql._schema(collectionName, attrDef, attrName) return 'ALTER TABLE ' + tableName + ' ADD ' + columnDefinition }, // @returns ALTER query for dropping a column - removeColumn: function (collectionName, attrName) { + removeColumn: function(collectionName, attrName) { var tableName = collectionName return 'ALTER TABLE ' + tableName + ' DROP COLUMN ' + attrName }, - selectQuery: function (collectionName, options) { + selectQuery: function(collectionName, options) { var query = utils.buildSelectStatement(options, collectionName) query += sql.serializeOptions(collectionName, options) if (options.skip) { @@ -80,23 +83,37 @@ var sql = { if (options.limit) { outerOffsetQuery += 'TOP ' + options.limit + ' ' } - outerOffsetQuery += '* FROM (' + query + ') __outeroffset__ WHERE __outeroffset__.__rownum__ > ' + options.skip + ' ' + outerOffsetQuery += + '* FROM (' + + query + + ') __outeroffset__ WHERE __outeroffset__.__rownum__ > ' + + options.skip + + ' ' query = outerOffsetQuery } return query }, - insertQuery: function (collectionName, data) { + insertQuery: function(collectionName, data) { var tableName = collectionName - return 'INSERT INTO ' + tableName + ' (' + sql.attributes(collectionName, data) + ')' + ' VALUES (' + sql.values(collectionName, data) + '); SELECT @@IDENTITY AS [id]' + return ( + 'INSERT INTO ' + + tableName + + ' (' + + sql.attributes(collectionName, data) + + ')' + + ' VALUES (' + + sql.values(collectionName, data) + + '); SELECT @@IDENTITY AS [id]' + ) }, // Create a schema csv for a DDL query - schema: function (collectionName, attributes) { + schema: function(collectionName, attributes) { return sql.build(collectionName, attributes, sql._schema) }, - _schema: function (collectionName, attribute, attrName) { + _schema: function(collectionName, attribute, attrName) { attrName = '[' + attrName + ']' var type = sqlTypeCast(attribute.type) @@ -119,23 +136,23 @@ var sql = { }, // Create an attribute csv for a DQL query - attributes: function (collectionName, attributes) { + attributes: function(collectionName, attributes) { return sql.build(collectionName, attributes, sql.prepareAttribute) }, // Create a value csv for a DQL query // key => optional, overrides the keys in the dictionary - values: function (collectionName, values, key) { + values: function(collectionName, values, key) { return sql.build(collectionName, values, sql.prepareValue, ', ', key) }, - updateCriteria: function (collectionName, values) { + updateCriteria: function(collectionName, values) { var query = sql.build(collectionName, values, sql.prepareCriterion) query = query.replace(/IS NULL/g, '=NULL') return query }, - prepareCriterion: function (collectionName, value, key, parentKey) { + prepareCriterion: function(collectionName, value, key, parentKey) { if (validSubAttrCriteria(value)) { return sql.where(collectionName, value, null, key) } @@ -150,22 +167,31 @@ var sql = { valueStr = sql.prepareValue(collectionName, value, parentKey) // Why don't we strip you out of those bothersome apostrophes? - var nakedButClean = _.str.trim(valueStr, '\'') + var nakedButClean = _.str.trim(valueStr, "'") if (key === '<' || key === 'lessThan') return attrStr + '<' + valueStr - else if (key === '<=' || key === 'lessThanOrEqual') return attrStr + '<=' + valueStr - else if (key === '>' || key === 'greaterThan') return attrStr + '>' + valueStr - else if (key === '>=' || key === 'greaterThanOrEqual') return attrStr + '>=' + valueStr + else if (key === '<=' || key === 'lessThanOrEqual') + return attrStr + '<=' + valueStr + else if (key === '>' || key === 'greaterThan') + return attrStr + '>' + valueStr + else if (key === '>=' || key === 'greaterThanOrEqual') + return attrStr + '>=' + valueStr else if (key === '!' || key === 'not') { if (value === null) return attrStr + ' IS NOT NULL' else if (_.isArray(value)) { // return attrStr + ' NOT IN (' + valueStr.split(',') + ')'; - return attrStr + ' NOT IN (' + sql.values(collectionName, value, key) + ')' + return ( + attrStr + ' NOT IN (' + sql.values(collectionName, value, key) + ')' + ) } else return attrStr + '<>' + valueStr - } else if (key === 'like') return attrStr + ' LIKE \'' + nakedButClean + '\'' - else if (key === 'contains') return attrStr + ' LIKE \'%' + nakedButClean + '%\'' - else if (key === 'startsWith') return attrStr + ' LIKE \'' + nakedButClean + '%\'' - else if (key === 'endsWith') return attrStr + ' LIKE \'%' + nakedButClean + '\'' + } else if (key === 'like') + return attrStr + " LIKE '" + nakedButClean + "'" + else if (key === 'contains') + return attrStr + " LIKE '%" + nakedButClean + "%'" + else if (key === 'startsWith') + return attrStr + " LIKE '" + nakedButClean + "%'" + else if (key === 'endsWith') + return attrStr + " LIKE '%" + nakedButClean + "'" else throw new Error('Unknown comparator: ' + key) } else { attrStr = sql.prepareAttribute(collectionName, value, key) @@ -176,7 +202,7 @@ var sql = { } }, - prepareValue: function (collectionName, value, attrName) { + prepareValue: function(collectionName, value, attrName) { // Cast dates to SQL if (_.isDate(value)) { value = toSqlDate(value) @@ -191,18 +217,25 @@ var sql = { return sql.escape(value) }, - prepareAttribute: function (collectionName, value, attrName) { + prepareAttribute: function(collectionName, value, attrName) { return '[' + attrName + ']' }, // Starting point for predicate evaluation // parentKey => if set, look for comparators and apply them to the parent key - where: function (collectionName, where, key, parentKey) { - return sql.build(collectionName, where, sql.predicate, ' AND ', undefined, parentKey) + where: function(collectionName, where, key, parentKey) { + return sql.build( + collectionName, + where, + sql.predicate, + ' AND ', + undefined, + parentKey + ) }, // Recursively parse a predicate calculus and build a SQL query - predicate: function (collectionName, criterion, key, parentKey) { + predicate: function(collectionName, criterion, key, parentKey) { var queryPart = '' if (parentKey) { @@ -218,20 +251,26 @@ var sql = { return ' ( ' + queryPart + ' ) ' } else if (_.isArray(criterion)) { var values = sql.values(collectionName, criterion, key) || 'NULL' - queryPart = sql.prepareAttribute(collectionName, null, key) + ' IN (' + values + ')' + queryPart = + sql.prepareAttribute(collectionName, null, key) + ' IN (' + values + ')' return queryPart } else if (key.toLowerCase() === 'like') { - return sql.build(collectionName, criterion, function (collectionName, value, attrName) { - var attrStr = sql.prepareAttribute(collectionName, value, attrName) - if (_.isRegExp(value)) { - throw new Error('RegExp not supported') - } - var valueStr = sql.prepareValue(collectionName, value, attrName) + return sql.build( + collectionName, + criterion, + function(collectionName, value, attrName) { + var attrStr = sql.prepareAttribute(collectionName, value, attrName) + if (_.isRegExp(value)) { + throw new Error('RegExp not supported') + } + var valueStr = sql.prepareValue(collectionName, value, attrName) // Handle escaped percent (%) signs [encoded as %%%] - valueStr = valueStr.replace(/%%%/g, '\\%') + valueStr = valueStr.replace(/%%%/g, '\\%') - return attrStr + ' LIKE ' + valueStr - }, ' AND ') + return attrStr + ' LIKE ' + valueStr + }, + ' AND ' + ) } else if (key.toLowerCase() === 'not') { throw new Error('NOT not supported yet!') } else { @@ -239,7 +278,7 @@ var sql = { } }, - serializeOptions: function (collectionName, options) { + serializeOptions: function(collectionName, options) { var queryPart = '' if (options.where) { @@ -251,7 +290,7 @@ var sql = { // Normalize to array if (!Array.isArray(options.groupBy)) options.groupBy = [options.groupBy] - options.groupBy.forEach(function (key) { + options.groupBy.forEach(function(key) { queryPart += key + ', ' }) @@ -264,7 +303,7 @@ var sql = { queryPart += 'ORDER BY ' // Sort through each sort attribute criteria - _.each(options.sort, function (direction, attrName) { + _.each(options.sort, function(direction, attrName) { queryPart += sql.prepareAttribute(collectionName, null, attrName) + ' ' // Basic MongoDB-style numeric sort direction @@ -284,11 +323,18 @@ var sql = { return queryPart }, - build: function (collectionName, collection, fn, separator, keyOverride, parentKey) { + build: function( + collectionName, + collection, + fn, + separator, + keyOverride, + parentKey + ) { separator = separator || ', ' var $sql = '' - _.each(collection, function (value, key) { + _.each(collection, function(value, key) { $sql += fn(collectionName, value, keyOverride || key, parentKey) // (always append separator) @@ -297,11 +343,10 @@ var sql = { return _.str.rtrim($sql, separator) } - } // Cast waterline types into SQL data types -function sqlTypeCast (type) { +function sqlTypeCast(type) { type = type && type.toLowerCase() switch (type) { @@ -342,22 +387,41 @@ function wrapInQuotes (val) { return '"' + val + '"' } */ -function toSqlDate (date) { - date = date.getUTCFullYear() + '-' + - ('00' + (date.getUTCMonth() + 1)).slice(-2) + '-' + - ('00' + date.getUTCDate()).slice(-2) + ' ' + - ('00' + date.getUTCHours()).slice(-2) + ':' + - ('00' + date.getUTCMinutes()).slice(-2) + ':' + +function toSqlDate(date) { + date = + date.getUTCFullYear() + + '-' + + ('00' + (date.getUTCMonth() + 1)).slice(-2) + + '-' + + ('00' + date.getUTCDate()).slice(-2) + + ' ' + + ('00' + date.getUTCHours()).slice(-2) + + ':' + + ('00' + date.getUTCMinutes()).slice(-2) + + ':' + ('00' + date.getUTCSeconds()).slice(-2) return date } -function validSubAttrCriteria (c) { - return _.isObject(c) && (!_.isUndefined(c.not) || !_.isUndefined(c.greaterThan) || !_.isUndefined(c.lessThan) || - !_.isUndefined(c.greaterThanOrEqual) || !_.isUndefined(c.lessThanOrEqual) || !_.isUndefined(c['<']) || - !_.isUndefined(c['<=']) || !_.isUndefined(c['!']) || !_.isUndefined(c['>']) || !_.isUndefined(c['>=']) || - !_.isUndefined(c.startsWith) || !_.isUndefined(c.endsWith) || !_.isUndefined(c.contains) || !_.isUndefined(c.like)) +function validSubAttrCriteria(c) { + return ( + _.isObject(c) && + (!_.isUndefined(c.not) || + !_.isUndefined(c.greaterThan) || + !_.isUndefined(c.lessThan) || + !_.isUndefined(c.greaterThanOrEqual) || + !_.isUndefined(c.lessThanOrEqual) || + !_.isUndefined(c['<']) || + !_.isUndefined(c['<=']) || + !_.isUndefined(c['!']) || + !_.isUndefined(c['>']) || + !_.isUndefined(c['>=']) || + !_.isUndefined(c.startsWith) || + !_.isUndefined(c.endsWith) || + !_.isUndefined(c.contains) || + !_.isUndefined(c.like)) + ) } module.exports = sql diff --git a/lib/utils.js b/lib/utils.js index c69b6cc..849be72 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -7,7 +7,7 @@ var _ = require('lodash') // Module Exports -var utils = module.exports = {} +var utils = (module.exports = {}) /** * Prepare values @@ -16,7 +16,7 @@ var utils = module.exports = {} * to strings. */ -utils.prepareValue = function (value) { +utils.prepareValue = function(value) { if (!value) return value // Cast functions to strings @@ -25,7 +25,10 @@ utils.prepareValue = function (value) { } // Store Arrays and Objects as strings - if (Array.isArray(value) || value.constructor && value.constructor.name === 'Object') { + if ( + Array.isArray(value) || + (value.constructor && value.constructor.name === 'Object') + ) { try { value = JSON.stringify(value) } catch (e) { @@ -37,11 +40,11 @@ utils.prepareValue = function (value) { return value } -utils.buildOrderByStatement = function (criteria) { +utils.buildOrderByStatement = function(criteria) { var queryPart = 'ORDER BY ' // Sort through each sort attribute criteria - _.each(criteria.sort, function (direction, attrName) { + _.each(criteria.sort, function(direction, attrName) { queryPart += '[' + attrName + '] ' // Basic MongoDB-style numeric sort direction @@ -63,14 +66,21 @@ utils.buildOrderByStatement = function (criteria) { * Builds a Select statement determining if Aggeregate options are needed. */ -utils.buildSelectStatement = function (criteria, table) { +utils.buildSelectStatement = function(criteria, table) { var query = 'SELECT ' - if (criteria.select || criteria.groupBy || criteria.sum || criteria.average || criteria.min || criteria.max) { + if ( + criteria.select || + criteria.groupBy || + criteria.sum || + criteria.average || + criteria.min || + criteria.max + ) { // Select only certain columns if (criteria.select) { if (criteria.select instanceof Array) { - criteria.select.forEach(function (opt) { + criteria.select.forEach(function(opt) { query += '[' + opt + '], ' }) } else { @@ -82,7 +92,7 @@ utils.buildSelectStatement = function (criteria, table) { // Append groupBy columns to select statement if (criteria.groupBy) { if (criteria.groupBy instanceof Array) { - criteria.groupBy.forEach(function (opt) { + criteria.groupBy.forEach(function(opt) { query += '[' + opt + '], ' }) } else { @@ -93,7 +103,7 @@ utils.buildSelectStatement = function (criteria, table) { // Handle SUM if (criteria.sum) { if (criteria.sum instanceof Array) { - criteria.sum.forEach(function (opt) { + criteria.sum.forEach(function(opt) { query += 'SUM([' + opt + ']) AS [' + opt + '], ' }) } else { @@ -104,18 +114,23 @@ utils.buildSelectStatement = function (criteria, table) { // Handle AVG (casting to float to fix percision with trailing zeros) if (criteria.average) { if (criteria.average instanceof Array) { - criteria.average.forEach(function (opt) { + criteria.average.forEach(function(opt) { query += 'AVG(CAST([' + opt + '] AS FLOAT)) AS [' + opt + '], ' }) } else { - query += 'AVG(CAST([' + criteria.average + '] AS FLOAT)) AS [' + criteria.average + '], ' + query += + 'AVG(CAST([' + + criteria.average + + '] AS FLOAT)) AS [' + + criteria.average + + '], ' } } // Handle MAX if (criteria.max) { if (criteria.max instanceof Array) { - criteria.max.forEach(function (opt) { + criteria.max.forEach(function(opt) { query += 'MAX([' + opt + ']) AS [' + opt + '], ' }) } else { @@ -126,7 +141,7 @@ utils.buildSelectStatement = function (criteria, table) { // Handle MIN if (criteria.min) { if (criteria.min instanceof Array) { - criteria.min.forEach(function (opt) { + criteria.min.forEach(function(opt) { query += 'MIN([' + opt + ']) AS [' + opt + '], ' }) } else { @@ -146,11 +161,12 @@ utils.buildSelectStatement = function (criteria, table) { if (criteria.skip) { var primaryKeySort = {} primaryKeySort[criteria.__primaryKey__] = 1 - // @todo what to do with no primary key OR sort? + // @todo what to do with no primary key OR sort? criteria.sort = criteria.sort || primaryKeySort - query += 'ROW_NUMBER() OVER (' + + query += + 'ROW_NUMBER() OVER (' + utils.buildOrderByStatement(criteria) + - ') AS \'__rownum__\', ' + ") AS '__rownum__', " } else if (criteria.limit) { // SQL Server implementation of LIMIT query += 'TOP ' + criteria.limit + ' ' diff --git a/package.json b/package.json index 49d46c4..f77bc17 100644 --- a/package.json +++ b/package.json @@ -51,16 +51,17 @@ ], "license": "MIT", "dependencies": { - "captains-log": "^0.11.11", - "lodash": "^3.8.0", - "mssql": "^3.3.0", - "underscore.string": "^3.0.0", - "waterline-cursor": "0.0.5", - "bunyan": "^1.8.1" + "bunyan": "1.8.12", + "captains-log": "2.0.0", + "eslint": "^4.16.0", + "lodash": "4.17.4", + "mssql": "4.1.0", + "underscore.string": "3.3.4", + "waterline-cursor": "0.0.7" }, "devDependencies": { - "dotenv": "^2.0.0", - "mocha": "*", + "dotenv": "4.0.0", + "mocha": "5.0.0", "waterline-adapter-tests": "git://github.com/tjwebb/waterline-adapter-tests.git" }, "waterlineAdapter": { @@ -109,4 +110,4 @@ "directories": {}, "_resolved": "https://registry.npmjs.org/sails-mssqlserver/-/sails-mssqlserver-0.12.0.tgz", "readme": "ERROR: No README data found!" -} \ No newline at end of file +}