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

Commit d041e77e by Gabe Gorelick Committed by Sushant

fix(model): destroying paranoid models with custom deletedAt (#11255)

1 parent c32ac014
...@@ -4052,29 +4052,19 @@ class Model { ...@@ -4052,29 +4052,19 @@ class Model {
const where = this.where(true); const where = this.where(true);
if (this.constructor._timestampAttributes.deletedAt && options.force === false) { if (this.constructor._timestampAttributes.deletedAt && options.force === false) {
const attribute = this.constructor.rawAttributes[this.constructor._timestampAttributes.deletedAt]; const attributeName = this.constructor._timestampAttributes.deletedAt;
const field = attribute.field || this.constructor._timestampAttributes.deletedAt; const attribute = this.constructor.rawAttributes[attributeName];
const values = Utils.mapValueFieldNames(this.dataValues, this.changed() || [], this.constructor); const defaultValue = Object.prototype.hasOwnProperty.call(attribute, 'defaultValue')
values[field] = new Date();
where[field] = Object.prototype.hasOwnProperty.call(attribute, 'defaultValue')
? attribute.defaultValue ? attribute.defaultValue
: null; : null;
const currentValue = this.getDataValue(attributeName);
const undefinedOrNull = currentValue == null && defaultValue == null;
if (undefinedOrNull || _.isEqual(currentValue, defaultValue)) {
// only update timestamp if it wasn't already set
this.setDataValue(attributeName, new Date());
}
this.setDataValue(field, values[field]); return this.save(_.defaults({ hooks: false }, options));
return this.constructor.QueryInterface.update(
this, this.constructor.getTableName(options), values, where, _.defaults({ hooks: false, model: this.constructor }, options)
).then(([results, rowsUpdated]) => {
if (this.constructor._versionAttribute && rowsUpdated < 1) {
throw new sequelizeErrors.OptimisticLockError({
modelName: this.constructor.name,
values,
where
});
}
return results;
});
} }
return this.constructor.QueryInterface.delete(this, this.constructor.getTableName(options), where, Object.assign({ type: QueryTypes.DELETE, limit: null }, options)); return this.constructor.QueryInterface.delete(this, this.constructor.getTableName(options), where, Object.assign({ type: QueryTypes.DELETE, limit: null }, options));
}).tap(() => { }).tap(() => {
......
...@@ -685,5 +685,109 @@ describe(Support.getTestDialectTeaser('Instance'), () => { ...@@ -685,5 +685,109 @@ describe(Support.getTestDialectTeaser('Instance'), () => {
expect(user.username).to.equal('Peter'); expect(user.username).to.equal('Peter');
}); });
}); });
it('supports custom deletedAt field', function() {
const ParanoidUser = this.sequelize.define('ParanoidUser', {
username: DataTypes.STRING,
destroyTime: DataTypes.DATE
}, { paranoid: true, deletedAt: 'destroyTime' });
return ParanoidUser.sync({ force: true }).then(() => {
return ParanoidUser.create({
username: 'username'
});
}).then(user => {
return user.destroy();
}).then(user => {
expect(user.destroyTime).to.be.ok;
expect(user.deletedAt).to.not.be.ok;
return user.restore();
}).then(user => {
expect(user.destroyTime).to.not.be.ok;
return ParanoidUser.findOne({ where: { username: 'username' } });
}).then(user => {
expect(user).to.be.ok;
expect(user.destroyTime).to.not.be.ok;
expect(user.deletedAt).to.not.be.ok;
});
});
it('supports custom deletedAt field name', function() {
const ParanoidUser = this.sequelize.define('ParanoidUser', {
username: DataTypes.STRING,
deletedAt: { type: DataTypes.DATE, field: 'deleted_at' }
}, { paranoid: true });
return ParanoidUser.sync({ force: true }).then(() => {
return ParanoidUser.create({
username: 'username'
});
}).then(user => {
return user.destroy();
}).then(user => {
expect(user.dataValues.deletedAt).to.be.ok;
expect(user.dataValues.deleted_at).to.not.be.ok;
return user.restore();
}).then(user => {
expect(user.dataValues.deletedAt).to.not.be.ok;
expect(user.dataValues.deleted_at).to.not.be.ok;
return ParanoidUser.findOne({ where: { username: 'username' } });
}).then(user => {
expect(user).to.be.ok;
expect(user.deletedAt).to.not.be.ok;
expect(user.deleted_at).to.not.be.ok;
});
});
it('supports custom deletedAt field and database column', function() {
const ParanoidUser = this.sequelize.define('ParanoidUser', {
username: DataTypes.STRING,
destroyTime: { type: DataTypes.DATE, field: 'destroy_time' }
}, { paranoid: true, deletedAt: 'destroyTime' });
return ParanoidUser.sync({ force: true }).then(() => {
return ParanoidUser.create({
username: 'username'
});
}).then(user => {
return user.destroy();
}).then(user => {
expect(user.dataValues.destroyTime).to.be.ok;
expect(user.dataValues.deletedAt).to.not.be.ok;
expect(user.dataValues.destroy_time).to.not.be.ok;
return user.restore();
}).then(user => {
expect(user.dataValues.destroyTime).to.not.be.ok;
expect(user.dataValues.destroy_time).to.not.be.ok;
return ParanoidUser.findOne({ where: { username: 'username' } });
}).then(user => {
expect(user).to.be.ok;
expect(user.destroyTime).to.not.be.ok;
expect(user.destroy_time).to.not.be.ok;
});
});
it('supports custom default value', function() {
const ParanoidUser = this.sequelize.define('ParanoidUser', {
username: DataTypes.STRING,
deletedAt: { type: DataTypes.DATE, defaultValue: new Date(0) }
}, { paranoid: true });
return ParanoidUser.sync({ force: true }).then(() => {
return ParanoidUser.create({
username: 'username'
});
}).then(user => {
return user.destroy();
}).then(user => {
return user.restore();
}).then(user => {
expect(user.dataValues.deletedAt.toISOString()).to.equal(new Date(0).toISOString());
return ParanoidUser.findOne({ where: { username: 'username' } });
}).then(user => {
expect(user).to.be.ok;
expect(user.deletedAt.toISOString()).to.equal(new Date(0).toISOString());
});
});
}); });
}); });
...@@ -35,7 +35,7 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -35,7 +35,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
this.stubDelete.restore(); this.stubDelete.restore();
}); });
it('can detect complexe objects', () => { it('can detect complex objects', () => {
const Where = function() { this.secretValue = '1'; }; const Where = function() { this.secretValue = '1'; };
expect(() => { expect(() => {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!