Skip to content

Commit 927ebb1

Browse files
Merge pull request #136 from GraphQLSwift/feature/oneOfAndSpecifiedBy
Adds `oneOf` and `specifiedBy` directive support
2 parents 3f15434 + ca69acc commit 927ebb1

File tree

6 files changed

+104
-7
lines changed

6 files changed

+104
-7
lines changed

Package.resolved

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"repositoryURL": "https://github.com/GraphQLSwift/GraphQL.git",
77
"state": {
88
"branch": null,
9-
"revision": "3cf2dbce764e7ccff8447d0b7d4634c0438449d3",
10-
"version": "2.9.2"
9+
"revision": "87649dbc3cdab0be0256c86235f2aec22ec1bfc1",
10+
"version": "2.10.0"
1111
}
1212
},
1313
{

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ let package = Package(
77
.library(name: "Graphiti", targets: ["Graphiti"]),
88
],
99
dependencies: [
10-
.package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "2.9.2"),
10+
.package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "2.10.0"),
1111
],
1212
targets: [
1313
.target(name: "Graphiti", dependencies: ["GraphQL"]),

Sources/Graphiti/Input/Input.swift

+9-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ public final class Input<
88
Resolver,
99
Context
1010
> {
11+
let isOneOf: Bool
1112
let fields: [InputFieldComponent<InputObjectType, Context>]
1213

1314
override func update(typeProvider: SchemaTypeProvider, coders _: Coders) throws {
1415
let inputObjectType = try GraphQLInputObjectType(
1516
name: name,
1617
description: description,
17-
fields: fields(typeProvider: typeProvider)
18+
fields: fields(typeProvider: typeProvider),
19+
isOneOf: isOneOf
1820
)
1921

2022
try typeProvider.add(type: InputObjectType.self, as: inputObjectType)
@@ -38,8 +40,10 @@ public final class Input<
3840
init(
3941
type _: InputObjectType.Type,
4042
name: String?,
43+
isOneOf: Bool,
4144
fields: [InputFieldComponent<InputObjectType, Context>]
4245
) {
46+
self.isOneOf = isOneOf
4347
self.fields = fields
4448
super.init(
4549
name: name ?? Reflection.name(for: InputObjectType.self),
@@ -52,18 +56,20 @@ public extension Input {
5256
convenience init(
5357
_ type: InputObjectType.Type,
5458
as name: String? = nil,
59+
isOneOf: Bool = false,
5560
@InputFieldComponentBuilder<InputObjectType, Context> _ fields: ()
5661
-> InputFieldComponent<InputObjectType, Context>
5762
) {
58-
self.init(type: type, name: name, fields: [fields()])
63+
self.init(type: type, name: name, isOneOf: isOneOf, fields: [fields()])
5964
}
6065

6166
convenience init(
6267
_ type: InputObjectType.Type,
6368
as name: String? = nil,
69+
isOneOf: Bool = false,
6470
@InputFieldComponentBuilder<InputObjectType, Context> _ fields: ()
6571
-> [InputFieldComponent<InputObjectType, Context>]
6672
) {
67-
self.init(type: type, name: name, fields: fields())
73+
self.init(type: type, name: name, isOneOf: isOneOf, fields: fields())
6874
}
6975
}

Sources/Graphiti/Scalar/Scalar.swift

+6
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import OrderedCollections
99
/// you may provide your own serialize, parseValue, and parseLiteral implementations.
1010
open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolver, Context> {
1111
// TODO: Change this no longer be an open class
12+
let specifiedByURL: String?
1213

1314
override func update(typeProvider: SchemaTypeProvider, coders: Coders) throws {
1415
let scalarType = try GraphQLScalarType(
1516
name: name,
1617
description: description,
18+
specifiedByURL: specifiedByURL,
1719
serialize: { value in
1820
if let serialize = self.serialize {
1921
return try serialize(value, coders)
@@ -70,10 +72,12 @@ open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolve
7072
init(
7173
type _: ScalarType.Type,
7274
name: String?,
75+
specifiedBy: String? = nil,
7376
serialize: ((Any, Coders) throws -> Map)? = nil,
7477
parseValue: ((Map, Coders) throws -> Map)? = nil,
7578
parseLiteral: ((GraphQL.Value, Coders) throws -> Map)? = nil
7679
) {
80+
specifiedByURL = specifiedBy
7781
self.serialize = serialize
7882
self.parseValue = parseValue
7983
self.parseLiteral = parseLiteral
@@ -88,13 +92,15 @@ public extension Scalar {
8892
convenience init(
8993
_ type: ScalarType.Type,
9094
as name: String? = nil,
95+
specifiedBy: String? = nil,
9196
serialize: ((Any, Coders) throws -> Map)? = nil,
9297
parseValue: ((Map, Coders) throws -> Map)? = nil,
9398
parseLiteral: ((GraphQL.Value, Coders) throws -> Map)? = nil
9499
) {
95100
self.init(
96101
type: type,
97102
name: name,
103+
specifiedBy: specifiedBy,
98104
serialize: serialize,
99105
parseValue: parseValue,
100106
parseLiteral: parseLiteral

Tests/GraphitiTests/DirectiveTests/DirectiveTests.swift

+85
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,89 @@ class DirectiveTests: XCTestCase {
7474

7575
XCTAssertEqual(response, expected)
7676
}
77+
78+
func testOneOfAcceptsGoodValue() throws {
79+
try XCTAssertEqual(
80+
OneOfAPI().execute(
81+
request: """
82+
query {
83+
test(input: {a: "abc"}) {
84+
a
85+
b
86+
}
87+
}
88+
""",
89+
context: NoContext(),
90+
on: group
91+
).wait(),
92+
GraphQLResult(
93+
data: [
94+
"test": [
95+
"a": "abc",
96+
"b": .null,
97+
],
98+
]
99+
)
100+
)
101+
}
102+
103+
func testOneOfRejectsBadValue() throws {
104+
try XCTAssertEqual(
105+
OneOfAPI().execute(
106+
request: """
107+
query {
108+
test(input: {a: "abc", b: 123}) {
109+
a
110+
b
111+
}
112+
}
113+
""",
114+
context: NoContext(),
115+
on: group
116+
).wait().errors[0].message,
117+
#"OneOf Input Object "TestInputObject" must specify exactly one key."#
118+
)
119+
}
120+
121+
struct OneOfAPI: API {
122+
struct TestObject: Codable {
123+
let a: String?
124+
let b: Int?
125+
}
126+
127+
struct TestInputObject: Codable {
128+
let a: String?
129+
let b: Int?
130+
}
131+
132+
struct TestArguments: Codable {
133+
let input: TestInputObject
134+
}
135+
136+
struct OneOfResolver {
137+
func test(context _: NoContext, arguments: TestArguments) -> TestObject {
138+
return TestObject(a: arguments.input.a, b: arguments.input.b)
139+
}
140+
}
141+
142+
let resolver = OneOfResolver()
143+
144+
let schema = try! Schema<OneOfResolver, NoContext> {
145+
Type(TestObject.self) {
146+
Field("a", at: \.a)
147+
Field("b", at: \.b)
148+
}
149+
150+
Input(TestInputObject.self, isOneOf: true) {
151+
InputField("a", at: \.a)
152+
InputField("b", at: \.b)
153+
}
154+
155+
Query {
156+
Field("test", at: OneOfResolver.test, as: TestObject.self) {
157+
Argument("input", at: \.input)
158+
}
159+
}
160+
}
161+
}
77162
}

Tests/GraphitiTests/HelloWorldTests/HelloWorldAsyncTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ import XCTest
353353
)
354354
subscribers.append(subscriber)
355355
}
356-
return ConcurrentEventStream<T>.init(asyncStream)
356+
return ConcurrentEventStream<T>(asyncStream)
357357
}
358358
}
359359

0 commit comments

Comments
 (0)