@apollo/client
Version:
A fully-featured caching GraphQL client.
267 lines • 12.3 kB
JavaScript
import { __assign } from "tslib";
import { invariant, InvariantError } from "../../utilities/globals/index.js";
import { Kind, } from 'graphql';
import { wrap } from 'optimism';
import { isField, resultKeyNameFromField, isReference, makeReference, shouldInclude, addTypenameToDocument, getDefaultValues, getMainDefinition, getQueryDefinition, getFragmentFromSelection, maybeDeepFreeze, mergeDeepArray, DeepMerger, isNonNullObject, canUseWeakMap, compact, } from "../../utilities/index.js";
import { maybeDependOnExistenceOfEntity, supportsResultCaching } from "./entityStore.js";
import { isArray, extractFragmentContext, getTypenameFromStoreObject, shouldCanonizeResults } from "./helpers.js";
import { MissingFieldError } from "../core/types/common.js";
import { canonicalStringify, ObjectCanon } from "./object-canon.js";
;
function execSelectionSetKeyArgs(options) {
return [
options.selectionSet,
options.objectOrReference,
options.context,
options.context.canonizeResults,
];
}
var StoreReader = (function () {
function StoreReader(config) {
var _this = this;
this.knownResults = new (canUseWeakMap ? WeakMap : Map)();
this.config = compact(config, {
addTypename: config.addTypename !== false,
canonizeResults: shouldCanonizeResults(config),
});
this.canon = config.canon || new ObjectCanon;
this.executeSelectionSet = wrap(function (options) {
var _a;
var canonizeResults = options.context.canonizeResults;
var peekArgs = execSelectionSetKeyArgs(options);
peekArgs[3] = !canonizeResults;
var other = (_a = _this.executeSelectionSet).peek.apply(_a, peekArgs);
if (other) {
if (canonizeResults) {
return __assign(__assign({}, other), { result: _this.canon.admit(other.result) });
}
return other;
}
maybeDependOnExistenceOfEntity(options.context.store, options.enclosingRef.__ref);
return _this.execSelectionSetImpl(options);
}, {
max: this.config.resultCacheMaxSize,
keyArgs: execSelectionSetKeyArgs,
makeCacheKey: function (selectionSet, parent, context, canonizeResults) {
if (supportsResultCaching(context.store)) {
return context.store.makeCacheKey(selectionSet, isReference(parent) ? parent.__ref : parent, context.varString, canonizeResults);
}
}
});
this.executeSubSelectedArray = wrap(function (options) {
maybeDependOnExistenceOfEntity(options.context.store, options.enclosingRef.__ref);
return _this.execSubSelectedArrayImpl(options);
}, {
max: this.config.resultCacheMaxSize,
makeCacheKey: function (_a) {
var field = _a.field, array = _a.array, context = _a.context;
if (supportsResultCaching(context.store)) {
return context.store.makeCacheKey(field, array, context.varString);
}
}
});
}
StoreReader.prototype.resetCanon = function () {
this.canon = new ObjectCanon;
};
StoreReader.prototype.diffQueryAgainstStore = function (_a) {
var store = _a.store, query = _a.query, _b = _a.rootId, rootId = _b === void 0 ? 'ROOT_QUERY' : _b, variables = _a.variables, _c = _a.returnPartialData, returnPartialData = _c === void 0 ? true : _c, _d = _a.canonizeResults, canonizeResults = _d === void 0 ? this.config.canonizeResults : _d;
var policies = this.config.cache.policies;
variables = __assign(__assign({}, getDefaultValues(getQueryDefinition(query))), variables);
var rootRef = makeReference(rootId);
var execResult = this.executeSelectionSet({
selectionSet: getMainDefinition(query).selectionSet,
objectOrReference: rootRef,
enclosingRef: rootRef,
context: __assign({ store: store, query: query, policies: policies, variables: variables, varString: canonicalStringify(variables), canonizeResults: canonizeResults }, extractFragmentContext(query, this.config.fragments)),
});
var missing;
if (execResult.missing) {
missing = [new MissingFieldError(firstMissing(execResult.missing), execResult.missing, query, variables)];
if (!returnPartialData) {
throw missing[0];
}
}
return {
result: execResult.result,
complete: !missing,
missing: missing,
};
};
StoreReader.prototype.isFresh = function (result, parent, selectionSet, context) {
if (supportsResultCaching(context.store) &&
this.knownResults.get(result) === selectionSet) {
var latest = this.executeSelectionSet.peek(selectionSet, parent, context, this.canon.isKnown(result));
if (latest && result === latest.result) {
return true;
}
}
return false;
};
StoreReader.prototype.execSelectionSetImpl = function (_a) {
var _this = this;
var selectionSet = _a.selectionSet, objectOrReference = _a.objectOrReference, enclosingRef = _a.enclosingRef, context = _a.context;
if (isReference(objectOrReference) &&
!context.policies.rootTypenamesById[objectOrReference.__ref] &&
!context.store.has(objectOrReference.__ref)) {
return {
result: this.canon.empty,
missing: "Dangling reference to missing ".concat(objectOrReference.__ref, " object"),
};
}
var variables = context.variables, policies = context.policies, store = context.store;
var typename = store.getFieldValue(objectOrReference, "__typename");
var objectsToMerge = [];
var missing;
var missingMerger = new DeepMerger();
if (this.config.addTypename &&
typeof typename === "string" &&
!policies.rootIdsByTypename[typename]) {
objectsToMerge.push({ __typename: typename });
}
function handleMissing(result, resultName) {
var _a;
if (result.missing) {
missing = missingMerger.merge(missing, (_a = {}, _a[resultName] = result.missing, _a));
}
return result.result;
}
var workSet = new Set(selectionSet.selections);
workSet.forEach(function (selection) {
var _a, _b;
if (!shouldInclude(selection, variables))
return;
if (isField(selection)) {
var fieldValue = policies.readField({
fieldName: selection.name.value,
field: selection,
variables: context.variables,
from: objectOrReference,
}, context);
var resultName = resultKeyNameFromField(selection);
if (fieldValue === void 0) {
if (!addTypenameToDocument.added(selection)) {
missing = missingMerger.merge(missing, (_a = {},
_a[resultName] = "Can't find field '".concat(selection.name.value, "' on ").concat(isReference(objectOrReference)
? objectOrReference.__ref + " object"
: "object " + JSON.stringify(objectOrReference, null, 2)),
_a));
}
}
else if (isArray(fieldValue)) {
fieldValue = handleMissing(_this.executeSubSelectedArray({
field: selection,
array: fieldValue,
enclosingRef: enclosingRef,
context: context,
}), resultName);
}
else if (!selection.selectionSet) {
if (context.canonizeResults) {
fieldValue = _this.canon.pass(fieldValue);
}
}
else if (fieldValue != null) {
fieldValue = handleMissing(_this.executeSelectionSet({
selectionSet: selection.selectionSet,
objectOrReference: fieldValue,
enclosingRef: isReference(fieldValue) ? fieldValue : enclosingRef,
context: context,
}), resultName);
}
if (fieldValue !== void 0) {
objectsToMerge.push((_b = {}, _b[resultName] = fieldValue, _b));
}
}
else {
var fragment = getFragmentFromSelection(selection, context.lookupFragment);
if (!fragment && selection.kind === Kind.FRAGMENT_SPREAD) {
throw __DEV__ ? new InvariantError("No fragment named ".concat(selection.name.value)) : new InvariantError(5);
}
if (fragment && policies.fragmentMatches(fragment, typename)) {
fragment.selectionSet.selections.forEach(workSet.add, workSet);
}
}
});
var result = mergeDeepArray(objectsToMerge);
var finalResult = { result: result, missing: missing };
var frozen = context.canonizeResults
? this.canon.admit(finalResult)
: maybeDeepFreeze(finalResult);
if (frozen.result) {
this.knownResults.set(frozen.result, selectionSet);
}
return frozen;
};
StoreReader.prototype.execSubSelectedArrayImpl = function (_a) {
var _this = this;
var field = _a.field, array = _a.array, enclosingRef = _a.enclosingRef, context = _a.context;
var missing;
var missingMerger = new DeepMerger();
function handleMissing(childResult, i) {
var _a;
if (childResult.missing) {
missing = missingMerger.merge(missing, (_a = {}, _a[i] = childResult.missing, _a));
}
return childResult.result;
}
if (field.selectionSet) {
array = array.filter(context.store.canRead);
}
array = array.map(function (item, i) {
if (item === null) {
return null;
}
if (isArray(item)) {
return handleMissing(_this.executeSubSelectedArray({
field: field,
array: item,
enclosingRef: enclosingRef,
context: context,
}), i);
}
if (field.selectionSet) {
return handleMissing(_this.executeSelectionSet({
selectionSet: field.selectionSet,
objectOrReference: item,
enclosingRef: isReference(item) ? item : enclosingRef,
context: context,
}), i);
}
if (__DEV__) {
assertSelectionSetForIdValue(context.store, field, item);
}
return item;
});
return {
result: context.canonizeResults ? this.canon.admit(array) : array,
missing: missing,
};
};
return StoreReader;
}());
export { StoreReader };
function firstMissing(tree) {
try {
JSON.stringify(tree, function (_, value) {
if (typeof value === "string")
throw value;
return value;
});
}
catch (result) {
return result;
}
}
function assertSelectionSetForIdValue(store, field, fieldValue) {
if (!field.selectionSet) {
var workSet_1 = new Set([fieldValue]);
workSet_1.forEach(function (value) {
if (isNonNullObject(value)) {
__DEV__ ? invariant(!isReference(value), "Missing selection set for object of type ".concat(getTypenameFromStoreObject(store, value), " returned for query field ").concat(field.name.value)) : invariant(!isReference(value), 6);
Object.values(value).forEach(workSet_1.add, workSet_1);
}
});
}
}
//# sourceMappingURL=readFromStore.js.map