Skip to content

Commit

Permalink
ExecutionInfo -> ObjectExecutionInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyMDev committed Sep 21, 2021
1 parent 086e9b4 commit a3e450e
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 53 deletions.
2 changes: 1 addition & 1 deletion Sources/Apollo/GraphQLDependencyTracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class GraphQLDependencyTracker: GraphQLResultAccumulator {
dependentKeys.insert(info.cachePath.joined)
}

func accept(fieldEntries: [Void], info: FieldExecutionInfo) {
func accept(fieldEntries: [Void], info: ObjectExecutionInfo) {
}

func finish(rootValue: Void) -> Set<CacheKey> {
Expand Down
69 changes: 35 additions & 34 deletions Sources/Apollo/GraphQLExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct GraphQLResolveInfo {
}
}

fileprivate struct ExecutionInfo { // TODO: Rename?
struct ObjectExecutionInfo {
let variables: [String: JSONEncodable]?
private(set) var responsePath: ResponsePath = []
private(set) var cachePath: ResponsePath = []
Expand All @@ -60,33 +60,13 @@ fileprivate struct ExecutionInfo { // TODO: Rename?
}
}

fileprivate struct FieldSelectionGrouping: Sequence {
private var fieldInfoList: [String: FieldExecutionInfo] = [:]

var count: Int { fieldInfoList.count }

mutating func append(field: Selection.Field, withInfo info: ExecutionInfo) {
let fieldKey = field.responseKey
if var fieldInfo = fieldInfoList[fieldKey] {
fieldInfo.mergedFields.append(field)
fieldInfoList[fieldKey] = fieldInfo
} else {
fieldInfoList[fieldKey] = FieldExecutionInfo(field: field, info: info)
}
}

func makeIterator() -> Dictionary<String, FieldExecutionInfo>.Iterator {
fieldInfoList.makeIterator()
}
}

/// Stores the information for executing a field and all duplicate fields on the same selection set.
///
/// GraphQL validation makes sure all fields sharing the same response key have the same
/// arguments and are of the same type, so we only need to resolve one field.
struct FieldExecutionInfo {
let field: Selection.Field
private let info: ExecutionInfo
private let parentInfo: ObjectExecutionInfo

var mergedFields: [Selection.Field]

Expand All @@ -98,20 +78,20 @@ struct FieldExecutionInfo {

fileprivate init(
field: Selection.Field,
info: ExecutionInfo
parentInfo: ObjectExecutionInfo
) {
self.field = field
self.info = info
self.parentInfo = parentInfo
mergedFields = [field]

let responseKey = field.responseKey
responsePath = info.responsePath.appending(responseKey)
responsePath = parentInfo.responsePath.appending(responseKey)
responseKeyForField = responseKey
}

fileprivate mutating func computeCacheKeyAndPath() throws {
let cacheKey = try field.cacheKey(with: info.variables)
cachePath = info.cachePath.appending(cacheKey)
let cacheKey = try field.cacheKey(with: parentInfo.variables)
cachePath = parentInfo.cachePath.appending(cacheKey)
cacheKeyForField = cacheKey
}

Expand All @@ -130,13 +110,33 @@ struct FieldExecutionInfo {
}

/// Returns the `ExecutionInfo` that should be used for executing the child selections.
fileprivate func executionInfoForChildSelections() -> ExecutionInfo {
return ExecutionInfo(variables: info.variables,
fileprivate func executionInfoForChildSelections() -> ObjectExecutionInfo {
return ObjectExecutionInfo(variables: parentInfo.variables,
responsePath: responsePath,
cachePath: cachePath)
}
}

fileprivate struct FieldSelectionGrouping: Sequence {
private var fieldInfoList: [String: FieldExecutionInfo] = [:]

var count: Int { fieldInfoList.count }

mutating func append(field: Selection.Field, withInfo info: ObjectExecutionInfo) {
let fieldKey = field.responseKey
if var fieldInfo = fieldInfoList[fieldKey] {
fieldInfo.mergedFields.append(field)
fieldInfoList[fieldKey] = fieldInfo
} else {
fieldInfoList[fieldKey] = FieldExecutionInfo(field: field, parentInfo: info)
}
}

func makeIterator() -> Dictionary<String, FieldExecutionInfo>.Iterator {
fieldInfoList.makeIterator()
}
}

/// An error which has occurred in processing a GraphQLResult
public struct GraphQLResultError: Error, LocalizedError {
let path: ResponsePath
Expand Down Expand Up @@ -491,7 +491,7 @@ final class GraphQLExecutor {
variables: [String: JSONEncodable]? = nil,
accumulator: Accumulator
) throws -> Accumulator.FinalResult {
let info = ExecutionInfo(variables: variables, rootCacheKey: key)
let info = ObjectExecutionInfo(variables: variables, rootCacheKey: key)

let rootValue = execute(selections: selections,
on: object,
Expand All @@ -504,7 +504,7 @@ final class GraphQLExecutor {
private func execute<Accumulator: GraphQLResultAccumulator>(
selections: [Selection],
on object: JSONObject,
info: ExecutionInfo,
info: ObjectExecutionInfo,
accumulator: Accumulator
) -> PossiblyDeferred<Accumulator.ObjectResult> {
do {
Expand Down Expand Up @@ -539,7 +539,7 @@ final class GraphQLExecutor {
private func groupFields(
_ selections: [Selection],
on object: JSONObject,
info: ExecutionInfo
info: ObjectExecutionInfo
) throws -> FieldSelectionGrouping {
var grouping = FieldSelectionGrouping()
try groupFields(selections,
Expand All @@ -559,7 +559,7 @@ final class GraphQLExecutor {
_ selections: [Selection],
forRuntimeType runtimeType: Object.Type?,
into groupedFields: inout FieldSelectionGrouping,
info: ExecutionInfo
info: ObjectExecutionInfo
) throws {
for selection in selections {
switch selection {
Expand Down Expand Up @@ -742,7 +742,8 @@ final class GraphQLExecutor {
private func executeChildSelections<Accumulator: GraphQLResultAccumulator>(
forObjectTypeFields fieldInfo: FieldExecutionInfo,
onChildObject object: JSONObject,
accumulator: Accumulator) -> PossiblyDeferred<Accumulator.PartialResult> {
accumulator: Accumulator
) -> PossiblyDeferred<Accumulator.PartialResult> {

let selections = fieldInfo.computeChildSelections()
var childExecutionInfo = fieldInfo.executionInfoForChildSelections()
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 (info.responseKeyForField, fieldEntry)
}

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

Expand Down
48 changes: 33 additions & 15 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(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry
func accept(fieldEntries: [FieldEntry], info: FieldExecutionInfo) throws -> ObjectResult
func accept(fieldEntries: [FieldEntry], info: ObjectExecutionInfo) throws -> ObjectResult

func finish(rootValue: ObjectResult) throws -> FinalResult
}
Expand Down Expand Up @@ -37,29 +37,35 @@ final class Zip2Accumulator<Accumulator1: GraphQLResultAccumulator, Accumulator2
}

func accept(scalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult {
return (try accumulator1.accept(scalar: scalar, info: info), try accumulator2.accept(scalar: scalar, info: info))
return (try accumulator1.accept(scalar: scalar, info: info),
try accumulator2.accept(scalar: scalar, info: info))
}

func acceptNullValue(info: FieldExecutionInfo) throws -> PartialResult {
return (try accumulator1.acceptNullValue(info: info), try accumulator2.acceptNullValue(info: info))
return (try accumulator1.acceptNullValue(info: info),
try accumulator2.acceptNullValue(info: info))
}

func accept(list: [PartialResult], info: FieldExecutionInfo) throws -> PartialResult {
let (list1, list2) = unzip(list)
return (try accumulator1.accept(list: list1, info: info), try accumulator2.accept(list: list2, info: info))
return (try accumulator1.accept(list: list1, info: info),
try accumulator2.accept(list: list2, info: info))
}

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))
return (try accumulator1.accept(fieldEntry: fieldEntry.0, info: info),
try accumulator2.accept(fieldEntry: fieldEntry.1, info: info))
}

func accept(fieldEntries: [FieldEntry], info: FieldExecutionInfo) throws -> ObjectResult {
func accept(fieldEntries: [FieldEntry], info: ObjectExecutionInfo) throws -> ObjectResult {
let (fieldEntries1, fieldEntries2) = unzip(fieldEntries)
return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info), try accumulator2.accept(fieldEntries: fieldEntries2, info: info))
return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info),
try accumulator2.accept(fieldEntries: fieldEntries2, info: info))
}

func finish(rootValue: ObjectResult) throws -> FinalResult {
return (try accumulator1.finish(rootValue: rootValue.0), try accumulator2.finish(rootValue: rootValue.1))
return (try accumulator1.finish(rootValue: rootValue.0),
try accumulator2.finish(rootValue: rootValue.1))
}
}

Expand All @@ -83,28 +89,40 @@ final class Zip3Accumulator<Accumulator1: GraphQLResultAccumulator, Accumulator2
}

func accept(scalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult {
return (try accumulator1.accept(scalar: scalar, info: info), try accumulator2.accept(scalar: scalar, info: info), try accumulator3.accept(scalar: scalar, info: info))
return (try accumulator1.accept(scalar: scalar, info: info),
try accumulator2.accept(scalar: scalar, info: info),
try accumulator3.accept(scalar: scalar, info: info))
}

func acceptNullValue(info: FieldExecutionInfo) throws -> PartialResult {
return (try accumulator1.acceptNullValue(info: info), try accumulator2.acceptNullValue(info: info), try accumulator3.acceptNullValue(info: info))
return (try accumulator1.acceptNullValue(info: info),
try accumulator2.acceptNullValue(info: info),
try accumulator3.acceptNullValue(info: info))
}

func accept(list: [PartialResult], info: FieldExecutionInfo) throws -> PartialResult {
let (list1, list2, list3) = unzip(list)
return (try accumulator1.accept(list: list1, info: info), try accumulator2.accept(list: list2, info: info), try accumulator3.accept(list: list3, info: info))
return (try accumulator1.accept(list: list1, info: info),
try accumulator2.accept(list: list2, info: info),
try accumulator3.accept(list: list3, info: info))
}

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))
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))
}

func accept(fieldEntries: [FieldEntry], info: FieldExecutionInfo) throws -> ObjectResult {
func accept(fieldEntries: [FieldEntry], info: ObjectExecutionInfo) throws -> ObjectResult {
let (fieldEntries1, fieldEntries2, fieldEntries3) = unzip(fieldEntries)
return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info), try accumulator2.accept(fieldEntries: fieldEntries2, info: info), try accumulator3.accept(fieldEntries: fieldEntries3, info: info))
return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info),
try accumulator2.accept(fieldEntries: fieldEntries2, info: info),
try accumulator3.accept(fieldEntries: fieldEntries3, info: info))
}

func finish(rootValue: ObjectResult) throws -> FinalResult {
return (try accumulator1.finish(rootValue: rootValue.0), try accumulator2.finish(rootValue: rootValue.1), try accumulator3.finish(rootValue: rootValue.2))
return (try accumulator1.finish(rootValue: rootValue.0),
try accumulator2.finish(rootValue: rootValue.1),
try accumulator3.finish(rootValue: rootValue.2))
}
}
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 (info.cacheKeyForField, fieldEntry)
}

func accept(fieldEntries: [(key: String, value: JSONValue)], info: FieldExecutionInfo) throws -> JSONValue {
func accept(fieldEntries: [(key: String, value: JSONValue)], info: ObjectExecutionInfo) throws -> JSONValue {
let cachePath = info.cachePath.joined

let object = JSONObject(fieldEntries, uniquingKeysWith: { (_, last) in last })
Expand Down
2 changes: 1 addition & 1 deletion Sources/Apollo/GraphQLSelectionSetMapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class GraphQLSelectionSetMapper<SelectionSet: AnySelectionSet>: GraphQLRes
return (info.responseKeyForField, fieldEntry)
}

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

Expand Down

0 comments on commit a3e450e

Please sign in to comment.