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

Commit 9d13c1b5 by Jan Aagaard Meier

Merge pull request #2540 from seth-admittedly/feature/undestroy

Undestroy method for paranoid models
2 parents 6b35d530 48437f3e
......@@ -239,8 +239,9 @@ module.exports = (function() {
*/
updateQuery: function(tableName, attrValueHash, where, options, attributes) {
options = options || {};
_.defaults(options, this.options);
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options);
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, options.omitNull, options);
var query
, values = [];
......@@ -1024,7 +1025,7 @@ module.exports = (function() {
}
}
joinOn = self.quoteTable(tableLeft) + '.' + self.quoteIdentifier(attrLeft);
}
}
joinOn += ' = ' + self.quoteTable(tableRight) + '.' + self.quoteIdentifier(attrRight);
......
......@@ -4,7 +4,8 @@ var Utils = require('../../utils')
, DataTypes = require('../../data-types')
, SqlString = require('../../sql-string')
, Transaction = require('../../transaction')
, util = require('util');
, util = require('util')
, _ = require("lodash");
var MySqlQueryGenerator = Utils._.extend(
Utils._.clone(require('../abstract/query-generator')),
......@@ -212,7 +213,10 @@ module.exports = (function() {
},
updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options);
options = options || {};
_.defaults(options, this.options);
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, options.omitNull, options);
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
, values = [];
......
......@@ -759,6 +759,39 @@ module.exports = (function() {
};
/**
* Restore the row corresponding to this instance. Only available for paranoid models.
*
* @param {Object} [options={}]
*
* @return {Promise<undefined>}
*/
Instance.prototype.restore = function(options) {
if (!this.Model._timestampAttributes.deletedAt) throw new Error("Model is not paranoid");
options = Utils._.extend({
hooks: true,
force: false
}, options || {});
var self = this;
return Promise.try(function() {
// Run before hook
if (options.hooks) {
return self.Model.runHooks('beforeRestore', self, options);
}
}).then(function() {
self.dataValues[self.Model._timestampAttributes.deletedAt] = null;
return self.save(_.extend(_.clone(options), {hooks : false, omitNull : false}));
}).tap(function(result) {
// Run after hook
if (options.hooks) {
return self.Model.runHooks('afterRestore', self, options);
}
});
};
/**
* Increment the value of one or more columns. This is done in the database, which means it does not use the values currently stored on the Instance. The increment is done using a
* ```sql
* SET column = column + X
......
......@@ -1389,6 +1389,70 @@ module.exports = (function() {
};
/**
* Restore multiple instances if `paranoid` is enabled.
*
* @param {Object} [options.where] Filter the restore
* @param {Boolean} [options.hooks=true] Run before / after bulk restore hooks?
* @param {Boolean} [options.individualHooks=false] If set to true, restore will find all records within the where parameter and will execute before / after bulkRestore hooks on each row
* @param {Number} [options.limit] How many rows to undelete
*
* @return {Promise<undefined>}
*/
Model.prototype.restore = function(options) {
if (!this._timestampAttributes.deletedAt) throw new Error("Model is not paranoid");
options = Utils._.extend({
hooks: true,
individualHooks: false
}, options || {});
options.type = QueryTypes.BULKUNDELETE;
var self = this
, instances;
mapFieldNames.call(this, options, this);
return Promise.try(function() {
// Run before hook
if (options.hooks) {
return self.runHooks('beforeBulkRestore', options);
}
}).then(function() {
// Get daos and run beforeDestroy hook on each record individually
if (options.individualHooks) {
return self.findAll({where: options.where}, {transaction: options.transaction}).map(function(instance) {
return self.runHooks('beforeRestore', instance, options).then(function() {
return instance;
});
}).then(function(_instances) {
instances = _instances;
});
}
}).then(function() {
// Run undelete query
var attrValueHash = {};
attrValueHash[self._timestampAttributes.deletedAt] = null;
options.omitNull = false;
return self.QueryInterface.bulkUpdate(self.getTableName(), attrValueHash, options.where, options, self._timestampAttributes.deletedAt);
}).tap(function() {
// Run afterDestroy hook on each record individually
if (options.individualHooks) {
return Promise.map(instances, function(instance) {
return self.runHooks('afterRestore', instance, options);
});
}
}).tap(function() {
// Run after hook
if (options.hooks) {
return self.runHooks('afterBulkRestore', options);
}
}).then(function(affectedRows) {
return affectedRows;
});
};
/**
* Update multiple instances that match the where options. The promise returns an array with one or two elements. The first element is always the number
* of affected rows, while the second element is the actual affected rows (only supported in postgres with `options.returning` true.)
*
......
......@@ -707,14 +707,14 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
User.sync({ force: true }).success(function() {
sequelize.transaction().then(function(t) {
User.create({ username: 'foo' }, { transaction: t }).success(function() {
User.findOrInitialize({
User.findOrInitialize({
where: {username: 'foo'}
}).spread(function(user1) {
User.findOrInitialize({
User.findOrInitialize({
where: {username: 'foo'},
transaction: t
}).spread(function(user2) {
User.findOrInitialize({
User.findOrInitialize({
where: {username: 'foo'},
defaults: { foo: 'asd' },
transaction: t
......@@ -1304,6 +1304,45 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
})
describe("restore", function(){
it("returns an error if the model is not paranoid", function(){
var self = this;
return this.User.create({username : "Peter", secretValue : "42"})
.then(function(user){
expect(function(){self.User.restore({where : {secretValue : "42"}});}).to.throw(Error, "Model is not paranoid");
})
})
it("restores a previously deleted model", function(){
var self = this
, ParanoidUser = self.sequelize.define('ParanoidUser', {
username: Sequelize.STRING,
secretValue: Sequelize.STRING,
data: Sequelize.STRING,
intVal: { type: Sequelize.INTEGER, defaultValue: 1}
}, {
paranoid: true
})
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '43' },
{ username: 'Bob', secretValue: '44' }]
return ParanoidUser.sync({ force: true }).then(function() {
return ParanoidUser.bulkCreate(data);
}).then(function() {
return ParanoidUser.destroy({where: {secretValue: '42'}});
}).then(function() {
return ParanoidUser.restore({where : {secretValue: '42'}});
}).then(function() {
return ParanoidUser.find({where : {secretValue : "42"}});
}).then(function(user){
expect(user).to.be.ok
expect(user.username).to.equal("Peter")
})
})
})
describe('equals', function() {
it("correctly determines equality of objects", function(done) {
this.User.create({username: 'hallo', data: 'welt'}).success(function(u) {
......
......@@ -1797,4 +1797,46 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
})
})
})
describe("restore", function(){
it("returns an error if the model is not paranoid", function(){
var self = this;
return this.User.create({username : "Peter", secretValue : "42"})
.then(function(user){
expect(function(){user.restore();}).to.throw(Error, "Model is not paranoid");
})
})
it("restores a previously deleted model", function(){
var self = this
, ParanoidUser = self.sequelize.define('ParanoidUser', {
username: DataTypes.STRING,
secretValue: DataTypes.STRING,
data: DataTypes.STRING,
intVal: { type: DataTypes.INTEGER, defaultValue: 1}
}, {
paranoid: true
})
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '43' },
{ username: 'Bob', secretValue: '44' }]
return ParanoidUser.sync({ force: true }).then(function() {
return ParanoidUser.bulkCreate(data)
}).then(function() {
return ParanoidUser.find({where : {secretValue : "42"}});
}).then(function(user){
return user.destroy()
.then(function(){
return user.restore();
});
}).then(function() {
return ParanoidUser.find({where : {secretValue : "42"}})
}).then(function(user){
expect(user).to.be.ok
expect(user.username).to.equal("Peter")
})
})
})
})
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!