Possability of parent event classes
twrayden opened this issue · comments
There are scenarios in where I would like to listen to a group of event types in my subscribers and also still listen to the granular event.
I looked at the source code and events are currently matched using instance.constructor
which treats each class as unique. I think to achieve this events will need to have decorators because I could not find any other way to get a class instance's parent metadata.
Basic idea:
class ResourceEvent {
constructor() {}
}
class ResourceCreateEvent extends ResourceEvent {
constructor() {}
}
dispatcher.dispatch(new ResourceCreateEvent());
// Fires:
// - ResourceEvent
// - ResourceCreateEvent
Scenario 1:
class ResourceEvent {
constructor() {}
}
class ResourceCreateEvent extends ResourceEvent {
constructor() {}
}
class JobCreateEvent extends ResourceCreateEvent {
constructor() {}
}
class UserCreateEvent extends ResourceCreateEvent {
constructor() {}
}
class CommentCreateEvent extends ResourceCreateEvent {
constructor() {}
}
class PaymentCreateEvent extends ResourceCreateEvent {
constructor() {}
}
class ContactCreateEvent extends ResourceCreateEvent {
constructor() {}
}
dispatcher.dispatch(new ContactCreateEvent ());
// Fires:
// - ResourceEvent
// - ResourceCreateEvent
// - ContactCreateEvent
@EventSubscriber()
export class ResourceSubscriber {
@On(ResourceCreateEvent)
async onCreate(event: ResourceCreateEvent): Promise<void> {
console.log("A resource was created! Could be a contact, job, comment, etc.");
}
}
@EventSubscriber()
export class ContactSubscriber {
@On(ContactCreateEvent)
async onCreate(event: ContactCreateEvent): Promise<void> {
console.log("A contact was created!");
}
}
Scenario 2:
class AnyEvent {
constructor(public sendToClient: boolean, public name: string) {}
}
class UserInvited extends AnyEvent {
constructor(public user: IUser) {
super(true, "user.invited");
}
}
@EventSubscriber()
export class Subscriber {
@On(AnyEvent)
async onAny(event: AnyEvent): Promise<void> {
console.log("All events will trigger this function!");
if (event.sendToClient) {
// Do something like
// Emit socket.io event
}
}
@On(UserInvited)
async onUserInvited(event: UserInvited): Promise<void> {
console.log("User invited!");
}
}
@thomasraydeniscool Hey there, Thomas.
I didn't catch this issue until now. We've been super busy.
So I decided to attempt this without creating decorators for events. I wanted events to be as plain as possible.
With that said, I refactored the code-base to support this in an attempt to clean everything up and implement this feature. I haven't quiet thought about the repercussions from the way I did it, but I'll explain my thoughts:
I now take all of the metadata for the EventDispatcher
's subscribers, do validation and create "cached" versions of the event subscriber's handlers. Then when a user dispatches an event, I then compute the entire event tree by iterating over the constructor's parents and cache it for consecutive calls.
Check out: https://github.com/j/type-events/tree/refactoring
If you don't mind playing with it and seeing if it works for your use-case, that'd be great.
One thing I don't do is.. if you emit AnyEvent
, I do not dispatch to the classes that inherit it, I do the inverse. Check out the bottom of the readme as well as the unit tests.
I wanted to note that I deprecated @EventSubscriber()
decorator as well since it's not really needed.
I also changed renamed isAsync
to background
and process background
by using nextTick
.
Regarding the repercussions from creating on-the-fly dispatchers on the dispatch
method is that it might take a lot of memory if someone uses tons of events and inheritance, though I think it'd be negligible compared to the way before anyway.
And since this library is currently still in a "preview" type phase, I'm willing to break each minor beta
version for the time being until I feel somewhat stable, then I'll tag a stable version and do better releases thereafter.
Also, I saw your https://github.com/thomasraydeniscool/monglow library. I'm not sure if you checked out my "ODM".
https://github.com/j/type-mongodb
I came to the same conclusion as you with current MongoDB ODMs in the JS world: they all do too much.
I made mine to just be a class mapper and used "JIT" style hydration pre-computation to be as fast as possible and stay away from doing too much special stuff. I could still make it better, but just wanted to let you know that that library itself has been running a pretty high traffic production e-commerce site.
@thomasraydeniscool added & pushed this in the recent master. I was able to get other projects' tests to pass, so just added this to the recent beta release.