UNPKG

falcor

Version:

A JavaScript library for efficient data fetching.

139 lines (123 loc) 4.13 kB
var followReference = require("./../get/followReference"); var clone = require("./../get/util/clone"); var isExpired = require("./../get/util/isExpired"); var promote = require("./../lru/promote"); var $ref = require("./../types/ref"); var $atom = require("./../types/atom"); var $error = require("./../types/error"); module.exports = function getValueSync(model, simplePath, noClone) { var root = model._root.cache; var len = simplePath.length; var optimizedPath = []; var shorted = false, shouldShort = false; var depth = 0; var key, i, next = root, curr = root, out = root, type, ref, refNode; var found = true; var expired = false; while (next && depth < len) { key = simplePath[depth++]; if (key !== null) { next = curr[key]; optimizedPath[optimizedPath.length] = key; } if (!next) { out = undefined; shorted = true; found = false; break; } type = next.$type; // A materialized item. There is nothing to deref to. if (type === $atom && next.value === undefined) { out = undefined; found = false; shorted = depth < len; break; } // Up to the last key we follow references, ensure that they are not // expired either. if (depth < len) { if (type === $ref) { // If the reference is expired then we need to set expired to // true. if (isExpired(next)) { expired = true; out = undefined; break; } ref = followReference(model, root, root, next, next.value); refNode = ref[0]; // The next node is also set to undefined because nothing // could be found, this reference points to nothing, so // nothing must be returned. if (!refNode) { out = void 0; next = void 0; found = false; break; } type = refNode.$type; next = refNode; optimizedPath = ref[1].slice(0); } if (type) { break; } } // If there is a value, then we have great success, else, report an undefined. else { out = next; } curr = next; } if (depth < len && !expired) { // Unfortunately, if all that follows are nulls, then we have not shorted. for (i = depth; i < len; ++i) { if (simplePath[depth] !== null) { shouldShort = true; break; } } // if we should short or report value. Values are reported on nulls. if (shouldShort) { shorted = true; out = void 0; } else { out = next; } for (i = depth; i < len; ++i) { if (simplePath[i] !== null) { optimizedPath[optimizedPath.length] = simplePath[i]; } } } // promotes if not expired if (out && type) { if (isExpired(out)) { out = void 0; } else { promote(model._root, out); } } // if (out && out.$type === $error && !model._treatErrorsAsValues) { if (out && type === $error && !model._treatErrorsAsValues) { /* eslint-disable no-throw-literal */ throw { path: depth === len ? simplePath : simplePath.slice(0, depth), value: out.value }; /* eslint-enable no-throw-literal */ } else if (out && model._boxed) { out = Boolean(type) && !noClone ? clone(out) : out; } else if (!out && model._materialized) { out = {$type: $atom}; } else if (out) { out = out.value; } return { value: out, shorted: shorted, optimizedPath: optimizedPath, found: found }; };