Source: manager.js

/*jslint plusplus: true, devel: true, nomen: true, vars: true, node: true, sloppy: true, indent: 4, maxerr: 50 */

"use strict";

var sift            = require("sift"),
    Strings         = require("./strings");

function execCond(cond, fact, man, cb) {
    switch (typeof cond) {
    case "function":
        cond(fact, cb);
        break;
    case "string":
        man.getRule(cond, function (err, rule) {
            if (err) {
                return cb(err);
            }
            execRule(rule, fact, man, cb);
        });
        break;
    default:
        try {
            cb(null, sift(cond).test(fact));
        } catch (err) {
            cb(err);
        }
        break;
    }
}

function execRule(rl, fact, man, cb) {
    var cond = rl.condition;
    if (Array.isArray(cond)) {
        var completed   = 0,
            iterate     = function () {
                execCond(cond[completed++], fact, man, function (err, res) {
                    if (err || !res || completed >= cond.length) {
                        cb(err, res);
                    } else {
                        iterate();
                    }
                });
            };

        iterate();
    } else {
        execCond(cond, fact, man, cb);
    }
}

/**
 * Constructor for Authority Manager.
 *
 * @class Represents an Authority Manager.
 * @param {(object|object[])=} ruleStores - An object or an array of objects capable of storing rules.
 * If ommited, {@link MemoryStore} is used.
 * @param {object=} opts - Additional options.
 */
function Manager(ruleStores, opts) {
    var that = this;

    this.stores = {};
    this.opts = opts || {};

    if (!ruleStores) {
        ruleStores = [new (require("./stores/memory"))()];
    } else if (!Array.isArray(ruleStores)) {
        ruleStores = [ruleStores];
    }

    if (!this.opts.defaultStore) {
        this.opts.defaultStore = ruleStores[0].name;
    }

    ruleStores.forEach(function (el) {
        that.stores[el.name] = el;
    });

    this._stores = ruleStores;
}

/**
 * Adds one or more rules to the default store.
 *
 * This method is simply alias to the `setRules` method of the default store.
 * If default store hasn't been set explicitly, the first store in the collection is assumed.
 *
 * @param {(object|object[])} rules - The rule or an array of rules to be added to the store.
 *
 * @param {boolean=} override - Specifies whether existing rules should be replaced by the ones provided to this method. Rules are matched by their name.
 * If this parameter is not specified or is false and there is a name conflict an error will be returned or thrown depending on the usage of the method.
 *
 * @param {function=} done - Optional callback function that will be called after the rule(s) have been added.
 * If the method is unsuccessful an error object will be passed as a single parameter to the callback.
 * If the callback is omitted and the method is unsuccessful an error will be thrown.
 *
 * @return {null}
 */
Manager.prototype.setRules = function (rules, override, done) {
    this.stores[this.opts.defaultStore].setRules(rules, override, done);
};

/**
 * Retrieves the specified rule from the first store that matches the name.
 *
 * @param {string} name - The name of the rule.
 * @param {function} done - The callback that handles the result.
 * The first parameter will be an error object if an error occurred, or null otherwise.
 * The second parameter will contain the requested rule or null if not found.
 * @return {null}
 */
Manager.prototype.getRule = function (name, done) {
    var getters     = this._stores,
        completed   = 0,
        iterate     = function () {
            getters[completed++].getRule(name, function (err, rule) {
                if (err || rule || completed >= getters.length) {
                    done(err, rule);
                } else {
                    iterate();
                }
            });
        };

    iterate();
};

/**
 * Executes the specified or provided rule.
 *
 * @param {(string|object)} rule - The name of a rule or an instance of a rule.
 * @param {object} fact - An object containing facts to which the current rule is matched against.
 * @param {function} done - Callback function that will be called after the rule has been evaluated.
 * The first parameter will be an error object if an error occurred, or null otherwise.
 * The second parameter will contain `true` or `false` indicating whether all conditions against the provided fact have been satisfied, including all conditions from all nested rules if any.
 * @return {null}
 */
Manager.prototype.execute = function (rule, fact, done) {
    if (!done) {
        throw new Error(Strings.ERR_REQUIRED_CALLBACK);
    }
    if (!rule || !fact) {
        return done(new Error(Strings.ERR_REQ_RULE_FACT));
    }

    var that = this;
    if (typeof rule === "string") {
        return this.getRule(rule, function (err, rl) {
            if (err) {
                return done(err);
            }
            execRule(rl, fact, that, done);
        });
    }
    execRule(rule, fact, that, done);
};

module.exports = Manager;
Authority Copyright © 2013-2014 The contributors to the Authority projects.
Documentation generated by JSDoc 3.2.2 on Sat Jan 18 2014 02:44:25 GMT+0200 (EET) using the DocStrap template.