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

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 (74) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/__cjs/cache/index.cjs.map +1 -1
  3. package/__cjs/cache/index.d.cts +1 -1
  4. package/__cjs/cache/inmemory/entityStore.cjs +12 -6
  5. package/__cjs/cache/inmemory/entityStore.cjs.map +1 -1
  6. package/__cjs/cache/inmemory/entityStore.d.cts +1 -0
  7. package/__cjs/cache/inmemory/readFromStore.cjs +0 -1
  8. package/__cjs/cache/inmemory/readFromStore.cjs.map +1 -1
  9. package/__cjs/cache/inmemory/writeToStore.cjs +6 -2
  10. package/__cjs/cache/inmemory/writeToStore.cjs.map +1 -1
  11. package/__cjs/core/ObservableQuery.cjs +1 -3
  12. package/__cjs/core/ObservableQuery.cjs.map +1 -1
  13. package/__cjs/core/QueryInfo.cjs +171 -7
  14. package/__cjs/core/QueryInfo.cjs.map +1 -1
  15. package/__cjs/core/QueryInfo.d.cts +5 -2
  16. package/__cjs/core/QueryManager.cjs +10 -17
  17. package/__cjs/core/QueryManager.cjs.map +1 -1
  18. package/__cjs/core/QueryManager.d.cts +0 -2
  19. package/__cjs/utilities/index.cjs.map +1 -1
  20. package/__cjs/utilities/index.d.cts +1 -0
  21. package/__cjs/utilities/internal/collectSiblingFields.cjs +61 -0
  22. package/__cjs/utilities/internal/collectSiblingFields.cjs.map +1 -0
  23. package/__cjs/utilities/internal/collectSiblingFields.d.cts +21 -0
  24. package/__cjs/utilities/internal/index.cjs +8 -2
  25. package/__cjs/utilities/internal/index.cjs.map +1 -1
  26. package/__cjs/utilities/internal/index.d.cts +4 -0
  27. package/__cjs/utilities/internal/isDeferredFragment.cjs +23 -0
  28. package/__cjs/utilities/internal/isDeferredFragment.cjs.map +1 -0
  29. package/__cjs/utilities/internal/isDeferredFragment.d.cts +4 -0
  30. package/__cjs/utilities/internal/isTypenameField.cjs +7 -0
  31. package/__cjs/utilities/internal/isTypenameField.cjs.map +1 -0
  32. package/__cjs/utilities/internal/isTypenameField.d.cts +3 -0
  33. package/__cjs/utilities/policies/pagination.cjs.map +1 -1
  34. package/__cjs/utilities/policies/pagination.d.cts +1 -1
  35. package/__cjs/utilities/subscriptions/relay/index.cjs +1 -0
  36. package/__cjs/utilities/subscriptions/relay/index.cjs.map +1 -1
  37. package/__cjs/version.cjs +1 -1
  38. package/cache/index.d.ts +1 -1
  39. package/cache/index.js.map +1 -1
  40. package/cache/inmemory/entityStore.d.ts +1 -0
  41. package/cache/inmemory/entityStore.js +12 -6
  42. package/cache/inmemory/entityStore.js.map +1 -1
  43. package/cache/inmemory/readFromStore.js +0 -1
  44. package/cache/inmemory/readFromStore.js.map +1 -1
  45. package/cache/inmemory/writeToStore.js +7 -3
  46. package/cache/inmemory/writeToStore.js.map +1 -1
  47. package/core/ObservableQuery.js +1 -3
  48. package/core/ObservableQuery.js.map +1 -1
  49. package/core/QueryInfo.d.ts +5 -2
  50. package/core/QueryInfo.js +172 -8
  51. package/core/QueryInfo.js.map +1 -1
  52. package/core/QueryManager.d.ts +0 -2
  53. package/core/QueryManager.js +10 -17
  54. package/core/QueryManager.js.map +1 -1
  55. package/package.json +1 -1
  56. package/utilities/index.d.ts +1 -0
  57. package/utilities/index.js.map +1 -1
  58. package/utilities/internal/collectSiblingFields.d.ts +21 -0
  59. package/utilities/internal/collectSiblingFields.js +58 -0
  60. package/utilities/internal/collectSiblingFields.js.map +1 -0
  61. package/utilities/internal/index.d.ts +4 -0
  62. package/utilities/internal/index.js +3 -0
  63. package/utilities/internal/index.js.map +1 -1
  64. package/utilities/internal/isDeferredFragment.d.ts +4 -0
  65. package/utilities/internal/isDeferredFragment.js +20 -0
  66. package/utilities/internal/isDeferredFragment.js.map +1 -0
  67. package/utilities/internal/isTypenameField.d.ts +3 -0
  68. package/utilities/internal/isTypenameField.js +4 -0
  69. package/utilities/internal/isTypenameField.js.map +1 -0
  70. package/utilities/policies/pagination.d.ts +1 -1
  71. package/utilities/policies/pagination.js.map +1 -1
  72. package/utilities/subscriptions/relay/index.js +1 -0
  73. package/utilities/subscriptions/relay/index.js.map +1 -1
  74. package/version.js +1 -1
@@ -29,8 +29,6 @@ const queryInfoIds = new WeakMap();
29
29
  // It is responsible for reporting results to the cache, merging and in a no-cache
30
30
  // scenario accumulating the response.
31
31
  class QueryInfo {
32
- // TODO remove soon - this should be able to be handled by cancelling old operations before starting new ones
33
- lastRequestId = 1;
34
32
  cache;
35
33
  queryManager;
36
34
  id;
@@ -100,7 +98,7 @@ class QueryInfo {
100
98
  }
101
99
  return incoming;
102
100
  }
103
- markQueryResult(incoming, { document: query, variables, errorPolicy, cacheWriteBehavior, }) {
101
+ markQueryResult(incoming, { document: query, variables, errorPolicy, cacheWriteBehavior, returnPartialData, }) {
104
102
  const diffOptions = {
105
103
  query,
106
104
  variables,
@@ -112,9 +110,26 @@ class QueryInfo {
112
110
  this.observableQuery?.["resetNotifications"]();
113
111
  const skipCache = cacheWriteBehavior === 0 /* CacheWriteBehavior.FORBID */;
114
112
  const lastDiff = skipCache ? undefined : this.cache.diff(diffOptions);
115
- let result = this.maybeHandleIncrementalResult(lastDiff?.result, incoming, query);
113
+ const incrementalResult = this.maybeHandleIncrementalResult(lastDiff?.result, incoming, query);
114
+ let result = {
115
+ ...incrementalResult,
116
+ dataState: incrementalResult.data == null ? "empty"
117
+ : this.hasNext ? "streaming"
118
+ : "complete",
119
+ };
116
120
  if (skipCache) {
117
- return result;
121
+ return {
122
+ ...result,
123
+ dataState: result.data == null ? "empty"
124
+ // Ww can simplify the checks for no-cache queries because the
125
+ // result is purely server driven which means we can assume a
126
+ // well-formed GraphQL response. In this case, `streaming` only
127
+ // makes sense if we are using the `@defer` directive and there are
128
+ // more chunks still streaming (i.e. this.hasNext is true). Purely
129
+ // `@stream` queries should always be complete.
130
+ : this.hasNext && (0, internal_1.hasDirectives)(["defer"], query) ? "streaming"
131
+ : "complete",
132
+ };
118
133
  }
119
134
  if (shouldWriteResult(result, errorPolicy)) {
120
135
  // Using a transaction here so we have a chance to read the result
@@ -182,7 +197,11 @@ class QueryInfo {
182
197
  if (lastDiff && lastDiff.complete) {
183
198
  // Reuse data from the last good (complete) diff that we
184
199
  // received, when possible.
185
- result = { ...result, data: lastDiff.result };
200
+ result = {
201
+ ...result,
202
+ data: lastDiff.result,
203
+ dataState: "complete",
204
+ };
186
205
  return;
187
206
  }
188
207
  // If the previous this.diff was incomplete, fall through to
@@ -195,7 +214,27 @@ class QueryInfo {
195
214
  // Set without setDiff to avoid triggering a notify call, since
196
215
  // we have other ways of notifying for this result.
197
216
  if (diff.complete) {
198
- result = { ...result, data: diff.result };
217
+ result = {
218
+ ...result,
219
+ data: diff.result,
220
+ dataState: "complete",
221
+ };
222
+ }
223
+ else if (this.hasNext && diff.result !== null) {
224
+ const isPartial = isStreamingPartial(diff, query, variables);
225
+ // If we tolerate partial results always apply `diff.result` to
226
+ // ensure we return the result of any transforms in cache read
227
+ // functions or custom scalars. If we don't tolerate partial
228
+ // results, we only want to apply the diff result if the only hole
229
+ // in the data is at a defer boundary (e.g.
230
+ // `diff.complete === false && isStreamingPartial === false`)
231
+ if (returnPartialData || !isPartial) {
232
+ result = {
233
+ ...result,
234
+ data: diff.result,
235
+ dataState: isPartial ? "partial" : "streaming",
236
+ };
237
+ }
199
238
  }
200
239
  },
201
240
  });
@@ -408,4 +447,129 @@ function shouldWriteResult(result, errorPolicy = "none") {
408
447
  }
409
448
  return writeWithErrors;
410
449
  }
450
+ function isStreamingPartial(diff, document, variables) {
451
+ if (!diff.missing)
452
+ return false;
453
+ const fragmentMap = (0, internal_1.createFragmentMap)((0, internal_1.getFragmentDefinitions)(document));
454
+ return isPartialInSelectionSet((0, internal_1.getMainDefinition)(document).selectionSet, diff.missing.missing, { fragmentMap, variables });
455
+ }
456
+ function isPartialInSelectionSet(selectionSet, missingTree, context) {
457
+ if (typeof missingTree === "string")
458
+ return true;
459
+ if (missingTree === undefined)
460
+ return false;
461
+ const missingKeys = Object.keys(missingTree);
462
+ if (missingKeys.length > 0 && missingKeys.every(isArrayIndex)) {
463
+ return missingKeys.some((key) => {
464
+ if (typeof missingTree[key] === "string")
465
+ return true;
466
+ return isPartialInSelectionSet(selectionSet, missingTree[key], context);
467
+ });
468
+ }
469
+ const { fragmentMap, variables } = context;
470
+ for (const selection of selectionSet.selections) {
471
+ if ((0, internal_1.isField)(selection)) {
472
+ if ((0, internal_1.isTypenameField)(selection))
473
+ continue;
474
+ const missing = missingTree[(0, internal_1.resultKeyNameFromField)(selection)];
475
+ // If a missing entry is absent, we have a value for this field
476
+ if (missing === undefined)
477
+ continue;
478
+ if (!selection.selectionSet ||
479
+ isPartialInSelectionSet(selection.selectionSet, missing, context)) {
480
+ return true;
481
+ }
482
+ }
483
+ else {
484
+ const fragment = (0, internal_1.getFragmentFromSelection)(selection, fragmentMap);
485
+ if (!fragment)
486
+ continue;
487
+ if ((0, internal_1.isDeferredFragment)(selection, variables)) {
488
+ // We need to know the non-deferred fields that might overlap with the
489
+ // deferred selection set so that we accurately report the right
490
+ // dataState when all the non-deferred fields are satisfied and only the
491
+ // selections inside the fragment are missing.
492
+ // For example:
493
+ //
494
+ // {
495
+ // recipient {
496
+ // name
497
+ // }
498
+ // ... @defer {
499
+ // recipient {
500
+ // name
501
+ // email
502
+ // }
503
+ // }
504
+ // }
505
+ //
506
+ // dataState should be `streaming`, not `partial` if `name` is present,
507
+ // but `email` is absent since `name` is not deferred.
508
+ if (isPartialDeferBoundary(fragment.selectionSet, missingTree, (0, internal_1.collectSiblingFields)(selectionSet, {
509
+ ...context,
510
+ exclude: selection,
511
+ }), fragmentMap)) {
512
+ return true;
513
+ }
514
+ }
515
+ else if (isPartialInSelectionSet(fragment.selectionSet, missingTree, context)) {
516
+ return true;
517
+ }
518
+ }
519
+ }
520
+ return false;
521
+ }
522
+ function isPartialDeferBoundary(selectionSet, missing, nonDeferredFields, fragmentMap) {
523
+ // This flag tracks whether all fields in this selection set should contain
524
+ // values or should all be missing. A defer boundary is only partial if some
525
+ // fields are missing. The first selection node will set this value and all
526
+ // sibling fields should match after that. As soon as we get a mismatch, we
527
+ // have a partial defer boundary.
528
+ let shouldContainValues;
529
+ for (const selection of selectionSet.selections) {
530
+ if ((0, internal_1.isField)(selection)) {
531
+ if ((0, internal_1.isTypenameField)(selection))
532
+ continue;
533
+ const name = (0, internal_1.resultKeyNameFromField)(selection);
534
+ const nonDeferredField = nonDeferredFields?.[name];
535
+ // If this field is not exclusive to this selection set, we don't care
536
+ // what the value is as far as the defer boundary is concerned. Ignore it
537
+ // and continue checking other siblings.
538
+ if (nonDeferredField === true)
539
+ continue;
540
+ // The value of missing means different things:
541
+ // - undefined: The field is fully satisfied (i.e. it has a value for the field)
542
+ // - string: the field is fully unsatisfied (no scalar value, or object is
543
+ // missing all fields)
544
+ // - object: The field has a selection set and is partially satisfied.
545
+ const missingField = missing[name];
546
+ if (typeof missingField !== "object") {
547
+ const hasValue = missingField === undefined;
548
+ if (shouldContainValues === undefined) {
549
+ shouldContainValues = hasValue;
550
+ }
551
+ if (hasValue !== shouldContainValues) {
552
+ return true;
553
+ }
554
+ continue;
555
+ }
556
+ if (selection.selectionSet &&
557
+ isPartialDeferBoundary(selection.selectionSet, missingField, nonDeferredField, fragmentMap)) {
558
+ return true;
559
+ }
560
+ }
561
+ else {
562
+ const fragment = (0, internal_1.getFragmentFromSelection)(selection, fragmentMap);
563
+ if (!fragment)
564
+ continue;
565
+ if (isPartialDeferBoundary(fragment.selectionSet, missing, nonDeferredFields, fragmentMap)) {
566
+ return true;
567
+ }
568
+ }
569
+ }
570
+ return false;
571
+ }
572
+ function isArrayIndex(key) {
573
+ return /^\d+$/.test(key);
574
+ }
411
575
  //# sourceMappingURL=QueryInfo.cjs.map