Hooks and Events
Hooks before Writing
When you define a module, you can pass the modifyPayloadOn
config, in which you can define functions you want to be executed every time BEFORE a write method is called.
The config you can pass for modifyPayloadOn
is an object with the following properties. All properties are optional.
write
— triggered every time for methodsinsert
,merge
,assign
,replace
insert
— triggered every time for methodinsert
merge
— triggered every time for methodmerge
assign
— triggered every time for methodassign
replace
— triggered every time for methodreplace
deleteProp
— triggered every time for methoddeleteProp
read
— triggered every time for methodstream
,fetch
stream
— triggered every time for methodstream
fetch
— triggered every time for methodfetch
Your modifyPayloadOn
-function will receive the payload
as param and must return the payload
again. The main purpose is that you can modify the payload before anything happens.
Here we give some examples with common use cases.
Apply Default Values on Insert
In this example we ensure that every insert will always include a set of props with some default values we choose.
const defaultsPokemon = () => ({
name: '',
type: '',
level: 0,
})
const pokedexModule = magnetar.collection('pokedex', {
modifyPayloadOn: {
insert: (payload) => {
return { ...defaultsPokemon(), ...payload }
},
},
})
// default values will be applied
pokedexModule.doc('abc').insert({ name: 'Unown' })
// pokedexModule.doc('abc').data ≈ { name: 'Unown', type: '', level: 0 }
Add Created At / Updated At Fields
In this example we ensure that every write will always include createdAt
and updatedAt
fields.
const pokedexModule = magnetar.collection('pokedex', {
modifyPayloadOn: {
insert: (payload) => {
const createdAt = new Date().toISOString()
return { createdAt, ...payload }
},
write: (payload) => {
const updatedAt = new Date().toISOString()
return { updatedAt, ...payload }
},
},
})
// default values will be applied
pokedexModule.doc('abc').insert({ name: 'Ponyta' })
// pokedexModule.doc('abc').data ≈ { name: 'Ponyta', createdAt: '2020-12-18T05:56:06.735Z', updatedAt: '2020-12-18T05:56:06.735Z' }
pokedexModule.doc('abc').merge({ name: 'Rappidash' })
// pokedexModule.doc('abc').data ≈ { name: 'Rappidash', createdAt: '2020-12-18T05:56:06.735Z', updatedAt: '2021-02-22T04:06:06.735Z' }
Here is a clean way you could reuse such logic easily in multiple modules:
export function addCreatedAt(payload) {
const createdAt = new Date().toISOString()
return { createdAt, ...payload }
}
export function addUpdatedAt(payload) {
const updatedAt = new Date().toISOString()
return { updatedAt, ...payload }
}
And then in the file(s) you define your modules:
import { addCreatedAt, addUpdatedAt } from './helpers/index.js'
const pokedexModule = magnetar.collection('pokedex', {
modifyPayloadOn: {
insert: addCreatedAt,
write: addUpdatedAt,
},
})
Convert undefined
to null
Some remote stores (eg. Firestore) do not allow the value undefined
. In this case you can set up a hook that converts undefined
to null
whenever data is written. For this example we're going to use a tiny helper utility I wrote called find-and-replace-anything.
import { findAndReplace } from 'find-and-replace-anything'
const pokedexModule = magnetar.collection('pokedex', {
modifyPayloadOn: {
write: (payload) => findAndReplace(payload, undefined, null),
},
})
// undefined will be converted to null
pokedexModule.doc('abc').insert({ name: 'Unown', type: undefined })
// pokedexModule.doc('abc').data ≈ { name: 'Unown', type: null }
Remove Certain Values
Some remote stores (eg. Firestore) do not allow the value undefined
. In this case you can set up a hook that completely removes undefined
before the data is sent to your cache and remote stores. For this example we're going to use a tiny helper utility I wrote called remove-anything.
import { removeProp } from 'remove-anything'
const pokedexModule = magnetar.collection('pokedex', {
modifyPayloadOn: {
write: (payload) => removeProp(payload, undefined),
},
})
// undefined will be removed
pokedexModule.doc('abc').insert({ name: 'Unown', type: undefined })
// pokedexModule.doc('abc').data ≈ { name: 'Unown' }
Omit Certain Props
If you have some props that you never want to be included, you can omit them from the payload on every write. For this example we're going to use a tiny helper utility I wrote called filter-anything.
import { omit } from 'filter-anything'
/**
* These props will be omitted on every write (the props below are hypothetical examples)
*/
const propsToOmit = ['metadataXYZ', '_temporaryTag']
const pokedexModule = magnetar.collection('pokedex', {
modifyPayloadOn: {
write: (payload) => omit(payload, propsToOmit),
},
})
// propsToOmit will be removed
pokedexModule.doc('abc').insert({ name: 'Unown', metadataXYZ: 'xyz', _temporaryTag: 'new' })
// pokedexModule.doc('abc').data ≈ { name: 'Unown' }
Hooks after Reading
When you define a module, you can pass the modifyReadResponseOn
config, in which you can define functions you want to be executed every time AFTER a document is retrieved from the remote store.
The config you can pass for modifyReadResponseOn
is an object with the following properties. All properties are optional.
added
— triggered every time data comes in from your remote store (the server), during the methodsstream
andfetch
modified
— triggered every time data is modified on your remote store (the server), during the methodstream
removed
— triggered every time data is removed from your remote store (the server) OR if a document satisfy the query filters of your module anymore, during the methodstream
Your modifyReadResponseOn
-function will receive a payload
as param which is the incoming data and must return that payload
again. The main purpose is that you can modify the payload before it is added to your local cache store.
Here we give some examples with common use cases.
Apply Default Values on Read
In this example we ensure that every time a document is read from your remote store (the server) that we always include a set of props with some default values we choose.
This might be useful when there is a chance that some parts of your database is outdated and misses props that you need in your front-end.
const defaultsPokemon = () => ({
name: '',
type: '',
level: 0,
})
const pokedexModule = magnetar.collection('pokedex', {
modifyReadResponseOn: {
added: (payload) => {
return { ...defaultsPokemon(), ...payload }
},
},
})
// default values will be applied when docs are retrieved during stream
pokedexModule.stream()
Prevent Doc Removal During Stream
documentation below is still WIP
hint: returning
undefined
will discard the document change and do nothing with the local cache store
Accessing Metadata when Reading Data
documentation WIP
hint: you can access the metadata as second param
Events
documentation WIP
on
hint: use case: toasts
hint: use case: developer logging (see setup for now)
Global Events
documentation WIP
hint: you can setup global events when you instantiate magnetar