UNPKG

18.8 kBJavaScriptView Raw
1import { __assign, __extends, __rest } from "tslib";
2import { invariant } from "../../utilities/globals/index.js";
3import { dep } from 'optimism';
4import { equal } from '@wry/equality';
5import { Trie } from '@wry/trie';
6import { isReference, makeReference, DeepMerger, maybeDeepFreeze, canUseWeakMap, isNonNullObject, } from "../../utilities/index.js";
7import { hasOwn, fieldNameFromStoreName } from "./helpers.js";
8var DELETE = Object.create(null);
9var delModifier = function () { return DELETE; };
10var INVALIDATE = Object.create(null);
11var EntityStore = (function () {
12 function EntityStore(policies, group) {
13 var _this = this;
14 this.policies = policies;
15 this.group = group;
16 this.data = Object.create(null);
17 this.rootIds = Object.create(null);
18 this.refs = Object.create(null);
19 this.getFieldValue = function (objectOrReference, storeFieldName) { return maybeDeepFreeze(isReference(objectOrReference)
20 ? _this.get(objectOrReference.__ref, storeFieldName)
21 : objectOrReference && objectOrReference[storeFieldName]); };
22 this.canRead = function (objOrRef) {
23 return isReference(objOrRef)
24 ? _this.has(objOrRef.__ref)
25 : typeof objOrRef === "object";
26 };
27 this.toReference = function (objOrIdOrRef, mergeIntoStore) {
28 if (typeof objOrIdOrRef === "string") {
29 return makeReference(objOrIdOrRef);
30 }
31 if (isReference(objOrIdOrRef)) {
32 return objOrIdOrRef;
33 }
34 var id = _this.policies.identify(objOrIdOrRef)[0];
35 if (id) {
36 var ref = makeReference(id);
37 if (mergeIntoStore) {
38 _this.merge(id, objOrIdOrRef);
39 }
40 return ref;
41 }
42 };
43 }
44 EntityStore.prototype.toObject = function () {
45 return __assign({}, this.data);
46 };
47 EntityStore.prototype.has = function (dataId) {
48 return this.lookup(dataId, true) !== void 0;
49 };
50 EntityStore.prototype.get = function (dataId, fieldName) {
51 this.group.depend(dataId, fieldName);
52 if (hasOwn.call(this.data, dataId)) {
53 var storeObject = this.data[dataId];
54 if (storeObject && hasOwn.call(storeObject, fieldName)) {
55 return storeObject[fieldName];
56 }
57 }
58 if (fieldName === "__typename" &&
59 hasOwn.call(this.policies.rootTypenamesById, dataId)) {
60 return this.policies.rootTypenamesById[dataId];
61 }
62 if (this instanceof Layer) {
63 return this.parent.get(dataId, fieldName);
64 }
65 };
66 EntityStore.prototype.lookup = function (dataId, dependOnExistence) {
67 if (dependOnExistence)
68 this.group.depend(dataId, "__exists");
69 if (hasOwn.call(this.data, dataId)) {
70 return this.data[dataId];
71 }
72 if (this instanceof Layer) {
73 return this.parent.lookup(dataId, dependOnExistence);
74 }
75 if (this.policies.rootTypenamesById[dataId]) {
76 return Object.create(null);
77 }
78 };
79 EntityStore.prototype.merge = function (older, newer) {
80 var _this = this;
81 var dataId;
82 if (isReference(older))
83 older = older.__ref;
84 if (isReference(newer))
85 newer = newer.__ref;
86 var existing = typeof older === "string"
87 ? this.lookup(dataId = older)
88 : older;
89 var incoming = typeof newer === "string"
90 ? this.lookup(dataId = newer)
91 : newer;
92 if (!incoming)
93 return;
94 __DEV__ ? invariant(typeof dataId === "string", "store.merge expects a string ID") : invariant(typeof dataId === "string", 1);
95 var merged = new DeepMerger(storeObjectReconciler).merge(existing, incoming);
96 this.data[dataId] = merged;
97 if (merged !== existing) {
98 delete this.refs[dataId];
99 if (this.group.caching) {
100 var fieldsToDirty_1 = Object.create(null);
101 if (!existing)
102 fieldsToDirty_1.__exists = 1;
103 Object.keys(incoming).forEach(function (storeFieldName) {
104 if (!existing || existing[storeFieldName] !== merged[storeFieldName]) {
105 fieldsToDirty_1[storeFieldName] = 1;
106 var fieldName = fieldNameFromStoreName(storeFieldName);
107 if (fieldName !== storeFieldName &&
108 !_this.policies.hasKeyArgs(merged.__typename, fieldName)) {
109 fieldsToDirty_1[fieldName] = 1;
110 }
111 if (merged[storeFieldName] === void 0 && !(_this instanceof Layer)) {
112 delete merged[storeFieldName];
113 }
114 }
115 });
116 if (fieldsToDirty_1.__typename &&
117 !(existing && existing.__typename) &&
118 this.policies.rootTypenamesById[dataId] === merged.__typename) {
119 delete fieldsToDirty_1.__typename;
120 }
121 Object.keys(fieldsToDirty_1).forEach(function (fieldName) { return _this.group.dirty(dataId, fieldName); });
122 }
123 }
124 };
125 EntityStore.prototype.modify = function (dataId, fields) {
126 var _this = this;
127 var storeObject = this.lookup(dataId);
128 if (storeObject) {
129 var changedFields_1 = Object.create(null);
130 var needToMerge_1 = false;
131 var allDeleted_1 = true;
132 var sharedDetails_1 = {
133 DELETE: DELETE,
134 INVALIDATE: INVALIDATE,
135 isReference: isReference,
136 toReference: this.toReference,
137 canRead: this.canRead,
138 readField: function (fieldNameOrOptions, from) { return _this.policies.readField(typeof fieldNameOrOptions === "string" ? {
139 fieldName: fieldNameOrOptions,
140 from: from || makeReference(dataId),
141 } : fieldNameOrOptions, { store: _this }); },
142 };
143 Object.keys(storeObject).forEach(function (storeFieldName) {
144 var fieldName = fieldNameFromStoreName(storeFieldName);
145 var fieldValue = storeObject[storeFieldName];
146 if (fieldValue === void 0)
147 return;
148 var modify = typeof fields === "function"
149 ? fields
150 : fields[storeFieldName] || fields[fieldName];
151 if (modify) {
152 var newValue = modify === delModifier ? DELETE :
153 modify(maybeDeepFreeze(fieldValue), __assign(__assign({}, sharedDetails_1), { fieldName: fieldName, storeFieldName: storeFieldName, storage: _this.getStorage(dataId, storeFieldName) }));
154 if (newValue === INVALIDATE) {
155 _this.group.dirty(dataId, storeFieldName);
156 }
157 else {
158 if (newValue === DELETE)
159 newValue = void 0;
160 if (newValue !== fieldValue) {
161 changedFields_1[storeFieldName] = newValue;
162 needToMerge_1 = true;
163 fieldValue = newValue;
164 }
165 }
166 }
167 if (fieldValue !== void 0) {
168 allDeleted_1 = false;
169 }
170 });
171 if (needToMerge_1) {
172 this.merge(dataId, changedFields_1);
173 if (allDeleted_1) {
174 if (this instanceof Layer) {
175 this.data[dataId] = void 0;
176 }
177 else {
178 delete this.data[dataId];
179 }
180 this.group.dirty(dataId, "__exists");
181 }
182 return true;
183 }
184 }
185 return false;
186 };
187 EntityStore.prototype.delete = function (dataId, fieldName, args) {
188 var _a;
189 var storeObject = this.lookup(dataId);
190 if (storeObject) {
191 var typename = this.getFieldValue(storeObject, "__typename");
192 var storeFieldName = fieldName && args
193 ? this.policies.getStoreFieldName({ typename: typename, fieldName: fieldName, args: args })
194 : fieldName;
195 return this.modify(dataId, storeFieldName ? (_a = {},
196 _a[storeFieldName] = delModifier,
197 _a) : delModifier);
198 }
199 return false;
200 };
201 EntityStore.prototype.evict = function (options, limit) {
202 var evicted = false;
203 if (options.id) {
204 if (hasOwn.call(this.data, options.id)) {
205 evicted = this.delete(options.id, options.fieldName, options.args);
206 }
207 if (this instanceof Layer && this !== limit) {
208 evicted = this.parent.evict(options, limit) || evicted;
209 }
210 if (options.fieldName || evicted) {
211 this.group.dirty(options.id, options.fieldName || "__exists");
212 }
213 }
214 return evicted;
215 };
216 EntityStore.prototype.clear = function () {
217 this.replace(null);
218 };
219 EntityStore.prototype.extract = function () {
220 var _this = this;
221 var obj = this.toObject();
222 var extraRootIds = [];
223 this.getRootIdSet().forEach(function (id) {
224 if (!hasOwn.call(_this.policies.rootTypenamesById, id)) {
225 extraRootIds.push(id);
226 }
227 });
228 if (extraRootIds.length) {
229 obj.__META = { extraRootIds: extraRootIds.sort() };
230 }
231 return obj;
232 };
233 EntityStore.prototype.replace = function (newData) {
234 var _this = this;
235 Object.keys(this.data).forEach(function (dataId) {
236 if (!(newData && hasOwn.call(newData, dataId))) {
237 _this.delete(dataId);
238 }
239 });
240 if (newData) {
241 var __META = newData.__META, rest_1 = __rest(newData, ["__META"]);
242 Object.keys(rest_1).forEach(function (dataId) {
243 _this.merge(dataId, rest_1[dataId]);
244 });
245 if (__META) {
246 __META.extraRootIds.forEach(this.retain, this);
247 }
248 }
249 };
250 EntityStore.prototype.retain = function (rootId) {
251 return this.rootIds[rootId] = (this.rootIds[rootId] || 0) + 1;
252 };
253 EntityStore.prototype.release = function (rootId) {
254 if (this.rootIds[rootId] > 0) {
255 var count = --this.rootIds[rootId];
256 if (!count)
257 delete this.rootIds[rootId];
258 return count;
259 }
260 return 0;
261 };
262 EntityStore.prototype.getRootIdSet = function (ids) {
263 if (ids === void 0) { ids = new Set(); }
264 Object.keys(this.rootIds).forEach(ids.add, ids);
265 if (this instanceof Layer) {
266 this.parent.getRootIdSet(ids);
267 }
268 else {
269 Object.keys(this.policies.rootTypenamesById).forEach(ids.add, ids);
270 }
271 return ids;
272 };
273 EntityStore.prototype.gc = function () {
274 var _this = this;
275 var ids = this.getRootIdSet();
276 var snapshot = this.toObject();
277 ids.forEach(function (id) {
278 if (hasOwn.call(snapshot, id)) {
279 Object.keys(_this.findChildRefIds(id)).forEach(ids.add, ids);
280 delete snapshot[id];
281 }
282 });
283 var idsToRemove = Object.keys(snapshot);
284 if (idsToRemove.length) {
285 var root_1 = this;
286 while (root_1 instanceof Layer)
287 root_1 = root_1.parent;
288 idsToRemove.forEach(function (id) { return root_1.delete(id); });
289 }
290 return idsToRemove;
291 };
292 EntityStore.prototype.findChildRefIds = function (dataId) {
293 if (!hasOwn.call(this.refs, dataId)) {
294 var found_1 = this.refs[dataId] = Object.create(null);
295 var root = this.data[dataId];
296 if (!root)
297 return found_1;
298 var workSet_1 = new Set([root]);
299 workSet_1.forEach(function (obj) {
300 if (isReference(obj)) {
301 found_1[obj.__ref] = true;
302 }
303 if (isNonNullObject(obj)) {
304 Object.keys(obj).forEach(function (key) {
305 var child = obj[key];
306 if (isNonNullObject(child)) {
307 workSet_1.add(child);
308 }
309 });
310 }
311 });
312 }
313 return this.refs[dataId];
314 };
315 EntityStore.prototype.makeCacheKey = function () {
316 return this.group.keyMaker.lookupArray(arguments);
317 };
318 return EntityStore;
319}());
320export { EntityStore };
321var CacheGroup = (function () {
322 function CacheGroup(caching, parent) {
323 if (parent === void 0) { parent = null; }
324 this.caching = caching;
325 this.parent = parent;
326 this.d = null;
327 this.resetCaching();
328 }
329 CacheGroup.prototype.resetCaching = function () {
330 this.d = this.caching ? dep() : null;
331 this.keyMaker = new Trie(canUseWeakMap);
332 };
333 CacheGroup.prototype.depend = function (dataId, storeFieldName) {
334 if (this.d) {
335 this.d(makeDepKey(dataId, storeFieldName));
336 var fieldName = fieldNameFromStoreName(storeFieldName);
337 if (fieldName !== storeFieldName) {
338 this.d(makeDepKey(dataId, fieldName));
339 }
340 if (this.parent) {
341 this.parent.depend(dataId, storeFieldName);
342 }
343 }
344 };
345 CacheGroup.prototype.dirty = function (dataId, storeFieldName) {
346 if (this.d) {
347 this.d.dirty(makeDepKey(dataId, storeFieldName), storeFieldName === "__exists" ? "forget" : "setDirty");
348 }
349 };
350 return CacheGroup;
351}());
352function makeDepKey(dataId, storeFieldName) {
353 return storeFieldName + '#' + dataId;
354}
355export function maybeDependOnExistenceOfEntity(store, entityId) {
356 if (supportsResultCaching(store)) {
357 store.group.depend(entityId, "__exists");
358 }
359}
360(function (EntityStore) {
361 var Root = (function (_super) {
362 __extends(Root, _super);
363 function Root(_a) {
364 var policies = _a.policies, _b = _a.resultCaching, resultCaching = _b === void 0 ? true : _b, seed = _a.seed;
365 var _this = _super.call(this, policies, new CacheGroup(resultCaching)) || this;
366 _this.stump = new Stump(_this);
367 _this.storageTrie = new Trie(canUseWeakMap);
368 if (seed)
369 _this.replace(seed);
370 return _this;
371 }
372 Root.prototype.addLayer = function (layerId, replay) {
373 return this.stump.addLayer(layerId, replay);
374 };
375 Root.prototype.removeLayer = function () {
376 return this;
377 };
378 Root.prototype.getStorage = function () {
379 return this.storageTrie.lookupArray(arguments);
380 };
381 return Root;
382 }(EntityStore));
383 EntityStore.Root = Root;
384})(EntityStore || (EntityStore = {}));
385var Layer = (function (_super) {
386 __extends(Layer, _super);
387 function Layer(id, parent, replay, group) {
388 var _this = _super.call(this, parent.policies, group) || this;
389 _this.id = id;
390 _this.parent = parent;
391 _this.replay = replay;
392 _this.group = group;
393 replay(_this);
394 return _this;
395 }
396 Layer.prototype.addLayer = function (layerId, replay) {
397 return new Layer(layerId, this, replay, this.group);
398 };
399 Layer.prototype.removeLayer = function (layerId) {
400 var _this = this;
401 var parent = this.parent.removeLayer(layerId);
402 if (layerId === this.id) {
403 if (this.group.caching) {
404 Object.keys(this.data).forEach(function (dataId) {
405 var ownStoreObject = _this.data[dataId];
406 var parentStoreObject = parent["lookup"](dataId);
407 if (!parentStoreObject) {
408 _this.delete(dataId);
409 }
410 else if (!ownStoreObject) {
411 _this.group.dirty(dataId, "__exists");
412 Object.keys(parentStoreObject).forEach(function (storeFieldName) {
413 _this.group.dirty(dataId, storeFieldName);
414 });
415 }
416 else if (ownStoreObject !== parentStoreObject) {
417 Object.keys(ownStoreObject).forEach(function (storeFieldName) {
418 if (!equal(ownStoreObject[storeFieldName], parentStoreObject[storeFieldName])) {
419 _this.group.dirty(dataId, storeFieldName);
420 }
421 });
422 }
423 });
424 }
425 return parent;
426 }
427 if (parent === this.parent)
428 return this;
429 return parent.addLayer(this.id, this.replay);
430 };
431 Layer.prototype.toObject = function () {
432 return __assign(__assign({}, this.parent.toObject()), this.data);
433 };
434 Layer.prototype.findChildRefIds = function (dataId) {
435 var fromParent = this.parent.findChildRefIds(dataId);
436 return hasOwn.call(this.data, dataId) ? __assign(__assign({}, fromParent), _super.prototype.findChildRefIds.call(this, dataId)) : fromParent;
437 };
438 Layer.prototype.getStorage = function () {
439 var p = this.parent;
440 while (p.parent)
441 p = p.parent;
442 return p.getStorage.apply(p, arguments);
443 };
444 return Layer;
445}(EntityStore));
446var Stump = (function (_super) {
447 __extends(Stump, _super);
448 function Stump(root) {
449 return _super.call(this, "EntityStore.Stump", root, function () { }, new CacheGroup(root.group.caching, root.group)) || this;
450 }
451 Stump.prototype.removeLayer = function () {
452 return this;
453 };
454 Stump.prototype.merge = function () {
455 return this.parent.merge.apply(this.parent, arguments);
456 };
457 return Stump;
458}(Layer));
459function storeObjectReconciler(existingObject, incomingObject, property) {
460 var existingValue = existingObject[property];
461 var incomingValue = incomingObject[property];
462 return equal(existingValue, incomingValue) ? existingValue : incomingValue;
463}
464export function supportsResultCaching(store) {
465 return !!(store instanceof EntityStore && store.group.caching);
466}
467//# sourceMappingURL=entityStore.js.map
\No newline at end of file