jagi / meteor-astronomy

Model layer for Meteor
https://atmospherejs.com/jagi/astronomy
MIT License
605 stars 66 forks source link

Q: is there an afterFieldSet event? #710

Closed lucaciraolo closed 5 years ago

lucaciraolo commented 5 years ago

I understand that it is possible to have transient fields evaluated on the fly, however, I need these transient fields to be actually stored in the database for performance reasons. I've been using beforeSave events to recompute the transient fields and modify the document, however this only happens when I call doc.save(). Is there another event (something like afterFieldSet) that could trigger the recomputation of the transient fields when the document is modified (i.e when doc.masterField = 5 is executed)?

Example:

const Entry = Class.create({
    name: 'Entry'
    fields: {
        localCurrencyValue: Number,
        localCurrency: String,
        exchangeRate: Number,
        usdValue: Number, //Transient: calculated from localCurrencyValue * exchangeRate
    },
    events: {
        beforeSave({currentTarget}) {
            currentTarget.usdValue = currentTarget.localCurrencyValue * currentTarget.exchangeRate;
        },
    },
});

const entry = new Entry({
    localCurrencyValue: 5,
    localCurrency: 'GBP',
    exchangeRate: 1.22,
});

// Currently entry.usdValue is not defined as I have not saved the doc
// It would be great to have a beforeFieldSet event so that the transient field could be recomputed whenever the field is set

entry.save();
// Now entry.usdValue is computed

Obviously in the example above I could use the afterInit event to compute the value but I would like it to be computed whenever entry.localCurrencyValue = 10 is set, not just on the document init.

Let me know what you think!

lukejagodzinski commented 5 years ago

There was such event in Astronomy 1, but then every change had to be made using the doc.set("propName", value) method. In Astronomy 2, I've decided to no go this route. This feature was adding extra complexity and performance wise it wasn't great. There is also browser compatibility issue where setters and getters are not supported in all browsers.

In your situation, I would create some helper method that would not only set field's value but also recompute transient field. You could probably also class prototype by defining some setters (Object.defineProperty) but that's unlikely to work well in this scenario