Skip to content

Instantly share code, notes, and snippets.

@zhbrass
Forked from dminkovsky/GraphQLPrinter.java
Last active September 14, 2016 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhbrass/1fd7fbabad852a323740682065708b1b to your computer and use it in GitHub Desktop.
Save zhbrass/1fd7fbabad852a323740682065708b1b to your computer and use it in GitHub Desktop.
Printer for the graphql-java library [https://github.com/graphql-java/graphql-java] that turns GraphQL document objects into proper query strings.
package your.package.here
import java.util.List;
import graphql.language.*;
/**
* Created by dminkovsky
* Updated by zhbrass to remove Java 8 features so it can be used with Android without using Jack
*/
public class GraphQLPrinter {
/**
* Used in place of java.util.function.Consumer
*/
interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
private int indentWidth = 4;
public String print(Document document) {
GraphQLPrinterImpl printer = new GraphQLPrinterImpl(document, indentWidth);
return printer.print();
}
private static class GraphQLPrinterImpl {
private final StringBuilder builder = new StringBuilder();
private final Node root;
private final int indentWidth;
private int indentLevel = 0;
GraphQLPrinterImpl(Node root, int indentWidth) {
this.root = root;
this.indentWidth = indentWidth;
}
public String print() {
print(root);
return builder.toString();
}
private <T extends Node> void join(List<T> nodes, String delimeter) {
int size = nodes.size();
for (int i = 0; i < size; i++) {
T node = nodes.get(i);
print(node);
if (i + 1 != size) {
builder.append(delimeter);
}
}
}
private <T> void wrap(String start, T thing, String end) {
wrap(start, thing, end, new Consumer<T>() {
@Override
public void accept(T t) {
builder.append(t);
}
});
}
@SuppressWarnings("unchecked")
private <T> void wrap(String start, T thing, String end, Consumer<T> inner) {
if (thing instanceof List<?> && ((List<T>) thing).isEmpty()) {
return;
}
builder.append(start);
inner.accept(thing);
builder.append(end);
}
private String getNewLine() {
StringBuilder builder = new StringBuilder();
builder.append("\n");
for (int i = 0; i < indentLevel; i++) {
for (int j = 0; i < indentWidth; i++) {
builder.append(" ");
}
}
return builder.toString();
}
private void line() {
line(1);
}
private void line(int count) {
for (int i = 0; i < count; i++) {
builder.append(getNewLine());
}
}
private void print(Node node) {
if (node instanceof Document) {
print((Document) node);
} else if (node instanceof OperationDefinition) {
print((OperationDefinition) node);
} else if (node instanceof FragmentDefinition) {
print((FragmentDefinition) node);
} else if (node instanceof VariableDefinition) {
print((VariableDefinition) node);
} else if (node instanceof ArrayValue) {
print((ArrayValue) node);
} else if (node instanceof BooleanValue) {
print((BooleanValue) node);
} else if (node instanceof EnumValue) {
print((EnumValue) node);
} else if (node instanceof FloatValue) {
print((FloatValue) node);
} else if (node instanceof IntValue) {
print((IntValue) node);
} else if (node instanceof ObjectValue) {
print((ObjectValue) node);
} else if (node instanceof StringValue) {
print((StringValue) node);
} else if (node instanceof VariableReference) {
print((VariableReference) node);
} else if (node instanceof ListType) {
print((ListType) node);
} else if (node instanceof NonNullType) {
print((NonNullType) node);
} else if (node instanceof TypeName) {
print((TypeName) node);
} else if (node instanceof Directive) {
print((Directive) node);
} else if (node instanceof Argument) {
print((Argument) node);
} else if (node instanceof ObjectField) {
print((ObjectField) node);
} else if (node instanceof SelectionSet) {
print((SelectionSet) node);
} else if (node instanceof Field) {
print((Field) node);
} else if (node instanceof InlineFragment) {
print((InlineFragment) node);
} else if (node instanceof FragmentSpread) {
print((FragmentSpread) node);
} else {
throw new RuntimeException("unknown type");
}
}
private void print(Document node) {
for (Definition defintition : node.getDefinitions()) {
print(defintition);
line(2);
}
line();
}
private void print(OperationDefinition node) {
String name = node.getName();
OperationDefinition.Operation operation = node.getOperation();
List<VariableDefinition> variableDefinitions = node.getVariableDefinitions();
List<Directive> directives = node.getDirectives();
SelectionSet selectionSet = node.getSelectionSet();
if (name == null && variableDefinitions.isEmpty() && directives.isEmpty() && operation == OperationDefinition.Operation.QUERY) {
print(selectionSet);
} else {
if (operation == OperationDefinition.Operation.QUERY) {
builder.append("query ");
} else if (operation == OperationDefinition.Operation.MUTATION) {
builder.append("mutation ");
} else {
throw new RuntimeException("unsupported operation");
}
if (name != null) {
builder.append(name);
}
wrap("(", variableDefinitions, ")", new Consumer<List<VariableDefinition>>() {
@Override
public void accept(List<VariableDefinition> definitions) {
join(definitions, ", ");
}
});
wrap(" ", directives, " ", new Consumer<List<Directive>>() {
@Override
public void accept(List<Directive> dirs) {
join(dirs, " ");
}
});
builder.append(" ");
print(selectionSet);
}
}
private void print(VariableDefinition node) {
builder.append(node.getName());
builder.append(": ");
print(node.getType());
Value defaultValue = node.getDefaultValue();
if (defaultValue != null) {
builder.append(" = ");
print(defaultValue);
}
}
private void print(Directive node) {
builder.append("@");
builder.append(node.getName());
wrap("(", node.getArguments(), ")", new Consumer<List<Argument>>() {
@Override
public void accept(List<Argument> arguments) {
join(arguments, ", ");
}
});
}
private void print(SelectionSet node) {
List<Selection> selections = node.getSelections();
if (selections.isEmpty()) {
return;
}
builder.append("{");
indentLevel++;
line();
join(selections, getNewLine());
indentLevel--;
line();
builder.append("}");
}
private void print(FragmentDefinition node) {
builder.append("fragment ");
builder.append(node.getName());
builder.append(" on ");
print(node.getTypeCondition());
wrap(" ", node.getDirectives(), " ", new Consumer<List<Directive>>() {
@Override
public void accept(List<Directive> directives) {
join(directives, " ");
}
});
print(node.getSelectionSet());
}
private void print(ArrayValue node) {
wrap("[", node.getValues(), "]", new Consumer<List<Value>>() {
@Override
public void accept(List<Value> values) {
join(values, ", ");
}
});
}
private void print(BooleanValue node) {
builder.append(node.isValue());
}
private void print(EnumValue node) {
builder.append(node.getName());
}
private void print(FloatValue node) {
builder.append(node.getValue());
}
private void print(IntValue node) {
builder.append(node.getValue());
}
private void print(ObjectValue node) {
wrap("{", node.getObjectFields(), "}", new Consumer<List<ObjectField>>() {
@Override
public void accept(List<ObjectField> fields) {
join(fields, ", ");
}
});
}
private void print(StringValue node) {
wrap("\"", node.getValue(), "\"");
}
private void print(VariableReference node) {
builder.append(node.getName());
}
private void print(ListType node) {
wrap("[", node.getType(), "]", new Consumer<Type>() {
@Override
public void accept(Type t) {
print(t);
}
});
}
private void print(NonNullType node) {
print(node.getType());
builder.append("!");
}
private void print(TypeName node) {
builder.append(node.getName());
}
private void print(Argument node) {
builder.append(node.getName());
builder.append(": ");
print(node.getValue());
}
private void print(Field node) {
String alias = node.getAlias();
if (alias != null) {
builder.append(alias);
builder.append(": ");
}
builder.append(node.getName());
List<Argument> arguments = node.getArguments();
wrap("(", arguments, ")", new Consumer<List<Argument>>() {
@Override
public void accept(List<Argument> args) {
join(args, ", ");
}
});
join(node.getDirectives(), " ");
SelectionSet selectionSet = node.getSelectionSet();
if (selectionSet != null) {
print(selectionSet);
}
}
private void print(ObjectField node) {
builder.append(node.getName());
builder.append(": ");
print(node.getValue());
}
private void print(InlineFragment node) {
builder.append("... on ");
builder.append(node.getTypeCondition().getName());
builder.append(" ");
join(node.getDirectives(), " ");
print(node.getSelectionSet());
}
private void print(FragmentSpread node) {
builder.append("...");
builder.append(node.getName());
join(node.getDirectives(), " ");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment