Skip to content

Commit adfb2db

Browse files
committed
Add scalars and simple async resolve functions.
1 parent c973388 commit adfb2db

File tree

7 files changed

+109
-57
lines changed

7 files changed

+109
-57
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ import NIO
133133
let root = MessageAPI()
134134
let context = MessageStore()
135135
let service = try MessageService(root: root)
136-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
136+
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
137137

138138
defer {
139139
try? group.syncShutdownGracefully()

Sources/Graphiti/ComponentsInitializer.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import Foundation
2+
import GraphQL
3+
14
public final class ComponentsInitializer<RootType : Keyable, Context> {
25
var components: [Component<RootType, Context>] = []
36

@@ -168,4 +171,59 @@ public final class ComponentsInitializer<RootType : Keyable, Context> {
168171
components.append(component)
169172
return ComponentInitializer(component)
170173
}
174+
175+
@discardableResult
176+
public func dateScalar(
177+
formatter: Formatter
178+
) -> ComponentInitializer<RootType, Context> {
179+
scalar(
180+
Date.self,
181+
serialize: { date in
182+
guard let string = formatter.string(for: date) else {
183+
throw GraphQLError(message: "Invalid value for Date scalar. Cannot convert \"\(date)\" to string.")
184+
}
185+
186+
return .string(string)
187+
},
188+
parse: { map in
189+
guard let string = map.string else {
190+
throw GraphQLError(message: "Invalid type for Date scalar. Expected string, but got \(map.typeDescription)")
191+
}
192+
193+
var date = Date()
194+
let datePointer = AutoreleasingUnsafeMutablePointer<AnyObject?>(&date)
195+
196+
guard formatter.getObjectValue(datePointer, for: string, errorDescription: nil) else {
197+
throw GraphQLError(message: "Invalid date string for Date scalar.")
198+
}
199+
200+
guard let formattedDate = datePointer.pointee as? Date else {
201+
throw GraphQLError(message: "Invalid date string for Date scalar.")
202+
}
203+
204+
return formattedDate
205+
}
206+
)
207+
}
208+
209+
@discardableResult
210+
public func urlScalar() -> ComponentInitializer<RootType, Context> {
211+
scalar(
212+
URL.self,
213+
serialize: { url in
214+
.string(url.absoluteString)
215+
},
216+
parse: { map in
217+
guard let string = map.string else {
218+
throw GraphQLError(message: "Invalid type for URL scalar.")
219+
}
220+
221+
guard let url = URL(string: string) else {
222+
throw GraphQLError(message: "Invalid url string for URL scalar.")
223+
}
224+
225+
return url
226+
}
227+
)
228+
}
171229
}

Sources/Graphiti/FieldsInitializer.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import NIO
2+
13
public final class FieldsInitializer<ObjectType, Keys : RawRepresentable, Context> where Keys.RawValue == String {
24
var fields: [FieldComponent<ObjectType, Keys, Context>] = []
35

@@ -96,4 +98,37 @@ public final class FieldsInitializer<ObjectType, Keys : RawRepresentable, Contex
9698
fields.append(field)
9799
return FieldInitializer(field)
98100
}
101+
102+
@discardableResult
103+
public func field<FieldType, ResolveType>(
104+
_ name: Keys,
105+
at function: @escaping SimpleAsyncResolve<ObjectType, Context, NoArguments, ResolveType>,
106+
overridingType: FieldType.Type = FieldType.self
107+
) -> FieldInitializer<ObjectType, Keys, Context, NoArguments> {
108+
let asyncResolve: AsyncResolve<ObjectType, Context, NoArguments, ResolveType> = { type in
109+
return { context, arguments, group in
110+
// We hop to guarantee that the future will
111+
// return in the same event loop group of the execution.
112+
try function(type)(context, arguments).hop(to: group.next())
113+
}
114+
}
115+
116+
return field(name, at: asyncResolve, overridingType: overridingType)
117+
}
118+
119+
@discardableResult
120+
public func field<Arguments : Decodable, ResolveType>(
121+
_ name: Keys,
122+
at function: @escaping SimpleAsyncResolve<ObjectType, Context, Arguments, ResolveType>
123+
) -> FieldInitializer<ObjectType, Keys, Context, Arguments> {
124+
let asyncResolve: AsyncResolve<ObjectType, Context, Arguments, ResolveType> = { type in
125+
return { context, arguments, group in
126+
// We hop to guarantee that the future will
127+
// return in the same event loop group of the execution.
128+
try function(type)(context, arguments).hop(to: group.next())
129+
}
130+
}
131+
132+
return field(name, at: asyncResolve)
133+
}
99134
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import NIO
2+
3+
public typealias SimpleAsyncResolve<ObjectType, Context, Arguments, ResolveType> = (
4+
_ object: ObjectType
5+
) -> (
6+
_ context: Context,
7+
_ arguments: Arguments
8+
) throws -> EventLoopFuture<ResolveType>

Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ struct HelloService : Service {
146146

147147
class HelloWorldTests : XCTestCase {
148148
private let service = HelloService()
149-
private var group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
149+
private var group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
150150

151151
deinit {
152152
try? self.group.syncShutdownGracefully()

Tests/GraphitiTests/StarWarsTests/StarWarsIntrospectionTests.swift

Lines changed: 5 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ import GraphQL
66

77
class StarWarsIntrospectionTests : XCTestCase {
88
private let service = StarWarsService()
9+
private let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
10+
11+
deinit {
12+
try? group.syncShutdownGracefully()
13+
}
914

1015
func testIntrospectionTypeQuery() throws {
11-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
12-
13-
defer {
14-
XCTAssertNoThrow(try group.syncShutdownGracefully())
15-
}
16-
1716
let query = "query IntrospectionTypeQuery {" +
1817
" __schema {" +
1918
" types {" +
@@ -95,12 +94,6 @@ class StarWarsIntrospectionTests : XCTestCase {
9594
}
9695

9796
func testIntrospectionQueryTypeQuery() throws {
98-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
99-
100-
defer {
101-
XCTAssertNoThrow(try group.syncShutdownGracefully())
102-
}
103-
10497
let query = "query IntrospectionQueryTypeQuery {" +
10598
" __schema {" +
10699
" queryType {" +
@@ -129,12 +122,6 @@ class StarWarsIntrospectionTests : XCTestCase {
129122
}
130123

131124
func testIntrospectionDroidTypeQuery() throws {
132-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
133-
134-
defer {
135-
XCTAssertNoThrow(try group.syncShutdownGracefully())
136-
}
137-
138125
let query = "query IntrospectionDroidTypeQuery {" +
139126
" __type(name: \"Droid\") {" +
140127
" name" +
@@ -159,12 +146,6 @@ class StarWarsIntrospectionTests : XCTestCase {
159146
}
160147

161148
func testIntrospectionDroidKindQuery() throws {
162-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
163-
164-
defer {
165-
XCTAssertNoThrow(try group.syncShutdownGracefully())
166-
}
167-
168149
let query = "query IntrospectionDroidKindQuery {" +
169150
" __type(name: \"Droid\") {" +
170151
" name" +
@@ -191,12 +172,6 @@ class StarWarsIntrospectionTests : XCTestCase {
191172
}
192173

193174
func testIntrospectionCharacterKindQuery() throws {
194-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
195-
196-
defer {
197-
XCTAssertNoThrow(try group.syncShutdownGracefully())
198-
}
199-
200175
let query = "query IntrospectionCharacterKindQuery {" +
201176
" __type(name: \"Character\") {" +
202177
" name" +
@@ -223,12 +198,6 @@ class StarWarsIntrospectionTests : XCTestCase {
223198
}
224199

225200
func testIntrospectionDroidFieldsQuery() throws {
226-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
227-
228-
defer {
229-
XCTAssertNoThrow(try group.syncShutdownGracefully())
230-
}
231-
232201
let query = "query IntrospectionDroidFieldsQuery {" +
233202
" __type(name: \"Droid\") {" +
234203
" name" +
@@ -304,12 +273,6 @@ class StarWarsIntrospectionTests : XCTestCase {
304273
}
305274

306275
func testIntrospectionDroidNestedFieldsQuery() throws {
307-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
308-
309-
defer {
310-
XCTAssertNoThrow(try group.syncShutdownGracefully())
311-
}
312-
313276
let query = "query IntrospectionDroidNestedFieldsQuery {" +
314277
" __type(name: \"Droid\") {" +
315278
" name" +
@@ -410,12 +373,6 @@ class StarWarsIntrospectionTests : XCTestCase {
410373
}
411374

412375
func testIntrospectionFieldArgsQuery() throws {
413-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
414-
415-
defer {
416-
XCTAssertNoThrow(try group.syncShutdownGracefully())
417-
}
418-
419376
let query = "query IntrospectionFieldArgsQuery {" +
420377
" __schema {" +
421378
" queryType {" +
@@ -529,12 +486,6 @@ class StarWarsIntrospectionTests : XCTestCase {
529486
}
530487

531488
func testIntrospectionDroidDescriptionQuery() throws {
532-
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
533-
534-
defer {
535-
XCTAssertNoThrow(try group.syncShutdownGracefully())
536-
}
537-
538489
let query = "query IntrospectionDroidDescriptionQuery {" +
539490
" __type(name: \"Droid\") {" +
540491
" name" +

Tests/GraphitiTests/StarWarsTests/StarWarsQueryTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import GraphQL
66
@available(OSX 10.15, *)
77
class StarWarsQueryTests : XCTestCase {
88
private let service = StarWarsService()
9-
private var group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
9+
private var group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
1010

1111
deinit {
1212
try? self.group.syncShutdownGracefully()

0 commit comments

Comments
 (0)