From e9b21893e33b3ca2ed1f3c5f5c5edfaf017b9683 Mon Sep 17 00:00:00 2001 From: Mathias Quintero Date: Wed, 15 Apr 2020 19:20:13 +0200 Subject: [PATCH] Making value resolvable not mandatory for inputs --- .../Array+InputResolvable.swift | 4 +-- .../Implementations/GraphQLInputObject.swift | 2 +- .../Optional+InputResolvable.swift | 5 ++-- .../RawRepresentable+InputResolvable.swift | 2 +- .../InputResolvable/InputResolvable.swift | 2 +- .../Resolvable/ValueResolvable.swift | 2 +- .../Resolution/Scalar/Enum/GraphQLEnum.swift | 4 +-- .../Scalar/Enum/KeyPath+GraphQLEnum.swift | 21 +++++--------- .../Scalar/Scalar/GraphQLScalar.swift | 4 +-- .../GraphZahl/Utils/MethodInfo+resolve.swift | 6 ++-- .../SchemaResolutionTests.swift | 28 +++++++++++++++++++ 11 files changed, 50 insertions(+), 30 deletions(-) diff --git a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Array+InputResolvable.swift b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Array+InputResolvable.swift index 2d4e231..68316c9 100644 --- a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Array+InputResolvable.swift +++ b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Array+InputResolvable.swift @@ -4,8 +4,8 @@ import GraphQL extension Array: ValueResolvable where Element: ValueResolvable { - public func map() throws -> Map? { - return .array(try compactMap { try $0.map() }) + public func map() throws -> Map { + return .array(try map { try $0.map() }) } } diff --git a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/GraphQLInputObject.swift b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/GraphQLInputObject.swift index 50836e3..c9d95fe 100644 --- a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/GraphQLInputObject.swift +++ b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/GraphQLInputObject.swift @@ -6,7 +6,7 @@ import Runtime private var propertiesForType = [Int : [String : PropertyInfo]]() -public protocol GraphQLInputObject: InputResolvable, ConcreteResolvable, KeyPathListable { } +public protocol GraphQLInputObject: InputResolvable, ConcreteResolvable, ValueResolvable, KeyPathListable { } extension GraphQLInputObject { diff --git a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Optional+InputResolvable.swift b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Optional+InputResolvable.swift index 7cd71bd..94937af 100644 --- a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Optional+InputResolvable.swift +++ b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/Optional+InputResolvable.swift @@ -4,9 +4,8 @@ import GraphQL extension Optional: ValueResolvable where Wrapped: ValueResolvable { - public func map() throws -> Map? { - guard let self = self else { return .null } - return try self.map() + public func map() throws -> Map { + return try map { try $0.map() } ?? .null } } diff --git a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/RawRepresentable+InputResolvable.swift b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/RawRepresentable+InputResolvable.swift index fc356e4..8de3eb8 100644 --- a/Sources/GraphZahl/Resolution/InputResolvable/Implementations/RawRepresentable+InputResolvable.swift +++ b/Sources/GraphZahl/Resolution/InputResolvable/Implementations/RawRepresentable+InputResolvable.swift @@ -4,7 +4,7 @@ import GraphQL extension RawRepresentable where Self: ValueResolvable, RawValue: ValueResolvable { - public func map() throws -> Map? { + public func map() throws -> Map { return try rawValue.map() } diff --git a/Sources/GraphZahl/Resolution/InputResolvable/InputResolvable.swift b/Sources/GraphZahl/Resolution/InputResolvable/InputResolvable.swift index 36b24ec..30e9a4a 100644 --- a/Sources/GraphZahl/Resolution/InputResolvable/InputResolvable.swift +++ b/Sources/GraphZahl/Resolution/InputResolvable/InputResolvable.swift @@ -2,7 +2,7 @@ import Foundation import GraphQL -public protocol InputResolvable: ValueResolvable { +public protocol InputResolvable: Resolvable { static func resolve(using context: inout Resolution.Context) throws -> GraphQLInputType static func create(from map: Map) throws -> Self diff --git a/Sources/GraphZahl/Resolution/Resolvable/ValueResolvable.swift b/Sources/GraphZahl/Resolution/Resolvable/ValueResolvable.swift index 5c8536e..036ed6e 100644 --- a/Sources/GraphZahl/Resolution/Resolvable/ValueResolvable.swift +++ b/Sources/GraphZahl/Resolution/Resolvable/ValueResolvable.swift @@ -3,5 +3,5 @@ import Foundation import GraphQL public protocol ValueResolvable: Resolvable { - func map() throws -> Map? + func map() throws -> Map } diff --git a/Sources/GraphZahl/Resolution/Scalar/Enum/GraphQLEnum.swift b/Sources/GraphZahl/Resolution/Scalar/Enum/GraphQLEnum.swift index 984fe43..aa73ce5 100644 --- a/Sources/GraphZahl/Resolution/Scalar/Enum/GraphQLEnum.swift +++ b/Sources/GraphZahl/Resolution/Scalar/Enum/GraphQLEnum.swift @@ -4,7 +4,7 @@ import GraphQL import NIO import ContextKit -public protocol GraphQLEnum: OutputResolvable, InputResolvable, ConcreteResolvable { +public protocol GraphQLEnum: OutputResolvable, InputResolvable, ConcreteResolvable, ValueResolvable { static func cases(using context: inout Resolution.Context) throws -> [String : Map] } @@ -12,7 +12,7 @@ extension GraphQLEnum where Self: CaseIterable & RawRepresentable, RawValue == S public static func cases(using context: inout Resolution.Context) throws -> [String : Map] { let keysAndValues = try allCases.map { ($0.rawValue, try $0.map()) } - return Dictionary(uniqueKeysWithValues: keysAndValues).compactMapValues { $0 } + return Dictionary(uniqueKeysWithValues: keysAndValues) } } diff --git a/Sources/GraphZahl/Resolution/Scalar/Enum/KeyPath+GraphQLEnum.swift b/Sources/GraphZahl/Resolution/Scalar/Enum/KeyPath+GraphQLEnum.swift index 87d29a0..6602948 100644 --- a/Sources/GraphZahl/Resolution/Scalar/Enum/KeyPath+GraphQLEnum.swift +++ b/Sources/GraphZahl/Resolution/Scalar/Enum/KeyPath+GraphQLEnum.swift @@ -15,30 +15,23 @@ extension KeyPath: ConcreteResolvable where Root: ConcreteResolvable & KeyPathLi } -extension KeyPath: ValueResolvable where Root: ConcreteResolvable & KeyPathListable { - public func map() throws -> Map? { - return nil - } -} - extension KeyPath: InputResolvable where Root: ConcreteResolvable & KeyPathListable { + public static func resolve(using context: inout Resolution.Context) throws -> GraphQLInputType { + return GraphQLNonNull(try GraphQLEnumType(name: concreteTypeName, values: try cases(using: &context))) + } + public static func create(from map: Map) throws -> Self { let name = try map.stringValue() return (\Root.[checkedMirrorDescendant: name] as WritableKeyPath) as! Self } -} - -extension KeyPath: OutputResolvable where Root: ConcreteResolvable & KeyPathListable { } - -extension KeyPath: GraphQLEnum where Root: ConcreteResolvable & KeyPathListable { - public static func cases(using context: inout Resolution.Context) throws -> [String : Map] { + private static func cases(using context: inout Resolution.Context) throws -> [String : GraphQLEnumValue] { let keyPaths: [String : KeyPath] = try Root.resolve() let cases = try keyPaths - .map { ($0.key, try $0.key.map()) } + .map { ($0.key.upperCamelized, try $0.key.map()) } - return Dictionary(cases) { $1 }.compactMapValues { $0 } + return Dictionary(cases) { $1 }.mapValues { GraphQLEnumValue(value: $0) } } } diff --git a/Sources/GraphZahl/Resolution/Scalar/Scalar/GraphQLScalar.swift b/Sources/GraphZahl/Resolution/Scalar/Scalar/GraphQLScalar.swift index 2d6e13e..540124a 100644 --- a/Sources/GraphZahl/Resolution/Scalar/Scalar/GraphQLScalar.swift +++ b/Sources/GraphZahl/Resolution/Scalar/Scalar/GraphQLScalar.swift @@ -2,7 +2,7 @@ import Foundation import GraphQL -public protocol GraphQLScalar: OutputResolvable, InputResolvable, ConcreteResolvable, KeyPathListable { +public protocol GraphQLScalar: OutputResolvable, InputResolvable, ConcreteResolvable, ValueResolvable, KeyPathListable { static func resolve() throws -> GraphQLScalarType init(scalar: ScalarValue) throws @@ -15,7 +15,7 @@ extension GraphQLScalar { return try GraphQLScalarType(name: concreteTypeName) { $0 as! Map } } - public func map() throws -> Map? { + public func map() throws -> Map { return try encodeScalar().graphql() } diff --git a/Sources/GraphZahl/Utils/MethodInfo+resolve.swift b/Sources/GraphZahl/Utils/MethodInfo+resolve.swift index fe74b8d..43cd0bb 100644 --- a/Sources/GraphZahl/Utils/MethodInfo+resolve.swift +++ b/Sources/GraphZahl/Utils/MethodInfo+resolve.swift @@ -19,11 +19,11 @@ extension MethodInfo { let type = try context.resolve(type: argumentType) - guard let defaultValue = try argument.defaultValue() as? ValueResolvable else { + guard let defaultValue = try argument.defaultValue() else { return GraphQLArgument(type: type, defaultValue: nil) } - guard let map = try defaultValue.map() else { + guard let valueResolvable = defaultValue as? ValueResolvable else { switch type { case let type as GraphQLNonNull: return GraphQLArgument(type: type.ofType as! GraphQLInputType, defaultValue: nil) @@ -32,7 +32,7 @@ extension MethodInfo { } } - return GraphQLArgument(type: type, defaultValue: map) + return GraphQLArgument(type: type, defaultValue: try valueResolvable.map()) } guard arguments.count == relevantArguments.count else { return nil } diff --git a/Sources/GraphZahlTests/SchemaResolutionTests.swift b/Sources/GraphZahlTests/SchemaResolutionTests.swift index c3d84c6..2bc3f64 100644 --- a/Sources/GraphZahlTests/SchemaResolutionTests.swift +++ b/Sources/GraphZahlTests/SchemaResolutionTests.swift @@ -38,6 +38,26 @@ class SchemaResolutionTests: XCTestCase { XCTAssertEqual(expectedData, result.data) } + func testKeypaths() throws { + let query = """ + { + foo(filter: Foo, equals: "Foo1") { + foo + } + } + """ + + let result = try Schema.perform(request: query).wait() + + let expectedData: Map = [ + "foo" : [ + ["foo": "Foo1"] + ] + ] + + XCTAssertEqual(expectedData, result.data) + } + } class Schema: GraphZahl.GraphQLSchema { @@ -47,6 +67,14 @@ class Schema: GraphZahl.GraphQLSchema { return .bar(Bar(bar: 42)) } + func foo(filter: KeyPath, equals: String) -> [Foo] { + return [ + Foo(foo: "Foo"), + Foo(foo: "Foo1"), + Foo(foo: "Foo2"), + ].filter { $0[keyPath: filter] == equals } + } + required init(viewerContext: ()) { } }