Skip to content

Commit 2b182f7

Browse files
AnthonyMDevclaude
andcommitted
Fix cache read failure for nested arrays of objects (#3609)
Resolve CacheReference values recursively in nested arrays so that 2D, 3D, and arbitrarily deep array-of-object fields can be read back from the normalized cache without throwing JSONDecodingError.wrongType. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5936a2a commit 2b182f7

File tree

1 file changed

+28
-19
lines changed

1 file changed

+28
-19
lines changed

Sources/Apollo/Execution/ExecutionSources/CacheDataExecutionSource.swift

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,7 @@ struct CacheDataExecutionSource: GraphQLExecutionSource {
4141
return deferredResolve(reference: reference).map { $0 as JSONValue }
4242

4343
case let referenceList as [JSONValue]:
44-
return referenceList
45-
.enumerated()
46-
.deferredFlatMap { index, element in
47-
guard let cacheReference = element as? CacheReference else {
48-
return .immediate(.success(element))
49-
}
50-
51-
return self.deferredResolve(reference: cacheReference)
52-
.mapError { error in
53-
if !(error is GraphQLExecutionError) {
54-
return GraphQLExecutionError(
55-
path: info.responsePath.appending(String(index)),
56-
underlying: error
57-
)
58-
} else {
59-
return error
60-
}
61-
}.map { $0 as JSONValue }
62-
}.map { $0 as JSONValue }
44+
return resolveReferences(in: referenceList, info: info).map { $0 as JSONValue? }
6345

6446
default:
6547
return .immediate(.success(value))
@@ -141,6 +123,33 @@ struct CacheDataExecutionSource: GraphQLExecutionSource {
141123
}
142124
}
143125

126+
private func resolveReferences(
127+
in list: [JSONValue],
128+
info: FieldExecutionInfo
129+
) -> PossiblyDeferred<JSONValue> {
130+
return list
131+
.enumerated()
132+
.deferredFlatMap { index, element in
133+
if let cacheReference = element as? CacheReference {
134+
return self.deferredResolve(reference: cacheReference)
135+
.mapError { error in
136+
if !(error is GraphQLExecutionError) {
137+
return GraphQLExecutionError(
138+
path: info.responsePath.appending(String(index)),
139+
underlying: error
140+
)
141+
} else {
142+
return error
143+
}
144+
}.map { $0 as JSONValue }
145+
} else if let nestedList = element as? [JSONValue] {
146+
return self.resolveReferences(in: nestedList, info: info)
147+
} else {
148+
return .immediate(.success(element))
149+
}
150+
}.map { $0 as JSONValue }
151+
}
152+
144153
private func deferredResolve(reference: CacheReference) -> PossiblyDeferred<Record> {
145154
guard let transaction else {
146155
return .immediate(.failure(ApolloStore.Error.notWithinReadTransaction))

0 commit comments

Comments
 (0)