Skip to content

Commit aae19d3

Browse files
committed
Refactoring in EntitiesDataFetcher
See gh-991
1 parent 43f41d2 commit aae19d3

File tree

1 file changed

+63
-81
lines changed

1 file changed

+63
-81
lines changed

spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java

Lines changed: 63 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.springframework.graphql.data.method.annotation.support.HandlerDataFetcherExceptionResolver;
4141
import org.springframework.graphql.execution.ErrorType;
4242
import org.springframework.lang.Nullable;
43-
import org.springframework.util.Assert;
4443

4544
/**
4645
* DataFetcher that handles the "_entities" query by invoking
@@ -93,12 +92,11 @@ public Mono<DataFetcherResult<List<Object>>> get(DataFetchingEnvironment env) {
9392
}
9493
else {
9594
if (!batchedTypes.contains(type)) {
96-
EntityBatchDelegate delegate = new EntityBatchDelegate(env, representations, handlerMethod, type);
97-
monoList.add(delegate.invokeEntityBatchMethod());
95+
monoList.add(invokeEntitiesMethod(env, handlerMethod, representations, type));
9896
batchedTypes.add(type);
9997
}
10098
else {
101-
// Covered by batch invocation, but zip needs a value (to be replaced by batch results)
99+
// Already covered, but zip needs a value (to be replaced by batch results)
102100
monoList.add(Mono.just(Collections.emptyMap()));
103101
}
104102
}
@@ -107,11 +105,48 @@ public Mono<DataFetcherResult<List<Object>>> get(DataFetchingEnvironment env) {
107105
}
108106

109107
private Mono<Object> invokeEntityMethod(
110-
DataFetchingEnvironment env, EntityHandlerMethod handlerMethod, Map<String, Object> map, int index) {
108+
DataFetchingEnvironment environment, EntityHandlerMethod handlerMethod,
109+
Map<String, Object> representation, int index) {
111110

112-
return handlerMethod.getEntity(env, map)
113-
.switchIfEmpty(Mono.error(new RepresentationNotResolvedException(map, handlerMethod)))
114-
.onErrorResume((ex) -> resolveException(ex, env, handlerMethod, index));
111+
return handlerMethod.getEntity(environment, representation)
112+
.switchIfEmpty(Mono.error(new RepresentationNotResolvedException(representation, handlerMethod)))
113+
.onErrorResume((ex) -> resolveException(ex, environment, handlerMethod, index));
114+
}
115+
116+
private Mono<EntitiesResultContainer> invokeEntitiesMethod(
117+
DataFetchingEnvironment environment, EntityHandlerMethod handlerMethod,
118+
List<Map<String, Object>> representations, String type) {
119+
120+
List<Map<String, Object>> typeRepresentations = new ArrayList<>();
121+
List<Integer> originalIndexes = new ArrayList<>();
122+
123+
for (int i = 0; i < representations.size(); i++) {
124+
Map<String, Object> map = representations.get(i);
125+
if (type.equals(map.get("__typename"))) {
126+
typeRepresentations.add(map);
127+
originalIndexes.add(i);
128+
}
129+
}
130+
131+
return handlerMethod.getEntities(environment, typeRepresentations)
132+
.mapNotNull((result) -> (((List<?>) result).isEmpty()) ? null : result)
133+
.switchIfEmpty(Mono.defer(() -> {
134+
List<Mono<?>> exceptions = new ArrayList<>(originalIndexes.size());
135+
for (int i = 0; i < originalIndexes.size(); i++) {
136+
exceptions.add(resolveException(
137+
new RepresentationNotResolvedException(typeRepresentations.get(i), handlerMethod),
138+
environment, handlerMethod, originalIndexes.get(i)));
139+
}
140+
return Mono.zip(exceptions, Arrays::asList);
141+
}))
142+
.onErrorResume((ex) -> {
143+
List<Mono<?>> list = new ArrayList<>();
144+
for (Integer index : originalIndexes) {
145+
list.add(resolveException(ex, environment, handlerMethod, index));
146+
}
147+
return Mono.zip(list, Arrays::asList);
148+
})
149+
.map((result) -> new EntitiesResultContainer((List<?>) result, originalIndexes));
115150
}
116151

117152
private Mono<ErrorContainer> resolveException(
@@ -141,8 +176,8 @@ private static DataFetcherResult<List<Object>> toDataFetcherResult(List<Object>
141176
List<GraphQLError> errors = new ArrayList<>();
142177
for (int i = 0; i < entities.size(); i++) {
143178
Object entity = entities.get(i);
144-
if (entity instanceof EntityBatchDelegate delegate) {
145-
delegate.processResults(entities, errors);
179+
if (entity instanceof EntitiesResultContainer resultHandler) {
180+
resultHandler.applyResults(entities, errors);
146181
}
147182
if (entity instanceof ErrorContainer errorContainer) {
148183
errors.addAll(errorContainer.errors());
@@ -153,77 +188,6 @@ private static DataFetcherResult<List<Object>> toDataFetcherResult(List<Object>
153188
}
154189

155190

156-
private class EntityBatchDelegate {
157-
158-
private final DataFetchingEnvironment environment;
159-
160-
private final EntityHandlerMethod handlerMethod;
161-
162-
private final List<Map<String, Object>> filteredRepresentations = new ArrayList<>();
163-
164-
private final List<Integer> indexes = new ArrayList<>();
165-
166-
@Nullable
167-
private List<?> resultList;
168-
169-
EntityBatchDelegate(
170-
DataFetchingEnvironment env, List<Map<String, Object>> allRepresentations,
171-
EntityHandlerMethod handlerMethod, String type) {
172-
173-
this.environment = env;
174-
this.handlerMethod = handlerMethod;
175-
for (int i = 0; i < allRepresentations.size(); i++) {
176-
Map<String, Object> map = allRepresentations.get(i);
177-
if (type.equals(map.get("__typename"))) {
178-
this.filteredRepresentations.add(map);
179-
this.indexes.add(i);
180-
}
181-
}
182-
}
183-
184-
Mono<Object> invokeEntityBatchMethod() {
185-
return this.handlerMethod.getEntities(this.environment, this.filteredRepresentations)
186-
.mapNotNull((result) -> (((List<?>) result).isEmpty()) ? null : result)
187-
.switchIfEmpty(Mono.defer(this::handleEmptyResult))
188-
.onErrorResume(this::handleErrorResult)
189-
.map((result) -> {
190-
this.resultList = (List<?>) result;
191-
return this;
192-
});
193-
}
194-
195-
Mono<Object> handleEmptyResult() {
196-
List<Mono<?>> exceptions = new ArrayList<>(this.indexes.size());
197-
for (int i = 0; i < this.indexes.size(); i++) {
198-
Map<String, Object> map = this.filteredRepresentations.get(i);
199-
Exception ex = new RepresentationNotResolvedException(map, this.handlerMethod);
200-
exceptions.add(resolveException(ex, this.environment, this.handlerMethod, this.indexes.get(i)));
201-
}
202-
return Mono.zip(exceptions, Arrays::asList);
203-
}
204-
205-
Mono<List<Object>> handleErrorResult(Throwable ex) {
206-
List<Mono<?>> list = new ArrayList<>();
207-
for (Integer index : this.indexes) {
208-
list.add(resolveException(ex, this.environment, this.handlerMethod, index));
209-
}
210-
return Mono.zip(list, Arrays::asList);
211-
}
212-
213-
void processResults(List<Object> entities, List<GraphQLError> errors) {
214-
Assert.state(this.resultList != null, "Expected resultList");
215-
for (int i = 0; i < this.resultList.size(); i++) {
216-
Object entity = this.resultList.get(i);
217-
if (entity instanceof ErrorContainer errorContainer) {
218-
errors.addAll(errorContainer.errors());
219-
entity = null;
220-
}
221-
entities.set(this.indexes.get(i), entity);
222-
}
223-
}
224-
}
225-
226-
227191
private static class IndexedDataFetchingEnvironment extends DelegatingDataFetchingEnvironment {
228192

229193
private final ExecutionStepInfo executionStepInfo;
@@ -242,6 +206,24 @@ public ExecutionStepInfo getExecutionStepInfo() {
242206
}
243207

244208

209+
private record EntitiesResultContainer(List<?> results, List<Integer> originalIndexes) {
210+
211+
public void applyResults(List<Object> entities, List<GraphQLError> errors) {
212+
for (int i = 0; i < this.results.size(); i++) {
213+
Object result = this.results.get(i);
214+
Integer index = this.originalIndexes.get(i);
215+
if (result instanceof ErrorContainer container) {
216+
errors.addAll(container.errors());
217+
entities.set(index, null);
218+
}
219+
else {
220+
entities.set(index, result);
221+
}
222+
}
223+
}
224+
}
225+
226+
245227
private record ErrorContainer(List<GraphQLError> errors) {
246228

247229
ErrorContainer(GraphQLError error) {

0 commit comments

Comments
 (0)