UNPKG

18.9 kBJavaScriptView Raw
1import { __assign, __rest } from "tslib";
2import { invariant, InvariantError } from "../../utilities/globals/index.js";
3import { storeKeyNameFromField, argumentsObjectFromField, isReference, getStoreKeyName, isNonNullObject, stringifyForDisplay, } from "../../utilities/index.js";
4import { hasOwn, fieldNameFromStoreName, storeValueIsStoreObject, selectionSetMatchesResult, TypeOrFieldNameRegExp, defaultDataIdFromObject, isArray, } from "./helpers.js";
5import { cacheSlot } from "./reactiveVars.js";
6import { canonicalStringify } from "./object-canon.js";
7import { keyArgsFnFromSpecifier, keyFieldsFnFromSpecifier } from "./key-extractor.js";
8getStoreKeyName.setStringify(canonicalStringify);
9function argsFromFieldSpecifier(spec) {
10 return spec.args !== void 0 ? spec.args :
11 spec.field ? argumentsObjectFromField(spec.field, spec.variables) : null;
12}
13var nullKeyFieldsFn = function () { return void 0; };
14var simpleKeyArgsFn = function (_args, context) { return context.fieldName; };
15var mergeTrueFn = function (existing, incoming, _a) {
16 var mergeObjects = _a.mergeObjects;
17 return mergeObjects(existing, incoming);
18};
19var mergeFalseFn = function (_, incoming) { return incoming; };
20var 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}());
339export { Policies };
340function 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}
362export 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}
385function 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//# sourceMappingURL=policies.js.map
\No newline at end of file