All files / framework/core/js DataSource.js

97.5% Statements 39/40
75% Branches 12/16
100% Functions 9/9
97.5% Lines 39/40
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209                        26x   26x             26x                 26x                 26x 59x 59x 26x   33x 33x             59x     26x 21x                                           26x                                                                                 26x                                                                     26x 378x       26x 447x 447x 447x 447x 447x                     26x 297x 297x 297x 297x                         26x 81x 81x 81x 81x 69x 69x 69x   12x   81x 81x        
/*
Copyright 2012-2017 OCAD University
Copyright 2014-2016 Raising the Floor - International
 
Licensed under the Educational Community License (ECL), Version 2.0 or the New
BSD license. You may not use this file except in compliance with one these
Licenses.
 
You may obtain a copy of the ECL 2.0 License and BSD License at
https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
*/
 
var fluid_3_0_0 = fluid_3_0_0 || {};
 
(function ($, fluid) {
    "use strict";
 
    /** NOTE: Much of this work originated from https://github.com/fluid-project/kettle/blob/master/lib/dataSource-core.js **/
 
    /** Some common content encodings - suitable to appear as the "encoding" subcomponent of a dataSource **/
 
    fluid.defaults("fluid.dataSource.encoding.JSON", {
        gradeNames: "fluid.component",
        invokers: {
            parse: "fluid.dataSource.parseJSON",
            render: "fluid.dataSource.stringifyJSON"
        },
        contentType: "application/json"
    });
 
    fluid.defaults("fluid.dataSource.encoding.none", {
        gradeNames: "fluid.component",
        invokers: {
            parse: "fluid.identity",
            render: "fluid.identity"
        },
        contentType: "text/plain"
    });
 
    fluid.dataSource.parseJSON = function (string) {
        var togo = fluid.promise();
        if (!string) {
            togo.resolve(undefined);
        } else {
            try {
                togo.resolve(JSON.parse(string));
            } catch (err) {
                togo.reject({
                    message: err
                });
            }
        }
        return togo;
    };
 
    fluid.dataSource.stringifyJSON = function (obj) {
        return obj === undefined ? "" : JSON.stringify(obj, null, 4);
    };
 
    /**
     * The head of the hierarchy of dataSource components. These abstract
     * over the process of read and write access to data, following a simple CRUD-type semantic, indexed by
     * a coordinate model (directModel) and which may be asynchronous.
     * Top-level methods are:
     *     get(directModel[, callback|options] -        to get the data from data resource
     *     set(directModel, model[, callback|options] - to set the data
     *
     *
     * directModel: An object expressing an "index" into some set of
     *              state which can be read or written.
     *
     * model: The payload sent to the storage.
     *
     * options: An object expressing implementation specific details
     *          regarding the handling of a request. Note: this does not
     *          include details for identifying the resource. Those should be
     *          placed in the directModel.
     */
    fluid.defaults("fluid.dataSource", {
        gradeNames: ["fluid.component"],
        events: {
            // The "onRead" event is operated in a custom workflow by fluid.fireTransformEvent to
            // process dataSource payloads during the get process. Each listener
            // receives the data returned by the last.
            onRead: null,
            onError: null
        },
        components: {
            encoding: {
                type: "fluid.dataSource.encoding.JSON"
            }
        },
        listeners: {
            // handler for "onRead.impl" must be implemented by a concrete subgrade
            // Note: The intial payload (first argument) will be undefined
            "onRead.impl": {
                func: "fluid.notImplemented",
                priority: "first"
            },
            "onRead.encoding": {
                func: "{encoding}.parse",
                priority: "after:impl"
            }
        },
        invokers: {
            get: {
                funcName: "fluid.dataSource.get",
                args: ["{that}", "{arguments}.0", "{arguments}.1"] // directModel, options/callback
            }
        }
    });
 
 
    /**
     * Base grade for adding write configuration to a dataSource.
     *
     * Grade linkage should be used to apply the concrete writable grade to the datasource configuration.
     * For example fluid.makeGradeLinkage("kettle.dataSource.CouchDB.linkage", ["fluid.dataSource.writable", "kettle.dataSource.CouchDB"], "kettle.dataSource.CouchDB.writable");
     */
    fluid.defaults("fluid.dataSource.writable", {
        gradeNames: ["fluid.component"],
        events: {
            // events "onWrite" and "onWriteResponse" are operated in a custom workflow by fluid.fireTransformEvent to
            // process dataSource payloads during the set process. Each listener
            // receives the data returned by the last.
            onWrite: null,
            onWriteResponse: null
        },
        listeners: {
            "onWrite.encoding": {
                func: "{encoding}.render"
            },
            // handler for "onWrite.impl" must be implemented by a concrete subgrade
            "onWrite.impl": {
                func: "fluid.notImplemented",
                priority: "after:encoding"
            },
            "onWriteResponse.encoding": {
                func: "{encoding}.parse"
            }
        },
        invokers: {
            set: {
                funcName: "fluid.dataSource.set",
                args: ["{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2"] // directModel, model, options/callback
            }
        }
    });
 
    // Registers the default promise handlers for a dataSource operation -
    // i) If the user has supplied a function in place of method `options`, register this function as a success handler
    // ii) if the user has supplied an onError handler in method `options`, this is registered - otherwise
    // we register the firer of the dataSource's own onError method.
 
    fluid.dataSource.registerStandardPromiseHandlers = function (that, promise, options) {
        promise.then(typeof(options) === "function" ? options : null,
            options.onError ? options.onError : that.events.onError.fire);
    };
 
    fluid.dataSource.defaultiseOptions = function (componentOptions, options, directModel, isSet) {
        options = options || {};
        options.directModel = directModel;
        options.operation = isSet ? "set" : "get";
        options.notFoundIsEmpty = options.notFoundIsEmpty || componentOptions.notFoundIsEmpty;
        return options;
    };
 
    /** Operate the core "transforming promise workflow" of a dataSource's `get` method. The initial listener provides the initial payload;
     *  which then proceeds through the transform chain to arrive at the final payload.
     * @param that {Component} The dataSource itself
     * @param directModel {Object} The direct model expressing the "coordinates" of the model to be fetched
     * @param options {Object} A structure of options configuring the action of this get request - many of these will be specific to the particular concrete DataSource
     * @return {Promise} A promise for the final resolved payload
     */
 
    fluid.dataSource.get = function (that, directModel, options) {
        options = fluid.dataSource.defaultiseOptions(that.options, options, directModel);
        var promise = fluid.promise.fireTransformEvent(that.events.onRead, undefined, options);
        fluid.dataSource.registerStandardPromiseHandlers(that, promise, options);
        return promise;
    };
 
    /** Operate the core "transforming promise workflow" of a dataSource's `set` method.
     * Any return from this is then pushed forwards through a range of the transforms (typically, e.g. just decoding it as JSON)
     * on its way back to the user via the onWriteResponse event.
     * @param that {Component} The dataSource itself
     * @param directModel {Object} The direct model expressing the "coordinates" of the model to be written
     * @param model {Object} The payload to be written to the dataSource
     * @param options {Object} A structure of options configuring the action of this set request - many of these will be specific to the particular concrete DataSource
     * @return {Promise} A promise for the final resolved payload (not all DataSources will provide any for a `set` method)
     */
 
    fluid.dataSource.set = function (that, directModel, model, options) {
        options = fluid.dataSource.defaultiseOptions(that.options, options, directModel, true); // shared and writeable between all participants
        var transformPromise = fluid.promise.fireTransformEvent(that.events.onWrite, model, options);
        var togo = fluid.promise();
        transformPromise.then(function (setResponse) {
            var options2 = fluid.dataSource.defaultiseOptions(that.options, fluid.copy(options), directModel);
            var retransformed = fluid.promise.fireTransformEvent(that.events.onWriteResponse, setResponse, options2);
            fluid.promise.follow(retransformed, togo);
        }, function (error) {
            togo.reject(error);
        });
        fluid.dataSource.registerStandardPromiseHandlers(that, togo, options);
        return togo;
    };
 
})(jQuery, fluid_3_0_0);