forked from smallrye/smallrye-graphql
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
smallrye#521: implement federation data fetcher and type resolver
- Loading branch information
Showing
2 changed files
with
119 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
server/implementation/src/main/java/io/smallrye/graphql/bootstrap/FederationDataFetcher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package io.smallrye.graphql.bootstrap; | ||
|
||
import static java.util.stream.Collectors.toList; | ||
import static java.util.stream.Collectors.toSet; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import com.apollographql.federation.graphqljava._Entity; | ||
|
||
import graphql.schema.DataFetcher; | ||
import graphql.schema.DataFetchingEnvironment; | ||
import graphql.schema.DelegatingDataFetchingEnvironment; | ||
import graphql.schema.GraphQLArgument; | ||
import graphql.schema.GraphQLCodeRegistry; | ||
import graphql.schema.GraphQLFieldDefinition; | ||
import graphql.schema.GraphQLObjectType; | ||
import graphql.schema.GraphQLOutputType; | ||
|
||
class FederationDataFetcher implements DataFetcher<List<Object>> { | ||
|
||
private final GraphQLObjectType queryType; | ||
private final GraphQLCodeRegistry codeRegistry; | ||
|
||
public FederationDataFetcher(GraphQLObjectType queryType, GraphQLCodeRegistry codeRegistry) { | ||
this.queryType = queryType; | ||
this.codeRegistry = codeRegistry; | ||
} | ||
|
||
@Override | ||
public List<Object> get(DataFetchingEnvironment environment) throws Exception { | ||
return environment.<List<Map<String, Object>>> getArgument(_Entity.argumentName).stream() | ||
.map(representations -> fetchEntities(environment, representations)) | ||
.collect(toList()); | ||
} | ||
|
||
private Object fetchEntities(DataFetchingEnvironment env, Map<String, Object> representations) { | ||
Map<String, Object> requestedArgs = new HashMap<>(representations); | ||
requestedArgs.remove("__typename"); | ||
String typename = (String) representations.get("__typename"); | ||
for (GraphQLFieldDefinition field : queryType.getFields()) { | ||
if (matchesReturnType(field, typename) && matchesArguments(requestedArgs, field)) { | ||
return execute(field, env, requestedArgs); | ||
} | ||
} | ||
throw new RuntimeException("no query found for " + typename + " by " + requestedArgs.keySet()); | ||
} | ||
|
||
private boolean matchesReturnType(GraphQLFieldDefinition field, String typename) { | ||
GraphQLOutputType returnType = field.getType(); | ||
return returnType instanceof GraphQLObjectType && ((GraphQLObjectType) returnType).getName().equals(typename); | ||
} | ||
|
||
private boolean matchesArguments(Map<String, Object> requestedArguments, GraphQLFieldDefinition field) { | ||
Set<String> argumentNames = field.getArguments().stream().map(GraphQLArgument::getName).collect(toSet()); | ||
return argumentNames.equals(requestedArguments.keySet()); | ||
} | ||
|
||
private Object execute(GraphQLFieldDefinition field, DataFetchingEnvironment env, Map<String, Object> requestedArgs) { | ||
DataFetcher<?> dataFetcher = codeRegistry.getDataFetcher(queryType, field); | ||
DataFetchingEnvironment argsEnv = new DelegatingDataFetchingEnvironment(env) { | ||
@Override | ||
public Map<String, Object> getArguments() { | ||
return requestedArgs; | ||
} | ||
|
||
@Override | ||
public boolean containsArgument(String name) { | ||
return requestedArgs.containsKey(name); | ||
} | ||
|
||
@Override | ||
public <T> T getArgument(String name) { | ||
//noinspection unchecked | ||
return (T) requestedArgs.get(name); | ||
} | ||
|
||
@Override | ||
public <T> T getArgumentOrDefault(String name, T defaultValue) { | ||
return containsArgument(name) ? getArgument(name) : defaultValue; | ||
} | ||
}; | ||
try { | ||
return dataFetcher.get(argsEnv); | ||
} catch (Exception e) { | ||
throw new RuntimeException("can't fetch data from " + field, e); | ||
} | ||
} | ||
} |