UNPKG

@apollo/client

Version:

A fully-featured caching GraphQL client.

1 lines 154 kB
{"version":3,"file":"readFromStore.cjs","sources":["../../../../src/cache/inmemory/readFromStore.ts"],"sourcesContent":["import { equal } from \"@wry/equality\";\nimport { Trie } from \"@wry/trie\";\nimport type {\n DocumentNode,\n FieldNode,\n SelectionNode,\n SelectionSetNode,\n} from \"graphql\";\nimport { Kind } from \"graphql\";\nimport type { OptimisticWrapperFunction } from \"optimism\";\nimport { wrap } from \"optimism\";\n\nimport type { Reference, StoreObject } from \"@apollo/client/utilities\";\nimport {\n addTypenameToDocument,\n cacheSizes,\n canonicalStringify,\n isReference,\n} from \"@apollo/client/utilities\";\nimport { __DEV__ } from \"@apollo/client/utilities/environment\";\nimport type {\n DeferInfoTrie,\n FragmentMap,\n FragmentMapFunction,\n StreamInfoTrie,\n} from \"@apollo/client/utilities/internal\";\nimport {\n compact,\n DeepMerger,\n getDefaultValues,\n getDirectiveArgValue,\n getFragmentFromSelection,\n getMainDefinition,\n getQueryDefinition,\n handleIncrementalSymbol,\n isArray,\n isDeferredFragment,\n isField,\n isNonNullObject,\n isStreamField,\n makeReference,\n maybeDeepFreeze,\n mergeDeepArray,\n resultKeyNameFromField,\n shouldInclude,\n} from \"@apollo/client/utilities/internal\";\nimport {\n invariant,\n newInvariantError,\n} from \"@apollo/client/utilities/invariant\";\n\nimport { defaultCacheSizes } from \"../../utilities/caching/sizes.js\";\nimport type { Cache } from \"../core/types/Cache.js\";\nimport type { MissingTree } from \"../core/types/common.js\";\nimport { MissingFieldError } from \"../core/types/common.js\";\n\nimport {\n maybeDependOnExistenceOfEntity,\n supportsResultCaching,\n} from \"./entityStore.js\";\nimport {\n extractFragmentContext,\n getTypenameFromStoreObject,\n} from \"./helpers.js\";\nimport type { InMemoryCache } from \"./inMemoryCache.js\";\nimport type { Policies } from \"./policies.js\";\nimport type {\n DiffIncrementalInfo,\n DiffQueryAgainstStoreOptions,\n InMemoryCacheConfig,\n NormalizedCache,\n ReadMergeModifyContext,\n} from \"./types.js\";\n\ntype DataState =\n // no data\n | \"empty\"\n // at least 1 non-deferred field is partial\n | \"partial\"\n // at least 1 defer boundary is partial. All non-incremental fields complete\n | \"deferPartial\"\n // at least 1 stream boundary is partial. All non-incremental fields complete\n | \"streamPartial\"\n // All defer boundaries are complete or empty (but not partial) or all stream\n // boundaries are complete (but not partial)\n | \"streaming\"\n // All fields have data\n | \"complete\";\n\ninterface ReadContext extends ReadMergeModifyContext {\n query: DocumentNode;\n policies: Policies;\n fragmentMap: FragmentMap;\n lookupFragment: FragmentMapFunction;\n streamInfo?: StreamInfoTrie;\n deferInfo?: DeferInfoTrie;\n}\n\ntype ExecResult<R = any> = {\n result: R;\n dataState: DataState;\n partialBoundaries: PartialBoundaries;\n missing?: MissingTree;\n};\n\ntype PruneResult<R = any> = {\n result: R;\n dataState: DataState;\n};\n\ntype ExecSelectionSetOptions = {\n selectionSet: SelectionSetNode;\n objectOrReference: StoreObject | Reference;\n enclosingRef: Reference;\n context: ReadContext;\n};\n\ntype ExecSubSelectedArrayOptions = {\n field: FieldNode;\n array: readonly any[];\n enclosingRef: Reference;\n context: ReadContext;\n};\n\ntype PruneSelectionSetOptions = {\n selectionSet: SelectionSetNode;\n context: ReadContext;\n path: Array<string | number>;\n data: any;\n boundaries: PartialBoundaries | undefined;\n};\n\ntype PruneArrayOptions = {\n field: FieldNode;\n context: ReadContext;\n path: Array<string | number>;\n array: any[];\n boundaries: PartialBoundaries | undefined;\n};\n\ninterface StoreReaderConfig {\n cache: InMemoryCache;\n fragments?: InMemoryCacheConfig[\"fragments\"];\n}\n\n// Arguments type after keyArgs translation.\ntype ExecSelectionSetKeyArgs = [\n SelectionSetNode,\n StoreObject | Reference,\n ReadMergeModifyContext,\n];\n\nfunction execSelectionSetKeyArgs(\n options: ExecSelectionSetOptions\n): ExecSelectionSetKeyArgs {\n return [options.selectionSet, options.objectOrReference, options.context];\n}\n\nexport class StoreReader {\n // cached version of executeSelectionSet\n private executeSelectionSet: OptimisticWrapperFunction<\n [ExecSelectionSetOptions], // Actual arguments tuple type.\n ExecResult, // Actual return type.\n ExecSelectionSetKeyArgs\n >;\n\n // cached version of executeSubSelectedArray\n private executeSubSelectedArray: OptimisticWrapperFunction<\n [ExecSubSelectedArrayOptions],\n ExecResult<any>,\n [ExecSubSelectedArrayOptions]\n >;\n\n private prunePartialStreamArray: OptimisticWrapperFunction<\n [PruneArrayOptions],\n PruneResult\n >;\n private prunePartialBoundaries: OptimisticWrapperFunction<\n [PruneSelectionSetOptions],\n PruneResult\n >;\n\n private config: {\n cache: InMemoryCache;\n fragments?: InMemoryCacheConfig[\"fragments\"];\n };\n\n private knownResults = new WeakMap<Record<string, any>, SelectionSetNode>();\n\n private keyMaker = new Trie();\n\n constructor(config: StoreReaderConfig) {\n this.config = config;\n\n // memoized functions in this class will be \"garbage-collected\"\n // by recreating the whole `StoreReader` in\n // `InMemoryCache.resetResultsCache`\n // (triggered from `InMemoryCache.gc` with `resetResultCache: true`)\n this.executeSelectionSet = wrap(\n (options) => {\n const peekArgs = execSelectionSetKeyArgs(options);\n\n const other = this.executeSelectionSet.peek(...peekArgs);\n\n if (other) {\n // If we previously read this result with canonization enabled, we can\n // return that canonized result as-is.\n return other;\n }\n\n maybeDependOnExistenceOfEntity(\n options.context.store,\n options.enclosingRef.__ref\n );\n\n // Finally, if we didn't find any useful previous results, run the real\n // execSelectionSetImpl method with the given options.\n return this.execSelectionSetImpl(options);\n },\n {\n max:\n cacheSizes[\"inMemoryCache.executeSelectionSet\"] ||\n defaultCacheSizes[\"inMemoryCache.executeSelectionSet\"],\n keyArgs: execSelectionSetKeyArgs,\n // Note that the parameters of makeCacheKey are determined by the\n // array returned by keyArgs.\n makeCacheKey(selectionSet, parent, context) {\n if (supportsResultCaching(context.store)) {\n return context.store.makeCacheKey(\n selectionSet,\n isReference(parent) ? parent.__ref : parent,\n context.varString\n );\n }\n },\n }\n );\n\n this.executeSubSelectedArray = wrap(\n (options: ExecSubSelectedArrayOptions) => {\n maybeDependOnExistenceOfEntity(\n options.context.store,\n options.enclosingRef.__ref\n );\n return this.execSubSelectedArrayImpl(options);\n },\n {\n max:\n cacheSizes[\"inMemoryCache.executeSubSelectedArray\"] ||\n defaultCacheSizes[\"inMemoryCache.executeSubSelectedArray\"],\n makeCacheKey({ field, array, context }) {\n if (supportsResultCaching(context.store)) {\n return context.store.makeCacheKey(field, array, context.varString);\n }\n },\n }\n );\n\n this.prunePartialBoundaries = wrap(\n (options) => this.prunePartialBoundariesImpl(options),\n {\n max:\n cacheSizes[\"inMemoryCache.prunePartialBoundaries\"] ||\n defaultCacheSizes[\"inMemoryCache.prunePartialBoundaries\"],\n makeCacheKey: ({ boundaries, context, selectionSet }) => {\n if (supportsResultCaching(context.store)) {\n return this.keyMaker.lookup(\n selectionSet,\n boundaries,\n context.streamInfo,\n context.deferInfo\n );\n }\n },\n }\n );\n\n this.prunePartialStreamArray = wrap(\n (options) => {\n const { field, context, path } = options;\n\n if (isStreamField(field, context.variables)) {\n context.streamInfo?.lookupArray(path).state.depend();\n }\n\n return this.prunePartialStreamArrayImpl(options);\n },\n {\n max:\n cacheSizes[\"inMemoryCache.prunePartialStreamArray\"] ||\n defaultCacheSizes[\"inMemoryCache.prunePartialStreamArray\"],\n makeCacheKey: ({ field, context, boundaries }) => {\n if (supportsResultCaching(context.store)) {\n return this.keyMaker.lookup(\n field,\n boundaries,\n context.streamInfo,\n context.deferInfo\n );\n }\n },\n }\n );\n }\n\n /**\n * Given a store and a query, return as much of the result as possible and\n * identify if any data was missing from the store.\n */\n public diffQueryAgainstStore<T>(\n options: DiffQueryAgainstStoreOptions & {\n [handleIncrementalSymbol]: DiffIncrementalInfo | undefined;\n }\n ): Cache.InternalDiffResultWithDataState<T>;\n\n public diffQueryAgainstStore<T>(\n options: DiffQueryAgainstStoreOptions\n ): Cache.DiffResult<T>;\n\n public diffQueryAgainstStore<T>({\n store,\n query,\n rootId = \"ROOT_QUERY\",\n variables,\n returnPartialData = true,\n ...options\n }: DiffQueryAgainstStoreOptions & {\n [handleIncrementalSymbol]?: DiffIncrementalInfo;\n }): Cache.DiffResult<T> & {\n dataState?: \"empty\" | \"partial\" | \"streaming\" | \"complete\";\n } {\n const returnIncremental = Object.hasOwn(options, handleIncrementalSymbol);\n const policies = this.config.cache.policies;\n\n variables = compact(getDefaultValues(getQueryDefinition(query)), variables);\n\n const rootRef = makeReference(rootId);\n const context: ReadContext = {\n store,\n query,\n policies,\n variables,\n varString: canonicalStringify(variables),\n ...extractFragmentContext(query, this.config.fragments),\n ...options[handleIncrementalSymbol],\n };\n let execResult = this.executeSelectionSet({\n selectionSet: getMainDefinition(query).selectionSet,\n objectOrReference: rootRef,\n enclosingRef: rootRef,\n context,\n });\n\n // Since executeSelectionSet doesn't know about returnPartialData, we need\n // to perform a 2nd pass over the result to prune any fields inside\n // partial defer boundaries. The \"deferPartial\" data state tells us that the\n // only part of the result that contributed to its partiality is data inside\n // a defer boundary.\n if (returnIncremental && shouldPrune(execResult, context)) {\n const pruned = this.prunePartialBoundaries({\n selectionSet: getMainDefinition(query).selectionSet,\n data: execResult.result,\n boundaries: execResult.partialBoundaries,\n context,\n path: [],\n });\n const changed = execResult.result !== pruned.result;\n // It's possible that pruning didn't actually change the result which can\n // happen if a defer boundary is misclassified as \"deferPartial\" instead\n // of \"streaming\" (sibling defer boundaries with overlapping selection\n // sets, one of which is complete). In this case, pruning corrects the\n // dataState to streaming instead of leaving it as partial. If we tolerate\n // partial results and pruning changed the result by dropping fields, then\n // we want to keep the original execResult which contains the partial\n // data.\n if (!changed || !returnPartialData) {\n // Omit `missing` property since pruning puts it in a state that doesn't\n // report missing fields.\n execResult = {\n result: pruned.result,\n partialBoundaries: execResult.partialBoundaries,\n dataState: pruned.dataState,\n };\n }\n }\n\n let { result, dataState, missing } = execResult;\n // Evaluate this condition before we start mucking with dataState for the\n // publicly returned value\n const includeMissing =\n !!missing &&\n // We don't need to report missing fields inside defer boundaries since\n // the \"streaming\" dataState tells us that the only missing fields in\n // the object is inside a defer boundary.\n (dataState !== \"streaming\" || !returnIncremental);\n\n // If we get all root @defer boundaries with an empty result, report it as\n // empty instead of streaming.\n if (dataState === \"streaming\" && Object.keys(result).length === 0) {\n dataState = \"empty\";\n }\n\n let missingError: MissingFieldError | undefined;\n\n if (\n dataState === \"deferPartial\" ||\n dataState === \"streamPartial\" ||\n (dataState === \"streaming\" && !returnIncremental)\n ) {\n dataState = \"partial\";\n }\n\n if (dataState === \"partial\" && !returnPartialData) {\n dataState = \"empty\";\n }\n\n const complete = dataState === \"complete\";\n const keepResult =\n complete ||\n dataState === \"streaming\" ||\n (returnPartialData && Object.keys(result).length);\n\n const diffResult = {\n result: keepResult ? result : null,\n complete,\n get missing() {\n if (includeMissing) {\n missingError ||= new MissingFieldError(\n firstMissing(missing)!,\n missing,\n query,\n variables\n );\n }\n return missingError;\n },\n } as Cache.DiffResult<T>;\n\n if (returnIncremental) {\n (diffResult as Cache.InternalDiffResultWithDataState<T>).dataState =\n dataState;\n }\n\n return diffResult;\n }\n\n public isFresh(\n result: Record<string, any>,\n parent: StoreObject | Reference,\n selectionSet: SelectionSetNode,\n context: ReadMergeModifyContext\n ): boolean {\n if (\n supportsResultCaching(context.store) &&\n this.knownResults.get(result) === selectionSet\n ) {\n const latest = this.executeSelectionSet.peek(\n selectionSet,\n parent,\n context\n );\n if (latest && result === latest.result) {\n return true;\n }\n }\n return false;\n }\n\n // Uncached version of executeSelectionSet.\n private execSelectionSetImpl({\n selectionSet,\n objectOrReference,\n enclosingRef,\n context,\n }: ExecSelectionSetOptions): ExecResult {\n if (\n isReference(objectOrReference) &&\n !context.policies.rootTypenamesById[objectOrReference.__ref] &&\n !context.store.has(objectOrReference.__ref)\n ) {\n return {\n result: {},\n dataState: \"empty\",\n missing: `Dangling reference to missing ${objectOrReference.__ref} object`,\n partialBoundaries: new PartialBoundaries(),\n };\n }\n\n const { variables, policies, store } = context;\n const typename = store.getFieldValue<string>(\n objectOrReference,\n \"__typename\"\n );\n\n const objectsToMerge: Record<string, any>[] = [];\n let dataState: DataState | undefined;\n let missing: MissingTree | undefined;\n const missingMerger = new DeepMerger();\n const partialBoundaries = new PartialBoundaries();\n\n if (typeof typename === \"string\" && !policies.rootIdsByTypename[typename]) {\n // Ensure we always include a default value for the __typename\n // field, if we have one. Note that this field can be overridden by other\n // merged objects.\n objectsToMerge.push({ __typename: typename });\n }\n\n function handleMissing<T>(result: ExecResult<T>, resultName: string) {\n if (result.missing) {\n missing = missingMerger.merge(missing, {\n [resultName]: result.missing,\n });\n }\n return result;\n }\n\n const workSet = new Set(selectionSet.selections);\n\n workSet.forEach((selection) => {\n // Omit fields with directives @skip(if: <truthy value>) or\n // @include(if: <falsy value>).\n if (!shouldInclude(selection, variables)) return;\n\n if (isField(selection)) {\n let fieldValue = policies.readField(\n {\n fieldName: selection.name.value,\n field: selection,\n variables: context.variables,\n from: objectOrReference,\n },\n context\n );\n\n const resultName = resultKeyNameFromField(selection);\n\n if (fieldValue === void 0) {\n if (!addTypenameToDocument.added(selection)) {\n const id =\n isReference(objectOrReference) ? objectOrReference.__ref\n : objectOrReference ? policies.identify(objectOrReference)[0]\n : undefined;\n\n missing = missingMerger.merge(missing, {\n [resultName]: `Can't find field '${selection.name.value}' on ${\n id ?\n `${id} object`\n : `object ${JSON.stringify(objectOrReference || {}, null, 2)}`\n }`,\n });\n\n dataState = mergeDataState(dataState, \"empty\");\n }\n } else if (isArray(fieldValue)) {\n if (fieldValue.length > 0) {\n const execResult = handleMissing(\n this.executeSubSelectedArray({\n field: selection,\n array: fieldValue,\n enclosingRef,\n context,\n }),\n resultName\n );\n\n fieldValue = execResult.result;\n dataState = mergeDataState(dataState, execResult.dataState);\n partialBoundaries.set(resultName, execResult.partialBoundaries);\n } else {\n dataState = mergeDataState(dataState, \"complete\");\n }\n } else if (!selection.selectionSet) {\n // Auto-inserted __typename should not affect dataState (see empty\n // @defer boundaries, which must stay \"empty\" → parent \"streaming\").\n if (!addTypenameToDocument.added(selection)) {\n dataState = mergeDataState(dataState, \"complete\");\n }\n } else if (fieldValue != null) {\n if (__DEV__) {\n const fieldName = selection.name.value;\n\n if (typename) {\n const policy = policies[\"getFieldPolicy\"](typename, fieldName);\n\n if (policy?.scalar) {\n invariant.warn(\n \"The field policy for '%s' is configured as a '%s' scalar, but the field is not a scalar field because it contains a selection set. The field value remains unchanged.\",\n `${typename}.${fieldName}`,\n policy.scalar\n );\n }\n }\n }\n // In this case, because we know the field has a selection set,\n // it must be trying to query a GraphQLObjectType, which is why\n // fieldValue must be != null.\n const execResult = handleMissing(\n this.executeSelectionSet({\n selectionSet: selection.selectionSet,\n objectOrReference: fieldValue as StoreObject | Reference,\n enclosingRef: isReference(fieldValue) ? fieldValue : enclosingRef,\n context,\n }),\n resultName\n );\n\n fieldValue = execResult.result;\n partialBoundaries.set(resultName, execResult.partialBoundaries);\n\n // If the object's fields resolved to an \"empty\" dataState (e.g. no\n // field resolved with a non-undefined value), but the fieldValue\n // object itself is present, this object should be considered\n // partial instead of empty. This also ensures defer boundaries that\n // select this object remain as partial defer boundaries rather than\n // mistakenly get reported as streaming. This is especially necessary\n // when combined with GraphQL Codegen which generates its type and\n // relies on the outer object to be absent when its fields haven't\n // streamed in. Reporting the defer boundary as \"streaming\" instead of\n // \"partial\" would otherwise have the potential to cause runtime\n // crashes since the runtime values and types would not line up\n // properly (types expect object to be undefined, but its instead\n // present without its fields)\n dataState = mergeDataState(\n dataState,\n execResult.dataState === \"empty\" ? \"partial\" : execResult.dataState\n );\n }\n\n if (fieldValue !== void 0) {\n objectsToMerge.push({ [resultName]: fieldValue });\n }\n } else {\n const fragment = getFragmentFromSelection(\n selection,\n context.lookupFragment\n );\n\n if (!fragment && selection.kind === Kind.FRAGMENT_SPREAD) {\n throw newInvariantError(`No fragment named %s`, selection.name.value);\n }\n\n if (fragment && policies.fragmentMatches(fragment, typename)) {\n const isDeferBoundary = isDeferredFragment(\n selection,\n context.variables\n );\n // Prior to 4.3, this branch just flattened the fragment's\n // selectionSet into the existing workSet so that it continued\n // iterating as if the fragment didn't exist. The cache is\n // incremental aware as of 4.3 and as such, we need to resolve the\n // per-fragment selection set so that we can properly strip partial\n // defer fragment data when returnPartialData is false. We need to\n // call execSelectionSetImpl directly (non-cached version) so that we\n // scope the dataState correctly for its fields. Using the cached\n // executeSelectionSet can result in cache poisoning when combined\n // with the fragment registry where it might cache either a) an error\n // thrown when a registered fragment references a named fragment that\n // the query is expected to supply and doesn't or b) resolve to the\n // wrong data result when combined with queries that provide different\n // implementations of the same fragment (see inmemory/fragmentRegistry and\n // cache.diff/incremental tests which provide guards against this\n // behavior).\n const execResult = this.execSelectionSetImpl({\n selectionSet: fragment.selectionSet,\n objectOrReference,\n enclosingRef,\n context,\n });\n const { result, dataState: nextDataState } = execResult;\n\n partialBoundaries.merge(execResult.partialBoundaries);\n\n if (result !== void 0) {\n objectsToMerge.push(result);\n }\n\n if (execResult.missing) {\n missing = missingMerger.merge(missing, execResult.missing);\n }\n\n if (\n isDeferBoundary &&\n (nextDataState === \"partial\" || nextDataState === \"empty\")\n ) {\n partialBoundaries.add(selection);\n }\n\n dataState = mergeDataState(\n dataState,\n isDeferBoundary ?\n nextDataState === \"empty\" ? \"streaming\"\n : nextDataState === \"partial\" ? \"deferPartial\"\n : nextDataState\n : nextDataState\n );\n }\n }\n });\n\n dataState ||= \"complete\";\n\n const result = mergeDeepArray(objectsToMerge);\n\n const finalResult: ExecResult = {\n result,\n missing,\n dataState,\n partialBoundaries,\n };\n const frozen = maybeDeepFreeze(finalResult);\n\n // Store this result with its selection set so that we can quickly\n // recognize it again in the StoreReader#isFresh method.\n if (frozen.result) {\n this.knownResults.set(frozen.result, selectionSet);\n }\n\n return frozen;\n }\n\n // Uncached version of executeSubSelectedArray.\n private execSubSelectedArrayImpl({\n field,\n array,\n enclosingRef,\n context,\n }: ExecSubSelectedArrayOptions): ExecResult {\n let dataState: DataState = \"complete\";\n let missing: MissingTree | undefined;\n let missingMerger = new DeepMerger();\n const partialBoundaries = new PartialBoundaries();\n const isStreamed = isStreamField(field, context.variables);\n\n function handleMissing<T>(childResult: ExecResult<T>, i: number): T {\n if (childResult.missing) {\n missing = missingMerger.merge(missing, { [i]: childResult.missing });\n }\n return childResult.result;\n }\n\n if (field.selectionSet) {\n array = array.filter(\n (item) => item === undefined || context.store.canRead(item)\n );\n }\n\n array = array.map((item, i) => {\n // null value in array\n if (item === null) {\n return null;\n }\n\n let execResult: ExecResult | undefined;\n\n // This is a nested array, recurse\n if (isArray(item)) {\n execResult = this.executeSubSelectedArray({\n field,\n array: item,\n enclosingRef,\n context,\n });\n } else if (field.selectionSet) {\n execResult = this.executeSelectionSet({\n selectionSet: field.selectionSet,\n objectOrReference: item,\n enclosingRef: isReference(item) ? item : enclosingRef,\n context,\n });\n }\n\n if (execResult) {\n const { dataState: nextDataState } = execResult;\n\n partialBoundaries.set(\n i,\n nextDataState === \"partial\" ?\n // avoid mutating the execResult partialBoundaries object\n execResult.partialBoundaries.clone().add(field)\n : execResult.partialBoundaries\n );\n\n dataState = mergeDataState(\n dataState,\n isStreamed ?\n nextDataState === \"partial\" ?\n \"streamPartial\"\n : nextDataState\n : nextDataState\n );\n\n return handleMissing(execResult, i);\n }\n\n if (__DEV__) {\n assertSelectionSetForIdValue(context.store, field, item);\n }\n\n return item;\n });\n\n return {\n result: array,\n dataState,\n missing,\n partialBoundaries,\n };\n }\n\n private prunePartialBoundariesImpl({\n boundaries,\n context,\n data,\n path,\n selectionSet,\n }: PruneSelectionSetOptions): PruneResult<any> {\n const { variables, lookupFragment, policies } = context;\n\n if (data == null || !boundaries) {\n return { result: data, dataState: \"complete\" };\n }\n\n const merger = new DeepMerger();\n\n let changed = false;\n let dataState: DataState = \"complete\";\n const result: Record<string, any> = {};\n\n // __typename might not be part of the selection set, so preserve it when\n // available, otherwise it gets removed since it's never visited when\n // iterating the selection set.\n if (Object.hasOwn(data, \"__typename\")) {\n result.__typename = data.__typename;\n }\n\n const workSet = new Set(selectionSet.selections);\n workSet.forEach((selection) => {\n if (!shouldInclude(selection, variables)) return;\n\n if (isField(selection)) {\n const resultName = resultKeyNameFromField(selection);\n\n if (!Object.hasOwn(data, resultName)) {\n return;\n }\n\n const fieldValue = data[resultName];\n\n if (Array.isArray(fieldValue)) {\n const pruned = this.prunePartialStreamArray({\n field: selection,\n array: fieldValue,\n boundaries: boundaries.getChild(resultName),\n context,\n path: path.concat(resultName),\n });\n\n changed ||= pruned.result !== fieldValue;\n result[resultName] = pruned.result;\n dataState = mergeDataState(dataState, pruned.dataState);\n } else if (!selection.selectionSet) {\n result[resultName] = fieldValue;\n } else {\n const pruned = this.prunePartialBoundaries({\n data: fieldValue,\n selectionSet: selection.selectionSet,\n boundaries: boundaries.getChild(resultName),\n context,\n path: path.concat(resultName),\n });\n\n changed ||= pruned.result !== fieldValue;\n dataState = mergeDataState(dataState, pruned.dataState);\n\n // A response key can be selected by more than one selection (e.g. a\n // field and an overlapping fragment), so merge their kept fields.\n result[resultName] =\n Object.hasOwn(result, resultName) ?\n merger.merge(result[resultName], pruned.result)\n : pruned.result;\n }\n\n return;\n }\n\n // Note: we do NOT set `changed` to true anywhere in this branch of the\n // conditional, despite the fact that we might have encountered a\n // partial @defer boundary. Dropping a fragment does not guarantee keys\n // are actually dropped which can happen when overlapping sibling\n // selections contribute to the construction of the object. The final\n // Object.keys(result).length check actually detects whether keys were\n // dropped or not.\n\n const fragment = getFragmentFromSelection(selection, lookupFragment);\n let prune = false;\n\n if (context.deferInfo && isDeferredFragment(selection, variables)) {\n const directive = selection.directives?.find(\n (d) => d.name.value === \"defer\"\n );\n const label =\n directive && getDirectiveArgValue(directive, \"label\", Kind.STRING);\n\n prune = !!context.deferInfo.peekArray(path.concat(label || []));\n }\n\n if (fragment && policies.fragmentMatches(fragment, data.__typename)) {\n if (boundaries.has(selection) || prune) {\n dataState = mergeDataState(dataState, \"streaming\");\n } else {\n fragment.selectionSet.selections.forEach(workSet.add, workSet);\n }\n }\n });\n\n if (Object.keys(result).length !== Object.keys(data).length) {\n changed = true;\n } else if (changed && boundaries.hasSelections()) {\n // Overlapping siblings may rebuild the same fields under a new object\n // identity (e.g. changed === true) after a partial @defer is skipped.\n // We perform a deep equality check to verify whether anything was\n // actually dropped by the partial @defer fragment.\n changed = !equal(result, data);\n }\n\n return { result: changed ? result : data, dataState };\n }\n\n private prunePartialStreamArrayImpl({\n field,\n array,\n boundaries,\n context,\n path,\n }: PruneArrayOptions): PruneResult<any> {\n if (!boundaries) return { result: array, dataState: \"complete\" };\n\n let changed = false;\n let dataState: DataState = \"complete\";\n let pruned: any[] = [];\n\n const state = context.streamInfo?.peekArray(path)?.state;\n const length = Math.min(\n array.length,\n state?.truncate ? state.streamPosition : Number.MAX_SAFE_INTEGER\n );\n\n for (let i = 0; i < length; i++) {\n const item = array[i];\n\n let prunedResult: PruneResult<any> = {\n result: item,\n dataState: \"complete\",\n };\n const boundary = boundaries.getChild(i);\n\n if (boundary?.has(field)) {\n // The presence of streamInfo determines how we truncate partial\n // stream arrays. Stream info is only given to cache.diff during\n // in-flight requests so we want keep items in the array equal to the\n // total that have streamed in (this is represented by streamPosition\n // above). For all other cache reads, partial stream boundaries are\n // pruned back to an empty array.\n if (state) {\n state.truncate = true;\n pruned = pruned.slice(0, state.streamPosition);\n } else {\n pruned = [];\n dataState = \"complete\";\n }\n\n break;\n }\n\n if (Array.isArray(item)) {\n prunedResult = this.prunePartialStreamArray({\n field,\n array: item,\n boundaries: boundaries.getChild(i),\n context,\n path: path.concat(i),\n });\n } else if (field.selectionSet) {\n prunedResult = this.prunePartialBoundaries({\n data: item,\n selectionSet: field.selectionSet,\n boundaries: boundaries.getChild(i),\n context,\n path: path.concat(i),\n });\n }\n\n pruned.push(prunedResult.result);\n changed ||= prunedResult.result !== item;\n dataState = mergeDataState(dataState, prunedResult.dataState);\n }\n\n changed ||= pruned.length !== array.length;\n\n return { result: changed ? pruned : array, dataState };\n }\n}\n\nfunction firstMissing(tree: MissingTree): string | undefined {\n try {\n JSON.stringify(tree, (_, value) => {\n if (typeof value === \"string\") throw value;\n return value;\n });\n } catch (result) {\n return result as string;\n }\n}\n\nfunction assertSelectionSetForIdValue(\n store: NormalizedCache,\n field: FieldNode,\n fieldValue: any\n) {\n if (!field.selectionSet) {\n const workSet = new Set([fieldValue]);\n workSet.forEach((value) => {\n if (isNonNullObject(value)) {\n invariant(\n !isReference(value),\n `Missing selection set for object of type %s returned for query field %s`,\n getTypenameFromStoreObject(store, value),\n field.name.value\n );\n Object.values(value).forEach(workSet.add, workSet);\n }\n });\n }\n}\n\n// We deliberately leave `returnPartialData` out of `executeSelectionSet`'s\n// cache key. `isFresh` runs during writes and cannot provide a reliable value\n// for this option, so including it would prevent a reliable cache hit.\n//\n// When `returnPartialData` is false, `diffQueryAgainstStore` prunes data from\n// partial @defer boundaries after reading the cached result. `PartialBoundaries`\n// records the selection paths needed for that pass, including empty nodes along\n// a path. Overlapping non-deferred selections must still be rebuilt so fields\n// contributed only by a partial deferred sibling are removed. The prune pass\n// can then skip unrelated result branches.\nclass PartialBoundaries {\n private selections = new Set<SelectionNode>();\n private children = new Map<string | number, PartialBoundaries>();\n\n add(selection: SelectionNode) {\n this.selections.add(selection);\n\n return this;\n }\n\n has(selection: SelectionNode) {\n return this.selections.has(selection);\n }\n\n hasSelections() {\n return this.selections.size > 0;\n }\n\n getChild(key: string | number) {\n return this.children.get(key);\n }\n\n clone() {\n return new PartialBoundaries().merge(this);\n }\n\n set(key: string | number, boundary: PartialBoundaries) {\n const child = this.getChild(key);\n\n this.children.set(\n key,\n // Create a new PartialBoundaries instance to avoid mutating any cached\n // execResult partialBoundaries objects\n child ? child.clone().merge(boundary) : boundary\n );\n }\n\n merge(boundaries: PartialBoundaries) {\n boundaries.selections.forEach((selection) => this.add(selection));\n boundaries.children.forEach((child, key) => this.set(key, child));\n\n return this;\n }\n}\n\nfunction shouldPrune({ dataState }: ExecResult<any>, context: ReadContext) {\n if (dataState === \"deferPartial\" || dataState === \"streamPartial\") {\n return true;\n }\n\n if (dataState === \"complete\" || dataState === \"streaming\") {\n return !!(\n // If the last cache write repaired a partial @stream array to a\n // complete array, the stream array might contain stale entries after\n // the last written value. We only want to deliver the results up to\n // the index the network wrote so we need to prune it too.\n (\n context.streamInfo ||\n // The network hasn't delivered these @defer boundaries yet, so prune\n // the (possibly complete) cached data sitting at them.\n context.deferInfo\n )\n );\n }\n\n return false;\n}\n\n// Describes the data state transitions that change the running state when it's\n// combined with the next data state. Omitted object values represent\n// \"impossible\" merges where the data state should remain the same.\nconst DATA_STATE_MERGES: Record<\n DataState,\n Partial<Record<DataState, DataState>>\n> = {\n empty: {\n complete: \"partial\",\n deferPartial: \"partial\",\n streaming: \"partial\",\n streamPartial: \"partial\",\n },\n deferPartial: {\n empty: \"partial\",\n },\n streamPartial: {\n deferPartial: \"deferPartial\",\n empty: \"partial\",\n },\n streaming: {\n deferPartial: \"deferPartial\",\n empty: \"partial\",\n streamPartial: \"streamPartial\",\n },\n complete: {\n deferPartial: \"deferPartial\",\n streaming: \"streaming\",\n streamPartial: \"streamPartial\",\n empty: \"partial\",\n },\n partial: {},\n};\n\nfunction mergeDataState(\n current: DataState | undefined,\n next: DataState\n): DataState {\n if (next === \"partial\") {\n return \"partial\";\n }\n\n if (!current || current === next) {\n return next;\n }\n\n return DATA_STATE_MERGES[current][next] || current;\n}\n"],"names":[],"mappings":";;;;;;;AAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAOA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAGA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAMA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAOA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAoBA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAQA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CA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