1 | import { __assign, __rest } from "tslib";
|
2 | import { invariant, InvariantError } from "../../utilities/globals/index.js";
|
3 | import { storeKeyNameFromField, argumentsObjectFromField, isReference, getStoreKeyName, isNonNullObject, stringifyForDisplay, } from "../../utilities/index.js";
|
4 | import { hasOwn, fieldNameFromStoreName, storeValueIsStoreObject, selectionSetMatchesResult, TypeOrFieldNameRegExp, defaultDataIdFromObject, isArray, } from "./helpers.js";
|
5 | import { cacheSlot } from "./reactiveVars.js";
|
6 | import { canonicalStringify } from "./object-canon.js";
|
7 | import { keyArgsFnFromSpecifier, keyFieldsFnFromSpecifier } from "./key-extractor.js";
|
8 | getStoreKeyName.setStringify(canonicalStringify);
|
9 | function argsFromFieldSpecifier(spec) {
|
10 | return spec.args !== void 0 ? spec.args :
|
11 | spec.field ? argumentsObjectFromField(spec.field, spec.variables) : null;
|
12 | }
|
13 | var nullKeyFieldsFn = function () { return void 0; };
|
14 | var simpleKeyArgsFn = function (_args, context) { return context.fieldName; };
|
15 | var mergeTrueFn = function (existing, incoming, _a) {
|
16 | var mergeObjects = _a.mergeObjects;
|
17 | return mergeObjects(existing, incoming);
|
18 | };
|
19 | var mergeFalseFn = function (_, incoming) { return incoming; };
|
20 | var Policies = (function () {
|
21 | function Policies(config) {
|
22 | this.config = config;
|
23 | this.typePolicies = Object.create(null);
|
24 | this.toBeAdded = Object.create(null);
|
25 | this.supertypeMap = new Map();
|
26 | this.fuzzySubtypes = new Map();
|
27 | this.rootIdsByTypename = Object.create(null);
|
28 | this.rootTypenamesById = Object.create(null);
|
29 | this.usingPossibleTypes = false;
|
30 | this.config = __assign({ dataIdFromObject: defaultDataIdFromObject }, config);
|
31 | this.cache = this.config.cache;
|
32 | this.setRootTypename("Query");
|
33 | this.setRootTypename("Mutation");
|
34 | this.setRootTypename("Subscription");
|
35 | if (config.possibleTypes) {
|
36 | this.addPossibleTypes(config.possibleTypes);
|
37 | }
|
38 | if (config.typePolicies) {
|
39 | this.addTypePolicies(config.typePolicies);
|
40 | }
|
41 | }
|
42 | Policies.prototype.identify = function (object, partialContext) {
|
43 | var _a;
|
44 | var policies = this;
|
45 | var typename = partialContext && (partialContext.typename ||
|
46 | ((_a = partialContext.storeObject) === null || _a === void 0 ? void 0 : _a.__typename)) || object.__typename;
|
47 | if (typename === this.rootTypenamesById.ROOT_QUERY) {
|
48 | return ["ROOT_QUERY"];
|
49 | }
|
50 | var storeObject = partialContext && partialContext.storeObject || object;
|
51 | var context = __assign(__assign({}, partialContext), { typename: typename, storeObject: storeObject, readField: partialContext && partialContext.readField || function () {
|
52 | var options = normalizeReadFieldOptions(arguments, storeObject);
|
53 | return policies.readField(options, {
|
54 | store: policies.cache["data"],
|
55 | variables: options.variables,
|
56 | });
|
57 | } });
|
58 | var id;
|
59 | var policy = typename && this.getTypePolicy(typename);
|
60 | var keyFn = policy && policy.keyFn || this.config.dataIdFromObject;
|
61 | while (keyFn) {
|
62 | var specifierOrId = keyFn(object, context);
|
63 | if (isArray(specifierOrId)) {
|
64 | keyFn = keyFieldsFnFromSpecifier(specifierOrId);
|
65 | }
|
66 | else {
|
67 | id = specifierOrId;
|
68 | break;
|
69 | }
|
70 | }
|
71 | id = id ? String(id) : void 0;
|
72 | return context.keyObject ? [id, context.keyObject] : [id];
|
73 | };
|
74 | Policies.prototype.addTypePolicies = function (typePolicies) {
|
75 | var _this = this;
|
76 | Object.keys(typePolicies).forEach(function (typename) {
|
77 | var _a = typePolicies[typename], queryType = _a.queryType, mutationType = _a.mutationType, subscriptionType = _a.subscriptionType, incoming = __rest(_a, ["queryType", "mutationType", "subscriptionType"]);
|
78 | if (queryType)
|
79 | _this.setRootTypename("Query", typename);
|
80 | if (mutationType)
|
81 | _this.setRootTypename("Mutation", typename);
|
82 | if (subscriptionType)
|
83 | _this.setRootTypename("Subscription", typename);
|
84 | if (hasOwn.call(_this.toBeAdded, typename)) {
|
85 | _this.toBeAdded[typename].push(incoming);
|
86 | }
|
87 | else {
|
88 | _this.toBeAdded[typename] = [incoming];
|
89 | }
|
90 | });
|
91 | };
|
92 | Policies.prototype.updateTypePolicy = function (typename, incoming) {
|
93 | var _this = this;
|
94 | var existing = this.getTypePolicy(typename);
|
95 | var keyFields = incoming.keyFields, fields = incoming.fields;
|
96 | function setMerge(existing, merge) {
|
97 | existing.merge =
|
98 | typeof merge === "function" ? merge :
|
99 | merge === true ? mergeTrueFn :
|
100 | merge === false ? mergeFalseFn :
|
101 | existing.merge;
|
102 | }
|
103 | setMerge(existing, incoming.merge);
|
104 | existing.keyFn =
|
105 | keyFields === false ? nullKeyFieldsFn :
|
106 | isArray(keyFields) ? keyFieldsFnFromSpecifier(keyFields) :
|
107 | typeof keyFields === "function" ? keyFields :
|
108 | existing.keyFn;
|
109 | if (fields) {
|
110 | Object.keys(fields).forEach(function (fieldName) {
|
111 | var existing = _this.getFieldPolicy(typename, fieldName, true);
|
112 | var incoming = fields[fieldName];
|
113 | if (typeof incoming === "function") {
|
114 | existing.read = incoming;
|
115 | }
|
116 | else {
|
117 | var keyArgs = incoming.keyArgs, read = incoming.read, merge = incoming.merge;
|
118 | existing.keyFn =
|
119 | keyArgs === false ? simpleKeyArgsFn :
|
120 | isArray(keyArgs) ? keyArgsFnFromSpecifier(keyArgs) :
|
121 | typeof keyArgs === "function" ? keyArgs :
|
122 | existing.keyFn;
|
123 | if (typeof read === "function") {
|
124 | existing.read = read;
|
125 | }
|
126 | setMerge(existing, merge);
|
127 | }
|
128 | if (existing.read && existing.merge) {
|
129 | existing.keyFn = existing.keyFn || simpleKeyArgsFn;
|
130 | }
|
131 | });
|
132 | }
|
133 | };
|
134 | Policies.prototype.setRootTypename = function (which, typename) {
|
135 | if (typename === void 0) { typename = which; }
|
136 | var rootId = "ROOT_" + which.toUpperCase();
|
137 | var old = this.rootTypenamesById[rootId];
|
138 | if (typename !== old) {
|
139 | __DEV__ ? invariant(!old || old === which, "Cannot change root ".concat(which, " __typename more than once")) : invariant(!old || old === which, 3);
|
140 | if (old)
|
141 | delete this.rootIdsByTypename[old];
|
142 | this.rootIdsByTypename[typename] = rootId;
|
143 | this.rootTypenamesById[rootId] = typename;
|
144 | }
|
145 | };
|
146 | Policies.prototype.addPossibleTypes = function (possibleTypes) {
|
147 | var _this = this;
|
148 | this.usingPossibleTypes = true;
|
149 | Object.keys(possibleTypes).forEach(function (supertype) {
|
150 | _this.getSupertypeSet(supertype, true);
|
151 | possibleTypes[supertype].forEach(function (subtype) {
|
152 | _this.getSupertypeSet(subtype, true).add(supertype);
|
153 | var match = subtype.match(TypeOrFieldNameRegExp);
|
154 | if (!match || match[0] !== subtype) {
|
155 | _this.fuzzySubtypes.set(subtype, new RegExp(subtype));
|
156 | }
|
157 | });
|
158 | });
|
159 | };
|
160 | Policies.prototype.getTypePolicy = function (typename) {
|
161 | var _this = this;
|
162 | if (!hasOwn.call(this.typePolicies, typename)) {
|
163 | var policy_1 = this.typePolicies[typename] = Object.create(null);
|
164 | policy_1.fields = Object.create(null);
|
165 | var supertypes = this.supertypeMap.get(typename);
|
166 | if (supertypes && supertypes.size) {
|
167 | supertypes.forEach(function (supertype) {
|
168 | var _a = _this.getTypePolicy(supertype), fields = _a.fields, rest = __rest(_a, ["fields"]);
|
169 | Object.assign(policy_1, rest);
|
170 | Object.assign(policy_1.fields, fields);
|
171 | });
|
172 | }
|
173 | }
|
174 | var inbox = this.toBeAdded[typename];
|
175 | if (inbox && inbox.length) {
|
176 | inbox.splice(0).forEach(function (policy) {
|
177 | _this.updateTypePolicy(typename, policy);
|
178 | });
|
179 | }
|
180 | return this.typePolicies[typename];
|
181 | };
|
182 | Policies.prototype.getFieldPolicy = function (typename, fieldName, createIfMissing) {
|
183 | if (typename) {
|
184 | var fieldPolicies = this.getTypePolicy(typename).fields;
|
185 | return fieldPolicies[fieldName] || (createIfMissing && (fieldPolicies[fieldName] = Object.create(null)));
|
186 | }
|
187 | };
|
188 | Policies.prototype.getSupertypeSet = function (subtype, createIfMissing) {
|
189 | var supertypeSet = this.supertypeMap.get(subtype);
|
190 | if (!supertypeSet && createIfMissing) {
|
191 | this.supertypeMap.set(subtype, supertypeSet = new Set());
|
192 | }
|
193 | return supertypeSet;
|
194 | };
|
195 | Policies.prototype.fragmentMatches = function (fragment, typename, result, variables) {
|
196 | var _this = this;
|
197 | if (!fragment.typeCondition)
|
198 | return true;
|
199 | if (!typename)
|
200 | return false;
|
201 | var supertype = fragment.typeCondition.name.value;
|
202 | if (typename === supertype)
|
203 | return true;
|
204 | if (this.usingPossibleTypes &&
|
205 | this.supertypeMap.has(supertype)) {
|
206 | var typenameSupertypeSet = this.getSupertypeSet(typename, true);
|
207 | var workQueue_1 = [typenameSupertypeSet];
|
208 | var maybeEnqueue_1 = function (subtype) {
|
209 | var supertypeSet = _this.getSupertypeSet(subtype, false);
|
210 | if (supertypeSet &&
|
211 | supertypeSet.size &&
|
212 | workQueue_1.indexOf(supertypeSet) < 0) {
|
213 | workQueue_1.push(supertypeSet);
|
214 | }
|
215 | };
|
216 | var needToCheckFuzzySubtypes = !!(result && this.fuzzySubtypes.size);
|
217 | var checkingFuzzySubtypes = false;
|
218 | for (var i = 0; i < workQueue_1.length; ++i) {
|
219 | var supertypeSet = workQueue_1[i];
|
220 | if (supertypeSet.has(supertype)) {
|
221 | if (!typenameSupertypeSet.has(supertype)) {
|
222 | if (checkingFuzzySubtypes) {
|
223 | __DEV__ && invariant.warn("Inferring subtype ".concat(typename, " of supertype ").concat(supertype));
|
224 | }
|
225 | typenameSupertypeSet.add(supertype);
|
226 | }
|
227 | return true;
|
228 | }
|
229 | supertypeSet.forEach(maybeEnqueue_1);
|
230 | if (needToCheckFuzzySubtypes &&
|
231 | i === workQueue_1.length - 1 &&
|
232 | selectionSetMatchesResult(fragment.selectionSet, result, variables)) {
|
233 | needToCheckFuzzySubtypes = false;
|
234 | checkingFuzzySubtypes = true;
|
235 | this.fuzzySubtypes.forEach(function (regExp, fuzzyString) {
|
236 | var match = typename.match(regExp);
|
237 | if (match && match[0] === typename) {
|
238 | maybeEnqueue_1(fuzzyString);
|
239 | }
|
240 | });
|
241 | }
|
242 | }
|
243 | }
|
244 | return false;
|
245 | };
|
246 | Policies.prototype.hasKeyArgs = function (typename, fieldName) {
|
247 | var policy = this.getFieldPolicy(typename, fieldName, false);
|
248 | return !!(policy && policy.keyFn);
|
249 | };
|
250 | Policies.prototype.getStoreFieldName = function (fieldSpec) {
|
251 | var typename = fieldSpec.typename, fieldName = fieldSpec.fieldName;
|
252 | var policy = this.getFieldPolicy(typename, fieldName, false);
|
253 | var storeFieldName;
|
254 | var keyFn = policy && policy.keyFn;
|
255 | if (keyFn && typename) {
|
256 | var context = {
|
257 | typename: typename,
|
258 | fieldName: fieldName,
|
259 | field: fieldSpec.field || null,
|
260 | variables: fieldSpec.variables,
|
261 | };
|
262 | var args = argsFromFieldSpecifier(fieldSpec);
|
263 | while (keyFn) {
|
264 | var specifierOrString = keyFn(args, context);
|
265 | if (isArray(specifierOrString)) {
|
266 | keyFn = keyArgsFnFromSpecifier(specifierOrString);
|
267 | }
|
268 | else {
|
269 | storeFieldName = specifierOrString || fieldName;
|
270 | break;
|
271 | }
|
272 | }
|
273 | }
|
274 | if (storeFieldName === void 0) {
|
275 | storeFieldName = fieldSpec.field
|
276 | ? storeKeyNameFromField(fieldSpec.field, fieldSpec.variables)
|
277 | : getStoreKeyName(fieldName, argsFromFieldSpecifier(fieldSpec));
|
278 | }
|
279 | if (storeFieldName === false) {
|
280 | return fieldName;
|
281 | }
|
282 | return fieldName === fieldNameFromStoreName(storeFieldName)
|
283 | ? storeFieldName
|
284 | : fieldName + ":" + storeFieldName;
|
285 | };
|
286 | Policies.prototype.readField = function (options, context) {
|
287 | var objectOrReference = options.from;
|
288 | if (!objectOrReference)
|
289 | return;
|
290 | var nameOrField = options.field || options.fieldName;
|
291 | if (!nameOrField)
|
292 | return;
|
293 | if (options.typename === void 0) {
|
294 | var typename = context.store.getFieldValue(objectOrReference, "__typename");
|
295 | if (typename)
|
296 | options.typename = typename;
|
297 | }
|
298 | var storeFieldName = this.getStoreFieldName(options);
|
299 | var fieldName = fieldNameFromStoreName(storeFieldName);
|
300 | var existing = context.store.getFieldValue(objectOrReference, storeFieldName);
|
301 | var policy = this.getFieldPolicy(options.typename, fieldName, false);
|
302 | var read = policy && policy.read;
|
303 | if (read) {
|
304 | var readOptions = makeFieldFunctionOptions(this, objectOrReference, options, context, context.store.getStorage(isReference(objectOrReference)
|
305 | ? objectOrReference.__ref
|
306 | : objectOrReference, storeFieldName));
|
307 | return cacheSlot.withValue(this.cache, read, [existing, readOptions]);
|
308 | }
|
309 | return existing;
|
310 | };
|
311 | Policies.prototype.getReadFunction = function (typename, fieldName) {
|
312 | var policy = this.getFieldPolicy(typename, fieldName, false);
|
313 | return policy && policy.read;
|
314 | };
|
315 | Policies.prototype.getMergeFunction = function (parentTypename, fieldName, childTypename) {
|
316 | var policy = this.getFieldPolicy(parentTypename, fieldName, false);
|
317 | var merge = policy && policy.merge;
|
318 | if (!merge && childTypename) {
|
319 | policy = this.getTypePolicy(childTypename);
|
320 | merge = policy && policy.merge;
|
321 | }
|
322 | return merge;
|
323 | };
|
324 | Policies.prototype.runMergeFunction = function (existing, incoming, _a, context, storage) {
|
325 | var field = _a.field, typename = _a.typename, merge = _a.merge;
|
326 | if (merge === mergeTrueFn) {
|
327 | return makeMergeObjectsFunction(context.store)(existing, incoming);
|
328 | }
|
329 | if (merge === mergeFalseFn) {
|
330 | return incoming;
|
331 | }
|
332 | if (context.overwrite) {
|
333 | existing = void 0;
|
334 | }
|
335 | return merge(existing, incoming, makeFieldFunctionOptions(this, void 0, { typename: typename, fieldName: field.name.value, field: field, variables: context.variables }, context, storage || Object.create(null)));
|
336 | };
|
337 | return Policies;
|
338 | }());
|
339 | export { Policies };
|
340 | function makeFieldFunctionOptions(policies, objectOrReference, fieldSpec, context, storage) {
|
341 | var storeFieldName = policies.getStoreFieldName(fieldSpec);
|
342 | var fieldName = fieldNameFromStoreName(storeFieldName);
|
343 | var variables = fieldSpec.variables || context.variables;
|
344 | var _a = context.store, toReference = _a.toReference, canRead = _a.canRead;
|
345 | return {
|
346 | args: argsFromFieldSpecifier(fieldSpec),
|
347 | field: fieldSpec.field || null,
|
348 | fieldName: fieldName,
|
349 | storeFieldName: storeFieldName,
|
350 | variables: variables,
|
351 | isReference: isReference,
|
352 | toReference: toReference,
|
353 | storage: storage,
|
354 | cache: policies.cache,
|
355 | canRead: canRead,
|
356 | readField: function () {
|
357 | return policies.readField(normalizeReadFieldOptions(arguments, objectOrReference, variables), context);
|
358 | },
|
359 | mergeObjects: makeMergeObjectsFunction(context.store),
|
360 | };
|
361 | }
|
362 | export function normalizeReadFieldOptions(readFieldArgs, objectOrReference, variables) {
|
363 | var fieldNameOrOptions = readFieldArgs[0], from = readFieldArgs[1], argc = readFieldArgs.length;
|
364 | var options;
|
365 | if (typeof fieldNameOrOptions === "string") {
|
366 | options = {
|
367 | fieldName: fieldNameOrOptions,
|
368 | from: argc > 1 ? from : objectOrReference,
|
369 | };
|
370 | }
|
371 | else {
|
372 | options = __assign({}, fieldNameOrOptions);
|
373 | if (!hasOwn.call(options, "from")) {
|
374 | options.from = objectOrReference;
|
375 | }
|
376 | }
|
377 | if (__DEV__ && options.from === void 0) {
|
378 | __DEV__ && invariant.warn("Undefined 'from' passed to readField with arguments ".concat(stringifyForDisplay(Array.from(readFieldArgs))));
|
379 | }
|
380 | if (void 0 === options.variables) {
|
381 | options.variables = variables;
|
382 | }
|
383 | return options;
|
384 | }
|
385 | function makeMergeObjectsFunction(store) {
|
386 | return function mergeObjects(existing, incoming) {
|
387 | if (isArray(existing) || isArray(incoming)) {
|
388 | throw __DEV__ ? new InvariantError("Cannot automatically merge arrays") : new InvariantError(4);
|
389 | }
|
390 | if (isNonNullObject(existing) &&
|
391 | isNonNullObject(incoming)) {
|
392 | var eType = store.getFieldValue(existing, "__typename");
|
393 | var iType = store.getFieldValue(incoming, "__typename");
|
394 | var typesDiffer = eType && iType && eType !== iType;
|
395 | if (typesDiffer) {
|
396 | return incoming;
|
397 | }
|
398 | if (isReference(existing) &&
|
399 | storeValueIsStoreObject(incoming)) {
|
400 | store.merge(existing.__ref, incoming);
|
401 | return existing;
|
402 | }
|
403 | if (storeValueIsStoreObject(existing) &&
|
404 | isReference(incoming)) {
|
405 | store.merge(existing, incoming.__ref);
|
406 | return incoming;
|
407 | }
|
408 | if (storeValueIsStoreObject(existing) &&
|
409 | storeValueIsStoreObject(incoming)) {
|
410 | return __assign(__assign({}, existing), incoming);
|
411 | }
|
412 | }
|
413 | return incoming;
|
414 | };
|
415 | }
|
416 |
|
\ | No newline at end of file |