.. Store.js documentation master file, created by
sphinx-quickstart on Fri Jan 13 21:42:04 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Store.js' documentation!
===================================
Store.js is a super lightweight implementation of Repository_ pattern for relational data and aggregates.
The library allows you to use Domain-Driven Design (DDD) on client-side as well as reactive programming.
This is similar to Object-Relational Mapping (ORM) for JavaScript, including the Data Mapper pattern (the data can be mapped between objects and a persistent data storage).
Canonical repo
--------------
* Home Page and Source Code: https://github.com/joor/store-js-external
* Docs: TODO
Edge (unstable) repo
--------------------
* Home Page and Source Code: https://github.com/emacsway/store
* Docs: https://edge-storejs.readthedocs.io/
Articles
--------
* Article (in English) "`Implementation of the pattern Repository for browser's JavaScript `_"
* Article (in Russian): "`Реализация паттерна Repository в браузерном JavaScript `_"
.. toctree::
:maxdepth: 2
:caption: Contents:
.. contents:: Contents
The :class:`IStore` class is a super lightweight implementation of Repository_ pattern for relational data and composed nested aggregates.
The main goal of Repository_ pattern is to hide the data source.
The :class:`IStore` class has simple interface, so, this abstract layer allows you easy to change the policy of data access.
For example, you can use as data source:
- `REST API `_
- `CORS `_ REST API
- JSON-RPC
- `html `__
- `Indexed Database API `_
- etc.
An essential attribute of Repository pattern is the pattern `Query Object`_, which is necessary to hide the data source.
This class was developed rapidly, in limited time, thus there is used the simplest query syntax similar to `MongoDB Query`_.
Features
========
- Store is easy to debug, since its code is written with a `KISS principle`_, and thus is easy to understand.
- Store handles composed primary keys and composite relations with ease (no need for surrogate keys).
- Store supports cascade deleting and updating with changeable cascade behavior.
- Store uses event system extensively.
- Store has reactive result which synchronizes his state when the observed subject (store or parent result collection) is changed.
- Store has easy query syntax similar to `MongoDB Query`_.
- Store allows you to keep models FULLY clean without any service logic, - only business rules.\
This is an important point when you use `DDD`_, thus your product team (or customer) will be able to read the business rules from code.
- Store allows you to work with stream of composed aggregates easily, regardless of the depth of nesting of aggregates.\
See method :func:`Store.prototype.decompose`.
- Store allows you to compose composed aggregates from stores using information about relations.\
See method :func:`Store.prototype.compose`.
- Store has implemented pattern `Identity Map`_, thus you can easily to work with model instances `by reference `__.\
You always will have the single instance of entity in a memory.
- Store does not have any external dependencies except RequireJS.
- Written in ES3 and should be fully compatible with ES3 (not really tested).
Implemented Patterns
====================
- `Repository`_
- `Query Object`_
- `Identity Map`_
- `Data Mapper`_
- `Gateway`_
- `Unit Of Work`_
- `Observer`_
- `Mediator`_
- `Adapter`_
Used programming paradigms
==========================
- `Reactive Programming`_
- `Event-driven programming`_
- `Aspect-oriented programming`_ (Cross-Cutting Concerns)
- `Declarative programming`_
Store
=====
Store public API
----------------
.. class:: Store([options])
:param Object options: the keyword arguments.
The ``options`` object can have the next keys:
:param options.pk: the name of Primary Key or list of names of composite Primary Key.\
Optional. The default value is 'id'.
:type options.pk: string or Array[string]
:param ObjectAccessor options.objectAccessor: an instance of :class:`ObjectAccessor`.
Optional. By default will be created on fly using ``options.pk``.
:param Array[string] options.indexes: the array of field names to be indexed for fast finding or instance of local store.\
Note, all field used by relations or primary key will be indexed automatically.\
Optional.
:type IStore options.localStore: an instance of :class:`IStore`. Optional.\
By default will be created on fly using ``options``
:param IStore options.remoteStore: an instance of :class:`IStore`. Optional.\
By default will be created on fly using ``options``
:param function options.model: the model constructor, which should be applied before to add object into the store.\
Can be usefull in combination with :func:`Store.prototype.decompose`.\
Optional. The default value is :class:`DefaultModel`
:param Serializer options.serializer: an instance of :class:`Serializer`. Optional.\
By default will be created on fly using ``options.model``
:param Object options.relations: the dictionary describes the schema relations.
The format of ``options.relations`` argument::
{
foreignKey: {
firstForeignKeyName: {
[field: fieldNameOfCurrentStore,] // (string | Array[string]),
// optional for Fk, in this case the relation name will be used as field name
relatedStore: nameOfRelatedStore, // (string)
relatedField: fieldNameOfRelatedStore, // (string | Array[string])
[onAdd: callableOnObjectAdd,] // (function) compose
[onDelete: callableOnObjectDelete,] // (function) cascade|setNull
[onUpdate: callableOnObjectUpdate,] // (function)
},
secondForeignKeyName: ...,
...
},
[oneToMany: {
firstOneToManyName: {
field: fieldNameOfCurrentStore, // (string | Array[string]),
relatedStore: nameOfRelatedStore, // (string)
relatedField: fieldNameOfRelatedStore, // (string | Array[string])
[relatedName: nameOfReverseRelationOfRelatedStore,]
[onAdd: callableOnObjectAdd,] // (function)
[onDelete: callableOnObjectDelete,] // (function) cascade|setNull|decompose
[onUpdate: callableOnObjectUpdate,] // (function)
},
secondOneToManyName: ...,
...
},]
manyToMany: {
fistManyToManyName: {
relation: relationNameOfCurrentStore, // (string)
// the name of foreignKey relation to middle M2M store.
relatedStore: nameOfRelatedStore, // (string)
relatedRelation: relationNameOfRelatedStore, // (string)
// the name of oneToMany relation from related store to middle M2M store.
[onAdd: callableOnObjectAdd,] // (function) compose
[onDelete: callableOnObjectDelete,] // (function) cascade|setNull|decompose
[onUpdate: callableOnObjectUpdate,] // (function)
},
secondManyToManyName: ...,
...
}
}
If oneToMany is not defined, it will be built automatically from foreignKey of related store.
In case the foreignKey don't has relatedName key, a new relatedName will be generated from the store name and "Set" suffix.
| If ``options.objectAccessor`` is provided, the ``options.pk`` will be ignored.
| If ``options.serializer`` is provided, the ``options.model`` and ``options.objectAccessor`` will be ignored.
| If ``options.localStorage`` is provided, the ``options.indexes`` will be ignored.
The public method of Store:
.. function:: Store.prototype.pull(query, options)
Populates local store from remote store.
:param Object query: the Query Object.
:param Object options: options to be passed to the remote store.
:rtype: Promise
.. function:: Store.prototype.get(pkOrQuery)
Retrieves a Model instance by primary key or by Query Object.
:param pkOrQuery: the primary key of required Model instance or Query Object.
:type pkOrQuery: number or string or Array or Object
.. function:: Store.prototype.add(obj)
Adds a Model instance into the Store instance.
:param Object obj: the Model instance to be added.
:rtype: Promise