@apollo/client 4.3.0-alpha.3 → 4.3.0-alpha.5

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 (220) hide show
  1. package/CHANGELOG.md +120 -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/core/types/Cache.d.cts +25 -0
  7. package/__cjs/cache/index.cjs.map +1 -1
  8. package/__cjs/cache/index.d.cts +1 -1
  9. package/__cjs/cache/inmemory/entityStore.cjs +3 -3
  10. package/__cjs/cache/inmemory/inMemoryCache.cjs.map +1 -1
  11. package/__cjs/cache/inmemory/inMemoryCache.d.cts +6 -3
  12. package/__cjs/cache/inmemory/key-extractor.cjs +1 -1
  13. package/__cjs/cache/inmemory/policies.cjs +4 -4
  14. package/__cjs/cache/inmemory/readFromStore.cjs +477 -49
  15. package/__cjs/cache/inmemory/readFromStore.cjs.map +1 -1
  16. package/__cjs/cache/inmemory/readFromStore.d.cts +11 -2
  17. package/__cjs/cache/inmemory/types.d.cts +10 -1
  18. package/__cjs/cache/inmemory/writeToStore.cjs +5 -9
  19. package/__cjs/cache/inmemory/writeToStore.cjs.map +1 -1
  20. package/__cjs/core/ApolloClient.cjs +21 -22
  21. package/__cjs/core/ApolloClient.cjs.map +1 -1
  22. package/__cjs/core/ApolloClient.d.cts +44 -10
  23. package/__cjs/core/ObservableQuery.cjs +46 -5
  24. package/__cjs/core/ObservableQuery.cjs.map +1 -1
  25. package/__cjs/core/ObservableQuery.d.cts +12 -1
  26. package/__cjs/core/QueryInfo.cjs +206 -269
  27. package/__cjs/core/QueryInfo.cjs.map +1 -1
  28. package/__cjs/core/QueryInfo.d.cts +20 -4
  29. package/__cjs/core/QueryManager.cjs +52 -28
  30. package/__cjs/core/QueryManager.cjs.map +1 -1
  31. package/__cjs/core/RefetchEventManager.cjs +3 -3
  32. package/__cjs/core/dataStateErrorCache.cjs +12 -0
  33. package/__cjs/core/dataStateErrorCache.cjs.map +1 -0
  34. package/__cjs/core/dataStateErrorCache.d.cts +3 -0
  35. package/__cjs/core/types.d.cts +2 -0
  36. package/__cjs/incremental/handlers/defer20220824.cjs.map +1 -1
  37. package/__cjs/incremental/handlers/defer20220824.d.cts +2 -4
  38. package/__cjs/incremental/handlers/graphql17Alpha9.cjs +46 -15
  39. package/__cjs/incremental/handlers/graphql17Alpha9.cjs.map +1 -1
  40. package/__cjs/incremental/handlers/graphql17Alpha9.d.cts +29 -6
  41. package/__cjs/incremental/types.d.cts +55 -4
  42. package/__cjs/invariantErrorCodes.cjs +50 -31
  43. package/__cjs/react/hooks/useBackgroundQuery.cjs.map +1 -1
  44. package/__cjs/react/hooks/useBackgroundQuery.d.cts +100 -47
  45. package/__cjs/react/hooks/useLazyQuery.cjs.map +1 -1
  46. package/__cjs/react/hooks/useLazyQuery.d.cts +26 -20
  47. package/__cjs/react/hooks/useLoadableQuery.cjs.map +1 -1
  48. package/__cjs/react/hooks/useLoadableQuery.d.cts +23 -15
  49. package/__cjs/react/hooks/useMutation.cjs.map +1 -1
  50. package/__cjs/react/hooks/useMutation.d.cts +10 -7
  51. package/__cjs/react/hooks/useQuery.cjs.map +1 -1
  52. package/__cjs/react/hooks/useQuery.d.cts +74 -32
  53. package/__cjs/react/hooks/useQueryRefHandlers.cjs.map +1 -1
  54. package/__cjs/react/hooks/useSuspenseQuery.cjs.map +1 -1
  55. package/__cjs/react/hooks/useSuspenseQuery.d.cts +83 -34
  56. package/__cjs/react/internal/cache/QueryReference.cjs.map +1 -1
  57. package/__cjs/react/internal/types.d.cts +14 -3
  58. package/__cjs/react/query-preloader/createQueryPreloader.cjs.map +1 -1
  59. package/__cjs/react/query-preloader/createQueryPreloader.d.cts +20 -5
  60. package/__cjs/testing/core/mocking/mockLink.cjs +21 -1
  61. package/__cjs/testing/core/mocking/mockLink.cjs.map +1 -1
  62. package/__cjs/testing/core/mocking/mockLink.d.cts +1 -2
  63. package/__cjs/utilities/caching/sizes.cjs.map +1 -1
  64. package/__cjs/utilities/caching/sizes.d.cts +39 -1
  65. package/__cjs/utilities/internal/StreamArrayState.cjs +27 -0
  66. package/__cjs/utilities/internal/StreamArrayState.cjs.map +1 -0
  67. package/__cjs/utilities/internal/StreamArrayState.d.cts +12 -0
  68. package/__cjs/utilities/internal/addDeferFragmentLabels.cjs +33 -0
  69. package/__cjs/utilities/internal/addDeferFragmentLabels.cjs.map +1 -0
  70. package/__cjs/utilities/internal/addDeferFragmentLabels.d.cts +3 -0
  71. package/__cjs/utilities/internal/constants.cjs +20 -1
  72. package/__cjs/utilities/internal/constants.cjs.map +1 -1
  73. package/__cjs/utilities/internal/constants.d.cts +19 -0
  74. package/__cjs/utilities/internal/getDirectiveArgValue.cjs +19 -0
  75. package/__cjs/utilities/internal/getDirectiveArgValue.cjs.map +1 -0
  76. package/__cjs/utilities/internal/getDirectiveArgValue.d.cts +9 -0
  77. package/__cjs/utilities/internal/getFragmentFromSelection.cjs +1 -1
  78. package/__cjs/utilities/internal/getFragmentFromSelection.cjs.map +1 -1
  79. package/__cjs/utilities/internal/getMemoryInternals.cjs +6 -0
  80. package/__cjs/utilities/internal/getMemoryInternals.cjs.map +1 -1
  81. package/__cjs/utilities/internal/getMemoryInternals.d.cts +4 -0
  82. package/__cjs/utilities/internal/index.cjs +13 -4
  83. package/__cjs/utilities/internal/index.cjs.map +1 -1
  84. package/__cjs/utilities/internal/index.d.cts +7 -3
  85. package/__cjs/utilities/internal/isDeferredFragment.cjs +19 -4
  86. package/__cjs/utilities/internal/isDeferredFragment.cjs.map +1 -1
  87. package/__cjs/utilities/internal/isDeferredFragment.d.cts +6 -1
  88. package/__cjs/utilities/internal/isStreamField.cjs +37 -0
  89. package/__cjs/utilities/internal/isStreamField.cjs.map +1 -0
  90. package/__cjs/utilities/internal/isStreamField.d.cts +9 -0
  91. package/__cjs/utilities/internal/makeStreamInfoTrie.cjs +17 -0
  92. package/__cjs/utilities/internal/makeStreamInfoTrie.cjs.map +1 -0
  93. package/__cjs/utilities/internal/makeStreamInfoTrie.d.cts +8 -0
  94. package/__cjs/utilities/internal/types/DeferInfo.cjs +3 -0
  95. package/__cjs/utilities/internal/types/DeferInfo.cjs.map +1 -0
  96. package/__cjs/utilities/internal/types/DeferInfo.d.cts +10 -0
  97. package/__cjs/utilities/internal/types/StreamInfoTrie.d.cts +2 -0
  98. package/__cjs/version.cjs +1 -1
  99. package/cache/core/cache.d.ts +5 -1
  100. package/cache/core/cache.js +1 -1
  101. package/cache/core/cache.js.map +1 -1
  102. package/cache/core/types/Cache.d.ts +25 -0
  103. package/cache/core/types/Cache.js.map +1 -1
  104. package/cache/index.d.ts +1 -1
  105. package/cache/index.js.map +1 -1
  106. package/cache/inmemory/entityStore.js +3 -3
  107. package/cache/inmemory/inMemoryCache.d.ts +6 -3
  108. package/cache/inmemory/inMemoryCache.js.map +1 -1
  109. package/cache/inmemory/key-extractor.js +1 -1
  110. package/cache/inmemory/policies.js +4 -4
  111. package/cache/inmemory/readFromStore.d.ts +11 -2
  112. package/cache/inmemory/readFromStore.js +478 -50
  113. package/cache/inmemory/readFromStore.js.map +1 -1
  114. package/cache/inmemory/types.d.ts +11 -2
  115. package/cache/inmemory/types.js.map +1 -1
  116. package/cache/inmemory/writeToStore.js +6 -10
  117. package/cache/inmemory/writeToStore.js.map +1 -1
  118. package/core/ApolloClient.d.ts +44 -10
  119. package/core/ApolloClient.js +21 -22
  120. package/core/ApolloClient.js.map +1 -1
  121. package/core/ObservableQuery.d.ts +12 -1
  122. package/core/ObservableQuery.js +46 -5
  123. package/core/ObservableQuery.js.map +1 -1
  124. package/core/QueryInfo.d.ts +20 -4
  125. package/core/QueryInfo.js +202 -269
  126. package/core/QueryInfo.js.map +1 -1
  127. package/core/QueryManager.js +52 -28
  128. package/core/QueryManager.js.map +1 -1
  129. package/core/RefetchEventManager.js +3 -3
  130. package/core/dataStateErrorCache.d.ts +3 -0
  131. package/core/dataStateErrorCache.js +9 -0
  132. package/core/dataStateErrorCache.js.map +1 -0
  133. package/core/types.d.ts +2 -0
  134. package/core/types.js.map +1 -1
  135. package/incremental/handlers/defer20220824.d.ts +2 -4
  136. package/incremental/handlers/defer20220824.js.map +1 -1
  137. package/incremental/handlers/graphql17Alpha9.d.ts +29 -6
  138. package/incremental/handlers/graphql17Alpha9.js +47 -16
  139. package/incremental/handlers/graphql17Alpha9.js.map +1 -1
  140. package/incremental/types.d.ts +55 -4
  141. package/incremental/types.js.map +1 -1
  142. package/invariantErrorCodes.js +50 -31
  143. package/package.json +1 -1
  144. package/react/hooks/useBackgroundQuery.d.ts +100 -47
  145. package/react/hooks/useBackgroundQuery.js.map +1 -1
  146. package/react/hooks/useLazyQuery.d.ts +26 -20
  147. package/react/hooks/useLazyQuery.js.map +1 -1
  148. package/react/hooks/useLoadableQuery.d.ts +23 -15
  149. package/react/hooks/useLoadableQuery.js.map +1 -1
  150. package/react/hooks/useMutation.d.ts +10 -7
  151. package/react/hooks/useMutation.js.map +1 -1
  152. package/react/hooks/useQuery.d.ts +74 -32
  153. package/react/hooks/useQuery.js.map +1 -1
  154. package/react/hooks/useQueryRefHandlers.js.map +1 -1
  155. package/react/hooks/useSuspenseQuery.d.ts +83 -34
  156. package/react/hooks/useSuspenseQuery.js.map +1 -1
  157. package/react/hooks-compiled/useBackgroundQuery.d.ts +100 -47
  158. package/react/hooks-compiled/useBackgroundQuery.js.map +1 -1
  159. package/react/hooks-compiled/useLazyQuery.d.ts +26 -20
  160. package/react/hooks-compiled/useLazyQuery.js.map +1 -1
  161. package/react/hooks-compiled/useLoadableQuery.d.ts +23 -15
  162. package/react/hooks-compiled/useLoadableQuery.js.map +1 -1
  163. package/react/hooks-compiled/useMutation.d.ts +10 -7
  164. package/react/hooks-compiled/useMutation.js.map +1 -1
  165. package/react/hooks-compiled/useQuery.d.ts +74 -32
  166. package/react/hooks-compiled/useQuery.js.map +1 -1
  167. package/react/hooks-compiled/useQueryRefHandlers.js.map +1 -1
  168. package/react/hooks-compiled/useSuspenseQuery.d.ts +83 -34
  169. package/react/hooks-compiled/useSuspenseQuery.js.map +1 -1
  170. package/react/internal/cache/QueryReference.js.map +1 -1
  171. package/react/internal/types.d.ts +15 -4
  172. package/react/internal/types.js.map +1 -1
  173. package/react/query-preloader/createQueryPreloader.d.ts +20 -5
  174. package/react/query-preloader/createQueryPreloader.js.map +1 -1
  175. package/testing/core/mocking/mockLink.d.ts +1 -2
  176. package/testing/core/mocking/mockLink.js +21 -1
  177. package/testing/core/mocking/mockLink.js.map +1 -1
  178. package/utilities/caching/sizes.d.ts +39 -1
  179. package/utilities/caching/sizes.js.map +1 -1
  180. package/utilities/internal/StreamArrayState.d.ts +12 -0
  181. package/utilities/internal/StreamArrayState.js +23 -0
  182. package/utilities/internal/StreamArrayState.js.map +1 -0
  183. package/utilities/internal/addDeferFragmentLabels.d.ts +3 -0
  184. package/utilities/internal/addDeferFragmentLabels.js +30 -0
  185. package/utilities/internal/addDeferFragmentLabels.js.map +1 -0
  186. package/utilities/internal/constants.d.ts +19 -0
  187. package/utilities/internal/constants.js +19 -0
  188. package/utilities/internal/constants.js.map +1 -1
  189. package/utilities/internal/getDirectiveArgValue.d.ts +9 -0
  190. package/utilities/internal/getDirectiveArgValue.js +16 -0
  191. package/utilities/internal/getDirectiveArgValue.js.map +1 -0
  192. package/utilities/internal/getFragmentFromSelection.js +1 -1
  193. package/utilities/internal/getFragmentFromSelection.js.map +1 -1
  194. package/utilities/internal/getMemoryInternals.d.ts +4 -0
  195. package/utilities/internal/getMemoryInternals.js +6 -0
  196. package/utilities/internal/getMemoryInternals.js.map +1 -1
  197. package/utilities/internal/index.d.ts +7 -3
  198. package/utilities/internal/index.js +6 -2
  199. package/utilities/internal/index.js.map +1 -1
  200. package/utilities/internal/isDeferredFragment.d.ts +7 -2
  201. package/utilities/internal/isDeferredFragment.js +19 -4
  202. package/utilities/internal/isDeferredFragment.js.map +1 -1
  203. package/utilities/internal/isStreamField.d.ts +9 -0
  204. package/utilities/internal/isStreamField.js +34 -0
  205. package/utilities/internal/isStreamField.js.map +1 -0
  206. package/utilities/internal/makeStreamInfoTrie.d.ts +8 -0
  207. package/utilities/internal/makeStreamInfoTrie.js +14 -0
  208. package/utilities/internal/makeStreamInfoTrie.js.map +1 -0
  209. package/utilities/internal/types/DeferInfo.d.ts +10 -0
  210. package/utilities/internal/types/DeferInfo.js +2 -0
  211. package/utilities/internal/types/DeferInfo.js.map +1 -0
  212. package/utilities/internal/types/StreamInfoTrie.d.ts +2 -0
  213. package/utilities/internal/types/StreamInfoTrie.js.map +1 -1
  214. package/version.js +1 -1
  215. package/__cjs/utilities/internal/collectSiblingFields.cjs +0 -61
  216. package/__cjs/utilities/internal/collectSiblingFields.cjs.map +0 -1
  217. package/__cjs/utilities/internal/collectSiblingFields.d.cts +0 -21
  218. package/utilities/internal/collectSiblingFields.d.ts +0 -21
  219. package/utilities/internal/collectSiblingFields.js +0 -58
  220. package/utilities/internal/collectSiblingFields.js.map +0 -1
@@ -1,13 +1,15 @@
1
1
  import type { DocumentNode, FormattedExecutionResult } from "graphql";
2
2
  import type { Cache } from "@apollo/client/cache";
3
+ import type { Incremental } from "@apollo/client/incremental";
3
4
  import type { ApolloLink } from "@apollo/client/link";
4
5
  import type { Unmasked } from "@apollo/client/masking";
5
6
  import type { ExtensionsWithStreamInfo } from "@apollo/client/utilities/internal";
6
7
  import type { ApolloClient } from "./ApolloClient.js";
8
+ import { NetworkStatus } from "./networkStatus.js";
7
9
  import type { ObservableQuery } from "./ObservableQuery.js";
8
10
  import type { QueryManager } from "./QueryManager.js";
9
11
  import type { DataValue, DefaultContext, InternalRefetchQueriesInclude, MutationUpdaterFunction, NormalizedExecutionResult, OnQueryUpdated, OperationVariables, TypedDocumentNode } from "./types.js";
10
- import type { ErrorPolicy } from "./watchQueryOptions.js";
12
+ import type { ErrorPolicy, WatchQueryFetchPolicy } from "./watchQueryOptions.js";
11
13
  type UpdateQueries<TData> = ApolloClient.MutateOptions<TData, any, any>["updateQueries"];
12
14
  export declare const enum CacheWriteBehavior {
13
15
  FORBID = 0,
@@ -18,6 +20,7 @@ interface LastWrite {
18
20
  result: FormattedExecutionResult<any, ExtensionsWithStreamInfo>;
19
21
  variables: ApolloClient.WatchQueryOptions["variables"];
20
22
  dmCount: number | undefined;
23
+ hasNext: boolean;
21
24
  }
22
25
  interface OperationInfo<TData, TVariables extends OperationVariables, AllowedCacheWriteBehavior = CacheWriteBehavior> {
23
26
  document: DocumentNode | TypedDocumentNode<TData, TVariables>;
@@ -38,8 +41,14 @@ export declare class QueryInfo<TData, TVariables extends OperationVariables = Op
38
41
  constructor(queryManager: QueryManager, observableQuery?: ObservableQuery<any, any>);
39
42
  /**
40
43
  * @internal
41
- * For feud-preventing behaviour, `lastWrite` should be shared by all `QueryInfo` instances of an `ObservableQuery`.
42
- * In the case of a standalone `QueryInfo`, we will keep a local version.
44
+ * Tracks the last result written to the cache so that `shouldWrite` can skip
45
+ * an identical write. Since a `QueryInfo` only ever represents a single
46
+ * network request, this is shared by all `QueryInfo` instances of an
47
+ * `ObservableQuery`. A standalone `QueryInfo` keeps a local version.
48
+ *
49
+ * A network result that was explicitly asked for always takes precedence over
50
+ * what is already cached, so `ObservableQuery.refetch` and polling clear this
51
+ * value before starting their request.
43
52
  *
44
53
  * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
45
54
  */
@@ -49,8 +58,15 @@ export declare class QueryInfo<TData, TVariables extends OperationVariables = Op
49
58
  resetLastWrite(): void;
50
59
  private shouldWrite;
51
60
  get hasNext(): boolean;
61
+ get incrementalHandler(): Incremental.Handler<Record<string, unknown>>;
52
62
  private maybeHandleIncrementalResult;
53
- markQueryResult(incoming: ApolloLink.Result<TData>, { document: query, variables, errorPolicy, cacheWriteBehavior, returnPartialData, }: OperationInfo<TData, TVariables>): MarkQueryResult<DataValue.Complete<TData> | DataValue.Streaming<TData>, ExtensionsWithStreamInfo>;
63
+ markQueryResult(incoming: ApolloLink.Result<TData>, { document: query, variables, errorPolicy, cacheWriteBehavior, returnPartialData, fetchPolicy, networkStatus, prunePendingDeferFragments: prune, }: OperationInfo<TData, TVariables> & {
64
+ fetchPolicy: WatchQueryFetchPolicy;
65
+ networkStatus: NetworkStatus;
66
+ prunePendingDeferFragments: boolean;
67
+ }): MarkQueryResult<DataValue.Complete<TData> | DataValue.Streaming<TData>, ExtensionsWithStreamInfo>;
68
+ private getIncrementalInfo;
69
+ private getDiff;
54
70
  markMutationResult(incoming: ApolloLink.Result<TData>, mutation: OperationInfo<TData, TVariables, CacheWriteBehavior.FORBID | CacheWriteBehavior.MERGE> & {
55
71
  context?: DefaultContext;
56
72
  updateQueries: UpdateQueries<TData>;
package/core/QueryInfo.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { equal } from "@wry/equality";
2
- import { collectSiblingFields, createFragmentMap, getFragmentDefinitions, getFragmentFromSelection, getMainDefinition, getOperationName, graphQLResultHasError, hasDirectives, isDeferredFragment, isField, isTypenameField, resultKeyNameFromField, streamInfoSymbol, } from "@apollo/client/utilities/internal";
2
+ import { Trie } from "@wry/trie";
3
+ import { __DEV__ } from "@apollo/client/utilities/environment";
4
+ import { getOperationName, graphQLResultHasError, handleIncrementalSymbol, hasDirectives, } from "@apollo/client/utilities/internal";
3
5
  import { invariant } from "@apollo/client/utilities/invariant";
6
+ import { NetworkStatus } from "./networkStatus.js";
4
7
  const IGNORE = {};
5
8
  const destructiveMethodCounts = new WeakMap();
6
9
  function wrapDestructiveCacheMethod(cache, methodName) {
@@ -39,10 +42,10 @@ export class QueryInfo {
39
42
  this.observableQuery = observableQuery;
40
43
  this.queryManager = queryManager;
41
44
  // Track how often cache.evict is called, since we want eviction to
42
- // override the feud-stopping logic in the markQueryResult method, by
43
- // causing shouldWrite to return true. Wrapping the cache.evict method
44
- // is a bit of a hack, but it saves us from having to make eviction
45
- // counting an official part of the ApolloCache API.
45
+ // override the write-skipping logic in `shouldWrite`, by causing it to
46
+ // return true. Wrapping the cache.evict method is a bit of a hack, but it
47
+ // saves us from having to make eviction counting an official part of the
48
+ // ApolloCache API.
46
49
  if (!destructiveMethodCounts.has(cache)) {
47
50
  destructiveMethodCounts.set(cache, 0);
48
51
  wrapDestructiveCacheMethod(cache, "evict");
@@ -52,8 +55,14 @@ export class QueryInfo {
52
55
  }
53
56
  /**
54
57
  * @internal
55
- * For feud-preventing behaviour, `lastWrite` should be shared by all `QueryInfo` instances of an `ObservableQuery`.
56
- * In the case of a standalone `QueryInfo`, we will keep a local version.
58
+ * Tracks the last result written to the cache so that `shouldWrite` can skip
59
+ * an identical write. Since a `QueryInfo` only ever represents a single
60
+ * network request, this is shared by all `QueryInfo` instances of an
61
+ * `ObservableQuery`. A standalone `QueryInfo` keeps a local version.
62
+ *
63
+ * A network result that was explicitly asked for always takes precedence over
64
+ * what is already cached, so `ObservableQuery.refetch` and polling clear this
65
+ * value before starting their request.
57
66
  *
58
67
  * @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
59
68
  */
@@ -69,178 +78,218 @@ export class QueryInfo {
69
78
  }
70
79
  shouldWrite(result, variables) {
71
80
  const { lastWrite } = this;
72
- return !(lastWrite &&
81
+ return (!lastWrite ||
73
82
  // If cache.evict has been called since the last time we wrote this
74
83
  // data into the cache, there's a chance writing this result into
75
84
  // the cache will repair what was evicted.
76
- lastWrite.dmCount === destructiveMethodCounts.get(this.cache) &&
77
- equal(variables, lastWrite.variables) &&
78
- equal(result.data, lastWrite.result.data) &&
85
+ lastWrite.dmCount !== destructiveMethodCounts.get(this.cache) ||
86
+ !equal(variables, lastWrite.variables) ||
87
+ !equal(result.data, lastWrite.result.data) ||
79
88
  // We have to compare these values because its possible the final chunk
80
89
  // emitted in the incremental result is just `hasNext: false`. This
81
90
  // ensures we trigger a cache write when we get `isLastChunk: true`.
82
- result.extensions?.[streamInfoSymbol] ===
83
- lastWrite.result.extensions?.[streamInfoSymbol]);
91
+ lastWrite.hasNext !== this.hasNext);
84
92
  }
85
93
  get hasNext() {
86
94
  return this.incremental ? this.incremental.hasNext : false;
87
95
  }
96
+ get incrementalHandler() {
97
+ return this.queryManager.incrementalHandler;
98
+ }
88
99
  maybeHandleIncrementalResult(cacheData, incoming, query) {
89
- const { incrementalHandler } = this.queryManager;
90
- if (incrementalHandler.isIncrementalResult(incoming)) {
91
- this.incremental ||= incrementalHandler.startRequest({
100
+ if (this.incrementalHandler.isIncrementalResult(incoming)) {
101
+ this.incremental ||= this.incrementalHandler.startRequest({
92
102
  query,
93
103
  });
94
104
  return this.incremental.handle(cacheData, incoming);
95
105
  }
96
106
  return incoming;
97
107
  }
98
- markQueryResult(incoming, { document: query, variables, errorPolicy, cacheWriteBehavior, returnPartialData, }) {
108
+ markQueryResult(incoming, { document: query, variables, errorPolicy, cacheWriteBehavior, returnPartialData, fetchPolicy, networkStatus, prunePendingDeferFragments: prune, }) {
99
109
  const diffOptions = {
100
110
  query,
101
111
  variables,
102
- returnPartialData: true,
103
112
  optimistic: true,
104
113
  };
105
114
  // Cancel the pending notify timeout (if it exists) to prevent extraneous network
106
115
  // requests. To allow future notify timeouts, diff and dirty are reset as well.
107
116
  this.observableQuery?.["resetNotifications"]();
108
117
  const skipCache = cacheWriteBehavior === 0 /* CacheWriteBehavior.FORBID */;
109
- const lastDiff = skipCache ? undefined : this.cache.diff(diffOptions);
110
- const incrementalResult = this.maybeHandleIncrementalResult(lastDiff?.result, incoming, query);
118
+ const diff = skipCache ? undefined : (this.getDiff({
119
+ ...diffOptions,
120
+ // We usually request partial data to ensure the network incremental
121
+ // result is merged with all existing data (especially true to
122
+ // maintain @stream arrays with partial list items in the right order
123
+ // or when chunk might otherwise replace a partial non-normalized
124
+ // object), but if we are about to throw away the result anyways due
125
+ // to the error policy (which early returns below), prune any
126
+ // pending boundaries so that CombinedGraphQLErrors contains the
127
+ // right `data` value.
128
+ returnPartialData: errorPolicy !== "none" ||
129
+ !this.incrementalHandler.extractErrors(incoming)?.length,
130
+ }, this.getIncrementalInfo({ prune })));
131
+ const incrementalResult = this.maybeHandleIncrementalResult(diff?.result, incoming, query);
111
132
  let result = {
112
133
  ...incrementalResult,
113
- dataState: incrementalResult.data == null ? "empty"
114
- : this.hasNext ? "streaming"
115
- : "complete",
134
+ dataState: incrementalResult.data == null ? "empty" : "complete",
116
135
  };
117
- if (skipCache) {
118
- return {
119
- ...result,
120
- dataState: result.data == null ? "empty"
121
- // Ww can simplify the checks for no-cache queries because the
122
- // result is purely server driven which means we can assume a
123
- // well-formed GraphQL response. In this case, `streaming` only
124
- // makes sense if we are using the `@defer` directive and there are
125
- // more chunks still streaming (i.e. this.hasNext is true). Purely
126
- // `@stream` queries should always be complete.
127
- : this.hasNext && hasDirectives(["defer"], query) ? "streaming"
128
- : "complete",
129
- };
136
+ const hasPendingDefer = this.incremental
137
+ ?.getPendingWithInfo?.()
138
+ .some((pending) => pending.type === "defer" && !pending.delivered);
139
+ if (hasPendingDefer ||
140
+ // The Defer20220824Handler cannot track pending/completed incremental
141
+ // chunks due to its data format so we naively set dataState to
142
+ // streaming if we are still processing chunks. The only case where
143
+ // streaming is incorrect and should actually be complete is when
144
+ // both a @defer and @stream boundary is present and the @defer chunk
145
+ // has completed before the `@stream` array.
146
+ //
147
+ // Assigning the naive "streaming" value avoids a much more expensive
148
+ // pass over `result.data` that would otherwise need to traverse the
149
+ // selection sets and evaluate the data object at each defer boundary
150
+ // to see if it fulfills the selection set. For such a narrow case where
151
+ // its incorrect on a format that is now outdated is not worth the
152
+ // fix so we are ok with reporting a `streaming` here.
153
+ (!this.incremental?.getPendingWithInfo &&
154
+ this.hasNext &&
155
+ hasDirectives(["defer"], query))) {
156
+ result.dataState = "streaming";
130
157
  }
131
- if (shouldWriteResult(result, errorPolicy)) {
132
- // Using a transaction here so we have a chance to read the result
133
- // back from the cache before the watch callback fires as a result
134
- // of writeQuery, so we can store the new diff quietly and ignore
135
- // it when we receive it redundantly from the watch callback.
136
- this.cache.batch({
137
- onWatchUpdated: (
138
- // all additional options on ObservableQuery.CacheWatchOptions are
139
- // optional so we can use the type here
140
- watch, diff) => {
141
- if (watch.watcher === this.observableQuery) {
142
- // see comment on `lastOwnDiff` for explanation
143
- watch.lastOwnDiff = diff;
144
- }
145
- },
146
- update: (cache) => {
147
- if (this.shouldWrite(result, variables)) {
148
- cache.writeQuery({
149
- query,
150
- data: result.data,
151
- variables,
152
- overwrite: cacheWriteBehavior === 1 /* CacheWriteBehavior.OVERWRITE */,
153
- extensions: result.extensions,
154
- });
155
- this.lastWrite = {
156
- result,
157
- variables,
158
- dmCount: destructiveMethodCounts.get(this.cache),
159
- };
160
- }
161
- else {
162
- // If result is the same as the last result we received from
163
- // the network (and the variables match too), avoid writing
164
- // result into the cache again. The wisdom of skipping this
165
- // cache write is far from obvious, since any cache write
166
- // could be the one that puts the cache back into a desired
167
- // state, fixing corruption or missing data. However, if we
168
- // always write every network result into the cache, we enable
169
- // feuds between queries competing to update the same data in
170
- // incompatible ways, which can lead to an endless cycle of
171
- // cache broadcasts and useless network requests. As with any
172
- // feud, eventually one side must step back from the brink,
173
- // letting the other side(s) have the last word(s). There may
174
- // be other points where we could break this cycle, such as
175
- // silencing the broadcast for cache.writeQuery (not a good
176
- // idea, since it just delays the feud a bit) or somehow
177
- // avoiding the network request that just happened (also bad,
178
- // because the server could return useful new data). All
179
- // options considered, skipping this cache write seems to be
180
- // the least damaging place to break the cycle, because it
181
- // reflects the intuition that we recently wrote this exact
182
- // result into the cache, so the cache *should* already/still
183
- // contain this data. If some other query has clobbered that
184
- // data in the meantime, that's too bad, but there will be no
185
- // winners if every query blindly reverts to its own version
186
- // of the data. This approach also gives the network a chance
187
- // to return new data, which will be written into the cache as
188
- // usual, notifying only those queries that are directly
189
- // affected by the cache updates, as usual. In the future, an
190
- // even more sophisticated cache could perhaps prevent or
191
- // mitigate the clobbering somehow, but that would make this
192
- // particular cache write even less important, and thus
193
- // skipping it would be even safer than it is today.
194
- if (lastDiff && lastDiff.complete) {
195
- // Reuse data from the last good (complete) diff that we
196
- // received, when possible.
197
- result = {
198
- ...result,
199
- data: lastDiff.result,
200
- dataState: "complete",
201
- };
202
- return;
203
- }
204
- // If the previous this.diff was incomplete, fall through to
205
- // re-reading the latest data with cache.diff, below.
206
- }
207
- const diff = cache.diff(diffOptions);
208
- // If we're allowed to write to the cache, and we can read a
209
- // complete result from the cache, update result.data to be the
210
- // result from the cache, rather than the raw network result.
211
- // Set without setDiff to avoid triggering a notify call, since
212
- // we have other ways of notifying for this result.
213
- if (diff.complete) {
214
- result = {
215
- ...result,
216
- data: diff.result,
217
- dataState: "complete",
218
- };
219
- }
220
- else if (this.hasNext && diff.result !== null) {
221
- const isPartial = isStreamingPartial(diff, query, variables);
222
- // If we tolerate partial results always apply `diff.result` to
223
- // ensure we return the result of any transforms in cache read
224
- // functions or custom scalars. If we don't tolerate partial
225
- // results, we only want to apply the diff result if the only hole
226
- // in the data is at a defer boundary (e.g.
227
- // `diff.complete === false && isStreamingPartial === false`)
228
- if (returnPartialData || !isPartial) {
229
- result = {
230
- ...result,
231
- data: diff.result,
232
- dataState: isPartial ? "partial" : "streaming",
233
- };
234
- }
235
- }
236
- },
237
- });
158
+ if (skipCache) {
159
+ return result;
238
160
  }
239
- else {
161
+ if (!shouldWriteResult(result, errorPolicy)) {
240
162
  this.lastWrite = void 0;
163
+ return result;
241
164
  }
165
+ let written = false;
166
+ // Using a transaction here so we have a chance to read the result
167
+ // back from the cache before the watch callback fires as a result
168
+ // of writeQuery, so we can store the new diff quietly and ignore
169
+ // it when we receive it redundantly from the watch callback.
170
+ this.cache.batch({
171
+ onWatchUpdated: (
172
+ // all additional options on ObservableQuery.CacheWatchOptions are
173
+ // optional so we can use the type here
174
+ watch, diff) => {
175
+ if (watch.watcher === this.observableQuery) {
176
+ // see comment on `lastOwnDiff` for explanation
177
+ watch.lastOwnDiff = diff;
178
+ }
179
+ },
180
+ update: (cache) => {
181
+ const shouldWrite = this.shouldWrite(result, variables);
182
+ // If result is the same as the last result we received from
183
+ // the network (and the variables match too), avoid writing
184
+ // result into the cache again. The wisdom of skipping this
185
+ // cache write is far from obvious, since any cache write
186
+ // could be the one that puts the cache back into a desired
187
+ // state, fixing corruption or missing data. However, if we
188
+ // always write every network result into the cache, we enable
189
+ // feuds between queries competing to update the same data in
190
+ // incompatible ways, which can lead to an endless cycle of
191
+ // cache broadcasts and useless network requests. As with any
192
+ // feud, eventually one side must step back from the brink,
193
+ // letting the other side(s) have the last word(s). There may
194
+ // be other points where we could break this cycle, such as
195
+ // silencing the broadcast for cache.writeQuery (not a good
196
+ // idea, since it just delays the feud a bit) or somehow
197
+ // avoiding the network request that just happened (also bad,
198
+ // because the server could return useful new data). All
199
+ // options considered, skipping this cache write seems to be
200
+ // the least damaging place to break the cycle, because it
201
+ // reflects the intuition that we recently wrote this exact
202
+ // result into the cache, so the cache *should* already/still
203
+ // contain this data. If some other query has clobbered that
204
+ // data in the meantime, that's too bad, but there will be no
205
+ // winners if every query blindly reverts to its own version
206
+ // of the data. This approach also gives the network a chance
207
+ // to return new data, which will be written into the cache as
208
+ // usual, notifying only those queries that are directly
209
+ // affected by the cache updates, as usual. In the future, an
210
+ // even more sophisticated cache could perhaps prevent or
211
+ // mitigate the clobbering somehow, but that would make this
212
+ // particular cache write even less important, and thus
213
+ // skipping it would be even safer than it is today.
214
+ if (shouldWrite) {
215
+ cache.writeQuery({
216
+ query,
217
+ data: result.data,
218
+ variables,
219
+ overwrite: cacheWriteBehavior === 1 /* CacheWriteBehavior.OVERWRITE */,
220
+ extensions: result.extensions,
221
+ });
222
+ this.lastWrite = {
223
+ result,
224
+ variables,
225
+ dmCount: destructiveMethodCounts.get(this.cache),
226
+ hasNext: this.hasNext,
227
+ };
228
+ written = true;
229
+ }
230
+ const { dataState, result: diffResult } = this.getDiff({
231
+ ...diffOptions,
232
+ returnPartialData: returnPartialData &&
233
+ // Never deliver partial data for network-only requests
234
+ (fetchPolicy !== "network-only" ||
235
+ networkStatus === NetworkStatus.refetch),
236
+ }, this.getIncrementalInfo({ prune }));
237
+ if (dataState === "complete" ||
238
+ dataState === "streaming" ||
239
+ (returnPartialData && dataState === "partial" && shouldWrite)) {
240
+ result = { ...result, data: diffResult, dataState };
241
+ }
242
+ else if (__DEV__ &&
243
+ written &&
244
+ // A result that is still streaming is expected to read back
245
+ // incomplete until the remaining chunks arrive.
246
+ !this.hasNext) {
247
+ warnAboutPartialCacheResult(query, result.data,
248
+ // Always show the partial result for debugging, otherwise the user
249
+ // sees `null` when `returnPartialData` is false which isn't helpful
250
+ // for figuring out where the problem is.
251
+ cache.diff({ ...diffOptions, returnPartialData: true }));
252
+ }
253
+ },
254
+ });
242
255
  return result;
243
256
  }
257
+ getIncrementalInfo({ prune }) {
258
+ const pending = this.incremental?.getPendingWithInfo?.() ?? [];
259
+ const streamInfo = this.incremental?.streamInfo;
260
+ const incrementalInfo = { streamInfo };
261
+ // We don't want to deliver stream items or complete defer boundaries
262
+ // for a network-only request if they haven't yet streamed from the
263
+ // network. We record all the still-pending paths so that cache.diff
264
+ // can prune complete defer/stream boundaries at those paths.
265
+ if (prune) {
266
+ for (const item of pending) {
267
+ if (item.type === "defer" && !item.delivered) {
268
+ incrementalInfo.deferInfo ||= new Trie(true, () => true);
269
+ incrementalInfo.deferInfo.lookupArray(item.path.concat(item.label || []));
270
+ }
271
+ else if (streamInfo && item.type === "stream") {
272
+ streamInfo.lookupArray(item.path).state.truncate = true;
273
+ }
274
+ }
275
+ }
276
+ return incrementalInfo;
277
+ }
278
+ getDiff(options, incrementalInfo) {
279
+ const diff = this.cache.diff({
280
+ ...options,
281
+ [handleIncrementalSymbol]: incrementalInfo,
282
+ });
283
+ if ("dataState" in diff) {
284
+ return diff;
285
+ }
286
+ return {
287
+ ...diff,
288
+ dataState: diff.complete ? "complete"
289
+ : diff.result === null ? "empty"
290
+ : "partial",
291
+ };
292
+ }
244
293
  markMutationResult(incoming, mutation, cache = this.cache) {
245
294
  const cacheWrites = [];
246
295
  const skipCache = mutation.cacheWriteBehavior === 0 /* CacheWriteBehavior.FORBID */;
@@ -435,6 +484,15 @@ export class QueryInfo {
435
484
  }
436
485
  }
437
486
  }
487
+ function warnAboutPartialCacheResult(query, networkResult, diff) {
488
+ __DEV__ && invariant.warn(
489
+ 89,
490
+ getOperationName(query, "(anonymous)"),
491
+ diff.missing?.missing,
492
+ networkResult,
493
+ diff.result
494
+ );
495
+ }
438
496
  function shouldWriteResult(result, errorPolicy = "none") {
439
497
  const ignoreErrors = errorPolicy === "ignore" || errorPolicy === "all";
440
498
  let writeWithErrors = !graphQLResultHasError(result);
@@ -443,129 +501,4 @@ function shouldWriteResult(result, errorPolicy = "none") {
443
501
  }
444
502
  return writeWithErrors;
445
503
  }
446
- function isStreamingPartial(diff, document, variables) {
447
- if (!diff.missing)
448
- return false;
449
- const fragmentMap = createFragmentMap(getFragmentDefinitions(document));
450
- return isPartialInSelectionSet(getMainDefinition(document).selectionSet, diff.missing.missing, { fragmentMap, variables });
451
- }
452
- function isPartialInSelectionSet(selectionSet, missingTree, context) {
453
- if (typeof missingTree === "string")
454
- return true;
455
- if (missingTree === undefined)
456
- return false;
457
- const missingKeys = Object.keys(missingTree);
458
- if (missingKeys.length > 0 && missingKeys.every(isArrayIndex)) {
459
- return missingKeys.some((key) => {
460
- if (typeof missingTree[key] === "string")
461
- return true;
462
- return isPartialInSelectionSet(selectionSet, missingTree[key], context);
463
- });
464
- }
465
- const { fragmentMap, variables } = context;
466
- for (const selection of selectionSet.selections) {
467
- if (isField(selection)) {
468
- if (isTypenameField(selection))
469
- continue;
470
- const missing = missingTree[resultKeyNameFromField(selection)];
471
- // If a missing entry is absent, we have a value for this field
472
- if (missing === undefined)
473
- continue;
474
- if (!selection.selectionSet ||
475
- isPartialInSelectionSet(selection.selectionSet, missing, context)) {
476
- return true;
477
- }
478
- }
479
- else {
480
- const fragment = getFragmentFromSelection(selection, fragmentMap);
481
- if (!fragment)
482
- continue;
483
- if (isDeferredFragment(selection, variables)) {
484
- // We need to know the non-deferred fields that might overlap with the
485
- // deferred selection set so that we accurately report the right
486
- // dataState when all the non-deferred fields are satisfied and only the
487
- // selections inside the fragment are missing.
488
- // For example:
489
- //
490
- // {
491
- // recipient {
492
- // name
493
- // }
494
- // ... @defer {
495
- // recipient {
496
- // name
497
- // email
498
- // }
499
- // }
500
- // }
501
- //
502
- // dataState should be `streaming`, not `partial` if `name` is present,
503
- // but `email` is absent since `name` is not deferred.
504
- if (isPartialDeferBoundary(fragment.selectionSet, missingTree, collectSiblingFields(selectionSet, {
505
- ...context,
506
- exclude: selection,
507
- }), fragmentMap)) {
508
- return true;
509
- }
510
- }
511
- else if (isPartialInSelectionSet(fragment.selectionSet, missingTree, context)) {
512
- return true;
513
- }
514
- }
515
- }
516
- return false;
517
- }
518
- function isPartialDeferBoundary(selectionSet, missing, nonDeferredFields, fragmentMap) {
519
- // This flag tracks whether all fields in this selection set should contain
520
- // values or should all be missing. A defer boundary is only partial if some
521
- // fields are missing. The first selection node will set this value and all
522
- // sibling fields should match after that. As soon as we get a mismatch, we
523
- // have a partial defer boundary.
524
- let shouldContainValues;
525
- for (const selection of selectionSet.selections) {
526
- if (isField(selection)) {
527
- if (isTypenameField(selection))
528
- continue;
529
- const name = resultKeyNameFromField(selection);
530
- const nonDeferredField = nonDeferredFields?.[name];
531
- // If this field is not exclusive to this selection set, we don't care
532
- // what the value is as far as the defer boundary is concerned. Ignore it
533
- // and continue checking other siblings.
534
- if (nonDeferredField === true)
535
- continue;
536
- // The value of missing means different things:
537
- // - undefined: The field is fully satisfied (i.e. it has a value for the field)
538
- // - string: the field is fully unsatisfied (no scalar value, or object is
539
- // missing all fields)
540
- // - object: The field has a selection set and is partially satisfied.
541
- const missingField = missing[name];
542
- if (typeof missingField !== "object") {
543
- const hasValue = missingField === undefined;
544
- if (shouldContainValues === undefined) {
545
- shouldContainValues = hasValue;
546
- }
547
- if (hasValue !== shouldContainValues) {
548
- return true;
549
- }
550
- continue;
551
- }
552
- if (selection.selectionSet &&
553
- isPartialDeferBoundary(selection.selectionSet, missingField, nonDeferredField, fragmentMap)) {
554
- return true;
555
- }
556
- }
557
- else {
558
- const fragment = getFragmentFromSelection(selection, fragmentMap);
559
- if (!fragment)
560
- continue;
561
- if (isPartialDeferBoundary(fragment.selectionSet, missing, nonDeferredFields, fragmentMap)) {
562
- return true;
563
- }
564
- }
565
- }
566
- return false;
567
- }
568
- function isArrayIndex(key) {
569
- return /^\d+$/.test(key);
570
- }
571
504
  //# sourceMappingURL=QueryInfo.js.map