1 | import { __assign, __extends, __rest } from "tslib";
|
2 | import { invariant } from "../../utilities/globals/index.js";
|
3 | import { dep } from 'optimism';
|
4 | import { equal } from '@wry/equality';
|
5 | import { Trie } from '@wry/trie';
|
6 | import { isReference, makeReference, DeepMerger, maybeDeepFreeze, canUseWeakMap, isNonNullObject, } from "../../utilities/index.js";
|
7 | import { hasOwn, fieldNameFromStoreName } from "./helpers.js";
|
8 | var DELETE = Object.create(null);
|
9 | var delModifier = function () { return DELETE; };
|
10 | var INVALIDATE = Object.create(null);
|
11 | var 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 | }());
|
320 | export { EntityStore };
|
321 | var 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 | }());
|
352 | function makeDepKey(dataId, storeFieldName) {
|
353 | return storeFieldName + '#' + dataId;
|
354 | }
|
355 | export 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 = {}));
|
385 | var 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));
|
446 | var 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));
|
459 | function storeObjectReconciler(existingObject, incomingObject, property) {
|
460 | var existingValue = existingObject[property];
|
461 | var incomingValue = incomingObject[property];
|
462 | return equal(existingValue, incomingValue) ? existingValue : incomingValue;
|
463 | }
|
464 | export function supportsResultCaching(store) {
|
465 | return !!(store instanceof EntityStore && store.group.caching);
|
466 | }
|
467 |
|
\ | No newline at end of file |