New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implementing deleted_at #53
Comments
Interesting, I had been considering soft deletes, but hadn't quite decided what the cleanest way of implementing them would be yet - maybe this will help. Personally, I would probably override the sync's var SoftDeleteModel = Bookshelf.Model.extend({
sync: function(options) {
var sync = Bookshelf.Model.prototype.sync.apply(this, arguments);
// This way, you can add a hardDelete flag to the options and it will
// actually delete the model.
if (!options.hardDelete) {
sync.del = function(options) {
return sync.update.call(sync, {deleted_at: new Date()});
};
}
return sync;
}
}); That way, you'll still get the For the second question, you should be able to use: model.query({whereNull: 'deleted_at'})...; ...which will use the Again, I'd also probably also do that with a little customization of the Let me know if that sounds like a good enough solution... or if there are any issues as I haven't tried it but I believe it should all work as I described. Edit: Actually, the event driven |
Thanks so much for the thoughts, Tim. Just a few follow-ups, if you don't mind! Unrelated to soft deletes, we noticed that code like models.Entity
.forge()
.query(function(qb) {
qb.where('uuid', '=', '110ec58a-a0f2-4ac4-8393-c866d813b8d1');
})
.then(function() {
console.log('success');
}, function(err) {
console.log('failure');
}); outputs return this.query.where(wheres).del(); If we change line 980 from var wheres, syncing = this.syncing.resetQuery(); to var wheres = {}, syncing = this.syncing.resetQuery(); we do get
as expected. Meanwhile, if we do override sync: function(options) {
var sync = Bookshelf.Model.prototype.sync.apply(this, arguments);
if (!options.hardDelete) {
sync.del = function(options) {
return sync.update.call(sync, {deleted_at: new Date()});
};
}
return sync;
}, we actually get a query of
which isn't syntactically valid (because of the missing key/value pair after Many thanks! |
Thanks for pointing that out - rather than using the Please let me know if there are any more issues with getting the soft delete to work correctly as it was previously described. Thanks! |
Thanks, Tim, working nicely now! For selects, meanwhile, we're currently using this.on('fetching', function(model, columns, options) {
model.query({whereNull: 'deleted_at'});
}); which works well. I was curious to ask, though, what you had in mind for soft delete-aware selects using sync.del = function(options) {
return sync.update.call(sync, {deleted_at: new Date()});
}; works well for overriding sync.select = function(options) {
return sync.select.call(sync, {deleted_at: null});
}; results, we realized, in infinite recursion. Just curious if you had a somewhat different approach in mind for injecting the |
Great, and yes, since you're calling the same method you're looking to overwrite, you'd need to grab a local reference to the original select function before it's overwritten, so you'd do something like this: sync: function(options) {
var sync = Bookshelf.Model.prototype.sync.apply(this, arguments);
var originalSelect = sync.select;
sync.select = function() {
sync.query.whereNull('deleted_at');
return originalSelect.call(sync);
};
return sync;
} Then that should give you what you're looking for. |
Hi Tim, all,
We're aspiring to implement soft deletions, whereby we set a field in our (MySQL) table (whose default value is otherwise
NULL
) to aDATETIME
when it's "deleted." At the moment, we're doing so withwhich results in SQL of:
Is that likely the cleanest approach, though? Or might we be better off overriding
destroy
for all entities? Separately, it looks like, perBookshelf.Model
's default implementation oftimestamp
, there's no way to preventupdated_at
from being updated in this scenario (which is a minor goal so that the final value ofupdated_at
reflects the last time its actual data was modified, as opposed to its metadata)?On the flip side, though, it was less clear to us how to go about tweaking
fetch
so thatSELECTs
include aWHERE deleted_at IS NULL
. For instance, addinggot us most of the way there but actually yielded a query with
WHERE deleted_at = NULL
as opposed toWHERE deleted_at IS NULL
. Is there perhaps some other way to achieve the latter, perhaps by dropping down into Knex?Many thanks!
The text was updated successfully, but these errors were encountered: