Skip to content

Commit 2d8ec03

Browse files
authored
Relay support for client classes (#1202)
1 parent f8c7f83 commit 2d8ec03

File tree

12 files changed

+585
-3
lines changed

12 files changed

+585
-3
lines changed

src/main/java/com/kobylynskyi/graphql/codegen/kotlin/KotlinGraphQLTypeMapper.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.kobylynskyi.graphql.codegen.mapper.GraphQLTypeMapper;
55
import com.kobylynskyi.graphql.codegen.model.MappingContext;
66
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
7+
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedFieldDefinition;
78
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
89
import com.kobylynskyi.graphql.codegen.utils.Utils;
910

@@ -150,8 +151,8 @@ public String getTypeConsideringPrimitive(MappingContext mappingContext,
150151
}
151152

152153
@Override
153-
public String getResponseReturnType(MappingContext mappingContext, NamedDefinition namedDefinition,
154-
String computedTypeName) {
154+
public String getResponseReturnType(MappingContext mappingContext, ExtendedFieldDefinition operationDef,
155+
NamedDefinition namedDefinition, String computedTypeName) {
155156
// Delegate to getTypeConsideringPrimitive.
156157
// For kotlin such as XXXXXXResponse do not implement the mandatory function of graphql
157158
// correctly when returnType is not List.

src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
import com.kobylynskyi.graphql.codegen.model.MappingContext;
44
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
5+
import com.kobylynskyi.graphql.codegen.model.RelayConfig;
6+
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedFieldDefinition;
7+
import graphql.language.Argument;
58
import graphql.language.Directive;
69
import graphql.language.DirectivesContainer;
710
import graphql.language.ListType;
811
import graphql.language.NamedNode;
912
import graphql.language.NonNullType;
13+
import graphql.language.StringValue;
1014
import graphql.language.Type;
1115
import graphql.language.TypeName;
1216

@@ -243,8 +247,25 @@ public String getTypeConsideringPrimitive(MappingContext mappingContext,
243247
}
244248

245249
public String getResponseReturnType(MappingContext mappingContext,
250+
ExtendedFieldDefinition operationDef,
246251
NamedDefinition namedDefinition,
247252
String computedTypeName) {
253+
RelayConfig relayConfig = mappingContext.getRelayConfig();
254+
if (relayConfig != null && relayConfig.getDirectiveName() != null) {
255+
List<Directive> connectionDirective = operationDef.getDirectives(relayConfig.getDirectiveName());
256+
if (!connectionDirective.isEmpty()) {
257+
Argument argument = connectionDirective.get(0).getArgument(relayConfig.getDirectiveArgumentName());
258+
// as of now supporting only string value of directive argument
259+
if (argument != null && argument.getValue() instanceof StringValue) {
260+
String graphqlTypeName = ((StringValue) argument.getValue()).getValue();
261+
String javaTypeName = getLanguageType(mappingContext,
262+
new TypeName(graphqlTypeName),
263+
graphqlTypeName, null, false, false).getJavaName();
264+
return getGenericsString(mappingContext, relayConfig.getConnectionType(), javaTypeName);
265+
}
266+
}
267+
}
268+
248269
return computedTypeName;
249270
}
250271

src/main/java/com/kobylynskyi/graphql/codegen/mapper/RequestResponseDefinitionToDataModelMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public Map<String, Object> mapResponse(MappingContext mappingContext,
177177
NamedDefinition namedDefinition = graphQLTypeMapper.getLanguageType(
178178
mappingContext, operationDef.getType(), operationDef.getName(), objectTypeName);
179179
String returnType = graphQLTypeMapper
180-
.getResponseReturnType(mappingContext, namedDefinition, namedDefinition.getJavaName());
180+
.getResponseReturnType(mappingContext, operationDef, namedDefinition, namedDefinition.getJavaName());
181181
Map<String, Object> dataModel = new HashMap<>();
182182
// Response classes are sharing the package with the model classes, so no imports are needed
183183
dataModel.put(PACKAGE, DataModelMapper.getModelPackageName(mappingContext));

src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenRelayTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,26 @@ void generateServerSideRelayClasses_CustomGenericsConnectionType() throws Except
7171

7272
}
7373

74+
@Test
75+
void generateClientSideRelayClasses() throws Exception {
76+
mappingConfig.setGenerateClient(true);
77+
mappingConfig.setGenerateApis(false);
78+
79+
generate();
80+
81+
File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
82+
Set<String> generatedFileNames = Arrays.stream(files).map(File::getName).collect(toSet());
83+
assertEquals(new HashSet<>(asList("Organization.java", "UserResponseProjection.java", "User.java",
84+
"UsersQueryResponse.java", "OrganizationResponseProjection.java", "OrganizationsQueryResponse.java",
85+
"UsersQueryRequest.java", "OrganizationsQueryRequest.java")), generatedFileNames);
86+
87+
for (File file : files) {
88+
assertSameTrimmedContent(
89+
new File(String.format("src/test/resources/expected-classes/relay/client/%s.txt", file.getName())),
90+
file);
91+
}
92+
}
93+
7494
private void generate() throws IOException {
7595
new JavaGraphQLCodegen(schemaFinder.findSchemas(), outputBuildDir, mappingConfig,
7696
TestUtils.getStaticGeneratedInfo(mappingConfig)).generate();
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLRequestSerializer;
2+
import java.util.StringJoiner;
3+
4+
@javax.annotation.Generated(
5+
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
6+
date = "2020-12-31T23:59:59-0500"
7+
)
8+
public class Organization implements java.io.Serializable {
9+
10+
private static final long serialVersionUID = 1L;
11+
12+
@javax.validation.constraints.NotNull
13+
private String id;
14+
15+
public Organization() {
16+
}
17+
18+
public Organization(String id) {
19+
this.id = id;
20+
}
21+
22+
public String getId() {
23+
return id;
24+
}
25+
public void setId(String id) {
26+
this.id = id;
27+
}
28+
29+
30+
@Override
31+
public String toString() {
32+
StringJoiner joiner = new StringJoiner(", ", "{ ", " }");
33+
if (id != null) {
34+
joiner.add("id: " + GraphQLRequestSerializer.getEntry(id));
35+
}
36+
return joiner.toString();
37+
}
38+
39+
public static Organization.Builder builder() {
40+
return new Organization.Builder();
41+
}
42+
43+
@javax.annotation.Generated(
44+
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
45+
date = "2020-12-31T23:59:59-0500"
46+
)
47+
public static class Builder {
48+
49+
private String id;
50+
51+
public Builder() {
52+
}
53+
54+
public Builder setId(String id) {
55+
this.id = id;
56+
return this;
57+
}
58+
59+
60+
public Organization build() {
61+
return new Organization(id);
62+
}
63+
64+
}
65+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLResponseField;
2+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLResponseProjection;
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.List;
6+
7+
/**
8+
* Response projection for Organization
9+
*/
10+
@javax.annotation.Generated(
11+
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
12+
date = "2020-12-31T23:59:59-0500"
13+
)
14+
public class OrganizationResponseProjection extends GraphQLResponseProjection {
15+
16+
private final Map<String, Integer> projectionDepthOnFields = new HashMap<>();
17+
18+
public OrganizationResponseProjection() {
19+
}
20+
21+
public OrganizationResponseProjection(OrganizationResponseProjection projection) {
22+
super(projection);
23+
}
24+
25+
public OrganizationResponseProjection(List<OrganizationResponseProjection> projections) {
26+
super(projections);
27+
}
28+
29+
public OrganizationResponseProjection all$() {
30+
return all$(3);
31+
}
32+
33+
public OrganizationResponseProjection all$(int maxDepth) {
34+
this.id();
35+
this.typename();
36+
return this;
37+
}
38+
39+
public OrganizationResponseProjection id() {
40+
return id(null);
41+
}
42+
43+
public OrganizationResponseProjection id(String alias) {
44+
add$(new GraphQLResponseField("id").alias(alias));
45+
return this;
46+
}
47+
48+
public OrganizationResponseProjection typename() {
49+
return typename(null);
50+
}
51+
52+
public OrganizationResponseProjection typename(String alias) {
53+
add$(new GraphQLResponseField("__typename").alias(alias));
54+
return this;
55+
}
56+
57+
@Override
58+
public OrganizationResponseProjection deepCopy$() {
59+
return new OrganizationResponseProjection(this);
60+
}
61+
62+
63+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
2+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperationRequest;
3+
import java.util.HashSet;
4+
import java.util.LinkedHashMap;
5+
import java.util.Map;
6+
import java.util.Objects;
7+
import java.util.Set;
8+
9+
@javax.annotation.Generated(
10+
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
11+
date = "2020-12-31T23:59:59-0500"
12+
)
13+
public class OrganizationsQueryRequest implements GraphQLOperationRequest {
14+
15+
public static final String OPERATION_NAME = "organizations";
16+
public static final GraphQLOperation OPERATION_TYPE = GraphQLOperation.QUERY;
17+
18+
private String alias;
19+
private final Map<String, Object> input = new LinkedHashMap<>();
20+
private final Set<String> useObjectMapperForInputSerialization = new HashSet<>();
21+
22+
public OrganizationsQueryRequest() {
23+
}
24+
25+
public OrganizationsQueryRequest(String alias) {
26+
this.alias = alias;
27+
}
28+
29+
public void setFirst(Integer first) {
30+
this.input.put("first", first);
31+
}
32+
33+
public void setAfter(String after) {
34+
this.input.put("after", after);
35+
}
36+
37+
@Override
38+
public GraphQLOperation getOperationType() {
39+
return OPERATION_TYPE;
40+
}
41+
42+
@Override
43+
public String getOperationName() {
44+
return OPERATION_NAME;
45+
}
46+
47+
@Override
48+
public String getAlias() {
49+
return alias != null ? alias : OPERATION_NAME;
50+
}
51+
52+
@Override
53+
public Map<String, Object> getInput() {
54+
return input;
55+
}
56+
57+
@Override
58+
public Set<String> getUseObjectMapperForInputSerialization() {
59+
return useObjectMapperForInputSerialization;
60+
}
61+
62+
@Override
63+
public String toString() {
64+
return Objects.toString(input);
65+
}
66+
67+
public static OrganizationsQueryRequest.Builder builder() {
68+
return new OrganizationsQueryRequest.Builder();
69+
}
70+
71+
@javax.annotation.Generated(
72+
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
73+
date = "2020-12-31T23:59:59-0500"
74+
)
75+
public static class Builder {
76+
77+
private String $alias;
78+
private Integer first;
79+
private String after;
80+
81+
public Builder() {
82+
}
83+
84+
public Builder alias(String alias) {
85+
this.$alias = alias;
86+
return this;
87+
}
88+
89+
public Builder setFirst(Integer first) {
90+
this.first = first;
91+
return this;
92+
}
93+
94+
public Builder setAfter(String after) {
95+
this.after = after;
96+
return this;
97+
}
98+
99+
100+
public OrganizationsQueryRequest build() {
101+
OrganizationsQueryRequest obj = new OrganizationsQueryRequest($alias);
102+
obj.setFirst(first);
103+
obj.setAfter(after);
104+
return obj;
105+
}
106+
107+
}
108+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLResult;
2+
import java.util.Map;
3+
4+
@javax.annotation.Generated(
5+
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
6+
date = "2020-12-31T23:59:59-0500"
7+
)
8+
public class OrganizationsQueryResponse extends GraphQLResult<Map<String, graphql.relay.Connection<Organization>>> {
9+
10+
private static final String OPERATION_NAME = "organizations";
11+
12+
public OrganizationsQueryResponse() {
13+
}
14+
15+
public graphql.relay.Connection<Organization> organizations() {
16+
Map<String, graphql.relay.Connection<Organization>> data = getData();
17+
return data != null ? data.get(OPERATION_NAME) : null;
18+
}
19+
20+
}

0 commit comments

Comments
 (0)