@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.
- package/CHANGELOG.md +155 -0
- package/__cjs/cache/index.cjs.map +1 -1
- package/__cjs/cache/index.d.cts +1 -1
- package/__cjs/cache/inmemory/entityStore.cjs +12 -6
- package/__cjs/cache/inmemory/entityStore.cjs.map +1 -1
- package/__cjs/cache/inmemory/entityStore.d.cts +1 -0
- package/__cjs/cache/inmemory/readFromStore.cjs +0 -1
- package/__cjs/cache/inmemory/readFromStore.cjs.map +1 -1
- package/__cjs/cache/inmemory/writeToStore.cjs +6 -2
- package/__cjs/cache/inmemory/writeToStore.cjs.map +1 -1
- package/__cjs/core/ObservableQuery.cjs +1 -3
- package/__cjs/core/ObservableQuery.cjs.map +1 -1
- package/__cjs/core/QueryInfo.cjs +171 -7
- package/__cjs/core/QueryInfo.cjs.map +1 -1
- package/__cjs/core/QueryInfo.d.cts +5 -2
- package/__cjs/core/QueryManager.cjs +10 -17
- package/__cjs/core/QueryManager.cjs.map +1 -1
- package/__cjs/core/QueryManager.d.cts +0 -2
- package/__cjs/utilities/index.cjs.map +1 -1
- package/__cjs/utilities/index.d.cts +1 -0
- package/__cjs/utilities/internal/collectSiblingFields.cjs +61 -0
- package/__cjs/utilities/internal/collectSiblingFields.cjs.map +1 -0
- package/__cjs/utilities/internal/collectSiblingFields.d.cts +21 -0
- package/__cjs/utilities/internal/index.cjs +8 -2
- package/__cjs/utilities/internal/index.cjs.map +1 -1
- package/__cjs/utilities/internal/index.d.cts +4 -0
- package/__cjs/utilities/internal/isDeferredFragment.cjs +23 -0
- package/__cjs/utilities/internal/isDeferredFragment.cjs.map +1 -0
- package/__cjs/utilities/internal/isDeferredFragment.d.cts +4 -0
- package/__cjs/utilities/internal/isTypenameField.cjs +7 -0
- package/__cjs/utilities/internal/isTypenameField.cjs.map +1 -0
- package/__cjs/utilities/internal/isTypenameField.d.cts +3 -0
- package/__cjs/utilities/policies/pagination.cjs.map +1 -1
- package/__cjs/utilities/policies/pagination.d.cts +1 -1
- package/__cjs/utilities/subscriptions/relay/index.cjs +1 -0
- package/__cjs/utilities/subscriptions/relay/index.cjs.map +1 -1
- package/__cjs/version.cjs +1 -1
- package/cache/index.d.ts +1 -1
- package/cache/index.js.map +1 -1
- package/cache/inmemory/entityStore.d.ts +1 -0
- package/cache/inmemory/entityStore.js +12 -6
- package/cache/inmemory/entityStore.js.map +1 -1
- package/cache/inmemory/readFromStore.js +0 -1
- package/cache/inmemory/readFromStore.js.map +1 -1
- package/cache/inmemory/writeToStore.js +7 -3
- package/cache/inmemory/writeToStore.js.map +1 -1
- package/core/ObservableQuery.js +1 -3
- package/core/ObservableQuery.js.map +1 -1
- package/core/QueryInfo.d.ts +5 -2
- package/core/QueryInfo.js +172 -8
- package/core/QueryInfo.js.map +1 -1
- package/core/QueryManager.d.ts +0 -2
- package/core/QueryManager.js +10 -17
- package/core/QueryManager.js.map +1 -1
- package/package.json +1 -1
- package/utilities/index.d.ts +1 -0
- package/utilities/index.js.map +1 -1
- package/utilities/internal/collectSiblingFields.d.ts +21 -0
- package/utilities/internal/collectSiblingFields.js +58 -0
- package/utilities/internal/collectSiblingFields.js.map +1 -0
- package/utilities/internal/index.d.ts +4 -0
- package/utilities/internal/index.js +3 -0
- package/utilities/internal/index.js.map +1 -1
- package/utilities/internal/isDeferredFragment.d.ts +4 -0
- package/utilities/internal/isDeferredFragment.js +20 -0
- package/utilities/internal/isDeferredFragment.js.map +1 -0
- package/utilities/internal/isTypenameField.d.ts +3 -0
- package/utilities/internal/isTypenameField.js +4 -0
- package/utilities/internal/isTypenameField.js.map +1 -0
- package/utilities/policies/pagination.d.ts +1 -1
- package/utilities/policies/pagination.js.map +1 -1
- package/utilities/subscriptions/relay/index.js +1 -0
- package/utilities/subscriptions/relay/index.js.map +1 -1
- package/version.js +1 -1
package/__cjs/core/QueryInfo.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 = {
|
|
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 = {
|
|
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
|