Source: store/storeViewModel.js

import noticeboard from 'scalejs.noticeboard';
import dataservice from 'dataservice';
import { receive } from 'scalejs.messagebus';
import { createViewModel } from 'scalejs.metadataFactory';
import { merge } from 'scalejs';

    //TODO: Rename results to resultsKey

    /**
     * Store: a component that takes a dataSourceEndpoint
     * and adds the results to the noticeboard.
     * It has no viewmodel and does not accept children.
     *
     * @module store
     *
     * @param {object} node
     *  The configuation object for the module
     * @param {string} node.type='store'
     * The type of the node is store     *
     * @param {object} node.storeKey
     *  The key that the results are stored on in the noticeboard
     * @param {object|Object[]} node.dataSourceEndpoint
     *  An object defining the endpoint(s) that makes the ajax calls
     * @param {string} node.dataSourceEndpoint.uri
     *   The uri for the endpoint
     * @param {string} [node.dataSourceEndpoint.url]
     *  The url for the endpoint
     * @param {object} [node.dataSourceEndpoint.options]
     *  Options for the ajax call
     * @param {object} [node.keyMap]
     *  A mapper object to map keys
     * @param {object} [node.keyMap.result]
     *  Map the results from the ajax call with this key
     */
    export default function (node) {
        var keyMap = node.keyMap || {},
            storeKey = node.storeKey,
            storeValue = node.storeValue,
            dataSourceEndpoint = node.dataSourceEndpoint,
            options = node.options || {},
            context = this,
            subs = [];

        if (!storeKey) {
            console.warn('Cannot store data without a storeKey', node);
            return;
        }

        if (!dataSourceEndpoint && !storeValue) {
            console.warn('Cannot set storeKey with data without a dataSourceEndpoint or storeValue', node);
            return;
        }

        //todo: check if storeKey is already in the noticeboard
        // option to persist data and not request endpoint multiple times
        function fetchData() {
            if (dataSourceEndpoint.uri) {
                console.warn('dataSourceEndpoint expects URI in "target". Please update your JSON to reflect the new syntax', node);
                dataSourceEndpoint = merge(dataSourceEndpoint, {
                    target: dataSourceEndpoint
                });
                delete dataSourceEndpoint.uri;
            }

            createViewModel.call(context, {
                "type": "action",
                "actionType": "ajax",
                "options": dataSourceEndpoint
            }).action({
                callback: function (error, results) {
                    if (error) {
                        console.error('Error when retrieving data for node', node, error);
                        noticeboard.setValue(storeKey, error);
                        return;
                    }
                    var value = keyMap.resultsKey ? results[keyMap.resultsKey] : results;

                    if (options.mapArrayToDictionaryWithKey) {
                        value = value.reduce(function (obj, item) {
                            var key = options.mapArrayToDictionaryWithKey;
                            if (options.aggregateMappedItems) {
                                obj[item[key]] = obj[item[key]] || [];
                                obj[item[key]].push(item);
                            } else {
                                obj[item[key]] = keyMap.resultsValueKey ? item[keyMap.resultsValueKey] : item; // will overwrite any existing items with the key
                            }
                            return obj;
                        }, {})
                    }
                    noticeboard.setValue(storeKey, value);
                }              
            });
        }

        if(dataSourceEndpoint) {
            fetchData(); //initial call

            if (node.id) { //setup refresh receiver if store has id
                subs.push(receive(node.id + '.refresh', function () {
                    fetchData();
                }));
            }
        }

        if(storeValue) {
            noticeboard.setValue(storeKey, storeValue);
        }


        return {
                dispose: function () {
                subs.forEach(function (sub) {
                    sub.dispose();
                });
            }
        }
    };