UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

467 lines 18.8 kB
import { __assign, __extends, __rest } from "tslib"; import { invariant } from "../../utilities/globals/index.js"; import { dep } from 'optimism'; import { equal } from '@wry/equality'; import { Trie } from '@wry/trie'; import { isReference, makeReference, DeepMerger, maybeDeepFreeze, canUseWeakMap, isNonNullObject, } from "../../utilities/index.js"; import { hasOwn, fieldNameFromStoreName } from "./helpers.js"; var DELETE = Object.create(null); var delModifier = function () { return DELETE; }; var INVALIDATE = Object.create(null); var EntityStore = (function () { function EntityStore(policies, group) { var _this = this; this.policies = policies; this.group = group; this.data = Object.create(null); this.rootIds = Object.create(null); this.refs = Object.create(null); this.getFieldValue = function (objectOrReference, storeFieldName) { return maybeDeepFreeze(isReference(objectOrReference) ? _this.get(objectOrReference.__ref, storeFieldName) : objectOrReference && objectOrReference[storeFieldName]); }; this.canRead = function (objOrRef) { return isReference(objOrRef) ? _this.has(objOrRef.__ref) : typeof objOrRef === "object"; }; this.toReference = function (objOrIdOrRef, mergeIntoStore) { if (typeof objOrIdOrRef === "string") { return makeReference(objOrIdOrRef); } if (isReference(objOrIdOrRef)) { return objOrIdOrRef; } var id = _this.policies.identify(objOrIdOrRef)[0]; if (id) { var ref = makeReference(id); if (mergeIntoStore) { _this.merge(id, objOrIdOrRef); } return ref; } }; } EntityStore.prototype.toObject = function () { return __assign({}, this.data); }; EntityStore.prototype.has = function (dataId) { return this.lookup(dataId, true) !== void 0; }; EntityStore.prototype.get = function (dataId, fieldName) { this.group.depend(dataId, fieldName); if (hasOwn.call(this.data, dataId)) { var storeObject = this.data[dataId]; if (storeObject && hasOwn.call(storeObject, fieldName)) { return storeObject[fieldName]; } } if (fieldName === "__typename" && hasOwn.call(this.policies.rootTypenamesById, dataId)) { return this.policies.rootTypenamesById[dataId]; } if (this instanceof Layer) { return this.parent.get(dataId, fieldName); } }; EntityStore.prototype.lookup = function (dataId, dependOnExistence) { if (dependOnExistence) this.group.depend(dataId, "__exists"); if (hasOwn.call(this.data, dataId)) { return this.data[dataId]; } if (this instanceof Layer) { return this.parent.lookup(dataId, dependOnExistence); } if (this.policies.rootTypenamesById[dataId]) { return Object.create(null); } }; EntityStore.prototype.merge = function (older, newer) { var _this = this; var dataId; if (isReference(older)) older = older.__ref; if (isReference(newer)) newer = newer.__ref; var existing = typeof older === "string" ? this.lookup(dataId = older) : older; var incoming = typeof newer === "string" ? this.lookup(dataId = newer) : newer; if (!incoming) return; __DEV__ ? invariant(typeof dataId === "string", "store.merge expects a string ID") : invariant(typeof dataId === "string", 1); var merged = new DeepMerger(storeObjectReconciler).merge(existing, incoming); this.data[dataId] = merged; if (merged !== existing) { delete this.refs[dataId]; if (this.group.caching) { var fieldsToDirty_1 = Object.create(null); if (!existing) fieldsToDirty_1.__exists = 1; Object.keys(incoming).forEach(function (storeFieldName) { if (!existing || existing[storeFieldName] !== merged[storeFieldName]) { fieldsToDirty_1[storeFieldName] = 1; var fieldName = fieldNameFromStoreName(storeFieldName); if (fieldName !== storeFieldName && !_this.policies.hasKeyArgs(merged.__typename, fieldName)) { fieldsToDirty_1[fieldName] = 1; } if (merged[storeFieldName] === void 0 && !(_this instanceof Layer)) { delete merged[storeFieldName]; } } }); if (fieldsToDirty_1.__typename && !(existing && existing.__typename) && this.policies.rootTypenamesById[dataId] === merged.__typename) { delete fieldsToDirty_1.__typename; } Object.keys(fieldsToDirty_1).forEach(function (fieldName) { return _this.group.dirty(dataId, fieldName); }); } } }; EntityStore.prototype.modify = function (dataId, fields) { var _this = this; var storeObject = this.lookup(dataId); if (storeObject) { var changedFields_1 = Object.create(null); var needToMerge_1 = false; var allDeleted_1 = true; var sharedDetails_1 = { DELETE: DELETE, INVALIDATE: INVALIDATE, isReference: isReference, toReference: this.toReference, canRead: this.canRead, readField: function (fieldNameOrOptions, from) { return _this.policies.readField(typeof fieldNameOrOptions === "string" ? { fieldName: fieldNameOrOptions, from: from || makeReference(dataId), } : fieldNameOrOptions, { store: _this }); }, }; Object.keys(storeObject).forEach(function (storeFieldName) { var fieldName = fieldNameFromStoreName(storeFieldName); var fieldValue = storeObject[storeFieldName]; if (fieldValue === void 0) return; var modify = typeof fields === "function" ? fields : fields[storeFieldName] || fields[fieldName]; if (modify) { var newValue = modify === delModifier ? DELETE : modify(maybeDeepFreeze(fieldValue), __assign(__assign({}, sharedDetails_1), { fieldName: fieldName, storeFieldName: storeFieldName, storage: _this.getStorage(dataId, storeFieldName) })); if (newValue === INVALIDATE) { _this.group.dirty(dataId, storeFieldName); } else { if (newValue === DELETE) newValue = void 0; if (newValue !== fieldValue) { changedFields_1[storeFieldName] = newValue; needToMerge_1 = true; fieldValue = newValue; } } } if (fieldValue !== void 0) { allDeleted_1 = false; } }); if (needToMerge_1) { this.merge(dataId, changedFields_1); if (allDeleted_1) { if (this instanceof Layer) { this.data[dataId] = void 0; } else { delete this.data[dataId]; } this.group.dirty(dataId, "__exists"); } return true; } } return false; }; EntityStore.prototype.delete = function (dataId, fieldName, args) { var _a; var storeObject = this.lookup(dataId); if (storeObject) { var typename = this.getFieldValue(storeObject, "__typename"); var storeFieldName = fieldName && args ? this.policies.getStoreFieldName({ typename: typename, fieldName: fieldName, args: args }) : fieldName; return this.modify(dataId, storeFieldName ? (_a = {}, _a[storeFieldName] = delModifier, _a) : delModifier); } return false; }; EntityStore.prototype.evict = function (options, limit) { var evicted = false; if (options.id) { if (hasOwn.call(this.data, options.id)) { evicted = this.delete(options.id, options.fieldName, options.args); } if (this instanceof Layer && this !== limit) { evicted = this.parent.evict(options, limit) || evicted; } if (options.fieldName || evicted) { this.group.dirty(options.id, options.fieldName || "__exists"); } } return evicted; }; EntityStore.prototype.clear = function () { this.replace(null); }; EntityStore.prototype.extract = function () { var _this = this; var obj = this.toObject(); var extraRootIds = []; this.getRootIdSet().forEach(function (id) { if (!hasOwn.call(_this.policies.rootTypenamesById, id)) { extraRootIds.push(id); } }); if (extraRootIds.length) { obj.__META = { extraRootIds: extraRootIds.sort() }; } return obj; }; EntityStore.prototype.replace = function (newData) { var _this = this; Object.keys(this.data).forEach(function (dataId) { if (!(newData && hasOwn.call(newData, dataId))) { _this.delete(dataId); } }); if (newData) { var __META = newData.__META, rest_1 = __rest(newData, ["__META"]); Object.keys(rest_1).forEach(function (dataId) { _this.merge(dataId, rest_1[dataId]); }); if (__META) { __META.extraRootIds.forEach(this.retain, this); } } }; EntityStore.prototype.retain = function (rootId) { return this.rootIds[rootId] = (this.rootIds[rootId] || 0) + 1; }; EntityStore.prototype.release = function (rootId) { if (this.rootIds[rootId] > 0) { var count = --this.rootIds[rootId]; if (!count) delete this.rootIds[rootId]; return count; } return 0; }; EntityStore.prototype.getRootIdSet = function (ids) { if (ids === void 0) { ids = new Set(); } Object.keys(this.rootIds).forEach(ids.add, ids); if (this instanceof Layer) { this.parent.getRootIdSet(ids); } else { Object.keys(this.policies.rootTypenamesById).forEach(ids.add, ids); } return ids; }; EntityStore.prototype.gc = function () { var _this = this; var ids = this.getRootIdSet(); var snapshot = this.toObject(); ids.forEach(function (id) { if (hasOwn.call(snapshot, id)) { Object.keys(_this.findChildRefIds(id)).forEach(ids.add, ids); delete snapshot[id]; } }); var idsToRemove = Object.keys(snapshot); if (idsToRemove.length) { var root_1 = this; while (root_1 instanceof Layer) root_1 = root_1.parent; idsToRemove.forEach(function (id) { return root_1.delete(id); }); } return idsToRemove; }; EntityStore.prototype.findChildRefIds = function (dataId) { if (!hasOwn.call(this.refs, dataId)) { var found_1 = this.refs[dataId] = Object.create(null); var root = this.data[dataId]; if (!root) return found_1; var workSet_1 = new Set([root]); workSet_1.forEach(function (obj) { if (isReference(obj)) { found_1[obj.__ref] = true; } if (isNonNullObject(obj)) { Object.keys(obj).forEach(function (key) { var child = obj[key]; if (isNonNullObject(child)) { workSet_1.add(child); } }); } }); } return this.refs[dataId]; }; EntityStore.prototype.makeCacheKey = function () { return this.group.keyMaker.lookupArray(arguments); }; return EntityStore; }()); export { EntityStore }; var CacheGroup = (function () { function CacheGroup(caching, parent) { if (parent === void 0) { parent = null; } this.caching = caching; this.parent = parent; this.d = null; this.resetCaching(); } CacheGroup.prototype.resetCaching = function () { this.d = this.caching ? dep() : null; this.keyMaker = new Trie(canUseWeakMap); }; CacheGroup.prototype.depend = function (dataId, storeFieldName) { if (this.d) { this.d(makeDepKey(dataId, storeFieldName)); var fieldName = fieldNameFromStoreName(storeFieldName); if (fieldName !== storeFieldName) { this.d(makeDepKey(dataId, fieldName)); } if (this.parent) { this.parent.depend(dataId, storeFieldName); } } }; CacheGroup.prototype.dirty = function (dataId, storeFieldName) { if (this.d) { this.d.dirty(makeDepKey(dataId, storeFieldName), storeFieldName === "__exists" ? "forget" : "setDirty"); } }; return CacheGroup; }()); function makeDepKey(dataId, storeFieldName) { return storeFieldName + '#' + dataId; } export function maybeDependOnExistenceOfEntity(store, entityId) { if (supportsResultCaching(store)) { store.group.depend(entityId, "__exists"); } } (function (EntityStore) { var Root = (function (_super) { __extends(Root, _super); function Root(_a) { var policies = _a.policies, _b = _a.resultCaching, resultCaching = _b === void 0 ? true : _b, seed = _a.seed; var _this = _super.call(this, policies, new CacheGroup(resultCaching)) || this; _this.stump = new Stump(_this); _this.storageTrie = new Trie(canUseWeakMap); if (seed) _this.replace(seed); return _this; } Root.prototype.addLayer = function (layerId, replay) { return this.stump.addLayer(layerId, replay); }; Root.prototype.removeLayer = function () { return this; }; Root.prototype.getStorage = function () { return this.storageTrie.lookupArray(arguments); }; return Root; }(EntityStore)); EntityStore.Root = Root; })(EntityStore || (EntityStore = {})); var Layer = (function (_super) { __extends(Layer, _super); function Layer(id, parent, replay, group) { var _this = _super.call(this, parent.policies, group) || this; _this.id = id; _this.parent = parent; _this.replay = replay; _this.group = group; replay(_this); return _this; } Layer.prototype.addLayer = function (layerId, replay) { return new Layer(layerId, this, replay, this.group); }; Layer.prototype.removeLayer = function (layerId) { var _this = this; var parent = this.parent.removeLayer(layerId); if (layerId === this.id) { if (this.group.caching) { Object.keys(this.data).forEach(function (dataId) { var ownStoreObject = _this.data[dataId]; var parentStoreObject = parent["lookup"](dataId); if (!parentStoreObject) { _this.delete(dataId); } else if (!ownStoreObject) { _this.group.dirty(dataId, "__exists"); Object.keys(parentStoreObject).forEach(function (storeFieldName) { _this.group.dirty(dataId, storeFieldName); }); } else if (ownStoreObject !== parentStoreObject) { Object.keys(ownStoreObject).forEach(function (storeFieldName) { if (!equal(ownStoreObject[storeFieldName], parentStoreObject[storeFieldName])) { _this.group.dirty(dataId, storeFieldName); } }); } }); } return parent; } if (parent === this.parent) return this; return parent.addLayer(this.id, this.replay); }; Layer.prototype.toObject = function () { return __assign(__assign({}, this.parent.toObject()), this.data); }; Layer.prototype.findChildRefIds = function (dataId) { var fromParent = this.parent.findChildRefIds(dataId); return hasOwn.call(this.data, dataId) ? __assign(__assign({}, fromParent), _super.prototype.findChildRefIds.call(this, dataId)) : fromParent; }; Layer.prototype.getStorage = function () { var p = this.parent; while (p.parent) p = p.parent; return p.getStorage.apply(p, arguments); }; return Layer; }(EntityStore)); var Stump = (function (_super) { __extends(Stump, _super); function Stump(root) { return _super.call(this, "EntityStore.Stump", root, function () { }, new CacheGroup(root.group.caching, root.group)) || this; } Stump.prototype.removeLayer = function () { return this; }; Stump.prototype.merge = function () { return this.parent.merge.apply(this.parent, arguments); }; return Stump; }(Layer)); function storeObjectReconciler(existingObject, incomingObject, property) { var existingValue = existingObject[property]; var incomingValue = incomingObject[property]; return equal(existingValue, incomingValue) ? existingValue : incomingValue; } export function supportsResultCaching(store) { return !!(store instanceof EntityStore && store.group.caching); } //# sourceMappingURL=entityStore.js.map