Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add MSSQL support (requested changes) #33

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 10 additions & 7 deletions lib/dialects/base/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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
});
});

Expand Down
3 changes: 2 additions & 1 deletion lib/dialects/base/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
};
79 changes: 79 additions & 0 deletions lib/dialects/mssql/blocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'use strict';

var _ = require('underscore');

module.exports = function(dialect) {
var parentValueBlock = dialect.blocks.get('value');

dialect.blocks.set('value', function(params) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#26 (comment)

Logic moved from builder._pushValue to blocks.js. number, string, and null/undefined cases are handled by parentValueBlock(params) I belive.

var value = params.value;

var result;
if (_.isBoolean(value)) {
result = String(Number(value));
} else {
result = parentValueBlock(params);
}

return result;
});

dialect.blocks.set('limit', function(params) {
var result = '';
if (_.isUndefined(params.offset)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#26 (comment)

_.isUndefined used.

result = 'top(' + dialect.builder._pushValue(params.limit) + ')';
}
return result;
});

dialect.blocks.set('offset', function(params) {
var prefix = (!params.sort) ? 'order by 1 ' : '';
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#26 (comment)
#26 (comment)

This function was refactored to clean up the program flow. offset case fixed

var offset = 'offset ' + dialect.builder._pushValue(params.offset) + ' ';
var limit = '';
var suffix = 'rows';

if (params.limit) {
limit = 'rows fetch next ' + dialect.builder._pushValue(params.limit) + ' ';
suffix = 'rows only';
}

return prefix + offset + limit + suffix;
});

dialect.blocks.set('returning', function(params) {
var result = dialect.buildBlock('fields', {fields: params.returning});

if (result) result = 'output ' + result;

return result;
});

dialect.blocks.set('insert:values', function(params) {
var values = params.values;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#26 (comment)

This function was refactored a little bit, as was the base blocks.js. This cleans up the values and fields variable assignment.

returning is needed here, because it is used in the next buildTemplate call. {returning} is now part of the insertValues template. See template

#26 (comment)
The unnecessary code was removed

var fields = params.fields;
var returning = params.returning;

if (!_.isArray(values)) values = [values];

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: returning
});
});
};
13 changes: 12 additions & 1 deletion lib/dialects/mssql/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,22 @@
var BaseDialect = require('../base');
var _ = require('underscore');
var util = require('util');
var templatesInit = require('./templates');
var blocksInit = require('./blocks');

var Dialect = module.exports = function(builder) {
BaseDialect.call(this, builder);

// init templates
templatesInit(this);

// init blocks
blocksInit(this);
};

util.inherits(Dialect, BaseDialect);

Dialect.prototype.config = _({}).extend(BaseDialect.prototype.config, {});
Dialect.prototype.config = _({}).extend(BaseDialect.prototype.config, {
identifierPrefix: '[',
identifierSuffix: ']'
});
130 changes: 130 additions & 0 deletions lib/dialects/mssql/templates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
'use strict';

var templateChecks = require('../../utils/templateChecks');
var orRegExp = /^(rollback|abort|replace|fail|ignore)$/i;

module.exports = function(dialect) {
dialect.templates.set('select', {
pattern: '{with} {withRecursive} select {limit} {distinct} {fields} ' +
'from {from} {table} {query} {select} {expression} {alias} ' +
'{join} {condition} {group} {having} {sort} {offset}',
defaults: {
fields: {}
},
validate: function(type, params) {
templateChecks.onlyOneOfProps(type, params, ['with', 'withRecursive']);
templateChecks.propType(type, params, 'with', 'object');
templateChecks.propType(type, params, 'withRecursive', 'object');

templateChecks.propType(type, params, 'distinct', 'boolean');

templateChecks.propType(type, params, 'fields', ['array', 'object']);

templateChecks.propType(type, params, 'from', ['string', 'array', 'object']);

templateChecks.atLeastOneOfProps(type, params, ['table', 'query', 'select', 'expression']);
templateChecks.onlyOneOfProps(type, params, ['table', 'query', 'select', 'expression']);

templateChecks.propType(type, params, 'table', 'string');
templateChecks.propType(type, params, 'query', 'object');
templateChecks.propType(type, params, 'select', 'object');
templateChecks.propType(type, params, 'expression', ['string', 'object']);

templateChecks.propType(type, params, 'alias', ['string', 'object']);

templateChecks.propType(type, params, 'join', ['array', 'object']);

templateChecks.propType(type, params, 'condition', ['array', 'object']);
templateChecks.propType(type, params, 'having', ['array', 'object']);

templateChecks.propType(type, params, 'group', ['string', 'array']);

templateChecks.propType(type, params, 'sort', ['string', 'array', 'object']);

templateChecks.propType(type, params, 'offset', ['number', 'string']);
templateChecks.propType(type, params, 'limit', ['number', 'string']);
}
});

dialect.templates.set('insert', {
pattern: '{with} {withRecursive} insert {or} into {table} {values} ' +
'{condition}',
validate: function(type, params) {
templateChecks.onlyOneOfProps(type, params, ['with', 'withRecursive']);
templateChecks.propType(type, params, 'with', 'object');
templateChecks.propType(type, params, 'withRecursive', 'object');

templateChecks.propType(type, params, 'or', 'string');
templateChecks.propMatch(type, params, 'or', orRegExp);

templateChecks.requiredProp(type, params, 'table');
templateChecks.propType(type, params, 'table', 'string');

templateChecks.requiredProp(type, params, 'values');
templateChecks.propType(type, params, 'values', ['array', 'object']);

templateChecks.propType(type, params, 'condition', ['array', 'object']);

}
});

dialect.templates.set('insertValues', {
pattern: '({fields}) {returning} values {values}',
validate: function(type, params) {
templateChecks.requiredProp('values', params, 'fields');
templateChecks.propType('values', params, 'fields', 'array');
templateChecks.minPropLength('values', params, 'fields', 1);

templateChecks.propType(type, params, 'returning', ['array', 'object']);

templateChecks.requiredProp('values', params, 'values');
templateChecks.propType('values', params, 'values', 'array');
templateChecks.minPropLength('values', params, 'values', 1);
}
});

dialect.templates.set('update', {
pattern: '{with} {withRecursive} update {or} {table} {alias} {modifier} {returning} ' +
'{condition} ',
validate: function(type, params) {
templateChecks.onlyOneOfProps(type, params, ['with', 'withRecursive']);
templateChecks.propType(type, params, 'with', 'object');
templateChecks.propType(type, params, 'withRecursive', 'object');

templateChecks.propType(type, params, 'or', 'string');
templateChecks.propMatch(type, params, 'or', orRegExp);

templateChecks.requiredProp(type, params, 'table');
templateChecks.propType(type, params, 'table', 'string');

templateChecks.propType(type, params, 'returning', ['array', 'object']);

templateChecks.propType(type, params, 'alias', 'string');

templateChecks.requiredProp(type, params, 'modifier');
templateChecks.propType(type, params, 'modifier', 'object');

templateChecks.propType(type, params, 'condition', ['array', 'object']);

}
});

dialect.templates.set('remove', {
pattern: '{with} {withRecursive} delete from {table} {returning} {alias} {condition} ',
validate: function(type, params) {
templateChecks.onlyOneOfProps(type, params, ['with', 'withRecursive']);
templateChecks.propType(type, params, 'with', 'object');
templateChecks.propType(type, params, 'withRecursive', 'object');

templateChecks.requiredProp(type, params, 'table');
templateChecks.propType(type, params, 'table', 'string');

templateChecks.propType(type, params, 'returning', ['array', 'object']);

templateChecks.propType(type, params, 'alias', 'string');

templateChecks.propType(type, params, 'condition', ['array', 'object']);

}
});
};
Loading