Skip to content

Commit

Permalink
Add scalars and simple async resolve functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulofaria committed Jun 26, 2020
1 parent c973388 commit adfb2db
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ import NIO
let root = MessageAPI()
let context = MessageStore()
let service = try MessageService(root: root)
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

defer {
try? group.syncShutdownGracefully()
Expand Down
58 changes: 58 additions & 0 deletions Sources/Graphiti/ComponentsInitializer.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import Foundation
import GraphQL

public final class ComponentsInitializer<RootType : Keyable, Context> {
var components: [Component<RootType, Context>] = []

Expand Down Expand Up @@ -168,4 +171,59 @@ public final class ComponentsInitializer<RootType : Keyable, Context> {
components.append(component)
return ComponentInitializer(component)
}

@discardableResult
public func dateScalar(
formatter: Formatter
) -> ComponentInitializer<RootType, Context> {
scalar(
Date.self,
serialize: { date in
guard let string = formatter.string(for: date) else {
throw GraphQLError(message: "Invalid value for Date scalar. Cannot convert \"\(date)\" to string.")
}

return .string(string)
},
parse: { map in
guard let string = map.string else {
throw GraphQLError(message: "Invalid type for Date scalar. Expected string, but got \(map.typeDescription)")
}

var date = Date()
let datePointer = AutoreleasingUnsafeMutablePointer<AnyObject?>(&date)

guard formatter.getObjectValue(datePointer, for: string, errorDescription: nil) else {
throw GraphQLError(message: "Invalid date string for Date scalar.")
}

guard let formattedDate = datePointer.pointee as? Date else {
throw GraphQLError(message: "Invalid date string for Date scalar.")
}

return formattedDate
}
)
}

@discardableResult
public func urlScalar() -> ComponentInitializer<RootType, Context> {
scalar(
URL.self,
serialize: { url in
.string(url.absoluteString)
},
parse: { map in
guard let string = map.string else {
throw GraphQLError(message: "Invalid type for URL scalar.")
}

guard let url = URL(string: string) else {
throw GraphQLError(message: "Invalid url string for URL scalar.")
}

return url
}
)
}
}
35 changes: 35 additions & 0 deletions Sources/Graphiti/FieldsInitializer.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import NIO

public final class FieldsInitializer<ObjectType, Keys : RawRepresentable, Context> where Keys.RawValue == String {
var fields: [FieldComponent<ObjectType, Keys, Context>] = []

Expand Down Expand Up @@ -96,4 +98,37 @@ public final class FieldsInitializer<ObjectType, Keys : RawRepresentable, Contex
fields.append(field)
return FieldInitializer(field)
}

@discardableResult
public func field<FieldType, ResolveType>(
_ name: Keys,
at function: @escaping SimpleAsyncResolve<ObjectType, Context, NoArguments, ResolveType>,
overridingType: FieldType.Type = FieldType.self
) -> FieldInitializer<ObjectType, Keys, Context, NoArguments> {
let asyncResolve: AsyncResolve<ObjectType, Context, NoArguments, ResolveType> = { type in
return { context, arguments, group in
// We hop to guarantee that the future will
// return in the same event loop group of the execution.
try function(type)(context, arguments).hop(to: group.next())
}
}

return field(name, at: asyncResolve, overridingType: overridingType)
}

@discardableResult
public func field<Arguments : Decodable, ResolveType>(
_ name: Keys,
at function: @escaping SimpleAsyncResolve<ObjectType, Context, Arguments, ResolveType>
) -> FieldInitializer<ObjectType, Keys, Context, Arguments> {
let asyncResolve: AsyncResolve<ObjectType, Context, Arguments, ResolveType> = { type in
return { context, arguments, group in
// We hop to guarantee that the future will
// return in the same event loop group of the execution.
try function(type)(context, arguments).hop(to: group.next())
}
}

return field(name, at: asyncResolve)
}
}
8 changes: 8 additions & 0 deletions Sources/Graphiti/SimpleAsyncResolve.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import NIO

public typealias SimpleAsyncResolve<ObjectType, Context, Arguments, ResolveType> = (
_ object: ObjectType
) -> (
_ context: Context,
_ arguments: Arguments
) throws -> EventLoopFuture<ResolveType>
2 changes: 1 addition & 1 deletion Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ struct HelloService : Service {

class HelloWorldTests : XCTestCase {
private let service = HelloService()
private var group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
private var group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

deinit {
try? self.group.syncShutdownGracefully()
Expand Down
59 changes: 5 additions & 54 deletions Tests/GraphitiTests/StarWarsTests/StarWarsIntrospectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import GraphQL

class StarWarsIntrospectionTests : XCTestCase {
private let service = StarWarsService()
private let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

deinit {
try? group.syncShutdownGracefully()
}

func testIntrospectionTypeQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionTypeQuery {" +
" __schema {" +
" types {" +
Expand Down Expand Up @@ -95,12 +94,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionQueryTypeQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionQueryTypeQuery {" +
" __schema {" +
" queryType {" +
Expand Down Expand Up @@ -129,12 +122,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionDroidTypeQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionDroidTypeQuery {" +
" __type(name: \"Droid\") {" +
" name" +
Expand All @@ -159,12 +146,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionDroidKindQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionDroidKindQuery {" +
" __type(name: \"Droid\") {" +
" name" +
Expand All @@ -191,12 +172,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionCharacterKindQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionCharacterKindQuery {" +
" __type(name: \"Character\") {" +
" name" +
Expand All @@ -223,12 +198,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionDroidFieldsQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionDroidFieldsQuery {" +
" __type(name: \"Droid\") {" +
" name" +
Expand Down Expand Up @@ -304,12 +273,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionDroidNestedFieldsQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionDroidNestedFieldsQuery {" +
" __type(name: \"Droid\") {" +
" name" +
Expand Down Expand Up @@ -410,12 +373,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionFieldArgsQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionFieldArgsQuery {" +
" __schema {" +
" queryType {" +
Expand Down Expand Up @@ -529,12 +486,6 @@ class StarWarsIntrospectionTests : XCTestCase {
}

func testIntrospectionDroidDescriptionQuery() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

let query = "query IntrospectionDroidDescriptionQuery {" +
" __type(name: \"Droid\") {" +
" name" +
Expand Down
2 changes: 1 addition & 1 deletion Tests/GraphitiTests/StarWarsTests/StarWarsQueryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import GraphQL
@available(OSX 10.15, *)
class StarWarsQueryTests : XCTestCase {
private let service = StarWarsService()
private var group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
private var group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

deinit {
try? self.group.syncShutdownGracefully()
Expand Down

0 comments on commit adfb2db

Please sign in to comment.