redux-orm-angular
Version:
Helpers for integrating Angular and Redux ORM
264 lines (263 loc) • 10.4 kB
JavaScript
import { ORM } from 'redux-orm';
/**
* List of functions from redux-orm/QuerySet that we are automatically wrapping.
* We wrap these functions to allow developers to chain them after their calls to model.all()
*/
var wrappedFunctions = [
{
name: 'at',
type: 'evaluator',
},
{
name: 'count',
type: 'evaluator',
},
{
name: 'exclude',
type: 'clause',
},
{
name: 'exists',
type: 'evaluator',
},
{
name: 'filter',
type: 'clause',
},
{
name: 'first',
type: 'evaluator',
},
{
name: 'last',
type: 'evaluator',
},
{
name: 'orderBy',
type: 'clause',
},
{
name: 'toModelArray',
type: 'evaluator',
},
{
name: 'toRefArray',
type: 'evaluator',
},
];
/**
* Queries to the database
*
* @param {?} getModelFromState
* @return {?} QuerySetSelector Returns an instance of QuerySetSelector that can be used to further specify the query to execute
*/
function QuerySet(getModelFromState) {
// List of functions to be called on the actual QuerySet when running the selector
// We keep pushing onto this list as functions are called on the QuerySetSelector
var /** @type {?} */ clausesChain = [];
// The evaluator that will be run at the end of the querying/filtering
// This launches the evaluation of the query by redux-orm and there can be only one so it is separate from the chain of "clauses"
var /** @type {?} */ evaluator = {
fn: { name: 'toModelArray', type: 'evaluator' },
args: null
};
/**
* The actual selector that will get called by angular-redux when watching changes
*
* @param Object state The current Redux state
*
* @return Array<Model> List of models returned by the query to redux-orm
*/
var selector = function (state) {
// Create a QuerySet from redux-orm
var querySet = getModelFromState(state).all();
// Replay the chain of calls to make sure we rebuild the whole QuerySet
clausesChain.forEach(function (call) {
var fn = call.fn, args = call.args;
querySet = querySet[fn.name].apply(querySet, args);
});
return querySet[evaluator.fn.name].apply(querySet, evaluator.args);
};
// Create a function on the selector for each wrapped function defined in wrappedFunctions
wrappedFunctions.forEach(function (fn) {
selector[fn.name] = function () {
/* istanbul ignore else */
if (fn.type === 'clause') {
// The function is a "clause" (like a filter or an order by)
// We push it onto the chain of calls and we return the selector so that the caller can keep chaining
clausesChain.push({
fn: fn,
args: arguments,
});
// Return the selector itself
// This is pretty important to be able to chain the calls like:
// selector.filter(...).orderBy(...)
return selector;
}
else if (fn.type === 'evaluator') {
// The function is an "evaluator" (like `at` or `count`) that launches the evaluation of the query by redux-orm
// We set it as the evaluator (there can be only one).
evaluator = {
fn: fn,
args: arguments,
};
return selector;
}
else {
/* istanbul ignore next */
throw new Error("Unknown function type \"" + fn.type + "\"");
}
};
});
return selector;
}
/**
* Select data from redux-orm
*
* This call replicates the API from redux-orm so the query syntax is the same.
* Only "read" functions are available: all, get, hasId, withId
*/
var ORMSelector = /** @class */ (function () {
/**
* @param {?} model
*/
function ORMSelector(model) {
if (typeof model === 'function' && model['modelName']) {
this.modelName = model['modelName'];
}
else if (typeof model === 'string') {
this.modelName = model;
}
else {
throw new Error('A valid model name (string) or model (object) must be provided to selectData');
}
}
/**
* Build a selector that queries the ORM
* See the `all` function from http://tommikaikkonen.github.io/redux-orm/Model.html
*
* @return {?} QuerySetSelector A function that gets all model instances from the state and allows further filtering
*/
ORMSelector.prototype.all = function () {
return QuerySet(this.getModelFromState.bind(this));
};
/**
* Build a selector that gets a model instance that matches properties in the `query` object
* See the `get` function from http://tommikaikkonen.github.io/redux-orm/Model.html
*
* If there is no instance matching the properties, `null` will be returned and no exception will be thrown (contrary to the behavior of redux-orm). This helps dealing with these cases in Angular.
* Warning: if there are multiple instances matching the properties, we will throw an error just like redux-orm does.
*
* @param {?} query
* @return {?} function A function that gets a model instance from the state
*/
ORMSelector.prototype.get = function (query) {
var _this = this;
return function (state) {
try {
return _this.getModelFromState(state).get(query);
}
catch (error) {
if (error.message === 'Model instance not found when calling get method') {
// No instance matches the query
// Simply return null
return null;
}
// Unhandled error, re-throw
throw error;
}
};
};
/**
* Build a selector that checks if a model instance with a given `id` exists in the store
* See the `hasId` function from http://tommikaikkonen.github.io/redux-orm/Model.html
*
* @param {?} id
* @return {?} function A function that returns a boolean indicating if an entity with the id `id` exists in the state
*/
ORMSelector.prototype.hasId = function (id) {
var _this = this;
return function (state) {
return _this.getModelFromState(state).hasId(id);
};
};
/**
* Build a selector that gets a model instance with the specified `id`
* See the `withId` function from http://tommikaikkonen.github.io/redux-orm/Model.html
*
* If there is no instance with that id, `null` will be returned and no exception will be thrown (contrary to the behavior of redux-orm). This helps dealing with these cases in Angular.
* Warning: if there are multiple instances matching the properties, we will throw an error just like redux-orm does.
*
* @param {?} id
* @return {?} function A function that gets a model instance from the state
*/
ORMSelector.prototype.withId = function (id) {
var _this = this;
return function (state) {
try {
return _this.getModelFromState(state).withId(id);
}
catch (error) {
/* istanbul ignore else */
if (error.message.indexOf("instance with id " + id + " not found") !== -1) {
// No instance matches the query
// Simply return null
return null;
}
// Unhandled error, re-throw
/* istanbul ignore next */
throw error;
}
};
};
/**
* Get a model from a session populated from the current state
*
* @param {?} state
* @return {?} Object A session model
*/
ORMSelector.prototype.getModelFromState = function (state) {
var /** @type {?} */ config = ORM.angularConfig;
// We use a global shared ORM instance that is expected to be set for the project during setup
// This is not ideal but that's how angular-redux does it as well because we could be in a decorator
// and do not have access to the Angular objects (components, services, etc.)
if (!config) {
throw new Error('ORM.angularConfig should be set before using `selectData`');
}
if (!config.instance) {
throw new Error('Impossible to find the ORM instance to use. Make sure you have configured ORM.angularConfig.instance to the ORM instance that you want to use with `selectData`');
}
if (!config.stateKey) {
throw new Error('Impossible to find the state key from the config. Make sure you have configured ORM.angularConfig.stateKey to a non-empty value');
}
if (!state[config.stateKey]) {
throw new Error('Impossible to find the DB state; make sure you have configured ORM.angularConfig.stateKey and that you have a reducer running your ORM');
}
// Create a session from the ORM instance
var /** @type {?} */ session = config.instance.session(state[config.stateKey]);
var /** @type {?} */ model = session[this.modelName];
return model;
};
return ORMSelector;
}());
/**
* Select data from redux-orm
*
* A helper function that can be used with angular-redux in the \@select decorator or when calling
* ngRedux.select (https://github.com/angular-redux/store/blob/master/articles/select-pattern.md) to select
* models from redux-orm.
*
* The function replicates the API from redux-orm so the query syntax is the same.
* Only "read" functions (withId, all) are available.
*
* @param {?} model
* @return {?}
*/
function selectData(model) {
return new ORMSelector(model);
}
/**
* Generated bundle index. Do not edit.
*/
export { ORMSelector, selectData };
//# sourceMappingURL=redux-orm-angular.es5.js.map