Skip to content

#1297 Allow to exclude fields from generated GraphQL objects #1299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/codegen-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* |
| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. |
| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. |
| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. |
| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` |
| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` |
| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
private String generatedAnnotation;
private Set<String> fieldsWithResolvers = new HashSet<>();
private Set<String> fieldsWithoutResolvers = new HashSet<>();
private Set<String> fieldsToExcludeFromGeneration = new HashSet<>();
private Set<String> typesAsInterfaces = new HashSet<>();
private Set<String> resolverArgumentAnnotations = new HashSet<>();
private Set<String> parametrizedResolverAnnotations = new HashSet<>();
Expand Down Expand Up @@ -182,6 +183,8 @@ public void generate() throws Exception {
fieldsWithResolvers != null ? fieldsWithResolvers : new HashSet<>());
mappingConfig.setFieldsWithoutResolvers(
fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>());
mappingConfig.setFieldsToExcludeFromGeneration(
fieldsToExcludeFromGeneration != null ? fieldsToExcludeFromGeneration : new HashSet<>());
mappingConfig.setTypesAsInterfaces(
typesAsInterfaces != null ? typesAsInterfaces : new HashSet<>());
mappingConfig.setResolverArgumentAnnotations(
Expand Down Expand Up @@ -762,6 +765,17 @@ public void setFieldsWithoutResolvers(Set<String> fieldsWithoutResolvers) {
this.fieldsWithoutResolvers = fieldsWithoutResolvers;
}

@Input
@Optional
@Override
public Set<String> getFieldsToExcludeFromGeneration() {
return fieldsToExcludeFromGeneration;
}

public void setFieldsToExcludeFromGeneration(Set<String> fieldsToExcludeFromGeneration) {
this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration;
}

@Input
@Optional
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter
private String[] fieldsWithoutResolvers;

@Parameter
private String[] fieldsToExcludeFromGeneration;

@Parameter
private RelayConfig relayConfig = new RelayConfig();

Expand Down Expand Up @@ -289,6 +292,7 @@ public void execute() throws MojoExecutionException {
mappingConfig.setGenerateModelsWithPublicFields(generateModelsWithPublicFields);
mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers));
mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers));
mappingConfig.setFieldsToExcludeFromGeneration(mapToHashSet(fieldsToExcludeFromGeneration));
mappingConfig.setRelayConfig(relayConfig);

mappingConfig.setGenerateClient(generateClient);
Expand Down Expand Up @@ -586,6 +590,11 @@ public Set<String> getFieldsWithoutResolvers() {
return mapToHashSet(fieldsWithoutResolvers);
}

@Override
public Set<String> getFieldsToExcludeFromGeneration() {
return mapToHashSet(fieldsToExcludeFromGeneration);
}

@Override
public Boolean getGenerateAllMethodInProjection() {
return generateAllMethodInProjection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ trait GraphQLCodegenKeys {

val fieldsWithoutResolvers = settingKey[util.Set[String]]("fieldsWithoutResolvers")

val fieldsToExcludeFromGeneration = settingKey[util.Set[String]]("fieldsToExcludeFromGeneration")

val typesAsInterfaces = settingKey[util.Set[String]]("typesAsInterfaces")

val generateClient = settingKey[Boolean]("generateClient")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
apiPackageName := None,
modelPackageName := None,
// field resolvers configs:
fieldsWithResolvers := new JHashSet[String](),
fieldsWithoutResolvers := new JHashSet[String](),
fieldsWithResolvers := new JHashSet[String](),
fieldsWithoutResolvers := new JHashSet[String](),
fieldsToExcludeFromGeneration := new JHashSet[String](),
// various toggles:
generateClient := MappingConfigConstants.DEFAULT_GENERATE_CLIENT,
generateParameterizedFieldsResolvers := MappingConfigConstants.DEFAULT_GENERATE_PARAMETERIZED_FIELDS_RESOLVERS,
Expand Down Expand Up @@ -167,6 +168,7 @@ class GraphQLCodegenPlugin(configuration: Configuration, private[codegen] val co
mappingConfig.setGenerateModelsForRootTypes((GraphQLCodegenConfig / generateModelsForRootTypes).value)
mappingConfig.setFieldsWithResolvers((GraphQLCodegenConfig / fieldsWithResolvers).value)
mappingConfig.setFieldsWithoutResolvers((GraphQLCodegenConfig / fieldsWithoutResolvers).value)
mappingConfig.setFieldsToExcludeFromGeneration((GraphQLCodegenConfig / fieldsToExcludeFromGeneration).value)
mappingConfig.setTypesAsInterfaces((GraphQLCodegenConfig / typesAsInterfaces).value)
mappingConfig.setGenerateClient((GraphQLCodegenConfig / generateClient).value)
mappingConfig.setRequestSuffix((GraphQLCodegenConfig / requestSuffix).value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.util.Collections;
import java.util.List;
import java.util.Set;

import static java.util.stream.Collectors.toList;

Expand All @@ -34,6 +35,22 @@ public FieldDefinitionToParameterMapper(MapperFactory mapperFactory,
this.inputValueDefinitionToParameterMapper = inputValueDefToParamMapper;
}

/**
* Check whether the given field should be generated.
*
* @param mappingContext Global mapping context
* @param fieldDef GraphQL field definition
* @param parentDefinition Parent GraphQL definition
* @return <code>true</code> if field will be generated (included) in the object. <code>false</code> otherwise
*/
public static boolean generateField(MappingContext mappingContext,
ExtendedFieldDefinition fieldDef,
ExtendedDefinition<?, ?> parentDefinition) {
String fieldDefName = parentDefinition.getName() + "." + fieldDef.getName();
Set<String> fieldsToExcludeFromGeneration = mappingContext.getFieldsToExcludeFromGeneration();
return !fieldsToExcludeFromGeneration.contains(fieldDefName);
}

/**
* Check whether FieldResolver should be generated for a given field.
*
Expand Down Expand Up @@ -95,6 +112,7 @@ public List<ParameterDefinition> mapFields(MappingContext mappingContext,
List<ExtendedFieldDefinition> fieldDefinitions,
ExtendedDefinition<?, ?> parentDefinition) {
return fieldDefinitions.stream()
.filter(fieldDef -> generateField(mappingContext, fieldDef, parentDefinition))
.filter(fieldDef -> !generateResolversForField(mappingContext, fieldDef, parentDefinition))
.map(fieldDef -> mapField(mappingContext, fieldDef, parentDefinition))
.collect(toList());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.kobylynskyi.graphql.codegen.model;

import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;

import java.io.File;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -330,6 +328,20 @@ public interface GraphQLCodegenConfiguration {
*/
Set<String> getFieldsWithoutResolvers();

/**
* Fields that WILL NOT be generated.
*
* <p>Values should be defined here in format: TypeName.fieldName
*
* <p>E.g.:
* <ul>
* <li>{@code Person.friends}</li>
* </ul>
*
* @return Set of types and fields that should NOT be generated.
*/
Set<String> getFieldsToExcludeFromGeneration();

/**
* Specifies whether return types of generated API interface should be wrapped into <code>java.util.Optional</code>
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.kobylynskyi.graphql.codegen.model;

import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -64,6 +62,7 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable<Ma
// field resolvers configs:
private Set<String> fieldsWithResolvers = new HashSet<>();
private Set<String> fieldsWithoutResolvers = new HashSet<>();
private Set<String> fieldsToExcludeFromGeneration = new HashSet<>();

// parent interfaces configs:
private String queryResolverParentInterface;
Expand Down Expand Up @@ -191,6 +190,7 @@ public void combine(MappingConfig source) {
GraphQLCodegenConfiguration::getParametrizedInputSuffix);
fieldsWithResolvers = combineSet(fieldsWithResolvers, source.fieldsWithResolvers);
fieldsWithoutResolvers = combineSet(fieldsWithoutResolvers, source.fieldsWithoutResolvers);
fieldsToExcludeFromGeneration = combineSet(fieldsToExcludeFromGeneration, source.fieldsToExcludeFromGeneration);
customTypesMapping = combineMap(customTypesMapping, source.customTypesMapping);
customTemplates = combineMap(customTemplates, source.customTemplates);
customAnnotationsMapping = combineMap(customAnnotationsMapping, source.customAnnotationsMapping);
Expand Down Expand Up @@ -589,6 +589,15 @@ public void setFieldsWithoutResolvers(Set<String> fieldsWithoutResolvers) {
this.fieldsWithoutResolvers = fieldsWithoutResolvers;
}

@Override
public Set<String> getFieldsToExcludeFromGeneration() {
return fieldsToExcludeFromGeneration;
}

public void setFieldsToExcludeFromGeneration(Set<String> fieldsToExcludeFromGeneration) {
this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration;
}

@Override
public String getQueryResolverParentInterface() {
return queryResolverParentInterface;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.kobylynskyi.graphql.codegen.model;

import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapperFactory;
import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
Expand Down Expand Up @@ -265,6 +264,11 @@ public Set<String> getFieldsWithoutResolvers() {
return config.getFieldsWithoutResolvers();
}

@Override
public Set<String> getFieldsToExcludeFromGeneration() {
return config.getFieldsToExcludeFromGeneration();
}

@Override
public Boolean getGenerateClient() {
return config.getGenerateClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.junit.jupiter.api.extension.ExtendWith;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -18,6 +19,7 @@
import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.junit.jupiter.api.Assertions.assertThrows;

@ExtendWith(MaxQueryTokensExtension.class)
class GraphQLCodegenFieldsResolversTest {
Expand Down Expand Up @@ -140,6 +142,24 @@ void generate_FieldResolversViaDirective() throws Exception {
getFileByName(files, "EventProperty.java"));
}

@Test
void generate_WithFieldsToExcludeFromGeneration() throws Exception {
mappingConfig.setModelNamePrefix("Github");
mappingConfig.setModelNameSuffix("TO");
mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(true);
mappingConfig.setFieldsToExcludeFromGeneration(Collections.singleton("AcceptTopicSuggestionPayload.topic"));

generate("src/test/resources/schemas/github.graphqls");

File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());

assertSameTrimmedContent(new File("src/test/resources/expected-classes/" +
"GithubAcceptTopicSuggestionPayloadTO.java.txt"),
getFileByName(files, "GithubAcceptTopicSuggestionPayloadTO.java"));
assertThrows(FileNotFoundException.class,
() -> getFileByName(files, "AcceptTopicSuggestionPayloadResolver.java"));
}

private void generate(String o) throws IOException {
new JavaGraphQLCodegen(singletonList(o),
outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo(mappingConfig)).generate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ private static MappingConfig buildMappingConfig() {
config.setApiRootInterfaceStrategy(ApiRootInterfaceStrategy.SINGLE_INTERFACE);
config.setFieldsWithResolvers(new HashSet<>(singletonList("5")));
config.setFieldsWithoutResolvers(new HashSet<>(singleton("8")));
config.setFieldsToExcludeFromGeneration(new HashSet<>(singleton("3")));
config.setRequestSuffix("6");
config.setResponseSuffix("10");
config.setResponseProjectionSuffix("7");
Expand Down Expand Up @@ -98,6 +99,7 @@ private static MappingConfig buildMappingConfig2() {
config.setApiRootInterfaceStrategy(ApiRootInterfaceStrategy.DO_NOT_GENERATE);
config.setFieldsWithResolvers(singleton("55"));
config.setFieldsWithoutResolvers(singleton("88"));
config.setFieldsToExcludeFromGeneration(singleton("33"));
config.setRequestSuffix("66");
config.setResponseSuffix("1010");
config.setResponseProjectionSuffix("77");
Expand Down Expand Up @@ -125,6 +127,7 @@ private static MappingConfig buildEmptyMappingConfig() {
mappingConfig.setDirectiveAnnotationsMapping(null);
mappingConfig.setFieldsWithResolvers(null);
mappingConfig.setFieldsWithoutResolvers(null);
mappingConfig.setFieldsToExcludeFromGeneration(null);
mappingConfig.setRelayConfig(null);
return mappingConfig;
}
Expand Down Expand Up @@ -156,6 +159,8 @@ private static void compareMappingConfigs(MappingConfig mappingConfig, MappingCo
mappingConfig.getGenerateExtensionFieldsResolvers());
assertEquals(expectedMappingConfig.getFieldsWithResolvers(), mappingConfig.getFieldsWithResolvers());
assertEquals(expectedMappingConfig.getFieldsWithoutResolvers(), mappingConfig.getFieldsWithoutResolvers());
assertEquals(expectedMappingConfig.getFieldsToExcludeFromGeneration(),
mappingConfig.getFieldsToExcludeFromGeneration());
assertEquals(expectedMappingConfig.getRequestSuffix(), mappingConfig.getRequestSuffix());
assertEquals(expectedMappingConfig.getResponseSuffix(), mappingConfig.getResponseSuffix());
assertEquals(expectedMappingConfig.getResponseProjectionSuffix(), mappingConfig.getResponseProjectionSuffix());
Expand Down Expand Up @@ -222,6 +227,7 @@ void combineDefaultWithCustom() {
assertEquals(ApiRootInterfaceStrategy.SINGLE_INTERFACE, mappingConfig.getApiRootInterfaceStrategy());
assertEquals(singleton("5"), mappingConfig.getFieldsWithResolvers());
assertEquals(singleton("8"), mappingConfig.getFieldsWithoutResolvers());
assertEquals(singleton("3"), mappingConfig.getFieldsToExcludeFromGeneration());
assertEquals("6", mappingConfig.getRequestSuffix());
assertEquals("10", mappingConfig.getResponseSuffix());
assertEquals("7", mappingConfig.getResponseProjectionSuffix());
Expand Down Expand Up @@ -268,6 +274,7 @@ void combineCustomWithDefault() {
assertEquals(ApiRootInterfaceStrategy.SINGLE_INTERFACE, mappingConfig.getApiRootInterfaceStrategy());
assertEquals(singleton("5"), mappingConfig.getFieldsWithResolvers());
assertEquals(singleton("8"), mappingConfig.getFieldsWithoutResolvers());
assertEquals(singleton("3"), mappingConfig.getFieldsToExcludeFromGeneration());
assertEquals("6", mappingConfig.getRequestSuffix());
assertEquals("10", mappingConfig.getResponseSuffix());
assertEquals("7", mappingConfig.getResponseProjectionSuffix());
Expand Down Expand Up @@ -320,6 +327,7 @@ void combineCustomWithCustom() {
assertEquals(ApiRootInterfaceStrategy.DO_NOT_GENERATE, mappingConfig.getApiRootInterfaceStrategy());
assertEquals(new HashSet<>(Arrays.asList("5", "55")), mappingConfig.getFieldsWithResolvers());
assertEquals(new HashSet<>(Arrays.asList("8", "88")), mappingConfig.getFieldsWithoutResolvers());
assertEquals(new HashSet<>(Arrays.asList("3", "33")), mappingConfig.getFieldsToExcludeFromGeneration());
assertEquals("66", mappingConfig.getRequestSuffix());
assertEquals("1010", mappingConfig.getResponseSuffix());
assertEquals("77", mappingConfig.getResponseProjectionSuffix());
Expand Down