Skip to content

Commit

Permalink
Merge pull request #59 from Shopify/support-query-directives
Browse files Browse the repository at this point in the history
Support Query & Mutation Directives
  • Loading branch information
cocoahero authored Jun 16, 2021
2 parents 18fd2c4 + 82f7624 commit 295f0e2
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 24 deletions.
10 changes: 9 additions & 1 deletion codegen/lib/graphql_java_gen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ def java_arg_expresions_with_empty_optional_args(field)
expressions.join(', ')
end

def java_directive_required_arg_defs(directive)
defs = []
directive.required_args.each do |arg|
defs << "#{java_input_type(arg.type)} #{escape_reserved_word(arg.camelize_name)}"
end
defs.join(', ')
end

def java_implements(type)
return "implements #{type.name} " unless type.object?
interfaces = abstract_types.fetch(type.name)
Expand Down Expand Up @@ -352,7 +360,7 @@ def java_doc(element)
doc << "\n*"
doc << "\n*"
else
doc << '*'
doc << '*'
end
doc << ' @deprecated '
doc << element.deprecation_reason
Expand Down
55 changes: 47 additions & 8 deletions codegen/lib/graphql_java_gen/templates/APISchema.java.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.shopify.graphql.support.AbstractResponse;
import com.shopify.graphql.support.Arguments;
import com.shopify.graphql.support.Directive;
import com.shopify.graphql.support.Error;
import com.shopify.graphql.support.Query;
import com.shopify.graphql.support.SchemaViolationError;
Expand All @@ -18,21 +19,27 @@ import com.shopify.graphql.support.Input;
<% end %>

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;

public class <%= schema_name %> {
public static final String API_VERSION = "<%= version %>";

<% [[:query, schema.query_root_name], [:mutation, schema.mutation_root_name]].each do |operation_type, root_name| %>
<% next unless root_name %>
public static <%= root_name %>Query <%= operation_type %>(<%= root_name %>QueryDefinition queryDef) {
StringBuilder queryString = new StringBuilder("<%= operation_type unless operation_type == :query %>{");
<%= root_name %>Query query = new <%= root_name %>Query(queryString);
queryDef.define(query);
queryString.append('}');
return query;
return <%= operation_type %>(Collections.emptyList(), queryDef);
}

public static <%= root_name %>Query <%= operation_type %>(List<Directive> directives, <%= root_name %>QueryDefinition queryDef) {
StringBuilder queryString = new StringBuilder("<%= operation_type %>");
for (Directive directive : directives) {
queryString.append(" " + directive.toString());
}
queryString.append(" {");
<%= root_name %>Query query = new <%= root_name %>Query(queryString);
queryDef.define(query);
queryString.append('}');
return query;
}

public static class <%= operation_type.capitalize %>Response {
Expand Down Expand Up @@ -68,6 +75,38 @@ public class <%= schema_name %> {
}
<% end %>

<% schema.directives.select { |directive| !(directive.locations & %w{QUERY MUTATION}).empty? }.each do |directive| %>
<%= java_doc(directive) %>
public static class <%= directive.classify_name %>Directive extends Directive {
<% directive.args.each do |arg| %>
public <%= java_input_type(arg.type) %> <%= escape_reserved_word(arg.camelize_name) %>;
<% end %>

public <%= directive.classify_name %>Directive(<%= java_directive_required_arg_defs(directive) %>) {
super("<%= directive.name %>");
}

<% unless directive.args.empty? %>
@Override
public String toString() {
StringBuilder _queryBuilder = new StringBuilder(super.toString());
_queryBuilder.append("(");
<% first_arg = true %>
<% directive.args.each do |arg| %>
if (<%= escape_reserved_word(arg.camelize_name) %> != null) {
<% unless first_arg %>_queryBuilder.append(", ");<% end %>
_queryBuilder.append("<%= arg.name %>:");
<%= generate_build_input_code(escape_reserved_word(arg.camelize_name), arg.type) %>
}
<% first_arg = false %>
<% end %>
_queryBuilder.append(")");
return _queryBuilder.toString();
}
<% end %>
}
<% end %>

<% schema.types.reject{ |type| type.name.start_with?('__') || type.scalar? }.each do |type| %>
<% case type.kind when 'OBJECT', 'INTERFACE', 'UNION' %>
<% fields = type.fields(include_deprecated: include_deprecated) || [] %>
Expand Down
2 changes: 1 addition & 1 deletion graphql_java_gen.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = ">= 2.1.0"

spec.add_dependency "graphql_schema", "~> 0.1.1"
spec.add_dependency "graphql_schema", "~> 0.1.8"

spec.add_development_dependency "bundler", "~> 2.1"
spec.add_development_dependency "rake", "~> 12.0"
Expand Down
14 changes: 14 additions & 0 deletions support/src/main/java/com/shopify/graphql/support/Directive.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.shopify.graphql.support;

public abstract class Directive {
private final String name;

protected Directive(String name) {
this.name = name;
}

@Override
public String toString() {
return "@" + name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shopify.graphql.support;

import org.junit.Test;

import static junit.framework.Assert.assertEquals;

public class DirectiveTest {
@Test
public void testName() {
Generated.SampleDirective directive = new Generated.SampleDirective();
assertEquals("@sample", directive.toString());
}
}
27 changes: 25 additions & 2 deletions support/src/test/java/com/shopify/graphql/support/Generated.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,35 @@

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class Generated {
public static final String API_VERSION = "2020-01";

public static QueryRootQuery query(QueryRootQueryDefinition queryDef) {
StringBuilder queryString = new StringBuilder("{");
return query(Collections.emptyList(), queryDef);
}

public static QueryRootQuery query(List<Directive> directives, QueryRootQueryDefinition queryDef) {
StringBuilder queryString = new StringBuilder("query");
for (Directive directive : directives) {
queryString.append(" " + directive.toString());
}
queryString.append(" {");
QueryRootQuery query = new QueryRootQuery(queryString);
queryDef.define(query);
queryString.append('}');
return query;
}

public static class SampleDirective extends Directive {
SampleDirective() {
super("sample");
}
}

public static class QueryResponse {
private TopLevelResponse response;
private QueryRoot data;
Expand Down Expand Up @@ -69,7 +84,15 @@ public static QueryResponse fromJson(String json) throws SchemaViolationError {
}

public static MutationQuery mutation(MutationQueryDefinition queryDef) {
StringBuilder queryString = new StringBuilder("mutation{");
return mutation(Collections.emptyList(), queryDef);
}

public static MutationQuery mutation(List<Directive> directives, MutationQueryDefinition queryDef) {
StringBuilder queryString = new StringBuilder("mutation");
for (Directive directive : directives) {
queryString.append(" " + directive.toString());
}
queryString.append(" {");
MutationQuery query = new MutationQuery(queryString);
queryDef.define(query);
queryString.append('}');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.shopify.graphql.support;

import junit.framework.Assert;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

Expand All @@ -20,13 +23,13 @@ public void testStringFieldQuery() throws Exception {
@Test
public void testRequiredArgQuery() throws Exception {
String queryString = Generated.query(query -> query.string("user:1:name")).toString();
assertEquals("{string(key:\"user:1:name\")}", queryString);
assertEquals("query {string(key:\"user:1:name\")}", queryString);
}

@Test
public void testOptionalArgQuery() throws Exception {
String queryString = Generated.query(query -> query.keys(10, args -> args.after("cursor"))).toString();
assertEquals("{keys(first:10,after:\"cursor\")}", queryString);
assertEquals("query {keys(first:10,after:\"cursor\")}", queryString);
}

@Test
Expand All @@ -37,7 +40,7 @@ public void testInterfaceQuery() throws Exception {
.onStringEntry(strEntry -> strEntry.value())
)
).toString();
assertEquals("{entry(key:\"user:1\"){__typename,ttl,... on StringEntry{value}}}", queryString);
assertEquals("query {entry(key:\"user:1\"){__typename,ttl,... on StringEntry{value}}}", queryString);
}

@Test
Expand All @@ -47,29 +50,29 @@ public void testUnionQuery() throws Exception {
.onStringEntry(strEntry -> strEntry.value())
)
).toString();
assertEquals("{entry_union(key:\"user:1\"){__typename,... on StringEntry{value}}}", queryString);
assertEquals("query {entry_union(key:\"user:1\"){__typename,... on StringEntry{value}}}", queryString);
}

@Test
public void testEnumInput() throws Exception {
String queryString = Generated.query(query -> query
.keys(10, args -> args.type(Generated.KeyType.INTEGER))
).toString();
assertEquals("{keys(first:10,type:INTEGER)}", queryString);
assertEquals("query {keys(first:10,type:INTEGER)}", queryString);
}

@Test
public void testMutation() throws Exception {
String queryString = Generated.mutation(mutation -> mutation.setString("foo", "bar")).toString();
assertEquals("mutation{set_string(key:\"foo\",value:\"bar\")}", queryString);
assertEquals("mutation {set_string(key:\"foo\",value:\"bar\")}", queryString);
}

@Test
public void testInputObject() throws Exception {
String queryString = Generated.mutation(mutation -> mutation
.setInteger(new Generated.SetIntegerInput("answer", 42).setNegate(true))
).toString();
assertEquals("mutation{set_integer(input:{key:\"answer\",value:42,negate:true})}", queryString);
assertEquals("mutation {set_integer(input:{key:\"answer\",value:42,negate:true})}", queryString);
}

@Test
Expand All @@ -78,7 +81,7 @@ public void testScalarInput() throws Exception {
String queryString = Generated.mutation(mutation -> mutation
.setInteger(new Generated.SetIntegerInput("answer", 42).setTtl(ttl))
).toString();
assertEquals("mutation{set_integer(input:{key:\"answer\",value:42,ttl:\"2017-01-31T10:09:48\"})}", queryString);
assertEquals("mutation {set_integer(input:{key:\"answer\",value:42,ttl:\"2017-01-31T10:09:48\"})}", queryString);
}

@Test
Expand Down Expand Up @@ -163,30 +166,38 @@ public void testOptionalFieldOnInput() throws Exception {
String queryString = Generated.mutation(mutation -> mutation
.setInteger(new Generated.SetIntegerInput("answer", 42).setTtl(null))
).toString();
assertEquals("mutation{set_integer(input:{key:\"answer\",value:42})}", queryString);
assertEquals("mutation {set_integer(input:{key:\"answer\",value:42})}", queryString);
}

@Test
public void testOptionalFieldOnInputAsUndefined() throws Exception {
String queryString = Generated.mutation(mutation -> mutation
.setInteger(new Generated.SetIntegerInput("answer", 42).setTtlInput(Input.<LocalDateTime>undefined()))
).toString();
assertEquals("mutation{set_integer(input:{key:\"answer\",value:42})}", queryString);
assertEquals("mutation {set_integer(input:{key:\"answer\",value:42})}", queryString);
}

@Test
public void testOptionalFieldOnInputAsExplicitNull() throws Exception {
String queryString = Generated.mutation(mutation -> mutation
.setInteger(new Generated.SetIntegerInput("answer", 42).setTtlInput(Input.<LocalDateTime>value(null)))
).toString();
assertEquals("mutation{set_integer(input:{key:\"answer\",value:42,ttl:null})}", queryString);
assertEquals("mutation {set_integer(input:{key:\"answer\",value:42,ttl:null})}", queryString);
}

@Test
public void testOptionalFieldOnInputAsInputValue() throws Exception {
String queryString = Generated.mutation(mutation -> mutation
.setInteger(new Generated.SetIntegerInput("answer", 42).setTtlInput(Input.<LocalDateTime>value(LocalDateTime.of(2017, 1, 31, 10, 9, 48))))
).toString();
assertEquals("mutation{set_integer(input:{key:\"answer\",value:42,ttl:\"2017-01-31T10:09:48\"})}", queryString);
assertEquals("mutation {set_integer(input:{key:\"answer\",value:42,ttl:\"2017-01-31T10:09:48\"})}", queryString);
}

@Test
public void testQueryWithDirectives() {
List<Directive> directives = new ArrayList<>();
directives.add(new Generated.SampleDirective());
Generated.QueryRootQuery query = Generated.query(directives, root -> root.integer("productCount"));
Assert.assertEquals("query @sample {integer(key:\"productCount\")}", query.toString());
}
}

0 comments on commit 295f0e2

Please sign in to comment.