This topic is open to consider implementation of the Event API, how best to proceed in designing such implementation that will continue to endure through future releases while being supportive of authors of the Vuex ORM ecosystem.
Global Events
As it stands, the @latest
release observes selection and mutation hooks. These hooks are triggered on a singleton (the Query
class) and accumulated from the models by way of declarative static methods.
The behaviour for event handling will need to change considering Query
is no longer a singleton and potentially out-of-scope for such a requirement. However, global hooks still require a singleton for global event listening/broadcasting.
One suggestion being that the database instance, given it is a singleton in instance form and easily accessible, could be a point of listening/emitting. For example:
store.$database.on('query:beforeSelect', handler)
The benefit of this pattern enables event scoping by prefix (in string representation). This is purely for emitting and subscribing to an event. Models can still declare static methods.
Naming Convention
The subject of normalizing or changing the naming convention for these hooks internally are also up for debate. By internally we mean the name of events emitted rather than the method names bound to a model since these model methods do not subscribe to events directly, rather they are declared as reference handlers.
Selection Hooks
The current selection hooks are: beforeSelect
, afterWhere
, afterOrderBy
and afterLimit
.
Selection hooks pass a collection of models tappable for mutation to which a query instance is currently processing.
Mutation Hooks
The current mutation hooks are: beforeCreate
, afterCreate
, beforeUpdate
, afterUpdate
, beforeDelete
and afterDelete
.
Mutation hooks pass the model in the current iteration queue for persistence. Should a models handler return false
, the model is skipped and not persisted.
Design Limitations
The crux with event handling is that it is stateless therefore a broadcasted event shouldn't be required to read, let alone expect, a response from subscribers – which proves problematic if events such as beforeCreate
or beforeSelect
may be required to return. The overhead caused by evaluating a response on each model that's listening inclusive of any additional subscribers to the event is cause for concern. In addition, the @latest
release already possesses quantitive performance degradation and @next
, at the time of writing, has no performance tests in place to verify any improvement on that front. So it's debatable how taxing this may still be.
For that reason, it's worth considering how to proceed with an idiomatic and synchronous Event API. For example, we may well continue to support return values from event handlers, consequently taking the natural hit on performance. Or we decide to cut ties with this approach and leave it down to user-land logic to process data before asking Vuex ORM to persist it.
Ecosystem
The Event API in its current form also works in favour of plugin authors. Not only can the Events API be integrated on objects that extend it, emitting internal events can enable plugin authors to tap into points for plugin logic. This isn't something we necessarily need to give too much thought, since plugin authors will often circumvent default behaviours through monkey-patching, but can grow as required for non-public logic.
Adding to this, plugins can leverage and adapt the Event API for its own use, rather than “bring your own” functionality which further bears weight on an application using assistive plugins.
Discuss.