Skip to content

Commit bba3088

Browse files
authored
Support DataFetchResult via new config: fieldsWithDataFetcherResult (#1431)
1 parent 3ac1021 commit bba3088

File tree

11 files changed

+358
-87
lines changed

11 files changed

+358
-87
lines changed

docs/codegen-options.md

+81-78
Large diffs are not rendered by default.

plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java

+14
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
103103
private Set<String> typesAsInterfaces = new HashSet<>();
104104
private Set<String> resolverArgumentAnnotations = new HashSet<>();
105105
private Set<String> parametrizedResolverAnnotations = new HashSet<>();
106+
private Set<String> fieldsWithDataFetcherResult = new HashSet<>();
106107
private final RelayConfig relayConfig = new RelayConfig();
107108

108109

@@ -193,6 +194,8 @@ public void generate() throws Exception {
193194
fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>());
194195
mappingConfig.setFieldsToExcludeFromGeneration(
195196
fieldsToExcludeFromGeneration != null ? fieldsToExcludeFromGeneration : new HashSet<>());
197+
mappingConfig.setFieldsWithDataFetcherResult(
198+
fieldsWithDataFetcherResult != null ? fieldsWithDataFetcherResult : new HashSet<>());
196199
mappingConfig.setTypesAsInterfaces(
197200
typesAsInterfaces != null ? typesAsInterfaces : new HashSet<>());
198201
mappingConfig.setResolverArgumentAnnotations(
@@ -815,6 +818,17 @@ public void setFieldsToExcludeFromGeneration(Set<String> fieldsToExcludeFromGene
815818
this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration;
816819
}
817820

821+
@Input
822+
@Optional
823+
@Override
824+
public Set<String> getFieldsWithDataFetcherResult() {
825+
return fieldsWithDataFetcherResult;
826+
}
827+
828+
public void setFieldsWithDataFetcherResult(Set<String> fieldsWithDataFetcherResult) {
829+
this.fieldsWithDataFetcherResult = fieldsWithDataFetcherResult;
830+
}
831+
818832
@Input
819833
@Optional
820834
@Override

plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java

+9
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
186186
@Parameter
187187
private String[] fieldsToExcludeFromGeneration;
188188

189+
@Parameter
190+
private String[] fieldsWithDataFetcherResult;
191+
189192
@Parameter
190193
private RelayConfig relayConfig = new RelayConfig();
191194

@@ -305,6 +308,7 @@ public void execute() throws MojoExecutionException {
305308
mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers));
306309
mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers));
307310
mappingConfig.setFieldsToExcludeFromGeneration(mapToHashSet(fieldsToExcludeFromGeneration));
311+
mappingConfig.setFieldsWithDataFetcherResult(mapToHashSet(fieldsWithDataFetcherResult));
308312
mappingConfig.setRelayConfig(relayConfig);
309313

310314
mappingConfig.setGenerateClient(generateClient);
@@ -627,6 +631,11 @@ public Set<String> getFieldsToExcludeFromGeneration() {
627631
return mapToHashSet(fieldsToExcludeFromGeneration);
628632
}
629633

634+
@Override
635+
public Set<String> getFieldsWithDataFetcherResult() {
636+
return mapToHashSet(fieldsWithDataFetcherResult);
637+
}
638+
630639
@Override
631640
public Boolean getGenerateAllMethodInProjection() {
632641
return generateAllMethodInProjection;

src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java

+31-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
88
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
99
import com.kobylynskyi.graphql.codegen.utils.Utils;
10+
import graphql.language.Directive;
1011
import graphql.language.InputValueDefinition;
1112
import graphql.language.NullValue;
1213

1314
import java.util.HashSet;
15+
import java.util.List;
1416
import java.util.Map;
1517
import java.util.Set;
1618
import java.util.regex.Matcher;
1719
import java.util.regex.Pattern;
20+
import java.util.stream.Collectors;
1821

1922
import static java.util.Arrays.asList;
2023

@@ -108,7 +111,8 @@ public boolean isPrimitive(String possiblyPrimitiveType) {
108111

109112
@Override
110113
public NamedDefinition getLanguageType(MappingContext mappingContext, String graphQLType, String name,
111-
String parentTypeName, boolean mandatory, boolean collection) {
114+
String parentTypeName, boolean mandatory, boolean collection,
115+
List<Directive> directives) {
112116
Map<String, String> customTypesMapping = mappingContext.getCustomTypesMapping();
113117
Set<String> serializeFieldsUsingObjectMapper = mappingContext.getUseObjectMapperForRequestSerialization();
114118
String langTypeName;
@@ -122,6 +126,9 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, String gra
122126
} else {
123127
langTypeName = DataModelMapper.getModelClassNameWithPrefixAndSuffix(mappingContext, graphQLType);
124128
}
129+
130+
langTypeName = wrapWithDataFetcherResultIfRequired(mappingContext, directives, langTypeName, name);
131+
125132
if (serializeFieldsUsingObjectMapper.contains(graphQLType) ||
126133
(name != null && parentTypeName != null &&
127134
serializeFieldsUsingObjectMapper.contains(parentTypeName + "." + name))) {
@@ -164,4 +171,26 @@ public String wrapApiDefaultValueIfRequired(MappingContext mappingContext, Named
164171
}
165172
}
166173

167-
}
174+
private String wrapWithDataFetcherResultIfRequired(MappingContext mappingContext,
175+
List<Directive> directives,
176+
String langTypeName,
177+
String name) {
178+
Set<String> fieldsWithDataFetcherResult = mappingContext.getFieldsWithDataFetcherResult();
179+
Set<String> directivesNames = directives.stream()
180+
.map(directive -> "@" + directive.getName())
181+
.collect(Collectors.toSet());
182+
183+
// Create the representation of 'name'
184+
String nameRepresentation = langTypeName + "." + name;
185+
186+
boolean shouldWrap = directivesNames.stream().anyMatch(fieldsWithDataFetcherResult::contains)
187+
|| fieldsWithDataFetcherResult.contains(langTypeName)
188+
|| fieldsWithDataFetcherResult.contains(nameRepresentation);
189+
190+
if (shouldWrap) {
191+
langTypeName = "graphql.execution.DataFetcherResult<" + langTypeName + ">";
192+
}
193+
194+
return langTypeName;
195+
}
196+
}

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ private ParameterDefinition mapField(MappingContext mappingContext,
146146
ExtendedFieldDefinition fieldDef,
147147
ExtendedDefinition<?, ?> parentDefinition) {
148148
NamedDefinition namedDefinition = graphQLTypeMapper
149-
.getLanguageType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentDefinition.getName());
149+
.getLanguageType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentDefinition.getName(),
150+
fieldDef.getDirectives()
151+
);
150152

151153
ParameterDefinition parameter = new ParameterDefinition();
152154
parameter.setName(dataModelMapper.capitalizeIfRestricted(mappingContext, fieldDef.getName()));

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

+44-6
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,23 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type<?> gr
217217
return getLanguageType(mappingContext, graphqlType, name, parentTypeName, false, false);
218218
}
219219

220+
/**
221+
* Convert GraphQL type to a corresponding language-specific type (java/scala/kotlin/etc)
222+
*
223+
* @param mappingContext Global mapping context
224+
* @param graphqlType GraphQL type
225+
* @param name GraphQL type name
226+
* @param parentTypeName Name of the parent type
227+
* @param directives GraphQL field directives
228+
* @return Corresponding language-specific type (java/scala/kotlin/etc)
229+
*/
230+
public NamedDefinition getLanguageType(MappingContext mappingContext, Type<?> graphqlType, String name,
231+
String parentTypeName, List<Directive> directives) {
232+
return getLanguageType(mappingContext, graphqlType, name, parentTypeName, false, false,
233+
directives
234+
);
235+
}
236+
220237
/**
221238
* Convert GraphQL type to a corresponding language-specific type (java/scala/kotlin/etc)
222239
*
@@ -231,12 +248,32 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type<?> gr
231248
public NamedDefinition getLanguageType(MappingContext mappingContext, Type<?> graphqlType,
232249
String name, String parentTypeName,
233250
boolean mandatory, boolean collection) {
251+
return getLanguageType(mappingContext, graphqlType, name, parentTypeName, mandatory, collection,
252+
Collections.emptyList()
253+
);
254+
}
255+
256+
/**
257+
* Convert GraphQL type to a corresponding language-specific type (java/scala/kotlin/etc)
258+
*
259+
* @param mappingContext Global mapping context
260+
* @param graphqlType GraphQL type
261+
* @param name GraphQL type name
262+
* @param parentTypeName Name of the parent type
263+
* @param mandatory GraphQL type is non-null
264+
* @param collection GraphQL type is collection
265+
* @param directives GraphQL field directives
266+
* @return Corresponding language-specific type (java/scala/kotlin/etc)
267+
*/
268+
public NamedDefinition getLanguageType(MappingContext mappingContext, Type<?> graphqlType,
269+
String name, String parentTypeName,
270+
boolean mandatory, boolean collection, List<Directive> directives) {
234271
if (graphqlType instanceof TypeName) {
235272
return getLanguageType(mappingContext, ((TypeName) graphqlType).getName(), name, parentTypeName, mandatory,
236-
collection);
273+
collection, directives);
237274
} else if (graphqlType instanceof ListType) {
238275
NamedDefinition mappedCollectionType = getLanguageType(mappingContext, ((ListType) graphqlType).getType(),
239-
name, parentTypeName, false, true);
276+
name, parentTypeName, false, true, directives);
240277
if (mappedCollectionType.isInterfaceOrUnion() &&
241278
isInterfaceOrUnion(mappingContext, parentTypeName)) {
242279
mappedCollectionType.setJavaName(
@@ -247,8 +284,8 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type<?> gr
247284
}
248285
return mappedCollectionType;
249286
} else if (graphqlType instanceof NonNullType) {
250-
return getLanguageType(mappingContext, ((NonNullType) graphqlType).getType(), name, parentTypeName, true,
251-
collection);
287+
return getLanguageType(mappingContext, ((NonNullType) graphqlType).getType(), name, parentTypeName,
288+
true, collection, directives);
252289
}
253290
throw new IllegalArgumentException("Unknown type: " + graphqlType);
254291
}
@@ -262,10 +299,12 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type<?> gr
262299
* @param parentTypeName Name of the parent type
263300
* @param mandatory GraphQL type is non-null
264301
* @param collection GraphQL type is collection
302+
* @param directives GraphQL field directives
265303
* @return Corresponding language-specific type (java/scala/kotlin/etc)
266304
*/
267305
public NamedDefinition getLanguageType(MappingContext mappingContext, String graphQLType, String name,
268-
String parentTypeName, boolean mandatory, boolean collection) {
306+
String parentTypeName, boolean mandatory, boolean collection,
307+
List<Directive> directives) {
269308
Map<String, String> customTypesMapping = mappingContext.getCustomTypesMapping();
270309
Set<String> serializeFieldsUsingObjectMapper = mappingContext.getUseObjectMapperForRequestSerialization();
271310
String langTypeName;
@@ -329,5 +368,4 @@ protected boolean isInterfaceOrUnion(MappingContext mappingContext, String graph
329368
return mappingContext.getInterfacesName().contains(graphQLType) ||
330369
mappingContext.getUnionsNames().contains(graphQLType);
331370
}
332-
333371
}

src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java

+15
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,21 @@ public interface GraphQLCodegenConfiguration {
349349
*/
350350
Set<String> getFieldsToExcludeFromGeneration();
351351

352+
/**
353+
* Fields that require DataFetcherResult.
354+
*
355+
* <p>Values should be defined here in format: TypeName, TypeName.fieldName, @directive
356+
*
357+
*
358+
* <p>E.g.:
359+
* <ul>
360+
* <li>{@code @dataFetcherResult}</li>
361+
* </ul>
362+
*
363+
* @return Set of types and fields that should have DataFetcherResult.
364+
*/
365+
Set<String> getFieldsWithDataFetcherResult();
366+
352367
/**
353368
* Specifies whether return types of generated API interface should be wrapped into <code>java.util.Optional</code>
354369
*

src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java

+11
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable<Ma
6565
private Set<String> fieldsWithResolvers = new HashSet<>();
6666
private Set<String> fieldsWithoutResolvers = new HashSet<>();
6767
private Set<String> fieldsToExcludeFromGeneration = new HashSet<>();
68+
private Set<String> fieldsWithDataFetcherResult = new HashSet<>();
6869

6970
// parent interfaces configs:
7071
private String queryResolverParentInterface;
@@ -195,6 +196,7 @@ public void combine(MappingConfig source) {
195196
parametrizedInputSuffix = getValueOrDefaultToThis(source,
196197
GraphQLCodegenConfiguration::getParametrizedInputSuffix);
197198
fieldsWithResolvers = combineSet(fieldsWithResolvers, source.fieldsWithResolvers);
199+
fieldsWithDataFetcherResult = combineSet(fieldsWithDataFetcherResult, source.fieldsWithDataFetcherResult);
198200
fieldsWithoutResolvers = combineSet(fieldsWithoutResolvers, source.fieldsWithoutResolvers);
199201
fieldsToExcludeFromGeneration = combineSet(fieldsToExcludeFromGeneration, source.fieldsToExcludeFromGeneration);
200202
customTypesMapping = combineMap(customTypesMapping, source.customTypesMapping);
@@ -622,6 +624,15 @@ public void setFieldsToExcludeFromGeneration(Set<String> fieldsToExcludeFromGene
622624
this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration;
623625
}
624626

627+
@Override
628+
public Set<String> getFieldsWithDataFetcherResult() {
629+
return fieldsWithDataFetcherResult;
630+
}
631+
632+
public void setFieldsWithDataFetcherResult(Set<String> fieldsWithDataFetcherResult) {
633+
this.fieldsWithDataFetcherResult = fieldsWithDataFetcherResult;
634+
}
635+
625636
@Override
626637
public String getQueryResolverParentInterface() {
627638
return queryResolverParentInterface;

src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java

+5
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ public Set<String> getFieldsToExcludeFromGeneration() {
279279
return config.getFieldsToExcludeFromGeneration();
280280
}
281281

282+
@Override
283+
public Set<String> getFieldsWithDataFetcherResult() {
284+
return config.getFieldsWithDataFetcherResult();
285+
}
286+
282287
@Override
283288
public Boolean getGenerateClient() {
284289
return config.getGenerateClient();

0 commit comments

Comments
 (0)