scottwrobinson / camo

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

How to overwrite hooks after the class is created? #34

Closed michaeljota closed 8 years ago

michaeljota commented 8 years ago

I'm trying to mimic the Angular-Fullstack sync function over socket.io.

They do it by calling the 'post save' hook in mongoose. However, I'm not able to reproduce this with camo.

I'm aware of Camo having hooks, but they are exposed as Object based. I wonder if there is somehow to get this Class based.

I not sure if I'm making clear myself, I think I'm not.

Sorry for my bad english, and my bad explanation.

Thanks.

PS: I think maybe this can explain what I mean: thing.socket.js

scottwrobinson commented 8 years ago

Hmm I'm not sure I understand what you want exactly. Can you post the Camo code that you would like to use (even if it doesn't work)? I would have described the hook system as the other way around (class-based as opposed to object-based) since hooks are defined within the class declaration and not on a per-instance basis.

scottwrobinson commented 8 years ago

Okay, I skimmed over your question too fast earlier, I think I know what you're looking for. If you want, you can define any hook within your Document class (preSave, postDelete, etc). But you can also reassign that hook for any Document instance.

For example, here I give the scott instance its own custom preSave hook:

'use strict';

var connect = require('camo').connect;
var Document = require('camo').Document;

class Person extends Document {
    constructor () {
        super();

        this.name = String;
    }

    preSave() {
        console.log('Original pre save');
    }
}

connect('nedb://memory').then(db => {
    const bill = Person.create({
        name: 'Bill'
    });

    const scott = Person.create({
        name: 'Scott'
    });

    scott.preSave = function() {
        console.log('NEW pre save');
    };

    Promise.all(bill.save(), scott.save()).then(data => {
        console.log('Saved people');
    });

}).catch(err => {
    console.log('Error:', err);
});

Here is the result:

$ node index.js
Original pre save
NEW pre save
$

Is this what you're trying to do? Hope this helps!

michaeljota commented 8 years ago

No. It would be more like:

var names = [];
connect('nedb://memory').then(db => {
    const bill = Person.create({
        name: 'Bill'
    });

    const scott = Person.create({
        name: 'Scott'
    });

    Person.preSave = function() {
        names.push(this.name);
        console.log('NEW pre save');
    };

    Promise.all(bill.save(), scott.save()).then(data => {
        console.log('Saved people');
    });

}).catch(err => {
    console.log('Error:', err);
});
console.log(JSON.stringify(names));

Resulting:

$ node index.js
NEW pre save
NEW pre save
[{"name":"Bill"},{"name":"Scott"}]
$

Can this be done?

I don't know how to reproduce the code in Camo, however, I posted how Mongoose would be.

michaeljota commented 8 years ago

I just will try this as I did it to see if this works. I think I tested it and it did not work.

michaeljota commented 8 years ago

Ok. I remember why that did not work, at least, I didn't know how to use it


'use strict';

var Thing = require('./thing.model');

exports.register = function(socket) {
  Thing.postSave = function (doc){
    onSave(socket, doc);
  });
  Thing.postDelete = function (doc) {
    onRemove(socket, doc);
  });
}

function onSave(socket, doc, cb) {
  socket.emit('thing:save', doc);
}

function onRemove(socket, doc, cb) {
  socket.emit('thing:remove', doc);
}

What I want it's the postSave and postDelete hooks to receive the document after saved.

Does it do that?

scottwrobinson commented 8 years ago

Ah I see. Yes, you are correct, this will not work. The problem is that all of the hooks are instance methods and not static methods. So Person.preSave does not exist, but scott.preSave does exist, because it is an instance.

scottwrobinson commented 8 years ago

Can you not just put names.push(this.name) in the original class declaration? Or do you need the hook to change often?

This works:

'use strict';

var connect = require('camo').connect;
var Document = require('camo').Document;

var names = [];

class Person extends Document {
    constructor () {
        super();

        this.name = String;
    }

    preSave() {
        names.push(this.name);
    }
}

connect('nedb://memory').then(db => {
    const bill = Person.create({
        name: 'Bill'
    });

    const scott = Person.create({
        name: 'Scott'
    });

    Promise.all([bill.save(), scott.save()]).then(data => {
        console.log('Saved people');
        console.log('Names:', JSON.stringify(names));
    }).catch(err => {
        console.log('Err:', err);
    });

}).catch(err => {
    console.log('Error:', err);
});

Another way would be to change the preSave hook on a per-instance basis, similar to what I showed earlier:

var names = [];

var preSaveHook = function() {
    names.push(this.name);
};

connect('nedb://memory').then(db => {
    const bill = Person.create({
        name: 'Bill'
    });

    const scott = Person.create({
        name: 'Scott'
    });

    bill.preSave = preSaveHook;
    scott.preSave = preSaveHook;

    Promise.all(bill.save(), scott.save()).then(data => {
        console.log('Saved people');
    });

}).catch(err => {
    console.log('Error:', err);
});
michaeljota commented 8 years ago

That was just to follow your example.

The one thing that I want it's to send the document over socket. As the last post example.

But, I'll try to do it that way to see if that works. :+1:

michaeljota commented 8 years ago

Ok. What I want/need it's the postSave to receive the document saved, to be able to send the document over socket. I think that might be possible.

I'll write some code and let you know.

michaeljota commented 8 years ago

Wao! Thanks you!

What I did, if anyone ends here:

The "SocketManager"


'use strict';

var _socket = null;

function register (socket) {
    _socket = socket;
    console.log('Socket is now: '+_socket);
}

function postSave (collection, doc) {
    console.log(collection+' sended: ' + doc.toJSON());
    if(_socket) {
        _socket.emit(collection+':saved', doc);
    }
}

function postDelete (collection, doc) {
    if(_socket) {
        _socket.emit(collection+':deleted', doc);
    }
}

module.exports.register = register;
module.exports.postSave = postSave;
module.exports.postDelete = postDelete;

Inside the class declaration, overriding the "postSave()" hook.

    postSave () {
        _postSave ('shapes', this);
    }

_postSave it's a require from the other file.

Thanks!

scottwrobinson commented 8 years ago

:thumbsup:

Glad this worked out for you! Let me know if you have any other questions.