Skip to content

Commit 9f4456e

Browse files
committed
Fixed wrong results when resolving futures.
1 parent 9618505 commit 9f4456e

File tree

2 files changed

+22
-118
lines changed

2 files changed

+22
-118
lines changed

Sources/GraphQL/Execution/Execute.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Dispatch
22
import Runtime
3-
import NIO
3+
import Async
44

55
/**
66
* Terminology
@@ -266,19 +266,19 @@ func execute(
266266

267267
return eventLoopGroup.next().newSucceededFuture(result: ["errors": [error].map])
268268
} catch {
269-
return eventLoopGroup.next().newFailedFuture(error: error)
269+
return eventLoopGroup.next().newSucceededFuture(result: ["errors": [["message": error.localizedDescription].map]])
270270
}
271271

272272
do {
273273
var executeErrors: [GraphQLError] = []
274274

275-
let data = try executeOperation(exeContext: context,
275+
return try executeOperation(exeContext: context,
276276
operation: context.operation,
277277
rootValue: rootValue)
278-
279-
return data.thenThrowing { data -> Map in
278+
279+
.thenThrowing { data -> Map in
280280
var dataMap: Map = [:]
281-
for (key, value) in data as! [String: Any] {
281+
for (key, value) in data {
282282
dataMap[key] = try map(from: value)
283283
}
284284
var result: [String: Map] = ["data": dataMap]
@@ -315,7 +315,7 @@ func execute(
315315
} catch let error as GraphQLError {
316316
return eventLoopGroup.next().newSucceededFuture(result: ["errors": [error].map])
317317
} catch {
318-
return eventLoopGroup.next().newFailedFuture(error: error)
318+
return eventLoopGroup.next().newSucceededFuture(result: ["errors": [["message": error.localizedDescription].map]])
319319
}
320320
}
321321

@@ -778,14 +778,20 @@ func completeValueCatchingError(
778778
info: info,
779779
path: path,
780780
result: result
781-
)
781+
).mapIfError { error -> Any? in
782+
guard let error = error as? GraphQLError else {
783+
fatalError()
784+
}
785+
exeContext.append(error: error)
786+
return nil
787+
}
782788

783789
return completed
784790
} catch let error as GraphQLError {
785791
// If `completeValueWithLocatedError` returned abruptly (threw an error),
786792
// log the error and return .null.
787793
exeContext.append(error: error)
788-
return exeContext.eventLoopGroup.next().newFailedFuture(error: error)
794+
return exeContext.eventLoopGroup.next().newSucceededFuture(result: nil)
789795
} catch {
790796
fatalError()
791797
}
@@ -873,7 +879,7 @@ func completeValue(
873879
}
874880
}
875881

876-
return result.thenThrowing { result -> EventLoopFuture<Any?> in
882+
return result.flatMap(to: Any?.self) { result -> EventLoopFuture<Any?> in
877883
// If result value is null-ish (nil or .null) then return .null.
878884
guard let result = result, let r = unwrap(result) else {
879885
return exeContext.eventLoopGroup.next().newSucceededFuture(result: nil)

Sources/GraphQL/Utilities/Dictionary+FutureType.swift

Lines changed: 6 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,22 @@
11
//
2-
// Dictionary+FutureType.swift
2+
// DictionaryFuture.swift
33
// GraphQL
44
//
5-
// Created by Kim de Vos on 26/05/2018.
5+
// Created by Jeff Seibert on 3/9/18.
66
//
77

88
import Foundation
99
import NIO
10-
11-
/// !! From Vapor Async start
12-
13-
/// Callback for accepting a result.
14-
public typealias FutureResultCallback<T> = (FutureResult<T>) -> ()
15-
16-
/// A future result type.
17-
/// Concretely implemented by `Future<T>`
18-
public protocol FutureType {
19-
/// This future's expectation.
20-
associatedtype Expectation
21-
22-
/// This future's result type.
23-
typealias Result = FutureResult<Expectation>
24-
25-
/// Adds a new awaiter to this `Future` that will be called when the result is ready.
26-
func addAwaiter(callback: @escaping FutureResultCallback<Expectation>)
27-
}
28-
29-
extension EventLoopFuture: FutureType {
30-
/// See `FutureType`.
31-
public typealias Expectation = T
32-
33-
/// See `FutureType`.
34-
public func addAwaiter(callback: @escaping (FutureResult<T>) -> ()) {
35-
_ = self.map { result in
36-
callback(.success(result))
37-
}.mapIfError { error in
38-
callback(.error(error))
39-
}
40-
}
41-
}
42-
43-
// Indirect so futures can be nested.
44-
public indirect enum FutureResult<T> {
45-
case error(Error)
46-
case success(T)
47-
48-
/// Returns the result error or `nil` if the result contains expectation.
49-
public var error: Error? {
50-
switch self {
51-
case .error(let error):
52-
return error
53-
default:
54-
return nil
55-
}
56-
}
57-
58-
/// Returns the result expectation or `nil` if the result contains an error.
59-
public var result: T? {
60-
switch self {
61-
case .success(let expectation):
62-
return expectation
63-
default:
64-
return nil
65-
}
66-
}
67-
68-
/// Throws an error if this contains an error, returns the Expectation otherwise
69-
public func unwrap() throws -> T {
70-
switch self {
71-
case .success(let data):
72-
return data
73-
case .error(let error):
74-
throw error
75-
}
76-
}
77-
}
78-
79-
extension Collection where Element : FutureType {
80-
/// Flattens an array of futures into a future with an array of results.
81-
/// note: the order of the results will match the order of the
82-
/// futures in the input array.
83-
///
84-
/// [Learn More →](https://docs.vapor.codes/3.0/async/advanced-futures/#combining-multiple-futures)
85-
public func flatten(on worker: EventLoopGroup) -> EventLoopFuture<[Element.Expectation]> {
86-
guard count > 0 else {
87-
return worker.next().newSucceededFuture(result: [])
88-
}
89-
var elements: [Element.Expectation] = []
90-
91-
let promise: EventLoopPromise<[Element.Expectation]> = worker.next().newPromise()
92-
elements.reserveCapacity(self.count)
93-
94-
for element in self {
95-
element.addAwaiter { result in
96-
switch result {
97-
case .error(let error): promise.fail(error: error)
98-
case .success(let expectation):
99-
elements.append(expectation)
100-
101-
if elements.count == self.count {
102-
promise.succeed(result: elements)
103-
}
104-
}
105-
}
106-
}
107-
108-
return promise.futureResult
109-
}
110-
}
111-
112-
/// !! From Vapor Async end
10+
import Async
11311

11412
extension Dictionary where Value: FutureType {
11513
func flatten(on worker: EventLoopGroup) -> EventLoopFuture<[Key: Value.Expectation]> {
14+
var elements: [Key: Value.Expectation] = [:]
15+
11616
guard self.count > 0 else {
117-
return worker.next().newSucceededFuture(result: [:])
17+
return worker.next().newSucceededFuture(result: elements)
11818
}
11919

120-
var elements: [Key: Value.Expectation] = [:]
121-
12220
let promise: EventLoopPromise<[Key: Value.Expectation]> = worker.next().newPromise()
12321
elements.reserveCapacity(self.count)
12422

0 commit comments

Comments
 (0)