scottwrobinson / camo

A class-based ES6 ODM for Mongo-like databases.
556 stars 80 forks source link

Pre/Post Update Hooks #59

Open kurdin opened 8 years ago

kurdin commented 8 years ago

Can we have Pre/Post Update Hooks?

Or what is the best way to auto update updated_at field in model?

scottwrobinson commented 8 years ago

If you're using .save() (for creating or updating a document) then you should be able to use the pre/post save hooks.

If you're using something like .findOneAndUpdate() then you'll run in to some trouble. The problem has to do with this being a class method and with it performing an atomic update. This issue (along with #25, which has a similar problem) are on the top of my Camo todo list right now.

If you need a temporary fix then I'd suggest using .save() for everything and then updating updated_at within your preSave() hook.

Hope this helps.

kurdin commented 8 years ago

Strange that .save() should works like findOneAndUpdate. Save should not be allowed for same id, it should throw error.

Let say I am already have data with { _id: 123, active: true, username: "me"} so if I want to update that data with { _id: 123, active: false, username: "you"} as you suggest I can do Model.create(data).save().then(m => m) but save should not be working here because _id already exist. Right? Or save will do update if _id exists?

Thanks for all your hard work and time.

scottwrobinson commented 8 years ago

The underlying reason it doesn't work is because .save() is an instance method and .findOneAndUpdate() is a class method. Adding hook support to class methods will take a bit more work.

Your way should work as well, as long as your _id is valid and already exists in the DB. Camo allows you to specify an _id.

What I was thinking is that your model would have been already loaded using .find() or .findOne(). Then you wouldn't need to worry about creating the model:

Model.findOne({username: "me"}).then(function(m) {
    m.active = false;
    m.username = "you";
    return m.save();        // preSave() gets called here
}).then(function(m) {
   // etc...
});

Hope this helps!

kurdin commented 8 years ago

@scottwrobinson This seems to be working, thank you for the example. Still one problem I see that if you somehow adding a not existed in model's schema key, it will be added to database on save. This might be related to another issue https://github.com/scottwrobinson/camo/issues/25

Model.findOne({username: "me"}).then(function(m) {
    m.active = false;
    m.username = "you";
    m.not_existed_key = "bad";
    return m.save();        // preSave() gets called here
}).then(function(m) {
  console.log(m);
});
console> {"_id":123, "active":false, username:"you", "not_existed_key":"bad"}