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

Commit 46f8b891 by Mick Hansen

refactor primary key stuff

1 parent feb56a6e
......@@ -120,72 +120,81 @@ module.exports = (function() {
this.primaryKeys = {}
self.options.uniqueKeys = {}
Utils._.each(this.rawAttributes, function(columnValues, columnName) {
if (columnValues.hasOwnProperty('unique') && columnValues.unique !== true && columnValues.unique !== false) {
var idxName = columnValues.unique
if (typeof columnValues.unique === "object") {
idxName = columnValues.unique.name
// Setup names of timestamp attributes
this._timestampAttributes = {}
if (this.options.timestamps) {
if (this.options.createdAt) {
this._timestampAttributes.createdAt = Utils._.underscoredIf(this.options.createdAt, this.options.underscored)
}
if (this.options.updatedAt) {
this._timestampAttributes.updatedAt = Utils._.underscoredIf(this.options.updatedAt, this.options.underscored)
}
if (this.options.paranoid && this.options.deletedAt) {
this._timestampAttributes.deletedAt = Utils._.underscoredIf(this.options.deletedAt, this.options.underscored)
}
}
// Identify primary and unique attributes
Utils._.each(this.rawAttributes, function(options, attribute) {
if (options.hasOwnProperty('unique') && options.unique !== true && options.unique !== false) {
var idxName = options.unique
if (typeof options.unique === "object") {
idxName = options.unique.name
}
self.options.uniqueKeys[idxName] = self.options.uniqueKeys[idxName] || {fields: [], msg: null}
self.options.uniqueKeys[idxName].fields.push(columnName)
self.options.uniqueKeys[idxName].msg = self.options.uniqueKeys[idxName].msg || columnValues.unique.msg || null
self.options.uniqueKeys[idxName].fields.push(attribute)
self.options.uniqueKeys[idxName].msg = self.options.uniqueKeys[idxName].msg || options.unique.msg || null
}
})
Utils._.each(this.attributes, function(dataTypeString, attributeName) {
if (dataTypeString.indexOf('PRIMARY KEY') !== -1) {
self.primaryKeys[attributeName] = dataTypeString
if (options.primaryKey === true) {
self.primaryKeys[attribute] = self.attributes[attribute]
}
})
// Add head and tail default attributes (id, timestamps)
addDefaultAttributes.call(this)
addOptionalClassMethods.call(this)
findAutoIncrementField.call(this)
// Primary key convenience variables
this.primaryKeyAttributes = Object.keys(this.primaryKeys)
this.primaryKeyAttribute = this.primaryKeyAttributes[0]
this.primaryKeyCount = this.primaryKeyAttributes.length
this.options.hasPrimaryKeys = this.hasPrimaryKeys = this.primaryKeyCount > 0
this._hasPrimaryKeys = this.options.hasPrimaryKeys = this.hasPrimaryKeys = this.primaryKeyCount > 0
this._isPrimaryKey = Utils._.memoize(function (key) {
return self.primaryKeyAttributes.indexOf(key) !== -1
})
if (typeof this.options.defaultScope === "object") {
Utils.injectScope.call(this, this.options.defaultScope)
}
// DAO prototype
// WTF ... ?
this.DAO = function() {
DAO.apply(this, arguments);
}
Util.inherits(this.DAO, DAO);
this._timestampAttributes = {}
if (this.options.timestamps) {
if (this.options.createdAt) {
this._timestampAttributes.createdAt = Utils._.underscoredIf(this.options.createdAt, this.options.underscored)
}
if (this.options.updatedAt) {
this._timestampAttributes.updatedAt = Utils._.underscoredIf(this.options.updatedAt, this.options.underscored)
}
if (this.options.paranoid && this.options.deletedAt) {
this._timestampAttributes.deletedAt = Utils._.underscoredIf(this.options.deletedAt, this.options.underscored)
}
this.DAO.prototype._readOnlyAttributes = Object.keys(this._timestampAttributes)
}
this._readOnlyAttributes = Object.keys(this._timestampAttributes)
this.DAO.prototype._readOnlyAttributes = this._readOnlyAttributes // To be removed
this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length
this.DAO.prototype._hasReadOnlyAttributes = this._hasReadOnlyAttributes // To be removed
this.DAO.prototype._hasReadOnlyAttributes = this.DAO.prototype._readOnlyAttributes && this.DAO.prototype._readOnlyAttributes.length
this.DAO.prototype._isReadOnlyAttribute = Utils._.memoize(function (key) {
return self.DAO.prototype._hasReadOnlyAttributes && self.DAO.prototype._readOnlyAttributes.indexOf(key) !== -1
this._isReadOnlyAttribute = Utils._.memoize(function (key) {
return self._hasReadOnlyAttributes && self._readOnlyAttributes.indexOf(key) !== -1
})
this.DAO.prototype._isReadOnlyAttribute = this._isReadOnlyAttribute // To be removed
addDefaultAttributes.call(this)
addOptionalClassMethods.call(this)
findAutoIncrementField.call(this)
this.DAO.prototype._hasPrimaryKeys = this._hasPrimaryKeys // To be removed
this.DAO.prototype._isPrimaryKey = this._isPrimaryKey // To be removed
this.DAO.prototype.rawAttributes = this.rawAttributes;
this.DAO.prototype._hasPrimaryKeys = this.options.hasPrimaryKeys
this.DAO.prototype._isPrimaryKey = Utils._.memoize(function (key) {
return self.primaryKeyAttributes.indexOf(key) !== -1 && key !== 'id'
})
if (this.options.instanceMethods) {
Utils._.each(this.options.instanceMethods, function(fct, name) {
self.DAO.prototype[name] = fct
......@@ -1273,7 +1282,11 @@ module.exports = (function() {
var addDefaultAttributes = function() {
var self = this
, tail = {}
, head = {
, head = {}
// Add id if no primary key was manually added to definition
if (!Object.keys(this.primaryKeys).length) {
head = {
id: {
type: DataTypes.INTEGER,
allowNull: false,
......@@ -1282,9 +1295,6 @@ module.exports = (function() {
_autoGenerated: true
}
}
if (this.hasPrimaryKeys) {
head = {}
}
if (this._timestampAttributes.createdAt) {
......@@ -1313,6 +1323,10 @@ module.exports = (function() {
self.rawAttributes[attr] = value
}
})
if (!Object.keys(this.primaryKeys).length) {
self.primaryKeys['id'] = self.attributes['id']
}
}
var findAutoIncrementField = function() {
......@@ -1341,8 +1355,12 @@ module.exports = (function() {
options.includeNames.push(include.as)
options.includeNames.push(include.as.substr(0,1).toLowerCase() + include.as.substr(1))
if (include.association.isMultiAssociation || include.hasMultiAssociation) options.hasMultiAssociation = true
if (include.association.isSingleAssociation || include.hasSingleAssociation) options.hasSingleAssociation = true
if (include.association.isMultiAssociation || include.hasMultiAssociation) {
options.hasMultiAssociation = true
}
if (include.association.isSingleAssociation || include.hasSingleAssociation) {
options.hasSingleAssociation = true
}
options.hasIncludeWhere = options.hasIncludeWhere || include.hasIncludeWhere || !!include.where
options.hasIncludeRequired = options.hasIncludeRequired || include.hasIncludeRequired || !!include.required
......@@ -1374,8 +1392,8 @@ module.exports = (function() {
var primaryKeys;
if (include.daoFactory.hasPrimaryKeys) {
primaryKeys = []
for (var field_name in include.daoFactory.primaryKeys) {
primaryKeys.push(field_name)
for (var field in include.daoFactory.primaryKeys) {
primaryKeys.push(field)
}
} else {
primaryKeys = ['id']
......@@ -1386,7 +1404,9 @@ module.exports = (function() {
}
// pseudo include just needed the attribute logic, return
if (include._pseudo) return include
if (include._pseudo) {
return include
}
if (include.hasOwnProperty('daoFactory') && (include.hasOwnProperty('as'))) {
var usesAlias = (include.as !== include.daoFactory.tableName)
......@@ -1403,7 +1423,9 @@ module.exports = (function() {
// If through, we create a pseudo child include, to ease our parsing later on
if (Object(include.association.through) === include.association.through) {
if (!include.include) include.include = []
if (!include.include) {
include.include = []
}
var through = include.association.through
include.through = {
......
......@@ -9,9 +9,9 @@ module.exports = (function() {
var DAO = function(values, options) {
this.dataValues = {}
this._previousDataValues = {}
this.__options = this.__factory.options
this.__options = this.Model.options
this.options = options
this.hasPrimaryKeys = this.__factory.options.hasPrimaryKeys
this.hasPrimaryKeys = this.Model.options.hasPrimaryKeys
// What is selected values even used for?
this.selectedValues = options.include ? _.omit(values, options.includeNames) : values
this.__eagerlyLoadedAssociations = []
......@@ -23,7 +23,7 @@ module.exports = (function() {
Utils._.extend(DAO.prototype, Mixin.prototype)
Object.defineProperty(DAO.prototype, 'sequelize', {
get: function(){ return this.__factory.daoFactoryManager.sequelize }
get: function(){ return this.Model.daoFactoryManager.sequelize }
})
Object.defineProperty(DAO.prototype, 'QueryInterface', {
......@@ -53,7 +53,7 @@ module.exports = (function() {
var result = {}
, self = this
Utils._.each(this.__factory.primaryKeys, function(_, attr) {
Utils._.each(this.Model.primaryKeys, function(_, attr) {
result[attr] = self.dataValues[attr]
})
......@@ -63,14 +63,9 @@ module.exports = (function() {
Object.defineProperty(DAO.prototype, "identifiers", {
get: function() {
var primaryKeys = Object.keys(this.__factory.primaryKeys)
var primaryKeys = Object.keys(this.Model.primaryKeys)
, result = {}
, self = this
if (!this.__factory.hasPrimaryKeys) {
primaryKeys = ['id']
}
primaryKeys.forEach(function(identifier) {
result[identifier] = self.dataValues[identifier]
})
......@@ -163,28 +158,22 @@ module.exports = (function() {
return
} else {
// If attempting to set primary key and primary key is already defined, return
if (this._hasPrimaryKeys && originalValue && this._isPrimaryKey(key)) {
return
}
// If attempting to set generated id and id is already defined, return
// This is hack since generated id is not in primaryKeys, although it should be
if (originalValue && key === "id") {
if (this.Model._hasPrimaryKeys && originalValue && this.Model._isPrimaryKey(key)) {
return
}
// If attempting to set read only attributes, return
if (!options.raw && this._hasReadOnlyAttributes && this._isReadOnlyAttribute(key)) {
if (!options.raw && this.Model._hasReadOnlyAttributes && this.Model._isReadOnlyAttribute(key)) {
return
}
// Convert boolean-ish values to booleans
if (this._hasBooleanAttributes && this._isBooleanAttribute(key) && value !== null && value !== undefined) {
if (this.Model._hasBooleanAttributes && this.Model._isBooleanAttribute(key) && value !== null && value !== undefined) {
value = !!value
}
// Convert date fields to real date objects
if (this._hasDateAttributes && this._isDateAttribute(key) && value !== null && !(value instanceof Date)) {
if (this.Model._hasDateAttributes && this.Model._isDateAttribute(key) && value !== null && !(value instanceof Date)) {
value = new Date(value)
}
......@@ -309,13 +298,13 @@ module.exports = (function() {
}
})
for (var attrName in self.daoFactory.rawAttributes) {
if (self.daoFactory.rawAttributes.hasOwnProperty(attrName)) {
var definition = self.daoFactory.rawAttributes[attrName]
for (var attrName in self.Model.rawAttributes) {
if (self.Model.rawAttributes.hasOwnProperty(attrName)) {
var definition = self.Model.rawAttributes[attrName]
, isHstore = !!definition.type && !!definition.type.type && definition.type.type === DataTypes.HSTORE.type
, isEnum = definition.type && (definition.type.toString() === DataTypes.ENUM.toString())
, isMySQL = ['mysql', 'mariadb'].indexOf(self.daoFactory.daoFactoryManager.sequelize.options.dialect) !== -1
, ciCollation = !!self.daoFactory.options.collate && self.daoFactory.options.collate.match(/_ci$/i)
, isMySQL = ['mysql', 'mariadb'].indexOf(self.Model.daoFactoryManager.sequelize.options.dialect) !== -1
, ciCollation = !!self.Model.options.collate && self.Model.options.collate.match(/_ci$/i)
, valueOutOfScope
// Unfortunately for MySQL CI collation we need to map/lowercase values again
......@@ -341,20 +330,20 @@ module.exports = (function() {
values[updatedAtAttr] = (
(
self.isNewRecord
&& !!self.daoFactory.rawAttributes[updatedAtAttr]
&& !!self.daoFactory.rawAttributes[updatedAtAttr].defaultValue
&& !!self.Model.rawAttributes[updatedAtAttr]
&& !!self.Model.rawAttributes[updatedAtAttr].defaultValue
)
? self.daoFactory.rawAttributes[updatedAtAttr].defaultValue
? self.Model.rawAttributes[updatedAtAttr].defaultValue
: Utils.now(self.sequelize.options.dialect))
}
if (self.isNewRecord && createdAtAttr && !values[createdAtAttr]) {
values[createdAtAttr] = (
(
!!self.daoFactory.rawAttributes[createdAtAttr]
&& !!self.daoFactory.rawAttributes[createdAtAttr].defaultValue
!!self.Model.rawAttributes[createdAtAttr]
&& !!self.Model.rawAttributes[createdAtAttr].defaultValue
)
? self.daoFactory.rawAttributes[createdAtAttr].defaultValue
? self.Model.rawAttributes[createdAtAttr].defaultValue
: values[updatedAtAttr])
}
......@@ -364,7 +353,7 @@ module.exports = (function() {
if (self.isNewRecord) {
query = 'insert'
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.__factory), values, options]
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.Model), values, options]
hook = 'Create'
} else {
var identifier = self.__options.hasPrimaryKeys ? self.primaryKeyValues : { id: self.id }
......@@ -374,7 +363,7 @@ module.exports = (function() {
}
query = 'update'
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.__factory), values, identifier, options]
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.Model), values, identifier, options]
hook = 'Update'
}
......@@ -382,7 +371,7 @@ module.exports = (function() {
self.dataValues = _.extend(self.dataValues, values)
// Run the beforeCreate / beforeUpdate hook
self.__factory.runHooks('before' + hook, self, function(err) {
self.Model.runHooks('before' + hook, self, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
......@@ -405,7 +394,7 @@ module.exports = (function() {
var fields = self.QueryInterface.QueryGenerator.uniqueConstraintMapping.map(err.toString())
if (fields !== false) {
fields = fields.filter(function(f) { return f !== self.daoFactory.tableName; })
fields = fields.filter(function(f) { return f !== self.Model.tableName; })
Utils._.each(self.__options.uniqueKeys, function(value, key) {
if (Utils._.isEqual(value.fields, fields) && !!value.msg) {
err = value.msg
......@@ -424,7 +413,7 @@ module.exports = (function() {
result.dataValues = _.extend(result.dataValues, values)
result._previousDataValues = _.clone(result.dataValues)
self.__factory.runHooks('after' + hook, result, function(err) {
self.Model.runHooks('after' + hook, result, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
......@@ -445,12 +434,12 @@ module.exports = (function() {
*/
DAO.prototype.reload = function(options) {
var where = [
this.QueryInterface.quoteIdentifier(this.__factory.tableName) + '.' + this.QueryInterface.quoteIdentifier('id')+'=?',
this.QueryInterface.quoteIdentifier(this.Model.tableName) + '.' + this.QueryInterface.quoteIdentifier('id')+'=?',
this.id
]
return new Utils.CustomEventEmitter(function(emitter) {
this.__factory.find({
this.Model.find({
where: where,
limit: 1,
include: this.options.include || null
......@@ -506,7 +495,7 @@ module.exports = (function() {
, query = null
return new Utils.CustomEventEmitter(function(emitter) {
self.daoFactory.runHooks(self.daoFactory.options.hooks.beforeDestroy, self, function(err) {
self.Model.runHooks(self.Model.options.hooks.beforeDestroy, self, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
......@@ -516,7 +505,7 @@ module.exports = (function() {
query = self.save(options)
} else {
var identifier = self.__options.hasPrimaryKeys ? self.primaryKeyValues : { id: self.id };
query = self.QueryInterface.delete(self, self.QueryInterface.QueryGenerator.addSchema(self.__factory.tableName, self.__factory.options.schema), identifier, options)
query = self.QueryInterface.delete(self, self.QueryInterface.QueryGenerator.addSchema(self.Model.tableName, self.Model.options.schema), identifier, options)
}
query.on('sql', function(sql) {
......@@ -526,7 +515,7 @@ module.exports = (function() {
emitter.emit('error', err)
})
.success(function(results) {
self.daoFactory.runHooks(self.daoFactory.options.hooks.afterDestroy, self, function(err) {
self.Model.runHooks(self.Model.options.hooks.afterDestroy, self, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
......@@ -574,7 +563,7 @@ module.exports = (function() {
countOrOptions.attributes[updatedAtAttr] = Utils.now(this.daoFactory.daoFactoryManager.sequelize.options.dialect)
}
return this.QueryInterface.increment(this, this.QueryInterface.QueryGenerator.addSchema(this.__factory.tableName, this.__factory.options.schema), values, identifier, countOrOptions)
return this.QueryInterface.increment(this, this.QueryInterface.QueryGenerator.addSchema(this.Model.tableName, this.Model.options.schema), values, identifier, countOrOptions)
}
DAO.prototype.decrement = function (fields, countOrOptions) {
......@@ -639,7 +628,7 @@ module.exports = (function() {
// private
var initValues = function(values, options) {
// set id to null if not passed as value, a newly created dao has no id
var defaults = this.hasPrimaryKeys ? {} : { id: null },
var defaults = {},
key;
values = values && _.clone(values) || {}
......
......@@ -208,7 +208,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
var product = Product.build({
price: 10
})
expect(product.toJSON()).to.deep.equal({withTaxes: 1250, price: 1000, id: null})
expect(product.toJSON()).to.deep.equal({withTaxes: 1250, price: 1000})
})
it('should work with save', function (done) {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!