不要怂,就是干,撸起袖子干!

Commit daaf3c3e by Matt Broadstone

refactor update/insert query to support additional features

  - added logic to handle corner cases regarding autoIncrement values
  - added support for OUTPUT variables (mssql)
  - added support for identity wrapping (related to point 1)
1 parent d5cef99f
...@@ -5,11 +5,28 @@ var AbstractDialect = function() { ...@@ -5,11 +5,28 @@ var AbstractDialect = function() {
}; };
AbstractDialect.prototype.supports = { AbstractDialect.prototype.supports = {
'RETURNING': false,
'DEFAULT': true, 'DEFAULT': true,
'DEFAULT VALUES': false, 'DEFAULT VALUES': false,
'VALUES ()': false, 'VALUES ()': false,
'LIMIT ON UPDATE': false, 'LIMIT ON UPDATE': false,
/* does the dialect support returning values for inserted/updated fields using RETURNING */
'RETURNING': false,
/* does the dialect support returning values for inserted/updated fields using OUTPUT */
'OUTPUT': false,
/* features specific to autoIncrement values */
autoIncrement: {
/* does the dialect require modification of insert queries when inserting auto increment fields */
identityInsert: false,
/* does the dialect support inserting default/null values for autoincrement fields */
defaultValue: true,
/* does the dialect support updating autoincrement fields */
update: true
},
schemas: false, schemas: false,
index: { index: {
collate: true, collate: true,
......
...@@ -154,12 +154,14 @@ module.exports = (function() { ...@@ -154,12 +154,14 @@ module.exports = (function() {
options = options || {}; options = options || {};
var query var query
, valueQuery = 'INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>)' , valueQuery = 'INSERT INTO <%= table %> (<%= attributes %>)<%= output %> VALUES (<%= values %>)'
, emptyQuery = 'INSERT INTO <%= table %>' , emptyQuery = 'INSERT INTO <%= table %><%= output %>'
, outputFragment
, fields = [] , fields = []
, values = [] , values = []
, key , key
, value , value
, identityWrapperRequired = false
, modelAttributeMap = {}; , modelAttributeMap = {};
if (modelAttributes) { if (modelAttributes) {
...@@ -177,9 +179,13 @@ module.exports = (function() { ...@@ -177,9 +179,13 @@ module.exports = (function() {
emptyQuery += ' VALUES ()'; emptyQuery += ' VALUES ()';
} }
// FIXME: ideally these two can be merged in the future, the only
// difference is placement of the value in the query
if (this._dialect.supports['RETURNING'] && options.returning) { if (this._dialect.supports['RETURNING'] && options.returning) {
valueQuery += ' RETURNING *'; valueQuery += ' RETURNING *';
emptyQuery += ' RETURNING *'; emptyQuery += ' RETURNING *';
} else if (this._dialect.supports['OUTPUT'] && options.returning) {
outputFragment = ' OUTPUT INSERTED.*';
} }
if (this._dialect.supports['EXCEPTION'] && options.exception) { if (this._dialect.supports['EXCEPTION'] && options.exception) {
...@@ -197,12 +203,18 @@ module.exports = (function() { ...@@ -197,12 +203,18 @@ module.exports = (function() {
// SERIALS' can't be NULL in postgresql, use DEFAULT where supported // SERIALS' can't be NULL in postgresql, use DEFAULT where supported
if (modelAttributeMap && modelAttributeMap[key] && modelAttributeMap[key].autoIncrement === true && !value) { if (modelAttributeMap && modelAttributeMap[key] && modelAttributeMap[key].autoIncrement === true && !value) {
if (this._dialect.supports['DEFAULT']) { if (!this._dialect.supports.autoIncrement.defaultValue) {
fields.splice(-1,1);
} else if (this._dialect.supports['DEFAULT']) {
values.push('DEFAULT'); values.push('DEFAULT');
} else { } else {
values.push(this.escape(null)); values.push(this.escape(null));
} }
} else { } else {
if (modelAttributeMap && modelAttributeMap[key] && modelAttributeMap[key].autoIncrement === true) {
identityWrapperRequired = true;
}
values.push(this.escape(value, (modelAttributeMap && modelAttributeMap[key]) || undefined)); values.push(this.escape(value, (modelAttributeMap && modelAttributeMap[key]) || undefined));
} }
} }
...@@ -211,10 +223,18 @@ module.exports = (function() { ...@@ -211,10 +223,18 @@ module.exports = (function() {
var replacements = { var replacements = {
table: this.quoteTable(table), table: this.quoteTable(table),
attributes: fields.join(','), attributes: fields.join(','),
output: outputFragment,
values: values.join(',') values: values.join(',')
}; };
query = (replacements.attributes.length ? valueQuery : emptyQuery) + ';'; query = (replacements.attributes.length ? valueQuery : emptyQuery) + ';';
if (identityWrapperRequired && this._dialect.supports.autoIncrement.identityInsert) {
query = [
'SET IDENTITY_INSERT', this.quoteTable(table), 'ON;',
query,
'SET IDENTITY_INSERT', this.quoteTable(table), 'OFF;',
].join(' ');
}
return Utils._.template(query)(replacements); return Utils._.template(query)(replacements);
}, },
...@@ -244,9 +264,11 @@ module.exports = (function() { ...@@ -244,9 +264,11 @@ module.exports = (function() {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, options.omitNull, options); attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, options.omitNull, options);
var query var query
, values = []; , values = []
, outputFragment
, modelAttributeMap = [];
query = 'UPDATE <%= table %> SET <%= values %> WHERE <%= where %>'; query = 'UPDATE <%= table %> SET <%= values %><%= output %> WHERE <%= where %>';
if (this._dialect.supports['LIMIT ON UPDATE'] && options.limit) { if (this._dialect.supports['LIMIT ON UPDATE'] && options.limit) {
query += ' LIMIT ' + this.escape(options.limit) + ' '; query += ' LIMIT ' + this.escape(options.limit) + ' ';
...@@ -254,9 +276,27 @@ module.exports = (function() { ...@@ -254,9 +276,27 @@ module.exports = (function() {
if (this._dialect.supports['RETURNING'] && options.returning) { if (this._dialect.supports['RETURNING'] && options.returning) {
query += ' RETURNING *'; query += ' RETURNING *';
} else if (this._dialect.supports['OUTPUT']) {
outputFragment = ' OUTPUT INSERTED.*';
}
if (attributes) {
Utils._.each(attributes, function(attribute, key) {
modelAttributeMap[key] = attribute;
if (attribute.field) {
modelAttributeMap[attribute.field] = attribute;
}
});
} }
for (var key in attrValueHash) { for (var key in attrValueHash) {
if (modelAttributeMap && modelAttributeMap[key] &&
modelAttributeMap[key].autoIncrement === true &&
!this._dialect.supports.autoIncrement.update) {
// not allowed to update identity column
continue;
}
var value = attrValueHash[key]; var value = attrValueHash[key];
values.push(this.quoteIdentifier(key) + '=' + this.escape(value, (!!attributes && !!attributes[key] ? attributes[key] : undefined))); values.push(this.quoteIdentifier(key) + '=' + this.escape(value, (!!attributes && !!attributes[key] ? attributes[key] : undefined)));
} }
...@@ -264,9 +304,14 @@ module.exports = (function() { ...@@ -264,9 +304,14 @@ module.exports = (function() {
var replacements = { var replacements = {
table: this.quoteTable(tableName), table: this.quoteTable(tableName),
values: values.join(','), values: values.join(','),
output: outputFragment,
where: this.getWhereConditions(where) where: this.getWhereConditions(where)
}; };
if (values.length === 0) {
return '';
}
return Utils._.template(query)(replacements); return Utils._.template(query)(replacements);
}, },
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!