Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Events API #8

Merged
merged 14 commits into from
May 9, 2020
Merged

feat: Events API #8

merged 14 commits into from
May 9, 2020

Conversation

cuebit
Copy link
Member

@cuebit cuebit commented May 7, 2020

Type of PR:

  • Bugfix
  • Feature
  • Refactor
  • Code style update
  • Build-related changes
  • Test
  • Documentation
  • Other, please describe:

Breaking changes:

  • No
  • Yes

Details

The Events API opens doors for better application hooks. This simple yet intelligent API is designed with Typescript in mind. It attempts to solve, but not limited to, the following pitfalls of a typical hook system:

  • Type-safety – exact typings for event payloads with inference new Events<MyEvents>
  • Functional – does not rely on this context
  • Extensive – can be inherited by classes or used as a singleton
  • Performant – written to execute at high operation cycles
  • Slim – less API pollution equals more agility

Usage

Define event interfaces using keys & argument tuples.

interface QueryEvents {
  selected: [Collection<Model>, string]
  updating: [Model]
}

Instantiate the Events object with the events interface.

const events = new Events<QueryEvents>()

Add or remove listeners.

const listener = (...args) => console.log(args)

events.on('selected', listener)
events.off('updating', listener)

// `on` returns a self-removing function.
const unregister = events.on('updating', (...args) => console.log(args))
unregister()

Add one-time listeners which are removed on the next broadcast event.

events.once('updating', (...args) => console.log(args))

Subscribe to all events.

events.subscribe(({ event, args }) => {
  if (event === 'selected') {
    const [models, entity] = args
    console.log(`${event} fired with ${models.length} for ${entity}`)
  }
})

Emit events.

events.emit('selected', collection, 'users')
events.emit('updating', model)

Noteworthy

The Events API is designed to emit events with payloads to listeners and subscribers. If the API is offered to authors within the ecosystem and general user-land, performance and optimisation plays a key role as the use-cases can be unprecedented. To cater for these needs, the following applies:

  • event listener maps are initialized with Object.create(null) to increase operation cycles.
  • event keys are removed to optimize memory when listeners for an event are unregistered and no more listeners exist.
  • listeners are not required to return which results in less operating overhead.
  • removeAllListeners(event: string) is a protected method to prevent side-effects from user-land intervention.
  • recursion and advanced usage is demonstrated within tests.

@cuebit cuebit added the enhancement New feature or request label May 7, 2020
@cuebit cuebit requested a review from kiaking May 7, 2020 05:35
@cuebit cuebit self-assigned this May 7, 2020
@codecov
Copy link

codecov bot commented May 7, 2020

Codecov Report

Merging #8 into master will decrease coverage by 0.22%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master       #8      +/-   ##
==========================================
- Coverage   97.15%   96.92%   -0.23%     
==========================================
  Files          31       32       +1     
  Lines         738     1008     +270     
  Branches      107      167      +60     
==========================================
+ Hits          717      977     +260     
- Misses         20       31      +11     
+ Partials        1        0       -1     
Impacted Files Coverage Δ
src/events/Events.ts 100.00% <100.00%> (ø)
src/model/Model.ts 92.85% <0.00%> (-0.37%) ⬇️
src/repository/Repository.ts 100.00% <0.00%> (ø)
src/support/Utils.ts 98.01% <0.00%> (+0.75%) ⬆️
src/query/Query.ts 95.33% <0.00%> (+0.81%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f5f5a79...016ec0d. Read the comment docs.

Copy link
Member

@kiaking kiaking left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot! This looks amazing. Just commented few styling things.

src/events/Events.ts Outdated Show resolved Hide resolved
src/events/Events.ts Outdated Show resolved Hide resolved
@cuebit cuebit requested a review from kiaking May 9, 2020 06:03
@kiaking
Copy link
Member

kiaking commented May 9, 2020

One another thing I want to discuss is how we get the results from the emit method. As for event API, it doesn't make much sense for emit to return a value since event can call event within event and such.

However, in Vuex ORM hooks, we need to know what user have returned. For example, if users return false from the beforeCreate hook, it should stop persisting it.

This discussion could be in different issue since this event api is pretty solid, though do you have any idea on this topic?

@cuebit cuebit requested a review from kiaking May 9, 2020 06:34
@cuebit
Copy link
Member Author

cuebit commented May 9, 2020

I’ve opened this up for debate here #12.

@kiaking
Copy link
Member

kiaking commented May 9, 2020

Great. Let's follow up the discussion over there. I'm gonna merge this since this looks pretty tasty 🥰

@kiaking kiaking merged commit 465c5d5 into master May 9, 2020
@kiaking kiaking deleted the feature/events branch May 9, 2020 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants