UNPKG

redux-orm-angular

Version:

Helpers for integrating Angular and Redux ORM

264 lines (263 loc) 10.4 kB
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