@apollo/client 4.3.0-alpha.4 → 4.3.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +3 -7
  3. package/__cjs/cache/core/cache.cjs +1 -1
  4. package/__cjs/cache/core/cache.cjs.map +1 -1
  5. package/__cjs/cache/core/cache.d.cts +5 -1
  6. package/__cjs/cache/inmemory/entityStore.cjs +3 -3
  7. package/__cjs/cache/inmemory/inMemoryCache.cjs +0 -4
  8. package/__cjs/cache/inmemory/inMemoryCache.cjs.map +1 -1
  9. package/__cjs/cache/inmemory/inMemoryCache.d.cts +3 -4
  10. package/__cjs/cache/inmemory/key-extractor.cjs +1 -1
  11. package/__cjs/cache/inmemory/policies.cjs +28 -6
  12. package/__cjs/cache/inmemory/policies.cjs.map +1 -1
  13. package/__cjs/cache/inmemory/readFromStore.cjs +71 -54
  14. package/__cjs/cache/inmemory/readFromStore.cjs.map +1 -1
  15. package/__cjs/cache/inmemory/readFromStore.d.cts +1 -1
  16. package/__cjs/cache/inmemory/types.d.cts +1 -2
  17. package/__cjs/cache/inmemory/writeToStore.cjs +4 -4
  18. package/__cjs/core/ApolloClient.cjs +21 -22
  19. package/__cjs/core/ApolloClient.cjs.map +1 -1
  20. package/__cjs/core/ApolloClient.d.cts +44 -10
  21. package/__cjs/core/ObservableQuery.cjs +56 -14
  22. package/__cjs/core/ObservableQuery.cjs.map +1 -1
  23. package/__cjs/core/ObservableQuery.d.cts +13 -2
  24. package/__cjs/core/QueryInfo.cjs +175 -161
  25. package/__cjs/core/QueryInfo.cjs.map +1 -1
  26. package/__cjs/core/QueryInfo.d.cts +15 -5
  27. package/__cjs/core/QueryManager.cjs +63 -38
  28. package/__cjs/core/QueryManager.cjs.map +1 -1
  29. package/__cjs/core/RefetchEventManager.cjs +3 -3
  30. package/__cjs/core/dataStateErrorCache.cjs +12 -0
  31. package/__cjs/core/dataStateErrorCache.cjs.map +1 -0
  32. package/__cjs/core/dataStateErrorCache.d.cts +3 -0
  33. package/__cjs/core/types.d.cts +2 -0
  34. package/__cjs/incremental/handlers/graphql17Alpha9.cjs +34 -11
  35. package/__cjs/incremental/handlers/graphql17Alpha9.cjs.map +1 -1
  36. package/__cjs/incremental/handlers/graphql17Alpha9.d.cts +26 -3
  37. package/__cjs/incremental/types.d.cts +41 -3
  38. package/__cjs/invariantErrorCodes.cjs +56 -32
  39. package/__cjs/react/hooks/useBackgroundQuery.cjs.map +1 -1
  40. package/__cjs/react/hooks/useBackgroundQuery.d.cts +100 -47
  41. package/__cjs/react/hooks/useLazyQuery.cjs.map +1 -1
  42. package/__cjs/react/hooks/useLazyQuery.d.cts +26 -20
  43. package/__cjs/react/hooks/useLoadableQuery.cjs.map +1 -1
  44. package/__cjs/react/hooks/useLoadableQuery.d.cts +23 -15
  45. package/__cjs/react/hooks/useMutation.cjs.map +1 -1
  46. package/__cjs/react/hooks/useMutation.d.cts +10 -7
  47. package/__cjs/react/hooks/useQuery.cjs.map +1 -1
  48. package/__cjs/react/hooks/useQuery.d.cts +74 -32
  49. package/__cjs/react/hooks/useQueryRefHandlers.cjs.map +1 -1
  50. package/__cjs/react/hooks/useSuspenseQuery.cjs.map +1 -1
  51. package/__cjs/react/hooks/useSuspenseQuery.d.cts +83 -34
  52. package/__cjs/react/internal/cache/QueryReference.cjs.map +1 -1
  53. package/__cjs/react/internal/types.d.cts +14 -3
  54. package/__cjs/react/query-preloader/createQueryPreloader.cjs.map +1 -1
  55. package/__cjs/react/query-preloader/createQueryPreloader.d.cts +20 -5
  56. package/__cjs/testing/core/mocking/mockLink.cjs +21 -1
  57. package/__cjs/testing/core/mocking/mockLink.cjs.map +1 -1
  58. package/__cjs/testing/core/mocking/mockLink.d.cts +1 -2
  59. package/__cjs/utilities/internal/addDeferFragmentLabels.cjs +33 -0
  60. package/__cjs/utilities/internal/addDeferFragmentLabels.cjs.map +1 -0
  61. package/__cjs/utilities/internal/addDeferFragmentLabels.d.cts +3 -0
  62. package/__cjs/utilities/internal/getDirectiveArgValue.cjs +19 -0
  63. package/__cjs/utilities/internal/getDirectiveArgValue.cjs.map +1 -0
  64. package/__cjs/utilities/internal/getDirectiveArgValue.d.cts +9 -0
  65. package/__cjs/utilities/internal/index.cjs +8 -2
  66. package/__cjs/utilities/internal/index.cjs.map +1 -1
  67. package/__cjs/utilities/internal/index.d.cts +3 -0
  68. package/__cjs/utilities/internal/toDiffWithDataState.cjs +20 -0
  69. package/__cjs/utilities/internal/toDiffWithDataState.cjs.map +1 -0
  70. package/__cjs/utilities/internal/toDiffWithDataState.d.cts +8 -0
  71. package/__cjs/version.cjs +1 -1
  72. package/cache/core/cache.d.ts +5 -1
  73. package/cache/core/cache.js +1 -1
  74. package/cache/core/cache.js.map +1 -1
  75. package/cache/inmemory/entityStore.js +3 -3
  76. package/cache/inmemory/inMemoryCache.d.ts +3 -4
  77. package/cache/inmemory/inMemoryCache.js +1 -5
  78. package/cache/inmemory/inMemoryCache.js.map +1 -1
  79. package/cache/inmemory/key-extractor.js +1 -1
  80. package/cache/inmemory/policies.js +28 -6
  81. package/cache/inmemory/policies.js.map +1 -1
  82. package/cache/inmemory/readFromStore.d.ts +1 -1
  83. package/cache/inmemory/readFromStore.js +72 -55
  84. package/cache/inmemory/readFromStore.js.map +1 -1
  85. package/cache/inmemory/types.d.ts +1 -2
  86. package/cache/inmemory/types.js.map +1 -1
  87. package/cache/inmemory/writeToStore.js +4 -4
  88. package/core/ApolloClient.d.ts +44 -10
  89. package/core/ApolloClient.js +21 -22
  90. package/core/ApolloClient.js.map +1 -1
  91. package/core/ObservableQuery.d.ts +13 -2
  92. package/core/ObservableQuery.js +57 -15
  93. package/core/ObservableQuery.js.map +1 -1
  94. package/core/QueryInfo.d.ts +15 -5
  95. package/core/QueryInfo.js +171 -161
  96. package/core/QueryInfo.js.map +1 -1
  97. package/core/QueryManager.js +63 -38
  98. package/core/QueryManager.js.map +1 -1
  99. package/core/RefetchEventManager.js +3 -3
  100. package/core/dataStateErrorCache.d.ts +3 -0
  101. package/core/dataStateErrorCache.js +9 -0
  102. package/core/dataStateErrorCache.js.map +1 -0
  103. package/core/types.d.ts +2 -0
  104. package/core/types.js.map +1 -1
  105. package/incremental/handlers/graphql17Alpha9.d.ts +26 -3
  106. package/incremental/handlers/graphql17Alpha9.js +35 -12
  107. package/incremental/handlers/graphql17Alpha9.js.map +1 -1
  108. package/incremental/types.d.ts +41 -3
  109. package/incremental/types.js.map +1 -1
  110. package/invariantErrorCodes.js +56 -32
  111. package/package.json +1 -1
  112. package/react/hooks/useBackgroundQuery.d.ts +100 -47
  113. package/react/hooks/useBackgroundQuery.js.map +1 -1
  114. package/react/hooks/useLazyQuery.d.ts +26 -20
  115. package/react/hooks/useLazyQuery.js.map +1 -1
  116. package/react/hooks/useLoadableQuery.d.ts +23 -15
  117. package/react/hooks/useLoadableQuery.js.map +1 -1
  118. package/react/hooks/useMutation.d.ts +10 -7
  119. package/react/hooks/useMutation.js.map +1 -1
  120. package/react/hooks/useQuery.d.ts +74 -32
  121. package/react/hooks/useQuery.js.map +1 -1
  122. package/react/hooks/useQueryRefHandlers.js.map +1 -1
  123. package/react/hooks/useSuspenseQuery.d.ts +83 -34
  124. package/react/hooks/useSuspenseQuery.js.map +1 -1
  125. package/react/hooks-compiled/useBackgroundQuery.d.ts +100 -47
  126. package/react/hooks-compiled/useBackgroundQuery.js.map +1 -1
  127. package/react/hooks-compiled/useLazyQuery.d.ts +26 -20
  128. package/react/hooks-compiled/useLazyQuery.js.map +1 -1
  129. package/react/hooks-compiled/useLoadableQuery.d.ts +23 -15
  130. package/react/hooks-compiled/useLoadableQuery.js.map +1 -1
  131. package/react/hooks-compiled/useMutation.d.ts +10 -7
  132. package/react/hooks-compiled/useMutation.js.map +1 -1
  133. package/react/hooks-compiled/useQuery.d.ts +74 -32
  134. package/react/hooks-compiled/useQuery.js.map +1 -1
  135. package/react/hooks-compiled/useQueryRefHandlers.js.map +1 -1
  136. package/react/hooks-compiled/useSuspenseQuery.d.ts +83 -34
  137. package/react/hooks-compiled/useSuspenseQuery.js.map +1 -1
  138. package/react/internal/cache/QueryReference.js.map +1 -1
  139. package/react/internal/types.d.ts +15 -4
  140. package/react/internal/types.js.map +1 -1
  141. package/react/query-preloader/createQueryPreloader.d.ts +20 -5
  142. package/react/query-preloader/createQueryPreloader.js.map +1 -1
  143. package/testing/core/mocking/mockLink.d.ts +1 -2
  144. package/testing/core/mocking/mockLink.js +21 -1
  145. package/testing/core/mocking/mockLink.js.map +1 -1
  146. package/utilities/internal/addDeferFragmentLabels.d.ts +3 -0
  147. package/utilities/internal/addDeferFragmentLabels.js +30 -0
  148. package/utilities/internal/addDeferFragmentLabels.js.map +1 -0
  149. package/utilities/internal/getDirectiveArgValue.d.ts +9 -0
  150. package/utilities/internal/getDirectiveArgValue.js +16 -0
  151. package/utilities/internal/getDirectiveArgValue.js.map +1 -0
  152. package/utilities/internal/index.d.ts +3 -0
  153. package/utilities/internal/index.js +3 -0
  154. package/utilities/internal/index.js.map +1 -1
  155. package/utilities/internal/toDiffWithDataState.d.ts +8 -0
  156. package/utilities/internal/toDiffWithDataState.js +17 -0
  157. package/utilities/internal/toDiffWithDataState.js.map +1 -0
  158. package/version.js +1 -1
@@ -22,7 +22,7 @@ export declare class StoreReader {
22
22
  * identify if any data was missing from the store.
23
23
  */
24
24
  diffQueryAgainstStore<T>(options: DiffQueryAgainstStoreOptions & {
25
- [handleIncrementalSymbol]: true | DiffIncrementalInfo;
25
+ [handleIncrementalSymbol]: DiffIncrementalInfo | undefined;
26
26
  }): Cache.InternalDiffResultWithDataState<T>;
27
27
  diffQueryAgainstStore<T>(options: DiffQueryAgainstStoreOptions): Cache.DiffResult<T>;
28
28
  isFresh(result: Record<string, any>, parent: StoreObject | Reference, selectionSet: SelectionSetNode, context: ReadMergeModifyContext): boolean;
@@ -4,7 +4,7 @@ import { Kind } from "graphql";
4
4
  import { wrap } from "optimism";
5
5
  import { addTypenameToDocument, cacheSizes, canonicalStringify, isReference, } from "@apollo/client/utilities";
6
6
  import { __DEV__ } from "@apollo/client/utilities/environment";
7
- import { DeepMerger, getDefaultValues, getFragmentFromSelection, getMainDefinition, getQueryDefinition, handleIncrementalSymbol, isArray, isDeferredFragment, isField, isNonNullObject, isStreamField, makeReference, maybeDeepFreeze, mergeDeepArray, resultKeyNameFromField, shouldInclude, } from "@apollo/client/utilities/internal";
7
+ import { compact, DeepMerger, getDefaultValues, getDirectiveArgValue, getFragmentFromSelection, getMainDefinition, getQueryDefinition, handleIncrementalSymbol, isArray, isDeferredFragment, isField, isNonNullObject, isStreamField, makeReference, maybeDeepFreeze, mergeDeepArray, resultKeyNameFromField, shouldInclude, } from "@apollo/client/utilities/internal";
8
8
  import { invariant, newInvariantError, } from "@apollo/client/utilities/invariant";
9
9
  import { MissingFieldError } from "../core/types/common.js";
10
10
  import { maybeDependOnExistenceOfEntity, supportsResultCaching, } from "./entityStore.js";
@@ -89,12 +89,10 @@ export class StoreReader {
89
89
  },
90
90
  });
91
91
  }
92
- diffQueryAgainstStore({ store, query, rootId = "ROOT_QUERY", variables, returnPartialData = true, [handleIncrementalSymbol]: handleIncremental, }) {
92
+ diffQueryAgainstStore({ store, query, rootId = "ROOT_QUERY", variables, returnPartialData = true, ...options }) {
93
+ const returnIncremental = Object.hasOwn(options, handleIncrementalSymbol);
93
94
  const policies = this.config.cache.policies;
94
- variables = {
95
- ...getDefaultValues(getQueryDefinition(query)),
96
- ...variables,
97
- };
95
+ variables = compact(getDefaultValues(getQueryDefinition(query)), variables);
98
96
  const rootRef = makeReference(rootId);
99
97
  const context = {
100
98
  store,
@@ -103,7 +101,7 @@ export class StoreReader {
103
101
  variables,
104
102
  varString: canonicalStringify(variables),
105
103
  ...extractFragmentContext(query, this.config.fragments),
106
- ...(typeof handleIncremental === "object" ? handleIncremental : (undefined)),
104
+ ...options[handleIncrementalSymbol],
107
105
  };
108
106
  let execResult = this.executeSelectionSet({
109
107
  selectionSet: getMainDefinition(query).selectionSet,
@@ -116,17 +114,7 @@ export class StoreReader {
116
114
  // partial defer boundaries. The "deferPartial" data state tells us that the
117
115
  // only part of the result that contributed to its partiality is data inside
118
116
  // a defer boundary.
119
- if (handleIncremental &&
120
- (execResult.dataState === "deferPartial" ||
121
- execResult.dataState === "streamPartial" ||
122
- // If the last cache write repaired a partial @stream array to a
123
- // complete array, the stream array might contain stale entries after
124
- // the last written value. We only want to deliver the results up to
125
- // the index the network wrote so we need to prune it too.
126
- context.streamInfo ||
127
- // The network hasn't delivered these @defer boundaries yet, so prune
128
- // the (possibly complete) cached data sitting at them.
129
- context.deferInfo)) {
117
+ if (returnIncremental && shouldPrune(execResult, context)) {
130
118
  const pruned = this.prunePartialBoundaries({
131
119
  selectionSet: getMainDefinition(query).selectionSet,
132
120
  data: execResult.result,
@@ -134,7 +122,7 @@ export class StoreReader {
134
122
  context,
135
123
  path: [],
136
124
  });
137
- const changed = execResult.result !== pruned;
125
+ const changed = execResult.result !== pruned.result;
138
126
  // It's possible that pruning didn't actually change the result which can
139
127
  // happen if a defer boundary is misclassified as "deferPartial" instead
140
128
  // of "streaming" (sibling defer boundaries with overlapping selection
@@ -144,19 +132,12 @@ export class StoreReader {
144
132
  // we want to keep the original execResult which contains the partial
145
133
  // data.
146
134
  if (!changed || !returnPartialData) {
147
- const { dataState } = execResult;
148
135
  // Omit `missing` property since pruning puts it in a state that doesn't
149
136
  // report missing fields.
150
137
  execResult = {
151
- result: pruned,
138
+ result: pruned.result,
152
139
  partialBoundaries: execResult.partialBoundaries,
153
- dataState: dataState === "deferPartial" ? "streaming"
154
- : dataState === "streamPartial" ? "complete"
155
- // A cached @defer boundary the network hasn't delivered was
156
- // pruned from an otherwise complete result, so we're still
157
- // streaming.
158
- : context.deferInfo && changed ? "streaming"
159
- : dataState,
140
+ dataState: pruned.dataState,
160
141
  };
161
142
  }
162
143
  }
@@ -167,7 +148,7 @@ export class StoreReader {
167
148
  // We don't need to report missing fields inside defer boundaries since
168
149
  // the "streaming" dataState tells us that the only missing fields in
169
150
  // the object is inside a defer boundary.
170
- (dataState !== "streaming" || !handleIncremental);
151
+ (dataState !== "streaming" || !returnIncremental);
171
152
  // If we get all root @defer boundaries with an empty result, report it as
172
153
  // empty instead of streaming.
173
154
  if (dataState === "streaming" && Object.keys(result).length === 0) {
@@ -176,7 +157,7 @@ export class StoreReader {
176
157
  let missingError;
177
158
  if (dataState === "deferPartial" ||
178
159
  dataState === "streamPartial" ||
179
- (dataState === "streaming" && !handleIncremental)) {
160
+ (dataState === "streaming" && !returnIncremental)) {
180
161
  dataState = "partial";
181
162
  }
182
163
  if (dataState === "partial" && !returnPartialData) {
@@ -196,7 +177,7 @@ export class StoreReader {
196
177
  return missingError;
197
178
  },
198
179
  };
199
- if (handleIncremental) {
180
+ if (returnIncremental) {
200
181
  diffResult.dataState =
201
182
  dataState;
202
183
  }
@@ -301,7 +282,7 @@ export class StoreReader {
301
282
  if (typename) {
302
283
  const policy = policies["getFieldPolicy"](typename, fieldName);
303
284
  if (policy?.scalar) {
304
- __DEV__ && invariant.warn(112, `${typename}.${fieldName}`, policy.scalar);
285
+ __DEV__ && invariant.warn(114, `${typename}.${fieldName}`, policy.scalar);
305
286
  }
306
287
  }
307
288
  }
@@ -338,7 +319,7 @@ export class StoreReader {
338
319
  else {
339
320
  const fragment = getFragmentFromSelection(selection, context.lookupFragment);
340
321
  if (!fragment && selection.kind === Kind.FRAGMENT_SPREAD) {
341
- throw newInvariantError(113, selection.name.value);
322
+ throw newInvariantError(115, selection.name.value);
342
323
  }
343
324
  if (fragment && policies.fragmentMatches(fragment, typename)) {
344
325
  const isDeferBoundary = isDeferredFragment(selection, context.variables);
@@ -372,7 +353,8 @@ export class StoreReader {
372
353
  if (execResult.missing) {
373
354
  missing = missingMerger.merge(missing, execResult.missing);
374
355
  }
375
- if (isDeferBoundary && nextDataState === "partial") {
356
+ if (isDeferBoundary &&
357
+ (nextDataState === "partial" || nextDataState === "empty")) {
376
358
  partialBoundaries.add(selection);
377
359
  }
378
360
  dataState = mergeDataState(dataState, isDeferBoundary ?
@@ -465,10 +447,12 @@ export class StoreReader {
465
447
  }
466
448
  prunePartialBoundariesImpl({ boundaries, context, data, path, selectionSet, }) {
467
449
  const { variables, lookupFragment, policies } = context;
468
- if (data == null || !boundaries)
469
- return data;
450
+ if (data == null || !boundaries) {
451
+ return { result: data, dataState: "complete" };
452
+ }
470
453
  const merger = new DeepMerger();
471
454
  let changed = false;
455
+ let dataState = "complete";
472
456
  const result = {};
473
457
  // __typename might not be part of the selection set, so preserve it when
474
458
  // available, otherwise it gets removed since it's never visited when
@@ -494,8 +478,9 @@ export class StoreReader {
494
478
  context,
495
479
  path: path.concat(resultName),
496
480
  });
497
- changed ||= pruned !== fieldValue;
498
- result[resultName] = pruned;
481
+ changed ||= pruned.result !== fieldValue;
482
+ result[resultName] = pruned.result;
483
+ dataState = mergeDataState(dataState, pruned.dataState);
499
484
  }
500
485
  else if (!selection.selectionSet) {
501
486
  result[resultName] = fieldValue;
@@ -508,13 +493,14 @@ export class StoreReader {
508
493
  context,
509
494
  path: path.concat(resultName),
510
495
  });
511
- changed ||= pruned !== fieldValue;
496
+ changed ||= pruned.result !== fieldValue;
497
+ dataState = mergeDataState(dataState, pruned.dataState);
512
498
  // A response key can be selected by more than one selection (e.g. a
513
499
  // field and an overlapping fragment), so merge their kept fields.
514
500
  result[resultName] =
515
501
  Object.hasOwn(result, resultName) ?
516
- merger.merge(result[resultName], pruned)
517
- : pruned;
502
+ merger.merge(result[resultName], pruned.result)
503
+ : pruned.result;
518
504
  }
519
505
  return;
520
506
  }
@@ -526,11 +512,19 @@ export class StoreReader {
526
512
  // Object.keys(result).length check actually detects whether keys were
527
513
  // dropped or not.
528
514
  const fragment = getFragmentFromSelection(selection, lookupFragment);
529
- if (fragment &&
530
- policies.fragmentMatches(fragment, data.__typename) &&
531
- !boundaries.has(selection) &&
532
- !context.deferInfo?.peekArray(path)) {
533
- fragment.selectionSet.selections.forEach(workSet.add, workSet);
515
+ let prune = false;
516
+ if (context.deferInfo && isDeferredFragment(selection, variables)) {
517
+ const directive = selection.directives?.find((d) => d.name.value === "defer");
518
+ const label = directive && getDirectiveArgValue(directive, "label", Kind.STRING);
519
+ prune = !!context.deferInfo.peekArray(path.concat(label || []));
520
+ }
521
+ if (fragment && policies.fragmentMatches(fragment, data.__typename)) {
522
+ if (boundaries.has(selection) || prune) {
523
+ dataState = mergeDataState(dataState, "streaming");
524
+ }
525
+ else {
526
+ fragment.selectionSet.selections.forEach(workSet.add, workSet);
527
+ }
534
528
  }
535
529
  });
536
530
  if (Object.keys(result).length !== Object.keys(data).length) {
@@ -543,18 +537,22 @@ export class StoreReader {
543
537
  // actually dropped by the partial @defer fragment.
544
538
  changed = !equal(result, data);
545
539
  }
546
- return changed ? result : data;
540
+ return { result: changed ? result : data, dataState };
547
541
  }
548
542
  prunePartialStreamArrayImpl({ field, array, boundaries, context, path, }) {
549
543
  if (!boundaries)
550
- return array;
544
+ return { result: array, dataState: "complete" };
551
545
  let changed = false;
546
+ let dataState = "complete";
552
547
  let pruned = [];
553
548
  const state = context.streamInfo?.peekArray(path)?.state;
554
549
  const length = Math.min(array.length, state?.truncate ? state.streamPosition : Number.MAX_SAFE_INTEGER);
555
550
  for (let i = 0; i < length; i++) {
556
551
  const item = array[i];
557
- let prunedItem = item;
552
+ let prunedResult = {
553
+ result: item,
554
+ dataState: "complete",
555
+ };
558
556
  const boundary = boundaries.getChild(i);
559
557
  if (boundary?.has(field)) {
560
558
  // The presence of streamInfo determines how we truncate partial
@@ -569,11 +567,12 @@ export class StoreReader {
569
567
  }
570
568
  else {
571
569
  pruned = [];
570
+ dataState = "complete";
572
571
  }
573
572
  break;
574
573
  }
575
574
  if (Array.isArray(item)) {
576
- prunedItem = this.prunePartialStreamArray({
575
+ prunedResult = this.prunePartialStreamArray({
577
576
  field,
578
577
  array: item,
579
578
  boundaries: boundaries.getChild(i),
@@ -582,7 +581,7 @@ export class StoreReader {
582
581
  });
583
582
  }
584
583
  else if (field.selectionSet) {
585
- prunedItem = this.prunePartialBoundaries({
584
+ prunedResult = this.prunePartialBoundaries({
586
585
  data: item,
587
586
  selectionSet: field.selectionSet,
588
587
  boundaries: boundaries.getChild(i),
@@ -590,11 +589,12 @@ export class StoreReader {
590
589
  path: path.concat(i),
591
590
  });
592
591
  }
593
- pruned.push(prunedItem);
594
- changed ||= prunedItem !== item;
592
+ pruned.push(prunedResult.result);
593
+ changed ||= prunedResult.result !== item;
594
+ dataState = mergeDataState(dataState, prunedResult.dataState);
595
595
  }
596
596
  changed ||= pruned.length !== array.length;
597
- return changed ? pruned : array;
597
+ return { result: changed ? pruned : array, dataState };
598
598
  }
599
599
  }
600
600
  function firstMissing(tree) {
@@ -616,7 +616,7 @@ function assertSelectionSetForIdValue(store, field, fieldValue) {
616
616
  if (isNonNullObject(value)) {
617
617
  invariant(
618
618
  !isReference(value),
619
- 114,
619
+ 116,
620
620
  getTypenameFromStoreObject(store, value),
621
621
  field.name.value
622
622
  );
@@ -667,6 +667,23 @@ class PartialBoundaries {
667
667
  return this;
668
668
  }
669
669
  }
670
+ function shouldPrune({ dataState }, context) {
671
+ if (dataState === "deferPartial" || dataState === "streamPartial") {
672
+ return true;
673
+ }
674
+ if (dataState === "complete" || dataState === "streaming") {
675
+ return !!(
676
+ // If the last cache write repaired a partial @stream array to a
677
+ // complete array, the stream array might contain stale entries after
678
+ // the last written value. We only want to deliver the results up to
679
+ // the index the network wrote so we need to prune it too.
680
+ (context.streamInfo ||
681
+ // The network hasn't delivered these @defer boundaries yet, so prune
682
+ // the (possibly complete) cached data sitting at them.
683
+ context.deferInfo));
684
+ }
685
+ return false;
686
+ }
670
687
  // Describes the data state transitions that change the running state when it's
671
688
  // combined with the next data state. Omitted object values represent
672
689
  // "impossible" merges where the data state should remain the same.