UNPKG

falcor

Version:

A JavaScript library for efficient data fetching.

245 lines (197 loc) 7.29 kB
var createHardlink = require("./../support/createHardlink"); var __prefix = require("./../internal/reservedPrefix"); var $ref = require("./../types/ref"); var getBoundValue = require("./../get/getBoundValue"); var isArray = Array.isArray; var hasOwn = require("./../support/hasOwn"); var isObject = require("./../support/isObject"); var isExpired = require("./../support/isExpired"); var isFunction = require("./../support/isFunction"); var isPrimitive = require("./../support/isPrimitive"); var expireNode = require("./../support/expireNode"); var incrementVersion = require("./../support/incrementVersion"); var mergeValueOrInsertBranch = require("./../support/mergeValueOrInsertBranch"); var NullInPathError = require("./../errors/NullInPathError"); /** * Sets a list of {@link PathMapEnvelope}s into a {@link JSONGraph}. * @function * @param {Object} model - the Model for which to insert the PathMaps. * @param {Array.<PathMapEnvelope>} pathMapEnvelopes - the a list of {@link PathMapEnvelope}s to set. * @return {Array.<Array.<Path>>} - an Array of Arrays where each inner Array is a list of requested and optimized paths (respectively) for the successfully set values. */ module.exports = function setPathMaps(model, pathMapEnvelopes, x, errorSelector, comparator) { var modelRoot = model._root; var lru = modelRoot; var expired = modelRoot.expired; var version = incrementVersion(); var bound = model._path; var cache = modelRoot.cache; var node = bound.length ? getBoundValue(model, bound).value : cache; var parent = node.$_parent || cache; var initialVersion = cache.$_version; var requestedPath = []; var requestedPaths = []; var optimizedPaths = []; var optimizedIndex = bound.length; var pathMapIndex = -1; var pathMapCount = pathMapEnvelopes.length; while (++pathMapIndex < pathMapCount) { var pathMapEnvelope = pathMapEnvelopes[pathMapIndex]; var optimizedPath = bound.slice(0); optimizedPath.index = optimizedIndex; setPathMap( pathMapEnvelope.json, 0, cache, parent, node, requestedPaths, optimizedPaths, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector ); } var newVersion = cache.$_version; var rootChangeHandler = modelRoot.onChange; if (isFunction(rootChangeHandler) && initialVersion !== newVersion) { rootChangeHandler(); } return [requestedPaths, optimizedPaths]; }; /* eslint-disable no-constant-condition */ function setPathMap( pathMap, depth, root, parent, node, requestedPaths, optimizedPaths, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector) { var keys = getKeys(pathMap); if (keys && keys.length) { var keyIndex = 0; var keyCount = keys.length; var optimizedIndex = optimizedPath.index; do { var key = keys[keyIndex]; var child = pathMap[key]; var branch = isObject(child) && !child.$type; requestedPath.depth = depth; var results = setNode( root, parent, node, key, child, branch, false, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector ); requestedPath[depth] = key; requestedPath.index = depth; optimizedPath[optimizedPath.index++] = key; var nextNode = results[0]; var nextParent = results[1]; if (nextNode) { if (branch) { setPathMap( child, depth + 1, root, nextParent, nextNode, requestedPaths, optimizedPaths, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector ); } else { requestedPaths.push(requestedPath.slice(0, requestedPath.index + 1)); optimizedPaths.push(optimizedPath.slice(0, optimizedPath.index)); } } if (++keyIndex >= keyCount) { break; } optimizedPath.index = optimizedIndex; } while (true); } } /* eslint-enable */ function setReference( value, root, node, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector) { var reference = node.value; optimizedPath.length = 0; optimizedPath.push.apply(optimizedPath, reference); if (isExpired(node)) { optimizedPath.index = reference.length; expireNode(node, expired, lru); return [undefined, root]; } var container = node; var parent = root; node = node.$_context; if (node != null) { parent = node.$_parent || root; optimizedPath.index = reference.length; } else { var index = 0; var count = reference.length - 1; optimizedPath.index = index; parent = node = root; do { var key = reference[index]; var branch = index < count; var results = setNode( root, parent, node, key, value, branch, true, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector ); node = results[0]; if (isPrimitive(node)) { optimizedPath.index = index; return results; } parent = results[1]; } while (index++ < count); optimizedPath.index = index; if (container.$_context !== node) { createHardlink(container, node); } } return [node, parent]; } function setNode( root, parent, node, key, value, branch, reference, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector) { var type = node.$type; while (type === $ref) { var results = setReference( value, root, node, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector); node = results[0]; if (isPrimitive(node)) { return results; } parent = results[1]; type = node && node.$type; } if (type !== void 0) { return [node, parent]; } if (key == null) { if (branch) { throw new NullInPathError(); } else if (node) { key = node.$_key; } } else { parent = node; node = parent[key]; } node = mergeValueOrInsertBranch( parent, node, key, value, branch, reference, requestedPath, optimizedPath, version, expired, lru, comparator, errorSelector ); return [node, parent]; } function getKeys(pathMap) { if (isObject(pathMap) && !pathMap.$type) { var keys = []; var itr = 0; if (isArray(pathMap)) { keys[itr++] = "length"; } for (var key in pathMap) { if (key[0] === __prefix || !hasOwn(pathMap, key)) { continue; } keys[itr++] = key; } return keys; } return void 0; }