Skip to content

Commit

Permalink
Executor handles nil FieldEntry values
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyMDev committed Sep 21, 2021
1 parent 901e7bf commit b91ac93
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 34 deletions.
18 changes: 9 additions & 9 deletions Sources/Apollo/Collection+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@ import Foundation
// MARK: - Unzipping
// MARK: Arrays of tuples to tuples of arrays

public func unzip<Element1, Element2>(_ array: [(Element1, Element2)]) -> ([Element1], [Element2]) {
public func unzip<Element1, Element2>(_ array: [(Element1?, Element2?)]) -> ([Element1], [Element2]) {
var array1: [Element1] = []
var array2: [Element2] = []

for element in array {
array1.append(element.0)
array2.append(element.1)
for elements in array {
if let element1 = elements.0 { array1.append(element1) }
if let element2 = elements.1 { array2.append(element2) }
}

return (array1, array2)
}

public func unzip<Element1, Element2, Element3>(_ array: [(Element1, Element2, Element3)]) -> ([Element1], [Element2], [Element3]) {
public func unzip<Element1, Element2, Element3>(_ array: [(Element1?, Element2?, Element3?)]) -> ([Element1], [Element2], [Element3]) {
var array1: [Element1] = []
var array2: [Element2] = []
var array3: [Element3] = []

for element in array {
array1.append(element.0)
array2.append(element.1)
array3.append(element.2)
for elements in array {
if let element1 = elements.0 { array1.append(element1) }
if let element2 = elements.1 { array2.append(element2) }
if let element3 = elements.2 { array3.append(element3) }
}

return (array1, array2, array3)
Expand Down
3 changes: 2 additions & 1 deletion Sources/Apollo/GraphQLDependencyTracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ final class GraphQLDependencyTracker: GraphQLResultAccumulator {
dependentKeys.insert(info.cachePath.joined)
}

func accept(fieldEntry: Void, info: FieldExecutionInfo) {
func accept(fieldEntry: Void, info: FieldExecutionInfo) -> ()? {
return ()
}

func accept(fieldEntries: [Void], info: ObjectExecutionInfo) {
Expand Down
6 changes: 3 additions & 3 deletions Sources/Apollo/GraphQLExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ final class GraphQLExecutor {
do {
let groupedFields = try groupFields(selections, on: object, info: info)

var fieldEntries: [PossiblyDeferred<Accumulator.FieldEntry>] = []
var fieldEntries: [PossiblyDeferred<Accumulator.FieldEntry?>] = []
fieldEntries.reserveCapacity(groupedFields.count)

for (_, fields) in groupedFields {
Expand All @@ -223,7 +223,7 @@ final class GraphQLExecutor {
fieldEntries.append(fieldEntry)
}

return lazilyEvaluateAll(fieldEntries).map {
return compactLazilyEvaluateAll(fieldEntries).map {
try accumulator.accept(fieldEntries: $0, info: info)
}

Expand Down Expand Up @@ -320,7 +320,7 @@ final class GraphQLExecutor {
fields: FieldExecutionInfo,
on object: JSONObject,
accumulator: Accumulator
) -> PossiblyDeferred<Accumulator.FieldEntry> {
) -> PossiblyDeferred<Accumulator.FieldEntry?> {
var fieldInfo = fields

if shouldComputeCachePath {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Apollo/GraphQLResponseGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class GraphQLResponseGenerator: GraphQLResultAccumulator {
return childObject
}

func accept(fieldEntry: JSONValue, info: FieldExecutionInfo) -> (key: String, value: JSONValue) {
func accept(fieldEntry: JSONValue, info: FieldExecutionInfo) -> (key: String, value: JSONValue)? {
return (info.responseKeyForField, fieldEntry)
}

Expand Down
10 changes: 5 additions & 5 deletions Sources/Apollo/GraphQLResultAccumulator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ protocol GraphQLResultAccumulator: AnyObject {
func accept(list: [PartialResult], info: FieldExecutionInfo) throws -> PartialResult
func accept(childObject: ObjectResult, info: FieldExecutionInfo) throws -> PartialResult

func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry
func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry?
func accept(fieldEntries: [FieldEntry], info: ObjectExecutionInfo) throws -> ObjectResult

func finish(rootValue: ObjectResult) throws -> FinalResult
Expand All @@ -25,7 +25,7 @@ func zip<Accumulator1: GraphQLResultAccumulator, Accumulator2: GraphQLResultAccu

final class Zip2Accumulator<Accumulator1: GraphQLResultAccumulator, Accumulator2: GraphQLResultAccumulator>: GraphQLResultAccumulator {
typealias PartialResult = (Accumulator1.PartialResult, Accumulator2.PartialResult)
typealias FieldEntry = (Accumulator1.FieldEntry, Accumulator2.FieldEntry)
typealias FieldEntry = (Accumulator1.FieldEntry?, Accumulator2.FieldEntry?)
typealias ObjectResult = (Accumulator1.ObjectResult, Accumulator2.ObjectResult)
typealias FinalResult = (Accumulator1.FinalResult, Accumulator2.FinalResult)

Expand Down Expand Up @@ -58,7 +58,7 @@ final class Zip2Accumulator<Accumulator1: GraphQLResultAccumulator, Accumulator2
try accumulator2.accept(childObject: childObject.1, info: info))
}

func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry {
func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry? {
return (try accumulator1.accept(fieldEntry: fieldEntry.0, info: info),
try accumulator2.accept(fieldEntry: fieldEntry.1, info: info))
}
Expand All @@ -77,7 +77,7 @@ final class Zip2Accumulator<Accumulator1: GraphQLResultAccumulator, Accumulator2

final class Zip3Accumulator<Accumulator1: GraphQLResultAccumulator, Accumulator2: GraphQLResultAccumulator, Accumulator3: GraphQLResultAccumulator>: GraphQLResultAccumulator {
typealias PartialResult = (Accumulator1.PartialResult, Accumulator2.PartialResult, Accumulator3.PartialResult)
typealias FieldEntry = (Accumulator1.FieldEntry, Accumulator2.FieldEntry, Accumulator3.FieldEntry)
typealias FieldEntry = (Accumulator1.FieldEntry?, Accumulator2.FieldEntry?, Accumulator3.FieldEntry?)
typealias ObjectResult = (Accumulator1.ObjectResult, Accumulator2.ObjectResult, Accumulator3.ObjectResult)
typealias FinalResult = (Accumulator1.FinalResult, Accumulator2.FinalResult, Accumulator3.FinalResult)

Expand Down Expand Up @@ -119,7 +119,7 @@ final class Zip3Accumulator<Accumulator1: GraphQLResultAccumulator, Accumulator2
try accumulator3.accept(childObject: childObject.2, info: info))
}

func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry {
func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry? {
return (try accumulator1.accept(fieldEntry: fieldEntry.0, info: info),
try accumulator2.accept(fieldEntry: fieldEntry.1, info: info),
try accumulator3.accept(fieldEntry: fieldEntry.2, info: info))
Expand Down
2 changes: 1 addition & 1 deletion Sources/Apollo/GraphQLResultNormalizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class GraphQLResultNormalizer: GraphQLResultAccumulator {
return childObject
}

func accept(fieldEntry: JSONValue, info: FieldExecutionInfo) -> (key: String, value: JSONValue) {
func accept(fieldEntry: JSONValue, info: FieldExecutionInfo) -> (key: String, value: JSONValue)? {
return (info.cacheKeyForField, fieldEntry)
}

Expand Down
11 changes: 6 additions & 5 deletions Sources/Apollo/GraphQLSelectionSetMapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,23 @@ final class GraphQLSelectionSetMapper<SelectionSet: AnySelectionSet>: GraphQLRes
return list
}

func accept(childObject: [String : Any?], info: FieldExecutionInfo) throws -> JSONValue? {
func accept(childObject: JSONObject, info: FieldExecutionInfo) throws -> JSONValue? {
return childObject
}

func accept(fieldEntry: JSONValue?, info: FieldExecutionInfo) -> (key: String, value: JSONValue?) {
func accept(fieldEntry: JSONValue?, info: FieldExecutionInfo) -> (key: String, value: JSONValue)? {
guard let fieldEntry = fieldEntry else { return nil }
return (info.responseKeyForField, fieldEntry)
}

func accept(
fieldEntries: [(key: String, value: JSONValue?)],
fieldEntries: [(key: String, value: JSONValue)],
info: ObjectExecutionInfo
) throws -> [String: Any?] {
) throws -> JSONObject {
return .init(fieldEntries, uniquingKeysWith: { (_, last) in last })
}

func finish(rootValue: [String: Any?]) -> SelectionSet {
func finish(rootValue: JSONObject) -> SelectionSet {
return SelectionSet.init(data: ResponseDict(rootValue))
}
}
10 changes: 10 additions & 0 deletions Sources/Apollo/PossiblyDeferred.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ func lazilyEvaluateAll<Value>(_ elements: [PossiblyDeferred<Value>]) -> Possibly
}
}

/// Lazily evaluates an array of possibly deferred optional values, filtering out any nil values.
/// - Parameters:
/// - elements: An array of possibly deferred values
/// - Returns: A deferred array with the result of evaluating each element.
func compactLazilyEvaluateAll<Value>(_ elements: [PossiblyDeferred<Value?>]) -> PossiblyDeferred<[Value]> {
return .deferred {
try elements.compactMap { try $0.get() }
}
}

/// A possibly deferred value that represents either an immediate success or failure value, or a deferred
/// value that is evaluated lazily when needed by invoking a throwing closure.
enum PossiblyDeferred<Value> {
Expand Down
10 changes: 5 additions & 5 deletions Sources/ApolloAPI/CodegenV1/ResponseDict.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/// A structure that wraps the underlying data dictionary used by `SelectionSet`s.
public struct ResponseDict {

let data: [String: Any?]
let data: JSONObject

public init(_ data: [String: Any?]) {
public init(_ data: JSONObject) {
self.data = data
}

Expand All @@ -16,17 +16,17 @@ public struct ResponseDict {
}

public subscript<T: SelectionSet>(_ key: String) -> T {
let objectData = data[key] as! [String: Any]
let objectData = data[key] as! JSONObject
return T.init(data: ResponseDict(objectData))
}

public subscript<T: SelectionSet>(_ key: String) -> T? {
guard let objectData = data[key] as? [String: Any] else { return nil }
guard let objectData = data[key] as? JSONObject else { return nil }
return T.init(data: ResponseDict(objectData))
}

public subscript<T: SelectionSet>(_ key: String) -> [T] {
let objectData = data[key] as! [[String: Any]]
let objectData = data[key] as! [JSONObject]
return objectData.map { T.init(data: ResponseDict($0)) }
}

Expand Down
8 changes: 4 additions & 4 deletions Sources/ApolloAPI/CodegenV1/SchemaConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ public protocol SchemaConfiguration {
}

extension SchemaConfiguration {
public static func cacheKey(for data: [String: JSONValue]) -> CacheKey? {
public static func cacheKey(for data: JSONObject) -> CacheKey? {
guard let __typename = data["__typename"] as? String,
let keyString = cacheKeyString(for: data, withTypename: __typename) else {
return nil
Expand All @@ -12,7 +12,7 @@ extension SchemaConfiguration {
}

private static func cacheKeyString(
for data: [String: JSONValue],
for data: JSONObject,
withTypename __typename: String
) -> String? {
if let objectType = objectType(forTypename: __typename),
Expand All @@ -29,10 +29,10 @@ extension SchemaConfiguration {
}

public protocol ObjectCacheKeyResolver {
static func cacheKey(for: [String: JSONValue]) -> String?
static func cacheKey(for: JSONObject) -> String?
}

public protocol SchemaUnknownTypeMapper {
static func cacheKeyForUnknownType(withTypename: String, data: [String: JSONValue]) -> String?
static func cacheKeyForUnknownType(withTypename: String, data: JSONObject) -> String?
}

0 comments on commit b91ac93

Please sign in to comment.