diff --git a/gulpfile.js b/gulpfile.js index 5e6064f..36b6912 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -18,7 +18,7 @@ gulp.task('coverage', function(callback) { .pipe(istanbul()) .pipe(istanbul.hookRequire()) .on('finish', function() { - gulp.src(['./tests/*.js'], {read: false}) + gulp.src(['./tests/**/*.js'], {read: false}) .pipe(mocha({ reporter: 'spec', bail: true diff --git a/lib/dialects/base/blocks.js b/lib/dialects/base/blocks.js index 6b29b1c..5421138 100644 --- a/lib/dialects/base/blocks.js +++ b/lib/dialects/base/blocks.js @@ -333,10 +333,11 @@ module.exports = function(dialect) { dialect.blocks.add('insert:values', function(params) { var values = params.values; + var fields = params.fields; if (!_.isArray(values)) values = [values]; - var fields = params.fields || _(values) + fields = fields || _(values) .chain() .map(function(row) { return _(row).keys(); @@ -345,13 +346,15 @@ module.exports = function(dialect) { .uniq() .value(); + values = _(values).map(function(row) { + return _(fields).map(function(field) { + return dialect.buildBlock('value', {value: row[field]}); + }); + }); + return dialect.buildTemplate('insertValues', { - fields: fields, - values: _(values).map(function(row) { - return _(fields).map(function(field) { - return dialect.buildBlock('value', {value: row[field]}); - }); - }) + values: values, + fields: fields }); }); diff --git a/lib/dialects/base/index.js b/lib/dialects/base/index.js index 5518974..8cb38ab 100644 --- a/lib/dialects/base/index.js +++ b/lib/dialects/base/index.js @@ -347,7 +347,8 @@ Dialect.prototype.buildTemplate = function(type, params) { return ''; } else { if (self.blocks.has(type + ':' + block)) block = type + ':' + block; - return self.buildBlock(block, params) + space; + var result = self.buildBlock(block, params); + return result === '' ? result : result + space; } }).trim(); }; diff --git a/lib/dialects/mssql/blocks.js b/lib/dialects/mssql/blocks.js index 163fc5c..853dc37 100644 --- a/lib/dialects/mssql/blocks.js +++ b/lib/dialects/mssql/blocks.js @@ -3,8 +3,38 @@ var _ = require('underscore'); module.exports = function(dialect) { + var parentValueBlock = dialect.blocks.get('value'); + + dialect.blocks.set('value', function(params) { + var value = params.value; + + var result; + if (_.isUndefined(value) || _.isNull(value)) { + result = 'null'; + } else if (_.isBoolean(value)) { + result = String(Number(value)); + } else if (_.isNumber(value)) { + result = String(value); + } else if (_.isString(value) || _.isDate(value)) { + if (dialect.builder.options.separatedValues) { + result = dialect.builder._pushValue(value); + } else { + if (_.isDate(value)) value = value.toISOString(); + result = '\'' + value + '\''; + } + } else { + result = parentValueBlock(params); + } + + return result; + }); + dialect.blocks.set('limit', function(params) { - return (!isNaN(params.offset)) ? '' : 'top(' + dialect.builder._pushValue(params.limit) + ')'; + var result = ''; + if (_.isUndefined(params.offset)) { + result = 'top(' + dialect.builder._pushValue(params.limit) + ')'; + } + return result; }); dialect.blocks.set('offset', function(params) { @@ -13,8 +43,8 @@ module.exports = function(dialect) { var str = pre + 'offset ' + dialect.builder._pushValue(params.offset); str += ' rows fetch next ' + dialect.builder._pushValue(params.limit) + ' rows only'; return str; - }else { - return pre + 'OFFSET ' + dialect.builder._pushValue(params.offset) + ' rows'; + } else { + return pre + 'offset ' + dialect.builder._pushValue(params.offset) + ' rows'; } }); @@ -28,32 +58,30 @@ module.exports = function(dialect) { dialect.blocks.set('insert:values', function(params) { var values = params.values; + var fields = params.fields; + var returning = params.returning; if (!_.isArray(values)) values = [values]; - var fields = params.fields || _(values) - .chain() - .map(function(row) { - return _(row).keys(); - }) - .flatten() - .uniq() - .value(); + fields = fields || _(values) + .chain() + .map(function(row) { + return _(row).keys(); + }) + .flatten() + .uniq() + .value(); + + values = _(values).map(function(row) { + return _(fields).map(function(field) { + return dialect.buildBlock('value', {value: row[field]}); + }); + }); return dialect.buildTemplate('insertValues', { + values: values, fields: fields, - returning: params.returning || undefined, - values: _(values).map(function(row) { - return _(fields).map(function(field) { - return dialect.buildBlock('value', {value: row[field]}); - }); - }) + returning: returning }); }); - - dialect.blocks.add('insertValues:values', function(params) { - return _(params.values).map(function(row) { - return '(' + row.join(', ') + ')'; - }).join(', '); - }); }; diff --git a/lib/dialects/mssql/index.js b/lib/dialects/mssql/index.js index 569d6d8..4675e9b 100644 --- a/lib/dialects/mssql/index.js +++ b/lib/dialects/mssql/index.js @@ -7,35 +7,6 @@ var templatesInit = require('./templates'); var blocksInit = require('./blocks'); var Dialect = module.exports = function(builder) { - - builder._pushValue = function(value) { - if (_.isUndefined(value) || _.isNull(value)) { - return 'null'; - } else if (_.isBoolean(value)) { - return String(Number(value)); - } else if (_.isNumber(value)) { - return String(value); - } else if (_.isString(value) || _.isDate(value)) { - if (this.options.separatedValues) { - var placeholder = this._getPlaceholder(); - - if (this.options.namedValues) { - this._values[placeholder] = value; - } else { - this._values.push(value); - } - - return this._wrapPlaceholder(placeholder); - } else { - if (_.isDate(value)) value = value.toISOString(); - - return '\'' + value + '\''; - } - } else { - throw new Error('Wrong value type "' + (typeof value) + '"'); - } - }; - BaseDialect.call(this, builder); // init templates @@ -43,9 +14,11 @@ var Dialect = module.exports = function(builder) { // init blocks blocksInit(this); - }; util.inherits(Dialect, BaseDialect); -Dialect.prototype.config = _({}).extend(BaseDialect.prototype.config, {}); +Dialect.prototype.config = _({}).extend(BaseDialect.prototype.config, { + identifierPrefix: '[', + identifierSuffix: ']' +}); diff --git a/lib/dialects/mssql/templates.js b/lib/dialects/mssql/templates.js index 79dbd0f..0741576 100644 --- a/lib/dialects/mssql/templates.js +++ b/lib/dialects/mssql/templates.js @@ -46,9 +46,9 @@ module.exports = function(dialect) { } }); - dialect.templates.add('insert', { + dialect.templates.set('insert', { pattern: '{with} {withRecursive} insert {or} into {table} {values} ' + - '{condition}', + '{condition}', validate: function(type, params) { templateChecks.onlyOneOfProps(type, params, ['with', 'withRecursive']); templateChecks.propType(type, params, 'with', 'object'); @@ -68,7 +68,7 @@ module.exports = function(dialect) { } }); - dialect.templates.add('insertValues', { + dialect.templates.set('insertValues', { pattern: '({fields}) {returning} values {values}', validate: function(type, params) { templateChecks.requiredProp('values', params, 'fields'); @@ -83,7 +83,7 @@ module.exports = function(dialect) { } }); - dialect.templates.add('update', { + dialect.templates.set('update', { pattern: '{with} {withRecursive} update {or} {table} {alias} {modifier} {returning} ' + '{condition} ', validate: function(type, params) { @@ -109,7 +109,7 @@ module.exports = function(dialect) { } }); - dialect.templates.add('remove', { + dialect.templates.set('remove', { pattern: '{with} {withRecursive} delete from {table} {returning} {alias} {condition} ', validate: function(type, params) { templateChecks.onlyOneOfProps(type, params, ['with', 'withRecursive']); diff --git a/tests/6_dialects/1_mssql.js b/tests/6_dialects/1_mssql.js index 625ef91..0020cd4 100644 --- a/tests/6_dialects/1_mssql.js +++ b/tests/6_dialects/1_mssql.js @@ -17,7 +17,7 @@ describe('MSSQL dialect', function() { 'name': {$eq: 'test'} } }); - expect(result.query).to.be.equal('select top(1) "user" from "test" where "name" = $1;'); + expect(result.query).to.be.equal('select top(1) [user] from [test] where [name] = $1;'); }); it('should be ok with `limit` and `offset` properties', function() { @@ -30,7 +30,7 @@ describe('MSSQL dialect', function() { 'name': {$eq: 'test'} } }); - expect(result.query).to.be.equal('select "user" from "test" where "name" = $1 order by 1' + + expect(result.query).to.be.equal('select [user] from [test] where [name] = $1 order by 1' + ' offset 2 rows fetch next 4 rows only;'); }); }); @@ -39,25 +39,29 @@ describe('MSSQL dialect', function() { var result = jsonSql.build({ type: 'remove', table: 'test', - returning: ['DELETED.*'], + returning: [ + {table: 'deleted', name: '*'} + ], condition: { Description: {$eq: 'test'} } }); - expect(result.query).to.be.equal('delete from "test" output "DELETED".* where ' + - '"Description" = $1;'); + expect(result.query).to.be.equal('delete from [test] output [deleted].* where ' + + '[Description] = $1;'); }); it('should be ok with `insert` type', function() { var result = jsonSql.build({ type: 'insert', table: 'test', - returning: ['INSERTED.*'], + returning: [ + {table: 'inserted', name: '*'} + ], values: { Description: 'test', } }); - expect(result.query).to.be.equal('insert into "test" ("Description") output ' + - '"INSERTED".* values ($1);'); + expect(result.query).to.be.equal('insert into [test] ([Description]) output ' + + '[inserted].* values ($1);'); }); }); });