Skip to content

Commit 8de3adc

Browse files
committed
Track pending fragment ids rather than completed ones.
1 parent 5160711 commit 8de3adc

File tree

6 files changed

+431
-81
lines changed

6 files changed

+431
-81
lines changed

libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo/api/BooleanExpression.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,20 @@ fun BooleanExpression<BTerm>.evaluate(
147147
return evaluate {
148148
when (it) {
149149
is BVariable -> !(variables?.contains(it.name) ?: false)
150-
is BLabel -> hasDeferredFragment(deferredFragmentIdentifiers, croppedPath!!, it.label)
150+
is BLabel -> !isDeferredFragmentPending(deferredFragmentIdentifiers, croppedPath!!, it.label)
151151
is BPossibleTypes -> it.possibleTypes.contains(typename)
152152
}
153153
}
154154
}
155155

156-
private fun hasDeferredFragment(deferredFragmentIdentifiers: Set<DeferredFragmentIdentifier>?, path: List<Any>, label: String?): Boolean {
156+
private fun isDeferredFragmentPending(
157+
deferredFragmentIdentifiers: Set<DeferredFragmentIdentifier>?,
158+
path: List<Any>,
159+
label: String?,
160+
): Boolean {
157161
if (deferredFragmentIdentifiers == null) {
158162
// By default, parse all deferred fragments - this is the case when parsing from the normalized cache.
159-
return true
163+
return false
160164
}
161165
return deferredFragmentIdentifiers.contains(DeferredFragmentIdentifier(path, label))
162166
}

libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo/internal/DeferredJsonMerger.kt

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ private typealias MutableJsonMap = MutableMap<String, Any?>
1212
/**
1313
* Utility class for merging GraphQL JSON payloads received in multiple chunks when using the `@defer` directive.
1414
*
15-
* Each call to [merge] will merge the given chunk into the [merged] Map, and will also update the [mergedFragmentIds] Set with the
15+
* Each call to [merge] will merge the given chunk into the [merged] Map, and will also update the [pendingFragmentIds] Set with the
1616
* value of its `path` and `label` field.
1717
*
1818
* The fields in `data` are merged into the node found in [merged] at the path known by looking at the `id` field (for the first call to
@@ -32,10 +32,8 @@ class DeferredJsonMerger {
3232
/**
3333
* Map of identifiers to their corresponding DeferredFragmentIdentifier, found in `pending`.
3434
*/
35-
private val idsToDeferredFragmentIdentifiers = mutableMapOf<String, DeferredFragmentIdentifier>()
36-
37-
private val _mergedFragmentIds = mutableSetOf<DeferredFragmentIdentifier>()
38-
val mergedFragmentIds: Set<DeferredFragmentIdentifier> = _mergedFragmentIds
35+
private val _pendingFragmentIds = mutableMapOf<String, DeferredFragmentIdentifier>()
36+
val pendingFragmentIds: Set<DeferredFragmentIdentifier> get() = _pendingFragmentIds.values.toSet()
3937

4038
var hasNext: Boolean = true
4139
private set
@@ -95,7 +93,7 @@ class DeferredJsonMerger {
9593
val id = pendingItem["id"] as String
9694
val path = pendingItem["path"] as List<Any>
9795
val label = pendingItem["label"] as String?
98-
idsToDeferredFragmentIdentifiers[id] = DeferredFragmentIdentifier(path = path, label = label)
96+
_pendingFragmentIds[id] = DeferredFragmentIdentifier(path = path, label = label)
9997
}
10098
}
10199
}
@@ -104,16 +102,14 @@ class DeferredJsonMerger {
104102
val completed = payload["completed"] as? List<JsonMap>
105103
if (completed != null) {
106104
for (completedItem in completed) {
105+
// Merge errors (if any) of the completed item
107106
val errors = completedItem["errors"] as? List<JsonMap>
108107
if (errors != null) {
109-
// Merge errors (if any) of the completed item
110108
getOrPutMergedErrors() += errors
111109
} else {
112-
// No errors: we have merged all the fields of the fragment so it can be parsed
110+
// Fragment is no longer pending - only if there were no errors
113111
val id = completedItem["id"] as String
114-
val deferredFragmentIdentifier = idsToDeferredFragmentIdentifiers.remove(id)
115-
?: error("Id '$id' not found in pending results")
116-
_mergedFragmentIds += deferredFragmentIdentifier
112+
_pendingFragmentIds.remove(id) ?: error("Id '$id' not found in pending results")
117113
}
118114
}
119115
}
@@ -123,7 +119,7 @@ class DeferredJsonMerger {
123119
val id = incrementalItem["id"] as String? ?: error("No id found in incremental item")
124120
val data = incrementalItem["data"] as JsonMap? ?: error("No data found in incremental item")
125121
val subPath = incrementalItem["subPath"] as List<Any>? ?: emptyList()
126-
val path = (idsToDeferredFragmentIdentifiers[id]?.path ?: error("Id '$id' not found in pending results")) + subPath
122+
val path = (_pendingFragmentIds[id]?.path ?: error("Id '$id' not found in pending results")) + subPath
127123
val mergedData = merged["data"] as JsonMap
128124
val nodeToMergeInto = nodeAtPath(mergedData, path) as MutableJsonMap
129125
deepMerge(nodeToMergeInto, data)
@@ -165,7 +161,7 @@ class DeferredJsonMerger {
165161

166162
fun reset() {
167163
_merged.clear()
168-
_mergedFragmentIds.clear()
164+
_pendingFragmentIds.clear()
169165
hasNext = true
170166
isEmptyPayload = false
171167
}

libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo/network/http/HttpNetworkTransport.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ private constructor(
213213
jsonMerger = DeferredJsonMerger()
214214
}
215215
val merged = jsonMerger!!.merge(part)
216-
val deferredFragmentIds = jsonMerger!!.mergedFragmentIds
216+
val deferredFragmentIds = jsonMerger!!.pendingFragmentIds
217217
val isLast = !jsonMerger!!.hasNext
218218

219219
if (jsonMerger!!.isEmptyPayload) {

libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo/network/websocket/WebSocketNetworkTransport.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ private class DefaultSubscriptionParser<D : Operation.Data>(private val request:
215215
}
216216

217217
val (payload, mergedFragmentIds) = if (responseMap.isDeferred()) {
218-
deferredJsonMerger.merge(responseMap) to deferredJsonMerger.mergedFragmentIds
218+
deferredJsonMerger.merge(responseMap) to deferredJsonMerger.pendingFragmentIds
219219
} else {
220220
responseMap to null
221221
}

libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo/network/ws/WebSocketNetworkTransport.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ import kotlinx.coroutines.flow.map
4545
import kotlinx.coroutines.flow.onCompletion
4646
import kotlinx.coroutines.flow.onSubscription
4747
import kotlinx.coroutines.launch
48-
import okio.use
4948

5049
/**
5150
* A [NetworkTransport] that manages a single instance of a [WebSocketConnection].
@@ -304,7 +303,7 @@ private constructor(
304303
val responsePayload = response.payload
305304
val requestCustomScalarAdapters = request.executionContext[CustomScalarAdapters]!!
306305
val (payload, mergedFragmentIds) = if (responsePayload.isDeferred()) {
307-
deferredJsonMerger.merge(responsePayload) to deferredJsonMerger.mergedFragmentIds
306+
deferredJsonMerger.merge(responsePayload) to deferredJsonMerger.pendingFragmentIds
308307
} else {
309308
responsePayload to null
310309
}

0 commit comments

Comments
 (0)