Skip to content

Commit fa8915d

Browse files
tinnoubbakerman
authored andcommitted
Fix AbsoluteGraphQLError source location bug.
1 parent 3a169c1 commit fa8915d

File tree

2 files changed

+82
-6
lines changed

2 files changed

+82
-6
lines changed

src/main/java/graphql/execution/AbsoluteGraphQLError.java

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package graphql.execution;
22

3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.Optional;
7+
import java.util.stream.Collectors;
8+
39
import graphql.ErrorType;
410
import graphql.GraphQLError;
511
import graphql.language.Field;
612
import graphql.language.SourceLocation;
713
import graphql.schema.DataFetcher;
8-
9-
import java.util.ArrayList;
10-
import java.util.Collections;
1114
import java.util.HashMap;
12-
import java.util.List;
1315
import java.util.Map;
14-
import java.util.Optional;
15-
import java.util.stream.Collectors;
1616

1717
import static graphql.Assert.assertNotNull;
1818

@@ -67,6 +67,15 @@ public Map<String, Object> getExtensions() {
6767
return extentions;
6868
}
6969

70+
/**
71+
* Creating absolute paths follows the following logic:
72+
* Relative path is null -> Absolute path null
73+
* Relative path is empty -> Absolute paths is path up to the field.
74+
* Relative path is not empty -> Absolute paths [base Path, relative Path]
75+
* @param relativeError relative error
76+
* @param executionStrategyParameters execution strategy params.
77+
* @return List of paths from the root.
78+
*/
7079
private List<Object> createAbsolutePath(ExecutionStrategyParameters executionStrategyParameters,
7180
GraphQLError relativeError) {
7281
return Optional.ofNullable(relativeError.getPath())
@@ -80,13 +89,28 @@ private List<Object> createAbsolutePath(ExecutionStrategyParameters executionStr
8089
.orElse(null);
8190
}
8291

92+
/**
93+
* Creating absolute locations follows the following logic:
94+
* Relative locations is null -> Absolute locations null
95+
* Relative locations is empty -> Absolute locations base locations of the field.
96+
* Relative locations is not empty -> Absolute locations [base line + relative line location]
97+
* @param relativeError relative error
98+
* @param fields fields on the current field.
99+
* @return List of locations from the root.
100+
*/
83101
private List<SourceLocation> createAbsoluteLocations(GraphQLError relativeError, List<Field> fields) {
84102
Optional<SourceLocation> baseLocation;
85103
if (!fields.isEmpty()) {
86104
baseLocation = Optional.ofNullable(fields.get(0).getSourceLocation());
87105
} else {
88106
baseLocation = Optional.empty();
89107
}
108+
109+
// relative error empty path should yield an absolute error with the base path
110+
if (relativeError.getLocations() != null && relativeError.getLocations().isEmpty()) {
111+
return baseLocation.map(Collections::singletonList).orElse(null);
112+
}
113+
90114
return Optional.ofNullable(
91115
relativeError.getLocations())
92116
.map(locations -> locations.stream()

src/test/groovy/graphql/execution/AbsoluteGraphQLErrorTest.groovy

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,32 @@ class AbsoluteGraphQLErrorTest extends Specification {
8282
error.getPath() == null
8383
}
8484

85+
def "when constructor receives empty path it should return the base field path"() {
86+
given:
87+
88+
def field = new Field("test")
89+
field.setSourceLocation(new SourceLocation(4, 5))
90+
91+
def parameters = newParameters()
92+
.typeInfo(ExecutionTypeInfo.newTypeInfo().type(objectType))
93+
.source(new Object())
94+
.fields(["fld": [new Field()]])
95+
.field([field])
96+
.path(ExecutionPath.fromList(["foo", "bar"]))
97+
.build()
98+
99+
def relativeError = new DataFetchingErrorGraphQLError("blah")
100+
relativeError.path = []
101+
102+
when:
103+
104+
def error = new AbsoluteGraphQLError(parameters, relativeError)
105+
106+
then:
107+
108+
error.getPath() == ["foo", "bar"]
109+
}
110+
85111
def "constructor handles missing locations as null"() {
86112
given:
87113

@@ -106,6 +132,32 @@ class AbsoluteGraphQLErrorTest extends Specification {
106132
error.getLocations() == null
107133
}
108134

135+
def "when constructor receives empty locations it should return the base field locations"() {
136+
given:
137+
138+
def field = new Field("test")
139+
def expectedSourceLocation = new SourceLocation(1, 2)
140+
field.setSourceLocation(expectedSourceLocation)
141+
142+
def parameters = newParameters()
143+
.typeInfo(ExecutionTypeInfo.newTypeInfo().type(objectType))
144+
.source(new Object())
145+
.fields(["fld": [new Field()]])
146+
.field([field])
147+
.path(ExecutionPath.fromList(["foo", "bar"]))
148+
.build()
149+
150+
def relativeError = new DataFetchingErrorGraphQLError("blah")
151+
relativeError.locations = []
152+
153+
when:
154+
def error = new AbsoluteGraphQLError(parameters, relativeError)
155+
156+
then:
157+
158+
error.getLocations() == [expectedSourceLocation]
159+
}
160+
109161
def "constructor transforms multiple source locations"() {
110162
given:
111163

0 commit comments

Comments
 (0)