Skip to content

Events: pub sub to model calls #399

@MrSwitch

Description

@MrSwitch

Listening for dare requests could be a useful addition

Such as:...

  • Record db mutations in a structured format
  • Provide awaits during testing for asynchronous modifications to mutate the db before making a request for that data
  • Trigger invalidations of caches

... etc.

Approach

For a given instance of dare. Add the following functions

  • on<eventname: string, callback>: Assign a callback function to a given event
  • once<eventname: string, callback>: Assign a callback function to a given event, and once run, immediately remove it.
  • off<eventname: string, callback>: Remove the callback function from given events
  • trigger<eventname: string, data: Data>: Trigger an event with data - used internally but nonetheless exposed.

Example: Integration tests example, awaiting for the operation to complete before proceeding

const dare = new Dare(options);
const {promise, resolve} = Promise.withResolvers();
dare.on('patch:member', ({request, response, state}) => {
    // The users model was patched
    console.log('Request data', request);
    console.log('Response data', response);
    console.log('state', state);
    resolve();
});
// Perform an operation, but dont await it... imagine this is deep within another function and is an incidental operation.
dare.patch('member', {id: 1337}, {favouriteQuote: "If you can't be good, be careful"});

// Test it worked by awaiting the Promise
await promise;

Internally this would trigger the callback defined above after dare.patch('users', ...); operation was completed.

Considerations:

  • An array callbackEvents needs to be maintained internally on each instance of Dare
  • When dare.use creates new instances, the trigger function should also look at parent instances and trigger matching callbackEvents too
  • Should model handlers be able to update the state object and have that pass through to callbackEvents?
  • Could this.once be used internally instead of this.after within Model Method Handlers?
  • Should we pass through the entire dare instance with the additional response to the Callback?
  • What should happen when the request is skipped or the modification does not affect any rows?
  • Should Model's be able to also define events? It would make sense to perhaps keep them together.
  • Are there any performance impacts of scanning the CallbackEvents[] for effected rows?
  • Callback Event Names
    • Is the event name [method]:[model] appropriate?
    • Could wild characters be used to match multiple? i.e. *:[model]
    • Match multiple patch:users, patch:userEmails or patch:users,userEmails
type ModelName = string;

interface CallbackEvent {
    name: `${"patch" | "post" | "delete" | "get"}:${ModelName}`
    callback: (Dare) => {},
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions