diff --git a/Sources/Apollo/ApolloStore.swift b/Sources/Apollo/ApolloStore.swift index e26df4416f..e2882ba09e 100644 --- a/Sources/Apollo/ApolloStore.swift +++ b/Sources/Apollo/ApolloStore.swift @@ -64,6 +64,13 @@ public final class ApolloStore { } } + /// Merges a `RecordSet` into the normalized cache. + /// - Parameters: + /// - records: The records to be merged into the cache. + /// - identifier: [optional] A unique identifier for the request that kicked off this change, + /// to assist in de-duping cache hits for watchers. + /// - callbackQueue: The queue to call the completion block on. Defaults to `DispatchQueue.main`. + /// - completion: [optional] A completion block to be called after records are merged into the cache. public func publish(records: RecordSet, identifier: UUID? = nil, callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) { queue.async(flags: .barrier) { do { diff --git a/Sources/Apollo/GraphQLResponse.swift b/Sources/Apollo/GraphQLResponse.swift index cd87ce79e6..3b1dc8881a 100644 --- a/Sources/Apollo/GraphQLResponse.swift +++ b/Sources/Apollo/GraphQLResponse.swift @@ -19,6 +19,11 @@ public final class GraphQLResponse { self.variables = operation.variables } + /// Parses a response into a `GraphQLResult` and a `RecordSet`. + /// The result can be sent to a completion block for a request. + /// The `RecordSet` can be merged into a local cache. + /// - Parameter cacheKeyForObject: See `CacheKeyForObject` + /// - Returns: A `GraphQLResult` and a `RecordSet`. public func parseResult(cacheKeyForObject: CacheKeyForObject? = nil) throws -> (GraphQLResult, RecordSet?) { let errors: [GraphQLError]? diff --git a/Sources/ApolloWebSocket/WebSocketTransport.swift b/Sources/ApolloWebSocket/WebSocketTransport.swift index 388397dde4..208f7b7ae4 100644 --- a/Sources/ApolloWebSocket/WebSocketTransport.swift +++ b/Sources/ApolloWebSocket/WebSocketTransport.swift @@ -79,6 +79,7 @@ public class WebSocketTransport { /// /// - Parameters: /// - websocket: The websocket client to use for creating a websocket connection. + /// - store: [optional] The `ApolloStore` used as a local cache. Defaults to `nil`. /// - clientName: The client name to use for this client. Defaults to `Self.defaultClientName` /// - clientVersion: The client version to use for this client. Defaults to `Self.defaultClientVersion`. /// - sendOperationIdentifiers: Whether or not to send operation identifiers with operations. Defaults to false. @@ -362,24 +363,36 @@ extension WebSocketTransport: NetworkTransport { return EmptyCancellable() } - return WebSocketTask(self, operation) { [store] result in + return WebSocketTask(self, operation) { [weak store, contextIdentifier, callbackQueue] result in switch result { case .success(let jsonBody): - let response = GraphQLResponse(operation: operation, body: jsonBody) - if let store = store { - do { - let (_, records) = try response.parseResult(cacheKeyForObject: store.cacheKeyForObject) - if let records = records { - store.publish(records: records, identifier: nil) + do { + let response = GraphQLResponse(operation: operation, body: jsonBody) + + if let store = store { + let (graphQLResult, parsedRecords) = try response.parseResult(cacheKeyForObject: store.cacheKeyForObject) + guard let records = parsedRecords else { + callCompletion(with: .success(graphQLResult)) + return + } + + store.publish(records: records, + identifier: contextIdentifier, + callbackQueue: callbackQueue) { result in + switch result { + case .success: + completionHandler(.success(graphQLResult)) + + case let .failure(error): + callCompletion(with: .failure(error)) + } } - } catch { - callCompletion(with: .failure(error)) + + } else { + let graphQLResult = try response.parseResultFast() + callCompletion(with: .success(graphQLResult)) } - } - - do { - let graphQLResult = try response.parseResultFast() - callCompletion(with: .success(graphQLResult)) + } catch { callCompletion(with: .failure(error)) }