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

Commit afd32fca by Mick Hansen

Merge pull request #1334 from janmeier/disableIndividualTimestamps

Make it possible to disable some but not all timestamp columns
2 parents 5733a3ea 516abae1
...@@ -14,7 +14,6 @@ module.exports = (function() { ...@@ -14,7 +14,6 @@ module.exports = (function() {
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt', updatedAt: 'updatedAt',
deletedAt: 'deletedAt', deletedAt: 'deletedAt',
touchedAt: 'touchedAt',
instanceMethods: {}, instanceMethods: {},
classMethods: {}, classMethods: {},
validate: {}, validate: {},
...@@ -83,11 +82,11 @@ module.exports = (function() { ...@@ -83,11 +82,11 @@ module.exports = (function() {
// inject the node-sql methods to the dao factory in order to // inject the node-sql methods to the dao factory in order to
// receive the syntax sugar ... // receive the syntax sugar ...
;(function() { ;(function() {
var instance = sql.define({ name: "dummy", columns: [] }) var instance = sql.define({ name: "dummy", columns: [] })
for (var methodName in instance) { for (var methodName in instance) {
;(function(methodName) { ;(function(methodName) {
DAOFactory.prototype[methodName] = function() { DAOFactory.prototype[methodName] = function() {
var dataset = this.dataset() var dataset = this.dataset()
, result = dataset[methodName].apply(dataset, arguments) , result = dataset[methodName].apply(dataset, arguments)
...@@ -148,10 +147,6 @@ module.exports = (function() { ...@@ -148,10 +147,6 @@ module.exports = (function() {
Utils.injectScope.call(this, this.options.defaultScope) Utils.injectScope.call(this, this.options.defaultScope)
} }
addDefaultAttributes.call(this)
addOptionalClassMethods.call(this)
findAutoIncrementField.call(this)
// DAO prototype // DAO prototype
// WTF ... ? // WTF ... ?
this.DAO = function() { this.DAO = function() {
...@@ -159,22 +154,20 @@ module.exports = (function() { ...@@ -159,22 +154,20 @@ module.exports = (function() {
} }
Util.inherits(this.DAO, DAO); Util.inherits(this.DAO, DAO);
this.DAO.prototype.rawAttributes = this.rawAttributes; this._timestampAttributes = {}
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.timestamps) { if (this.options.timestamps) {
this.DAO.prototype._timestampAttributes = { if (this.options.createdAt) {
createdAt: Utils._.underscoredIf(this.options.createdAt, this.options.underscored), this._timestampAttributes.createdAt = Utils._.underscoredIf(this.options.createdAt, this.options.underscored)
updatedAt: Utils._.underscoredIf(this.options.updatedAt, this.options.underscored), }
deletedAt: Utils._.underscoredIf(this.options.deletedAt, 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.DAO.prototype._timestampAttributes) this.DAO.prototype._readOnlyAttributes = Object.keys(this._timestampAttributes)
} }
this.DAO.prototype._hasReadOnlyAttributes = this.DAO.prototype._readOnlyAttributes && this.DAO.prototype._readOnlyAttributes.length this.DAO.prototype._hasReadOnlyAttributes = this.DAO.prototype._readOnlyAttributes && this.DAO.prototype._readOnlyAttributes.length
...@@ -182,6 +175,17 @@ module.exports = (function() { ...@@ -182,6 +175,17 @@ module.exports = (function() {
return self.DAO.prototype._hasReadOnlyAttributes && self.DAO.prototype._readOnlyAttributes.indexOf(key) !== -1 return self.DAO.prototype._hasReadOnlyAttributes && self.DAO.prototype._readOnlyAttributes.indexOf(key) !== -1
}) })
addDefaultAttributes.call(this)
addOptionalClassMethods.call(this)
findAutoIncrementField.call(this)
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) { if (this.options.instanceMethods) {
Utils._.each(this.options.instanceMethods, function(fct, name) { Utils._.each(this.options.instanceMethods, function(fct, name) {
self.DAO.prototype[name] = fct self.DAO.prototype[name] = fct
...@@ -799,8 +803,8 @@ module.exports = (function() { ...@@ -799,8 +803,8 @@ module.exports = (function() {
} }
var self = this var self = this
, updatedAtAttr = Utils._.underscoredIf(self.options.updatedAt, self.options.underscored) , updatedAtAttr = this._timestampAttributes.updatedAt
, createdAtAttr = Utils._.underscoredIf(self.options.createdAt, self.options.underscored) , createdAtAttr = this._timestampAttributes.createdAt
, errors = [] , errors = []
, daos = records.map(function(v) { return self.build(v) }) , daos = records.map(function(v) { return self.build(v) })
...@@ -865,14 +869,12 @@ module.exports = (function() { ...@@ -865,14 +869,12 @@ module.exports = (function() {
values[field] = dao.dataValues[field] values[field] = dao.dataValues[field]
}) })
if (self.options.timestamps) { if (createdAtAttr && !values[createdAtAttr]) {
if (!values[createdAtAttr]) { values[createdAtAttr] = Utils.now(self.daoFactoryManager.sequelize.options.dialect)
values[createdAtAttr] = Utils.now(self.daoFactoryManager.sequelize.options.dialect) }
}
if (!values[updatedAtAttr]) { if (updatedAtAttr && !values[updatedAtAttr]) {
values[updatedAtAttr] = Utils.now(self.daoFactoryManager.sequelize.options.dialect) values[updatedAtAttr] = Utils.now(self.daoFactoryManager.sequelize.options.dialect)
}
} }
records.push(values) records.push(values)
...@@ -966,10 +968,9 @@ module.exports = (function() { ...@@ -966,10 +968,9 @@ module.exports = (function() {
where = newWhere || where where = newWhere || where
if (self.options.timestamps && self.options.paranoid && options.force === false) { if (self._timestampAttributes.deletedAt && options.force === false) {
var attr = Utils._.underscoredIf(self.options.deletedAt, self.options.underscored)
var attrValueHash = {} var attrValueHash = {}
attrValueHash[attr] = Utils.now() attrValueHash[self._timestampAttributes.deletedAt] = Utils.now()
query = 'bulkUpdate' query = 'bulkUpdate'
args = [self.tableName, attrValueHash, where] args = [self.tableName, attrValueHash, where]
} else { } else {
...@@ -1078,9 +1079,8 @@ module.exports = (function() { ...@@ -1078,9 +1079,8 @@ module.exports = (function() {
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks) options.hooks = options.hooks === undefined ? false : Boolean(options.hooks)
options.type = QueryTypes.BULKUPDATE options.type = QueryTypes.BULKUPDATE
if (self.options.timestamps) { if (self._timestampAttributes.updatedAt) {
var attr = Utils._.underscoredIf(self.options.updatedAt, self.options.underscored) attrValueHash[self._timestampAttributes.updatedAt] = Utils.now()
attrValueHash[attr] = Utils.now()
} }
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
...@@ -1231,7 +1231,7 @@ module.exports = (function() { ...@@ -1231,7 +1231,7 @@ module.exports = (function() {
options = options || {} options = options || {}
options.where = options.where || {} options.where = options.where || {}
var deletedAtCol = Utils._.underscoredIf(this.options.deletedAt, this.options.underscored) var deletedAtCol = this._timestampAttributes.deletedAt
, quoteIdentifiedDeletedAtCol = this.QueryInterface.quoteIdentifier(deletedAtCol) , quoteIdentifiedDeletedAtCol = this.QueryInterface.quoteIdentifier(deletedAtCol)
// Don't overwrite our explicit deletedAt search value if we provide one // Don't overwrite our explicit deletedAt search value if we provide one
...@@ -1268,7 +1268,6 @@ module.exports = (function() { ...@@ -1268,7 +1268,6 @@ module.exports = (function() {
var addDefaultAttributes = function() { var addDefaultAttributes = function() {
var self = this var self = this
, head = {}
, tail = {} , tail = {}
, head = { , head = {
id: { id: {
...@@ -1284,12 +1283,14 @@ module.exports = (function() { ...@@ -1284,12 +1283,14 @@ module.exports = (function() {
head = {} head = {}
} }
if (this.options.timestamps) { if (this._timestampAttributes.createdAt) {
tail[Utils._.underscoredIf(this.options.createdAt, this.options.underscored)] = {type: DataTypes.DATE, allowNull: false} tail[this._timestampAttributes.createdAt] = {type: DataTypes.DATE, allowNull: false}
tail[Utils._.underscoredIf(this.options.updatedAt, this.options.underscored)] = {type: DataTypes.DATE, allowNull: false} }
if (this._timestampAttributes.updatedAt) {
if (this.options.paranoid) tail[this._timestampAttributes.updatedAt] = {type: DataTypes.DATE, allowNull: false}
tail[Utils._.underscoredIf(this.options.deletedAt, this.options.underscored)] = {type: DataTypes.DATE} }
if (this._timestampAttributes.deletedAt) {
tail[this._timestampAttributes.deletedAt] = {type: DataTypes.DATE}
} }
var existingAttributes = Utils._.clone(self.rawAttributes) var existingAttributes = Utils._.clone(self.rawAttributes)
......
...@@ -17,7 +17,7 @@ module.exports = (function() { ...@@ -17,7 +17,7 @@ module.exports = (function() {
this.__eagerlyLoadedAssociations = [] this.__eagerlyLoadedAssociations = []
this.isNewRecord = options.isNewRecord this.isNewRecord = options.isNewRecord
initValues.call(this, values, options) initValues.call(this, values, options);
} }
Utils._.extend(DAO.prototype, Mixin.prototype) Utils._.extend(DAO.prototype, Mixin.prototype)
...@@ -32,10 +32,7 @@ module.exports = (function() { ...@@ -32,10 +32,7 @@ module.exports = (function() {
Object.defineProperty(DAO.prototype, 'isDeleted', { Object.defineProperty(DAO.prototype, 'isDeleted', {
get: function() { get: function() {
var result = this.__options.timestamps && this.__options.paranoid return this.Model._timestampAttributes.deletedAt && this.dataValues[this.Model._timestampAttributes.deletedAt] !== null
result = result && this.dataValues[Utils._.underscoredIf(this.__options.deletedAt, this.__options.underscored)] !== null
return result
} }
}) })
...@@ -191,7 +188,9 @@ module.exports = (function() { ...@@ -191,7 +188,9 @@ module.exports = (function() {
value = new Date(value) value = new Date(value)
} }
if (originalValue !== value) this._previousDataValues[key] = originalValue if (originalValue !== value) {
this._previousDataValues[key] = originalValue
}
this.dataValues[key] = value this.dataValues[key] = value
} }
} }
...@@ -237,14 +236,14 @@ module.exports = (function() { ...@@ -237,14 +236,14 @@ module.exports = (function() {
value.forEach(function(data) { value.forEach(function(data) {
var daoInstance = include.daoFactory.build(data, { var daoInstance = include.daoFactory.build(data, {
isNewRecord: false, isNewRecord: false,
isDirty: false, isDirty: false,
include: include.include, include: include.include,
includeNames: include.includeNames, includeNames: include.includeNames,
includeMap: include.includeMap, includeMap: include.includeMap,
includeValidated: true, includeValidated: true,
raw: options.raw raw: options.raw
}) })
, isEmpty = !Utils.firstValueOfHash(daoInstance.identifiers) , isEmpty = !Utils.firstValueOfHash(daoInstance.identifiers)
if (association.isSingleAssociation) { if (association.isSingleAssociation) {
...@@ -287,18 +286,16 @@ module.exports = (function() { ...@@ -287,18 +286,16 @@ module.exports = (function() {
var self = this var self = this
, values = {} , values = {}
, updatedAtAttr = Utils._.underscoredIf(this.__options.updatedAt, this.__options.underscored) , updatedAtAttr = this.Model._timestampAttributes.updatedAt
, createdAtAttr = Utils._.underscoredIf(this.__options.createdAt, this.__options.underscored) , createdAtAttr = this.Model._timestampAttributes.createdAt
if (options.fields) { if (options.fields) {
if (self.__options.timestamps) { if (updatedAtAttr && options.fields.indexOf(updatedAtAttr) === -1) {
if (options.fields.indexOf(updatedAtAttr) === -1) { options.fields.push(updatedAtAttr)
options.fields.push(updatedAtAttr) }
}
if (options.fields.indexOf(createdAtAttr) === -1 && this.isNewRecord === true) { if (createdAtAttr && options.fields.indexOf(createdAtAttr) === -1 && this.isNewRecord === true) {
options.fields.push(createdAtAttr) options.fields.push(createdAtAttr)
}
} }
} }
...@@ -340,7 +337,7 @@ module.exports = (function() { ...@@ -340,7 +337,7 @@ module.exports = (function() {
} }
} }
if (self.__options.timestamps) { if (updatedAtAttr) {
values[updatedAtAttr] = ( values[updatedAtAttr] = (
( (
self.isNewRecord self.isNewRecord
...@@ -348,18 +345,18 @@ module.exports = (function() { ...@@ -348,18 +345,18 @@ module.exports = (function() {
&& !!self.daoFactory.rawAttributes[updatedAtAttr].defaultValue && !!self.daoFactory.rawAttributes[updatedAtAttr].defaultValue
) )
? self.daoFactory.rawAttributes[updatedAtAttr].defaultValue ? self.daoFactory.rawAttributes[updatedAtAttr].defaultValue
: Utils.now(self.sequelize.options.dialect)) : Utils.now(self.sequelize.options.dialect))
if (self.isNewRecord && !values[createdAtAttr]) {
values[createdAtAttr] = (
(
!!self.daoFactory.rawAttributes[createdAtAttr]
&& !!self.daoFactory.rawAttributes[createdAtAttr].defaultValue
)
? self.daoFactory.rawAttributes[createdAtAttr].defaultValue
: values[updatedAtAttr])
}
} }
if (self.isNewRecord && createdAtAttr && !values[createdAtAttr]) {
values[createdAtAttr] = (
(
!!self.daoFactory.rawAttributes[createdAtAttr]
&& !!self.daoFactory.rawAttributes[createdAtAttr].defaultValue
)
? self.daoFactory.rawAttributes[createdAtAttr].defaultValue
: values[updatedAtAttr])
}
var query = null var query = null
, args = [] , args = []
...@@ -517,9 +514,8 @@ module.exports = (function() { ...@@ -517,9 +514,8 @@ module.exports = (function() {
return emitter.emit('error', err) return emitter.emit('error', err)
} }
if (self.__options.timestamps && self.__options.paranoid && options.force === false) { if (self.Model._timestampAttributes.deletedAt && options.force === false) {
var attr = Utils._.underscoredIf(self.__options.deletedAt, self.__options.underscored) self.dataValues[self.Model._timestampAttributes.deletedAt] = new Date()
self.dataValues[attr] = new Date()
query = self.save(options) query = self.save(options)
} else { } else {
var identifier = self.__options.hasPrimaryKeys ? self.primaryKeyValues : { id: self.id }; var identifier = self.__options.hasPrimaryKeys ? self.primaryKeyValues : { id: self.id };
...@@ -553,7 +549,7 @@ module.exports = (function() { ...@@ -553,7 +549,7 @@ module.exports = (function() {
}) })
var identifier = this.__options.hasPrimaryKeys ? this.primaryKeyValues : { id: this.id } var identifier = this.__options.hasPrimaryKeys ? this.primaryKeyValues : { id: this.id }
, updatedAtAttr = Utils._.underscoredIf(this.__options.updatedAt, this.__options.underscored) , updatedAtAttr = this.Model._timestampAttributes.updatedAt
, values = {} , values = {}
if (countOrOptions === undefined) { if (countOrOptions === undefined) {
...@@ -577,10 +573,8 @@ module.exports = (function() { ...@@ -577,10 +573,8 @@ module.exports = (function() {
values = fields values = fields
} }
if (this.__options.timestamps) { if (updatedAtAttr && !values[updatedAtAttr]) {
if (!values[updatedAtAttr]) { countOrOptions.attributes[updatedAtAttr] = Utils.now(this.daoFactory.daoFactoryManager.sequelize.options.dialect)
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.__factory.tableName, this.__factory.options.schema), values, identifier, countOrOptions)
...@@ -646,7 +640,6 @@ module.exports = (function() { ...@@ -646,7 +640,6 @@ module.exports = (function() {
} }
// private // private
var initValues = function(values, options) { var initValues = function(values, options) {
// set id to null if not passed as value, a newly created dao has no id // set id to null if not passed as value, a newly created dao has no id
var defaults = this.hasPrimaryKeys ? {} : { id: null }, var defaults = this.hasPrimaryKeys ? {} : { id: null },
...@@ -663,21 +656,19 @@ module.exports = (function() { ...@@ -663,21 +656,19 @@ module.exports = (function() {
}) })
} }
if (this.__options.timestamps) { if (this.Model._timestampAttributes.createdAt && defaults[this.Model._timestampAttributes.createdAt]) {
if (defaults[this._timestampAttributes.createdAt]) { this.dataValues[this.Model._timestampAttributes.createdAt] = Utils.toDefaultValue(defaults[this.Model._timestampAttributes.createdAt]);
this.dataValues[this._timestampAttributes.createdAt] = Utils.toDefaultValue(defaults[this._timestampAttributes.createdAt]); delete defaults[this.Model._timestampAttributes.createdAt];
delete defaults[this._timestampAttributes.createdAt]; }
}
if (defaults[this._timestampAttributes.updatedAt]) { if (this.Model._timestampAttributes.updatedAt && defaults[this.Model._timestampAttributes.updatedAt]) {
this.dataValues[this._timestampAttributes.updatedAt] = Utils.toDefaultValue(defaults[this._timestampAttributes.updatedAt]); this.dataValues[this.Model._timestampAttributes.updatedAt] = Utils.toDefaultValue(defaults[this.Model._timestampAttributes.updatedAt]);
delete defaults[this._timestampAttributes.updatedAt]; delete defaults[this.Model._timestampAttributes.updatedAt];
} }
if (defaults[this._timestampAttributes.deletedAt]) { if (this.Model._timestampAttributes.createdAt && defaults[this.Model._timestampAttributes.deletedAt]) {
this.dataValues[this._timestampAttributes.deletedAt] = Utils.toDefaultValue(defaults[this._timestampAttributes.deletedAt]); this.dataValues[this.Model._timestampAttributes.deletedAt] = Utils.toDefaultValue(defaults[this.Model._timestampAttributes.deletedAt]);
delete defaults[this._timestampAttributes.deletedAt]; delete defaults[this.Model._timestampAttributes.deletedAt];
}
} }
} }
if (Object.keys(defaults).length) { if (Object.keys(defaults).length) {
......
...@@ -205,6 +205,30 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -205,6 +205,30 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
}) })
it('should allow me to disable some of the timestamp fields', function(done) {
var UpdatingUser = this.sequelize.define('UpdatingUser', {}, {
timestamps: true,
updatedAt: false,
createdAt: false,
deletedAt: 'deletedAtThisTime',
paranoid: true
})
UpdatingUser.sync({force: true}).success(function() {
UpdatingUser.create().success(function (user) {
expect(user.createdAt).not.to.exist
expect(user.false).not.to.exist // because, you know we might accidentally add a field named 'false'
user.save().success(function (user) {
expect(user.updatedAt).not.to.exist
user.destroy().success(function(user) {
expect(user.deletedAtThisTime).to.exist
done()
})
})
})
})
})
it('should allow me to override updatedAt, createdAt, and deletedAt fields with underscored being true', function(done) { it('should allow me to override updatedAt, createdAt, and deletedAt fields with underscored being true', function(done) {
var UserTable = this.sequelize.define('UserCol', { var UserTable = this.sequelize.define('UserCol', {
aNumber: Sequelize.INTEGER aNumber: Sequelize.INTEGER
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!