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

Commit 37087559 by Jan Aagaard Meier

Rebase and Merge pull request #1024 from durango/newindex

2 parents 4845800a 8a81de1e
...@@ -115,10 +115,24 @@ module.exports = (function() { ...@@ -115,10 +115,24 @@ module.exports = (function() {
})() })()
DAOFactory.prototype.init = function(daoFactoryManager) { DAOFactory.prototype.init = function(daoFactoryManager) {
var self = this; var self = this
this.daoFactoryManager = daoFactoryManager
this.primaryKeys = {}
self.options.uniqueKeys = {}
Utils._.each(this.rawAttributes, function(columnValues, columnName) {
if (columnValues.hasOwnProperty('unique') && columnValues.unique !== true) {
var idxName = columnValues.unique
if (typeof columnValues.unique === "object") {
idxName = columnValues.unique.name
}
this.daoFactoryManager = daoFactoryManager self.options.uniqueKeys[idxName] = self.options.uniqueKeys[idxName] || {fields: [], msg: null}
this.primaryKeys = {}; self.options.uniqueKeys[idxName].fields.push(columnName)
self.options.uniqueKeys[idxName].msg = self.options.uniqueKeys[idxName].msg || columnValues.unique.msg || null
}
})
Utils._.each(this.attributes, function(dataTypeString, attributeName) { Utils._.each(this.attributes, function(dataTypeString, attributeName) {
if (dataTypeString.indexOf('PRIMARY KEY') !== -1) { if (dataTypeString.indexOf('PRIMARY KEY') !== -1) {
......
...@@ -396,7 +396,23 @@ module.exports = (function() { ...@@ -396,7 +396,23 @@ module.exports = (function() {
args[2] = values args[2] = values
self.QueryInterface[query].apply(self.QueryInterface, args) self.QueryInterface[query].apply(self.QueryInterface, args)
.proxy(emitter, {events: ['sql', 'error']}) .proxy(emitter, {events: ['sql']})
.error(function(err) {
if (!!self.__options.uniqueKeys && err.code && self.QueryInterface.QueryGenerator.uniqueConstraintMapping.code === err.code) {
var fields = self.QueryInterface.QueryGenerator.uniqueConstraintMapping.map(err.toString())
if (fields !== false) {
fields = fields.filter(function(f) { return f !== self.daoFactory.tableName; })
Utils._.each(self.__options.uniqueKeys, function(value, key) {
if (Utils._.isEqual(value.fields, fields) && !!value.msg) {
err = value.msg
}
})
}
}
emitter.emit('error', err)
})
.success(function(result) { .success(function(result) {
// Transfer database generated values (defaults, autoincrement, etc) // Transfer database generated values (defaults, autoincrement, etc)
values = _.extend(values, result.dataValues) values = _.extend(values, result.dataValues)
......
...@@ -2,7 +2,19 @@ var Utils = require("../../utils") ...@@ -2,7 +2,19 @@ var Utils = require("../../utils")
module.exports = (function() { module.exports = (function() {
var QueryGenerator = { var QueryGenerator = {
dialect: 'mariadb' dialect: 'mariadb',
uniqueConstraintMapping: {
code: 1062,
map: function(str) {
// we're manually remvoving uniq_ here for a future capability of defining column names explicitly
var match = str.replace('uniq_', '').match(/Duplicate entry .* for key '(.*?)'$/)
if (match === null || match.length < 2) {
return false
}
return match[1].split('_')
}
},
} }
// "MariaDB is a drop-in replacement for MySQL." - so thats exactly what we do, drop in the mysql query generator // "MariaDB is a drop-in replacement for MySQL." - so thats exactly what we do, drop in the mysql query generator
......
...@@ -76,6 +76,12 @@ module.exports = (function() { ...@@ -76,6 +76,12 @@ module.exports = (function() {
} }
, pkString = primaryKeys.map(function(pk) { return this.quoteIdentifier(pk) }.bind(this)).join(", ") , pkString = primaryKeys.map(function(pk) { return this.quoteIdentifier(pk) }.bind(this)).join(", ")
if (!!options.uniqueKeys) {
Utils._.each(options.uniqueKeys, function(columns) {
values.attributes += ", UNIQUE uniq_" + tableName + '_' + columns.fields.join('_') + " (" + columns.fields.join(', ') + ")"
})
}
if (pkString.length > 0) { if (pkString.length > 0) {
values.attributes += ", PRIMARY KEY (" + pkString + ")" values.attributes += ", PRIMARY KEY (" + pkString + ")"
} }
...@@ -103,6 +109,19 @@ module.exports = (function() { ...@@ -103,6 +109,19 @@ module.exports = (function() {
return 'SHOW TABLES;' return 'SHOW TABLES;'
}, },
uniqueConstraintMapping: {
code: 'ER_DUP_ENTRY',
map: function(str) {
// we're manually remvoving uniq_ here for a future capability of defining column names explicitly
var match = str.replace('uniq_', '').match(/Duplicate entry .* for key '(.*?)'$/)
if (match === null || match.length < 2) {
return false
}
return match[1].split('_')
}
},
addColumnQuery: function(tableName, attributes) { addColumnQuery: function(tableName, attributes) {
var query = "ALTER TABLE `<%= tableName %>` ADD <%= attributes %>;" var query = "ALTER TABLE `<%= tableName %>` ADD <%= attributes %>;"
, attrString = [] , attrString = []
...@@ -317,7 +336,7 @@ module.exports = (function() { ...@@ -317,7 +336,7 @@ module.exports = (function() {
template += " DEFAULT " + this.escape(dataType.defaultValue) template += " DEFAULT " + this.escape(dataType.defaultValue)
} }
if (dataType.unique) { if (dataType.unique === true) {
template += " UNIQUE" template += " UNIQUE"
} }
......
...@@ -44,6 +44,8 @@ module.exports = (function() { ...@@ -44,6 +44,8 @@ module.exports = (function() {
}, },
createTableQuery: function(tableName, attributes, options) { createTableQuery: function(tableName, attributes, options) {
var self = this
options = Utils._.extend({ options = Utils._.extend({
}, options || {}) }, options || {})
...@@ -76,6 +78,12 @@ module.exports = (function() { ...@@ -76,6 +78,12 @@ module.exports = (function() {
comments: Utils._.template(comments, { table: this.quoteIdentifiers(tableName)}) comments: Utils._.template(comments, { table: this.quoteIdentifiers(tableName)})
} }
if (!!options.uniqueKeys) {
Utils._.each(options.uniqueKeys, function(columns) {
values.attributes += ", UNIQUE (" + columns.fields.map(function(f) { return self.quoteIdentifiers(f) }).join(', ') + ")"
})
}
var pks = primaryKeys[tableName].map(function(pk){ var pks = primaryKeys[tableName].map(function(pk){
return this.quoteIdentifier(pk) return this.quoteIdentifier(pk)
}.bind(this)).join(",") }.bind(this)).join(",")
...@@ -114,6 +122,18 @@ module.exports = (function() { ...@@ -114,6 +122,18 @@ module.exports = (function() {
}) })
}, },
uniqueConstraintMapping: {
code: '23505',
map: function(str) {
var match = str.match(/duplicate key value violates unique constraint "(.*?)_key"/)
if (match === null || match.length < 2) {
return false
}
return match[1].split('_').splice(1)
}
},
addColumnQuery: function(tableName, attributes) { addColumnQuery: function(tableName, attributes) {
var query = "ALTER TABLE <%= tableName %> ADD COLUMN <%= attributes %>;" var query = "ALTER TABLE <%= tableName %> ADD COLUMN <%= attributes %>;"
, attrString = [] , attrString = []
...@@ -448,7 +468,7 @@ module.exports = (function() { ...@@ -448,7 +468,7 @@ module.exports = (function() {
replacements.defaultValue = this.escape(dataType.defaultValue) replacements.defaultValue = this.escape(dataType.defaultValue)
} }
if (dataType.unique) { if (dataType.unique === true) {
template += " UNIQUE" template += " UNIQUE"
} }
......
...@@ -109,6 +109,12 @@ module.exports = (function() { ...@@ -109,6 +109,12 @@ module.exports = (function() {
} }
, pkString = primaryKeys.map(function(pk) { return this.quoteIdentifier(pk) }.bind(this)).join(", ") , pkString = primaryKeys.map(function(pk) { return this.quoteIdentifier(pk) }.bind(this)).join(", ")
if (!!options.uniqueKeys) {
Utils._.each(options.uniqueKeys, function(columns) {
values.attributes += ", UNIQUE (" + columns.fields.join(', ') + ")"
})
}
if (pkString.length > 0) { if (pkString.length > 0) {
values.attributes += ", PRIMARY KEY (" + pkString + ")" values.attributes += ", PRIMARY KEY (" + pkString + ")"
} }
...@@ -131,6 +137,18 @@ module.exports = (function() { ...@@ -131,6 +137,18 @@ module.exports = (function() {
}) })
}, },
uniqueConstraintMapping: {
code: 'SQLITE_CONSTRAINT',
map: function(str) {
var match = str.match(/columns (.*?) are/)
if (match === null || match.length < 2) {
return false
}
return match[1].split(', ')
}
},
addLimitAndOffset: function(options, query){ addLimitAndOffset: function(options, query){
query = query || "" query = query || ""
if (options.offset && !options.limit) { if (options.offset && !options.limit) {
...@@ -184,6 +202,26 @@ module.exports = (function() { ...@@ -184,6 +202,26 @@ module.exports = (function() {
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
, values = []
for (var key in attrValueHash) {
var value = attrValueHash[key]
values.push(this.quoteIdentifier(key) + "=" + this.escape(value))
}
var replacements = {
table: this.quoteIdentifier(tableName),
values: values.join(","),
where: this.getWhereConditions(where)
}
return Utils._.template(query)(replacements)
},
deleteQuery: function(tableName, where, options) { deleteQuery: function(tableName, where, options) {
options = options || {} options = options || {}
...@@ -226,7 +264,7 @@ module.exports = (function() { ...@@ -226,7 +264,7 @@ module.exports = (function() {
replacements.defaultValue = this.escape(dataType.defaultValue) replacements.defaultValue = this.escape(dataType.defaultValue)
} }
if (dataType.unique) { if (dataType.unique === true) {
template += " UNIQUE" template += " UNIQUE"
} }
......
...@@ -246,6 +246,39 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -246,6 +246,39 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
}) })
}) })
it('allows multiple column unique keys to be defined', function(done) {
var User = this.sequelize.define('UserWithUniqueUsername', {
username: { type: Sequelize.STRING, unique: 'user_and_email' },
email: { type: Sequelize.STRING, unique: 'user_and_email' },
aCol: { type: Sequelize.STRING, unique: 'a_and_b' },
bCol: { type: Sequelize.STRING, unique: 'a_and_b' }
})
User.sync({ force: true }).on('sql', function(sql) {
expect(sql).to.match(/UNIQUE\s*(uniq_UserWithUniqueUsernames_username_email)?\s*\([`"]?username[`"]?, [`"]?email[`"]?\)/)
expect(sql).to.match(/UNIQUE\s*(uniq_UserWithUniqueUsernames_aCol_bCol)?\s*\([`"]?aCol[`"]?, [`"]?bCol[`"]?\)/)
done()
})
})
it('allows us to customize the error message for unique constraint', function(done) {
var User = this.sequelize.define('UserWithUniqueUsername', {
username: { type: Sequelize.STRING, unique: { name: 'user_and_email', msg: 'User and email must be unique' }},
email: { type: Sequelize.STRING, unique: 'user_and_email' },
aCol: { type: Sequelize.STRING, unique: 'a_and_b' },
bCol: { type: Sequelize.STRING, unique: 'a_and_b' }
})
User.sync({ force: true }).success(function() {
User.create({username: 'tobi', email: 'tobi@tobi.me'}).success(function() {
User.create({username: 'tobi', email: 'tobi@tobi.me'}).error(function(err) {
expect(err).to.equal('User and email must be unique')
done()
})
})
})
})
}) })
describe('build', function() { describe('build', function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!