Skip to content

Instantly share code, notes, and snippets.

@DarkSeraphim
Last active June 19, 2019 17:02
Show Gist options
  • Save DarkSeraphim/7bb6fd698701e3ba0be8877073863807 to your computer and use it in GitHub Desktop.
Save DarkSeraphim/7bb6fd698701e3ba0be8877073863807 to your computer and use it in GitHub Desktop.
GraphQL4J design v2
public interface FieldResolver extends BiFunction<SelectionSet, Map<String, Object>, CompletableFuture<?>> {
}
public interface Resolvable {
default Map<String, FieldResolver> nodes();
}
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
class UData {
public String name;
public long playing;
}
class GraphExecutor {
public CompletableFuture<Map<String, ?>> execute(SelectionSet selectionSet, Map<String, Object> args) {
UserQuery userQuery = getUserQuery();
return resolve(selectionSet, args, userQuery);
}
public CompletableFuture<Map<String, ?>> resolve(SelectionSet selectionSet, Map<String, Object> args, Resolvable resolvable) {
Map<String, FieldResolver> resolvers = resolvable.nodes();
Map<String, ?> result = new ConcurrentHashMap<>();
return CompletableFuture.allOf(selectionSet.map(field -> {
FieldResolver resolver = resolvers.get(field);
return resolver.apply(selectionSet, args).thenApply(object -> {
if (object instanceof Resolvable) {
return resolve(selectionSet.getChild(field), args, (Resolvable) object);
}
return object;
}).thenAccept(value -> result.put(field, value));
})).thenApply($ -> result);
}
private UserQuery getUserQuery() {
return new UserQuery() {
CompletableFuture<User> userById(SelectionSet selectionSet, UUID id) {
return getUser(selectionSet, id);
}
}
}
private User getUser(SelectionSet selectionSet, UUID id) {
Supplier<CompletableFuture<UData>> query = loadUser(selectionSet.asSet(), id);
return new User() {
public CompletableFuture<String> name() {
return query.get().thenApply(data -> data.name);
}
public CompletableFuture<Long> playingFor(TimeUnit unit) {
return query.get().thenApply(data -> unit.toMillis(data.playing));
}
};
}
// Out of scope:
private static Supplier<CompletableFuture<UData>> loadUser(Set<String> fields, UUID id) {
return () -> CompletableFuture.completedFuture(new UData() {
{
super.name = "Foo";
super.playing = 5;
}
});
}
}
public class SelectionSet {
private Map<String, SelectionSet> fields;
public <T> Stream<T> map(Function<String, T> mapper) {
return fields.keySet().stream().map(mapper);
}
public SelectionSet getChild(String field) {
return fields.get(field);
}
public Set<String> asSet() {
return Collections.unmodifiableSet(field.keySet());
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
public interface User extends Resolvable {
// Scalars don't need their selection set
CompletableFuture<String> name();
CompletableFuture<Long> playingFor(TimeUnit units);
default Map<String, FieldResolver> nodes() {
return NODES(this);
}
static Map<String, FieldResolver> NODES(User instance) {
return new HashMap<String, FieldResolver>() {{
put("name", (selectionSet, args) -> instance.name());
put("playingFor", (selectionSet, args) -> instance.playingFor((TimeUnit) args.get("unit")));
}};
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
public interface UserQuery extends Resolvable {
CompletableFuture<User> userById(SelectionSet selectionSet, UUID id);
default Map<String, FieldResolver> nodes() {
return NODES(this);
}
static Map<String, FieldResolver> NODES(UserQuery instance) {
return new HashMap<String, BiFunction<SelectionSet, Map<String, Object>, ?>>(){
{
put("userById", (selectionSet, args) -> instance.userById(selectionSet, (UUID) args.get("uuid")));
}};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment