Skip to content

Commit c2b52db

Browse files
feature: Adds UniqueOperationNamesRule
1 parent 2bcecfe commit c2b52db

File tree

3 files changed

+183
-1
lines changed

3 files changed

+183
-1
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
/**
3+
* Unique operation names
4+
*
5+
* A GraphQL document is only valid if all defined operations have unique names.
6+
*
7+
* See https://spec.graphql.org/draft/#sec-Operation-Name-Uniqueness
8+
*/
9+
func UniqueOperationNamesRule(context: ValidationContext) -> Visitor {
10+
var knownOperationNames = [String: Name]()
11+
return Visitor(
12+
enter: { node, _, _, _, _ in
13+
if let operation = node as? OperationDefinition {
14+
if let operationName = operation.name {
15+
if let knownOperationName = knownOperationNames[operationName.value] {
16+
context.report(
17+
error: GraphQLError(
18+
message: "There can be only one operation named \"\(operationName.value)\".",
19+
nodes: [knownOperationName, operationName]
20+
)
21+
)
22+
} else {
23+
knownOperationNames[operationName.value] = operationName
24+
}
25+
}
26+
}
27+
return .continue
28+
}
29+
)
30+
}

Sources/GraphQL/Validation/SpecifiedRules.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
public let specifiedRules: [(ValidationContext) -> Visitor] = [
55
// ExecutableDefinitionsRule,
6-
// UniqueOperationNamesRule,
6+
UniqueOperationNamesRule,
77
// LoneAnonymousOperationRule,
88
// SingleFieldSubscriptionsRule,
99
// KnownTypeNamesRule,
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
@testable import GraphQL
2+
import XCTest
3+
4+
class UniqueOperationNamesRuleTests: ValidationTestCase {
5+
override func setUp() {
6+
rule = UniqueOperationNamesRule
7+
}
8+
9+
func testNoOperations() throws {
10+
try assertValid(
11+
"""
12+
fragment fragA on Type {
13+
field
14+
}
15+
"""
16+
)
17+
}
18+
19+
func testOneAnonOperation() throws {
20+
try assertValid(
21+
"""
22+
{
23+
field
24+
}
25+
"""
26+
)
27+
}
28+
29+
func testOneNamedOperation() throws {
30+
try assertValid(
31+
"""
32+
query Foo {
33+
field
34+
}
35+
"""
36+
)
37+
}
38+
39+
func testMultipleOperations() throws {
40+
try assertValid(
41+
"""
42+
query Foo {
43+
field
44+
}
45+
46+
query Bar {
47+
field
48+
}
49+
"""
50+
)
51+
}
52+
53+
func testMultipleOperationsOfDifferentTypes() throws {
54+
try assertValid(
55+
"""
56+
query Foo {
57+
field
58+
}
59+
60+
mutation Bar {
61+
field
62+
}
63+
64+
subscription Baz {
65+
field
66+
}
67+
"""
68+
)
69+
}
70+
71+
func testFragmentAndOperationNamedTheSame() throws {
72+
try assertValid(
73+
"""
74+
query Foo {
75+
...Foo
76+
}
77+
fragment Foo on Type {
78+
field
79+
}
80+
"""
81+
)
82+
}
83+
84+
func testMultipleOperationsOfSameName() throws {
85+
let errors = try assertInvalid(
86+
errorCount: 1,
87+
query:
88+
"""
89+
query Foo {
90+
fieldA
91+
}
92+
query Foo {
93+
fieldB
94+
}
95+
"""
96+
)
97+
try assertValidationError(
98+
error: errors[0],
99+
locations: [
100+
(line: 1, column: 7),
101+
(line: 4, column: 7),
102+
],
103+
message: "There can be only one operation named \"Foo\"."
104+
)
105+
}
106+
107+
func testMultipleOperationsOfDifferentTypesMutation() throws {
108+
let errors = try assertInvalid(
109+
errorCount: 1,
110+
query:
111+
"""
112+
query Foo {
113+
fieldA
114+
}
115+
mutation Foo {
116+
fieldB
117+
}
118+
"""
119+
)
120+
try assertValidationError(
121+
error: errors[0],
122+
locations: [
123+
(line: 1, column: 7),
124+
(line: 4, column: 10),
125+
],
126+
message: "There can be only one operation named \"Foo\"."
127+
)
128+
}
129+
130+
func testMultipleOperationsOfDifferentTypesSubscription() throws {
131+
let errors = try assertInvalid(
132+
errorCount: 1,
133+
query:
134+
"""
135+
query Foo {
136+
fieldA
137+
}
138+
subscription Foo {
139+
fieldB
140+
}
141+
"""
142+
)
143+
try assertValidationError(
144+
error: errors[0],
145+
locations: [
146+
(line: 1, column: 7),
147+
(line: 4, column: 14),
148+
],
149+
message: "There can be only one operation named \"Foo\"."
150+
)
151+
}
152+
}

0 commit comments

Comments
 (0)