defineStash
Category
Tags
Export size
min 5.71 kB · gzip 2.37 kB
See also
Stashes the items of a call before it runs, to compare them with the items after it. Returns a pair: stash fetches the items before the call, stashed returns them - paired with the items after the call once it ran.
Every defineStash() is its own stash. Stashes of one call with equal params share their fetches. Nothing is stored on params, so concurrent calls with one params object and nested calls stay apart.
stash and stashed without options are exported as well.
ts
import { defineStash } from 'feathers-utils/utils';Example
ts
import { defineStash } from 'feathers-utils/utils'
const { stash, stashed } = defineStash<User>()
app.service('users').hooks({
before: { patch: [stash] },
after: {
patch: [
async (context) => {
for (const { before, result } of await stashed(context)) {
if (before?.email !== result?.email) await sendMail(result)
}
},
],
},
})Type declaration
Show Type Declarations
ts
/**
* Like `TransformParamsFn`, but may be async and gets the context
*/
export type StashTransformParams<H extends HookContext = HookContext> = (
params: Params,
context: H,
) => Params | void | Promise<Params | void>
export type StashOptions<H extends HookContext = HookContext> = {
/**
* Fetches the items before the call. Without it, `before` stays
* `undefined`, but `result` is still refetched for `transformParams` or
* `$select`.
*
* @default true
*/
fetchBefore?: boolean
/**
* Adjusts the params of both fetches, before and after the call - e.g. to
* populate the items. Gets a copy of the params, so it may change them in
* place, nested objects included. The query of the call is still in
* `context.params.query`.
*
* @example
* ```ts
* defineStash({
* transformParams: (params) => ({ ...params, $populate: ['profile'] }),
* })
* ```
*/
transformParams?: StashTransformParams<H>
}
export type StashedItem<T = any> = {
id: Id
/**
* The item before the call. `undefined` on `create`, without `fetchBefore`,
* or if it wasn't found before the call.
*/
before: T | undefined
/**
* The item after the call. `undefined` until the call ran, or if the
* refetch didn't return it. On `remove`, the removed item.
*/
result: T | undefined
}
export type Stash<T = any, H extends HookContext = HookContext> = {
/**
* Fetches the items before the call and waits for them, so the call can't
* overtake the fetch. A `before` or `around` hook, or called from one
* before `next()`.
*/
stash: (context: H, next?: NextFunction) => Promise<void>
/**
* The items of the call: before the call with `before` only, after the
* call paired with `result` by id.
*/
stashed: (context: H) => Promise<StashedItem<T>[]>
}
/**
* Stashes the items of a call before it runs, to compare them with the items
* after it. Returns a pair: `stash` fetches the items before the call,
* `stashed` returns them - paired with the items after the call once it ran.
*
* Every `defineStash()` is its own stash. Stashes of one call with equal
* params share their fetches. Nothing is stored on `params`, so concurrent
* calls with one `params` object and nested calls stay apart.
*
* `stash` and `stashed` without options are exported as well.
*
* @example
* ```ts
*
*
* const { stash, stashed } = defineStash<User>()
*
* app.service('users').hooks({
* before: { patch: [stash] },
* after: {
* patch: [
* async (context) => {
* for (const { before, result } of await stashed(context)) {
* if (before?.email !== result?.email) await sendMail(result)
* }
* },
* ],
* },
* })
* ```
*
* @see https://utils.feathersjs.com/utils/define-stash.html
*/
export declare function defineStash<
T = any,
H extends HookContext = HookContext,
>(options?: StashOptions<H>): Stash<T, H>
/**
* `stash` and `stashed` without options
*
* @example
* ```ts
*
*
* app.service('users').hooks({
* before: {
* patch: [
* stash,
* async (context) => {
* const [{ before }] = await stashed(context)
* if (before?.locked) throw new Forbidden('locked')
* },
* ],
* },
* })
* ```
*/
export declare const stash: (
context: HookContext<Application<any, any>, any>,
next?: NextFunction,
) => Promise<void>,
stashed: (
context: HookContext<Application<any, any>, any>,
) => Promise<StashedItem<any>[]>| Argument | Type | Description |
|---|---|---|
| options | StashOptions<H> |
Without options, stash and stashed can be imported directly:
ts
import { stash, stashed } from 'feathers-utils/utils'Options
stash
- Use it as a
beforeoraroundhook, or call it from one beforenext():await stash(context, next). - Works on
create,update,patchandremove. Oncreatethere is nothing to fetch,beforestaysundefined. - Fetches with
find, a call with anidby its id, so the items before and after the call go through the same hooks. - Waits for the fetch, so the call can't overtake it. If the fetch fails, the call fails.
- Throws after the call ran, e.g. in an around hook after
next(). - Calling the same
stashagain in one call does nothing.
stashed
Returns an array of { id, before, result }, with one entry for a call with an id:
ts
const [{ before }] = await stashed(context)- Before the call ran, only
beforeis set — e.g. to validate a patch against the stored item. - After the call, the items of
context.resultare paired with the items before by id, in the order of the result. Onremove,resultis the removed item. - With
transformParamsor$select, the items after the call are refetched by id, with the params of the call. Otherwisecontext.resultis used as it is. - Throws if
stashdidn't run for this call.
Migrating from stashable
ts
// before
import { stashable } from 'feathers-utils/hooks'
app.service('users').hooks({
before: { patch: [stashable()] },
})
const before = await context.params.stashed()
// after
import { stash, stashed } from 'feathers-utils/utils'
app.service('users').hooks({
before: { patch: [stash] },
})
const [{ before }] = await stashed(context)stashable | defineStash |
|---|---|
context.params.stashed() | stashed(context) |
propName option | not needed, every defineStash() is its own stash |
stashFunc option | transformParams adjusts the params of the fetch |
get for a call with an id | always find, a call with an id by its id |
multi: the array of find | an array of { id, before, result } |
| starts the fetch without waiting for it | waits for the fetch, so the call can't overtake it |
a failing fetch returns undefined | a failing fetch fails the call |
