State-Clerk
Perform immutable CRUD operation on your application state.
Table of contents
Installation
npm install state-clerk
Creating an instance
Creating a clerk instance is straight-forward.
const clerk = state /* the state object */
Methods
The following mock data will be used in the examples:
const state = todos: a: _id: 'a' label: 'Buy milk' completed: false b: _id: 'b' label: 'Use state-clerk' completed: true c: _id: 'c' label: 'Do stuff' completed: true lists: _id: 'x' name: 'Shopping' todos: 'a' _id: 'y' name: 'Dev' todos: 'b' _id: 'z' name: 'Random' todos: 'c' foo: 'bar' const clerk = state
Throughout the examples we'll be referring to:
collection object
: a collection of type Object ({})collection array
: a collection of type Array ([])payload
: resource or data to be created/updated/patchedidentifier
: a string|number or an object ({ id: 1 }
) used to identify a specific resource.- string|number would represent a key inside a collection object
- object is a key/value pair used for matching a resource inside a collection array
The Clerk instance has the following API:
get
clerk.get(collection [, identifier])
- It throws if the specified collection doesn't exist or it's not a collection.
- It returns the entire collection if identifier is null or undefined.
For collection objects:
- It returns the resource found at the specified key (identifier).
- It returns an object of resources that have a matching key/value pair with the one of the identifier object (e.g.:
{ completed: true }
). - It returns undefined if no resource found with the provided identifier.
For collection arrays:
- It returns a list of resources that have a matching key/value pair with the one of the identifier object (e.g.: { completed: true }).
- It returns an empty list if identifier is not an object.
- It returns an empty list if no resource found with the provided identifier.
// Valid: clerk// Returns: { id: 'a', label: 'Buy milk', completed: false } clerk// Returns:// {// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true }// } clerk// Returns:// {// a: { _id: 'a', label: 'Buy milk', completed: false },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true }// } clerk// Returns: [{ _id: 'x', name: 'Shopping', todos: ['a'] }] clerk// not a valid identifier for lists// Returns: [] clerk// Returns:// [// { _id: 'x', name: 'Shopping', todos: ['a'] },// { _id: 'y', name: 'Dev', todos: ['b'] },// { _id: 'z', name: 'Random', todos: ['c'] }// ] // Invalid: clerk// Throws: The "users" collection does not exist. You can create one using your clerk instance by running(clerk.addCollection('users')) clerk// Throws: "foo" is not a collection. You can access it like any other property on the state object
post
clerk.post(collection, payload [, identifier])
- It throws if the specified collection doesn't exist or it's not a collection.
- It throws if not providing a payload.
For collection objects:
- It throws if trying to post to a collection object without specifying an identifier.
- It adds to the collection at the specified identifier and returns the new resource.
- It adds the resource for any type of identifier.
For collection arrays:
- It adds the resource without the need of an identifier.
// Valid: clerk// Returns: { _id: 'd', label: 'Git gud!', completed: false }//// state.todos:// {// a: { _id: 'a', label: 'Buy milk', completed: false },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true },// d: { _id: 'd', label: 'Git gud!' },// } clerk// Returns: { _id: 'w', name: 'Groceries' }//// state.lists:// [// { _id: 'x', name: 'Shopping', todos: ['a'] },// { _id: 'y', name: 'Dev', todos: ['b'] },// { _id: 'z', name: 'Random', todos: ['c'] },// { _id: 'w', name: 'Groceries' }// ] // Invalid: clerk// Throws: The "users" collection does not exist. You can create one using your clerk instance by running(clerk.addCollection('users')) clerk// Throws: "foo" is not a collection. You can access it like any other property on the state object clerk// Throws: You forgot to specify the payload clerk// Throws: You are trying to post to a collection object but haven't specified an identifier. Try again with "clerk.post('todos', payload, identifier)"
put
clerk.put(collection, payload, identifier)
- It throws if the specified collection doesn't exist or it's not a collection.
For collection objects:
- It throws when trying to update a resource without specifying an identifier.
- It creates and returns the resource if no match found.
- It replaces an existing resource and returns the new data.
For collection arrays:
- It throws if the identifier is not an object.
- It creates and returns the resource if no identifier provided.
- It creates and returns the resource if no match found.
- It replaces an existing resource and returns the new data.
// Valid: clerk// Returns: { id: 'a', label: 'Buy food' }//// state.todos:// {// a: { label: 'Buy food' },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true },// } clerk// Returns: { name: 'Foobar' }//// state.lists:// [// { _id: 'x', name: 'Shopping', todos: ['a'] },// { _id: 'y', name: 'Dev', todos: ['b'] }// { name: 'Foobar' }// ] // Invalid: clerk// Throws: The "users" collection does not exist. You can create one using your clerk instance by running(clerk.addCollection('users')) clerk// Throws: "foo" is not a collection. You can access it like any other property on the state object clerk// You are trying to update a resource but haven't specified the identifier. Try again with "clerk.put('todos', payload, identifier)" clerk// Throws: When updating a resource inside a list you have to specify an identifier object containing the key/value pair you want to match.
patch
clerk.patch(collection, payload, identifier)
- It throws if the specified collection doesn't exist or it's not a collection.
- It throws if no identifier provided.
- It returns undefined if no match found.
For collection objects:
- It partially updates an existing resource and returns it.
For collection arrays:
- It throws if the identifier is not an object.
- It partially updates an existing resource and returns it.
// Valid: clerk// Returns: undefined//// state.todos:// {// a: { _id: 'a', label: 'Buy milk', completed: false },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true },// } clerk// Returns: { _id: 'a', label: 'Buy milk', completed: true }//// state.todos:// {// a: { _id: 'a', label: 'Buy milk', completed: true },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true },// } clerk// Returns: { name: 'Foobar' }//// state.lists:// [// { _id: 'x', name: 'Shopping', todos: ['a'] },// { _id: 'y', name: 'Programming', todos: ['b'] },// { _id: 'z', name: 'Random', todos: ['c'] }// ] // Invalid: clerk// Throws: The "users" collection does not exist. You can create one using your clerk instance by running(clerk.addCollection('users')) clerk// Throws: "foo" is not a collection. You can access it like any other property on the state object clerk// You are trying to patch a resource but haven't specified the identifier. Try again with "clerk.patch('todos', payload, identifier)" clerk// Throws: When patching a resource inside a list you have to specify an identifier object containing the key/value pair you want to match.
delete
clerk.delete(collection, identifier)
- It throws if the specified collection doesn't exist or it's not a collection.
- It returns undefined and doesn't remove anything if no identifier provided.
- It returns undefined and doesn't remove anything if no match found.
For collection objects:
- It removes the matching resource from the collection
For collection arrays:
- It returns undefined and doesn't remove anything if identifier is not an object
- It removes the matching resource from the collection
// Valid: clerk || clerk// Returns: undefined//// state.todos:// {// a: { _id: 'a', label: 'Buy milk', completed: false },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true }// }// clerk// Returns: { _id: 'a', label: 'Buy milk', completed: false }//// state.todos:// {// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true }// } clerk || clerk || clerk// Returns: undefined//// state.lists// [// { _id: 'x', name: 'Shopping', todos: ['a'] },// { _id: 'y', name: 'Dev', todos: ['b'] },// { _id: 'z', name: 'Random', todos: ['c'] }// ] clerk// Returns: { _id: 'x', name: 'Shopping', todos: ['a'] }//// state.lists// [// { _id: 'y', name: 'Dev', todos: ['b'] },// { _id: 'z', name: 'Random', todos: ['c'] }// ] // Invalid: clerk// Throws: The "users" collection does not exist. You can create one using your clerk instance by running(clerk.addCollection('users')) clerk// Throws: "foo" is not a collection. You can access it like any other property on the state object
getCollection
clerk.getCollection(collectionName)
clerk// Returns:// {// a: { _id: 'a', label: 'Buy milk', completed: false },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true }// } clerk// Returns: undefined
addCollection
clerk.addCollection(collectionName [, type = Object])
clerk// state:// {// todos: {...},// lists: [...],// foo: 'bar',// users: {},// } clerk// state:// {// todos: {...},// lists: [...],// foo: 'bar',// users: {},// comments: [],// }
removeCollection
clerk.removeCollection(collectionName [, type = Object])
clerk// Returns:// {// a: { _id: 'a', label: 'Buy milk', completed: false },// b: { _id: 'b', label: 'Use state-clerk', completed: true },// c: { _id: 'c', label: 'Do stuff', completed: true }// }// // state:// {// lists: [...],// foo: 'bar'// } clerk// Returns: undefined//// state:// {// todos: {...},// lists: [...],// foo: 'bar'// }