Node js library allowing easy management of data stores respecting predefined models.
model-graph lets you build smart features on top of your request functions :
- update desired store with returned entity
- update any other linked stores if this entity has any linking attribute
- saved calls allow you to
- keep trace of their last usage
- synchronise 2 simultaneous same call with the same promise (instead of executing twice)
- use one shot calls (unique instance over the entire program run)
- autogetters looks for a given entity id before executing request
- quick inserts update stores with your freshly created entity before running the request. Request return result updates this temporary entity, or deletes it on failure.
- models can be given a prototype to extend all of their entities features
- entity groups lets you organize entities in groups
npm --save i model-graph
import { DataScheme } from 'model-graph';
Lets you define models and links.
models
may contain model names and their options (key / value)
opts
may contain various DataScheme options.
DataScheme options :
- idAttribute : id attribute name, 'id' by default
Creates a new Model
identified by modelName
, with opts
options.
This is the same method called by constructor with each key / value pairs. Note that modelName
will also be the name of the corresponding DataStore
.
Model options :
- idAttribute : id attribute name, if different from DataScheme level
- proto : prototype object to be inherited by
modelName
entities
Call schemeFn with an object containing every models as parameter, in order to link them in a more convenient way.
Returns every stores in a single object
Returns name
store
Returns name
model
Prepares and returns a new request on name
stores
Returns informations about callId
saved call, or undefined if it does not exist yet.
Returns if callId
is currently running or not.
Template of a specific entity type, contains the few logic needed by datascheme declaration, should not be used outside this context.
Model
should never be instantiated directly but only via DataScheme
(constructor or define method), since it needs the enclosing DataScheme
instance.
Links this model to linkedModel
through attrName
attribute. If attrName
is meant to be an array (containing every linked entities), linkedModel
should be an array as well (only containing the proper Model
).
When receiving an entity of such a linked model, model-graph tries to extract the linked entity from attrName
to its owner DataStore
, leaving only ids in attrName
.
Example :
datascheme.model('todos').link('owner', datascheme.model('users'))
__link options : __
- via : object defining an autolink between the two models.
- attr : indicates the remote model attribute name supposed to refer to an instance of current model.
With an autolink attribute, each linkedModel
entity creation makes model-graph check if any entity of current model (referred by remote entity via.attr
attribute) could have its attrName
updated.
In short, this feature ensures that any incoming new entity would bind to their linked entities in a bidirectionnal way.
Example :
datascheme.model('users').link('todos', [datascheme.model('todos')], { via: { attr: 'owner' } })
Suppose we already have an user 5 (with an empty todos attr) and we receive {objectId: 37, owner: 5, descr: "My awesome todo"}
:
the autolink would have user 5 todos
attribute updated with [37]
value
Contains every entities of a specific model. Should never be instantiated directly, since DataScheme already takes care of this in the same time a Model is defined.
Returns an array of every entities
Return entity corresponding to id
Returns an array of group
entities
Update this store with entities (can be a single entity or an array)
Always ensure that each entity still have its prototype.
Returns entities
, but please not it may have been re-instantiated / altered (prototypes).
update options :
- groups : array of groups
entities
should be assigned at
Delete entity id
and clear groups accordingly
Remove id
entity from group
Replace oldId
entity by newEntity
. Essentially, means we insert newEntity
at same position than oldId
.
Interface between your request functions and datascheme, implements an important part of model-graph features.
Built in a functionnal way such that most use cases will fit in one chained instruction (so every methods return current instance)
Note that every intermediates values and calls are always promised, so think about it when using it.
Requests have an attribute updatedStores (Set
container) that lets you know which stores have been updated at any time, by store
or delete
methods.
Redux users should use the available middleware instead of directly ModelRequest
.
exported requestBuilder is a currying function that thake care of building the request with proper environment : datascheme object then desired store name.
import { requestBuilder } from 'model-graph';
// ... datascheme building
const schemeRequest = requestBuilder(datascheme);
const storeRequest = schemeRequest('users');
var myRequest = storeRequest().call(...)...
It is generally easier to build this from the datascheme :
var myRequest = datascheme.request('users').call(...)...
Get and save entity id
(via DataStore.get)
Save value
Shortcut of currentInstance.result.then
, currentInstance.result
being the current promise
Generally the last method called in the chain, updates the target store with the last computed value, and save the store's returned value (e.g prototype update)
This is where various link extractions are operated.
store options :
- value : any value to overwrite current one
- groups : an array of groups to be given to
DataStore.update
- replace : entity id to
replace
instead ofupdate
Updates updatedStores
.
As soon as current promise has resolved, call fn
with current promise result as first parameter, before args
additional parameters.
Example :
function likeThisUser(user) {
return ({id: user.id, likes: [...user.likes, 0]})
}
datascheme.request('users')
.get(5)
.call(likeThisUser)
.store()
.then(updated => {
console.log(updated.likes)
})
Same as call
, except that we are saving this call with a given id.
Notifies DataScheme after both request beginning and ending (running true than false).
params:
- fn : required, the function to be executed
- callId : required, string identifying this call
- oneshot : true by default, prevents any other call
callId
execution, for the entire program running. If false, just prevent from 2 parallel executions. - params : Array of parameters to be given to
fn
, empty by default
If id
is undefined, looks for it in result.id
(where result is last computed value).
Then dispatch this deletion to DataStore.delete
.
Updates updatedStores