未验证 提交 de08b9e2 编写于 作者: B Bogdan Kobylynskyi 提交者: GitHub

Support fields resolvers #25 (#31)

* Support fields resolvers #25

* Code coverage for MappingConfig #25
上级 510a61c4
......@@ -13,24 +13,26 @@ Please refer to:
## Supported Options
| Key | Data Type | Default value | Description |
| ------------------------- | ------------------ | ----------------------------------------- | ----------- |
| graphqlSchemaPaths | List(String) | None | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. |
| packageName | String | Empty | Java package for generated classes. |
| outputDir | String | None | The output target directory into which code will be generated. |
| apiPackage | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). |
| modelPackage | String | Empty | Java package for generated model classes (type, input, interface, enum, union). |
| generateApis | Boolean | True | Specifies whether api classes should be generated as well as model classes. |
| customTypesMapping | Map(String,String) | Empty | Can be used to supply custom mappings for scalars. <br/> Supports:<br/> * Map of (GraphqlObjectName.fieldName) to (JavaType) <br/> * Map of (GraphqlType) to (JavaType) |
| customAnnotationsMapping | Map(String,String) | Empty | Can be used to supply custom annotations (serializers) for scalars. <br/> Supports:<br/> * Map of (GraphqlObjectName.fieldName) to (JavaType) <br/> * Map of (GraphqlType) to (JavaType) |
| modelValidationAnnotation | String | @javax.validation.<br>constraints.NotNull | Annotation for mandatory (NonNull) fields. Can be null/empty. |
| modelNamePrefix | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). |
| modelNameSuffix | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). |
| subscriptionReturnType | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. |
| generateEqualsAndHashCode | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. |
| generateToString | Boolean | False | Specifies whether generated model classes should have toString method defined. |
| generateAsyncApi | Boolean | False | If true, then wrap type into `java.util.concurrent.CompletableFuture` or `subscriptionReturnType` |
| jsonConfigurationFile | String | Empty | Path to an external mapping configuration. |
| Key | Data Type | Default value | Description |
| ------------------------------------ | ------------------ | ----------------------------------------- | ----------- |
| graphqlSchemaPaths | List(String) | None | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. |
| packageName | String | Empty | Java package for generated classes. |
| outputDir | String | None | The output target directory into which code will be generated. |
| apiPackage | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). |
| modelPackage | String | Empty | Java package for generated model classes (type, input, interface, enum, union). |
| generateApis | Boolean | True | Specifies whether api classes should be generated as well as model classes. |
| customTypesMapping | Map(String,String) | Empty | Can be used to supply custom mappings for scalars. <br/> Supports:<br/> * Map of (GraphqlObjectName.fieldName) to (JavaType) <br/> * Map of (GraphqlType) to (JavaType) |
| customAnnotationsMapping | Map(String,String) | Empty | Can be used to supply custom annotations (serializers) for scalars. <br/> Supports:<br/> * Map of (GraphqlObjectName.fieldName) to (JavaType) <br/> * Map of (GraphqlType) to (JavaType) |
| modelValidationAnnotation | String | @javax.validation.<br>constraints.NotNull | Annotation for mandatory (NonNull) fields. Can be null/empty. |
| modelNamePrefix | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). |
| modelNameSuffix | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). |
| subscriptionReturnType | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. |
| generateEqualsAndHashCode | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. |
| generateToString | Boolean | False | Specifies whether generated model classes should have toString method defined. |
| generateAsyncApi | Boolean | False | If true, then wrap type into `java.util.concurrent.CompletableFuture` or `subscriptionReturnType` |
| 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. |
| fieldsResolvers | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName`. |
| jsonConfigurationFile | String | Empty | Path to an external mapping configuration. |
### External mapping configuration
......
......@@ -14,6 +14,7 @@ class FreeMarkerTemplatesRegistry {
static Template unionTemplate;
static Template interfaceTemplate;
static Template operationsTemplate;
static Template fieldsResolverTemplate;
static {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
......@@ -29,6 +30,7 @@ class FreeMarkerTemplatesRegistry {
unionTemplate = configuration.getTemplate("templates/javaClassGraphqlUnion.ftl");
interfaceTemplate = configuration.getTemplate("templates/javaClassGraphqlInterface.ftl");
operationsTemplate = configuration.getTemplate("templates/javaClassGraphqlOperations.ftl");
fieldsResolverTemplate = configuration.getTemplate("templates/javaClassGraphqlFieldsResolver.ftl");
} catch (IOException e) {
throw new UnableToLoadFreeMarkerTemplateException(e);
}
......
......@@ -13,6 +13,8 @@ import java.io.IOException;
import java.util.List;
import java.util.Map;
import static java.util.stream.Collectors.toList;
/**
* Generator of:
* - Interface for each GraphQL query
......@@ -38,7 +40,6 @@ public class GraphqlCodegen {
this(schemas, outputDir, mappingConfig, null);
}
public GraphqlCodegen(List<String> schemas, File outputDir, MappingConfig mappingConfig, MappingConfigSupplier externalMappingConfigSupplier) {
this.schemas = schemas;
this.outputDir = outputDir;
......@@ -60,6 +61,9 @@ public class GraphqlCodegen {
if (mappingConfig.getGenerateApis() == null) {
mappingConfig.setGenerateApis(DefaultMappingConfigValues.DEFAULT_GENERATE_APIS);
}
if (mappingConfig.getGenerateParameterizedFieldsResolvers() == null) {
mappingConfig.setGenerateParameterizedFieldsResolvers(DefaultMappingConfigValues.DEFAULT_GENERATE_PARAMETERIZED_FIELDS_RESOLVERS);
}
}
......@@ -89,6 +93,7 @@ public class GraphqlCodegen {
break;
case TYPE:
generateType((ObjectTypeDefinition) definition, document);
generateFieldResolvers((ObjectTypeDefinition) definition);
break;
case INTERFACE:
generateInterface((InterfaceTypeDefinition) definition);
......@@ -134,6 +139,16 @@ public class GraphqlCodegen {
GraphqlCodegenFileCreator.generateFile(FreeMarkerTemplatesRegistry.typeTemplate, dataModel, outputDir);
}
private void generateFieldResolvers(ObjectTypeDefinition definition) throws IOException, TemplateException {
List<FieldDefinition> fieldDefsWithResolvers = definition.getFieldDefinitions().stream()
.filter(fieldDef -> FieldDefinitionToParameterMapper.generateResolversForField(mappingConfig, fieldDef, definition.getName()))
.collect(toList());
if (!fieldDefsWithResolvers.isEmpty()) {
Map<String, Object> dataModel = FieldResolverDefinitionToDataModelMapper.map(mappingConfig, fieldDefsWithResolvers, definition.getName());
GraphqlCodegenFileCreator.generateFile(FreeMarkerTemplatesRegistry.fieldsResolverTemplate, dataModel, outputDir);
}
}
private void generateInput(InputObjectTypeDefinition definition) throws IOException, TemplateException {
Map<String, Object> dataModel = InputDefinitionToDataModelMapper.map(mappingConfig, definition);
GraphqlCodegenFileCreator.generateFile(FreeMarkerTemplatesRegistry.typeTemplate, dataModel, outputDir);
......
......@@ -2,6 +2,7 @@ package com.kobylynskyi.graphql.codegen.mapper;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.model.ParameterDefinition;
import com.kobylynskyi.graphql.codegen.utils.Utils;
import graphql.language.FieldDefinition;
import java.util.Collections;
......@@ -30,8 +31,17 @@ public class FieldDefinitionToParameterMapper {
return Collections.emptyList();
}
return fieldDefinitions.stream()
.map(fieldDefinition -> GraphqlTypeToJavaTypeMapper.map(mappingConfig, fieldDefinition, parentTypeName))
.filter(fieldDef -> !generateResolversForField(mappingConfig, fieldDef, parentTypeName))
.map(fieldDef -> GraphqlTypeToJavaTypeMapper.map(mappingConfig, fieldDef, parentTypeName))
.collect(Collectors.toList());
}
public static boolean generateResolversForField(MappingConfig mappingConfig,
FieldDefinition fieldDef,
String parentTypeName) {
boolean resolverForParamField = mappingConfig.getGenerateParameterizedFieldsResolvers() && !Utils.isEmpty(fieldDef.getInputValueDefinitions());
boolean resolverForSpecificField = mappingConfig.getFieldsResolvers().contains(parentTypeName + "." + fieldDef.getName());
return resolverForParamField || resolverForSpecificField;
}
}
package com.kobylynskyi.graphql.codegen.mapper;
import com.kobylynskyi.graphql.codegen.model.FieldResolverDefinition;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.model.ParameterDefinition;
import com.kobylynskyi.graphql.codegen.utils.Utils;
import graphql.language.FieldDefinition;
import graphql.language.InputValueDefinition;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.kobylynskyi.graphql.codegen.model.DataModelFields.*;
import static java.util.Collections.emptyList;
/**
* Map field definition resolver to a Freemarker data model
*
* @author kobylynskyi
*/
public class FieldResolverDefinitionToDataModelMapper {
/**
* Map field definition to a Freemarker data model
*
* @param mappingConfig Global mapping configuration
* @param fieldDefs GraphQL field definitions that require resolvers
* @param typeName Name of the type for which Resolver will be generated
* @return Freemarker data model of the GraphQL parametrized field
*/
public static Map<String, Object> map(MappingConfig mappingConfig, List<FieldDefinition> fieldDefs,
String typeName) {
Map<String, Object> dataModel = new HashMap<>();
String packageName = MapperUtils.getApiPackageName(mappingConfig);
dataModel.put(PACKAGE, packageName);
dataModel.put(IMPORTS, MapperUtils.getImportsForFieldResolvers(mappingConfig, packageName));
dataModel.put(CLASS_NAME, getClassName(typeName));
dataModel.put(FIELDS, fieldDefs.stream()
.map(fieldDef -> mapFieldDefinition(mappingConfig, fieldDef, typeName))
.collect(Collectors.toList()));
return dataModel;
}
/**
* Map GraphQL's FieldDefinition to a Freemarker-understandable format of operation
*
* @param mappingConfig Global mapping configuration
* @param typeName Name of the type for which Resolver will be generated
* @param fieldDef GraphQL definition of the field which should have resolver
* @return Freemarker-understandable format of Parametrized Field
*/
private static FieldResolverDefinition mapFieldDefinition(MappingConfig mappingConfig,
FieldDefinition fieldDef,
String typeName) {
FieldResolverDefinition parametrizedFieldDef = new FieldResolverDefinition();
parametrizedFieldDef.setName(fieldDef.getName());
parametrizedFieldDef.setType(GraphqlTypeToJavaTypeMapper.getJavaType(mappingConfig, fieldDef.getType(), fieldDef.getName(), typeName));
List<ParameterDefinition> parameters = new ArrayList<>();
// 1. Add type as a first method argument
String typeNameParameterName = MapperUtils.capitalizeIfRestricted(Utils.uncapitalize(typeName)); // Commit -> commit
parameters.add(new ParameterDefinition(typeName, typeNameParameterName, null, emptyList()));
// 2. Add each field parameter as a method argument
for (InputValueDefinition parameterDef : fieldDef.getInputValueDefinitions()) {
String parameterDefType = GraphqlTypeToJavaTypeMapper.getJavaType(mappingConfig, parameterDef.getType(), parameterDef.getName(), fieldDef.getName());
String defaultValue = DefaultValueMapper.map(parameterDef.getDefaultValue(), parameterDef.getType());
parameters.add(new ParameterDefinition(parameterDefType, parameterDef.getName(), defaultValue, emptyList()));
}
// 3. Add DataFetchingEnvironment as a last method argument
parameters.add(new ParameterDefinition("DataFetchingEnvironment", "env", null, emptyList()));
parametrizedFieldDef.setParameters(parameters);
return parametrizedFieldDef;
}
/**
* Examples:
* - PersonResolver
*/
private static String getClassName(String typeName) {
return Utils.capitalize(typeName) + "Resolver";
}
}
package com.kobylynskyi.graphql.codegen.mapper;
import static graphql.language.OperationDefinition.*;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.model.ParameterDefinition;
import com.kobylynskyi.graphql.codegen.utils.Utils;
......@@ -11,6 +9,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static graphql.language.OperationDefinition.Operation;
/**
* Map GraphQL type to Java type
*
......
......@@ -164,10 +164,10 @@ public class MapperUtils {
* Returns imports required for the particular case of field definitions (operations), taking into account async
* operations, etc.
*
* @param mappingConfig
* @param packageName
* @param objectTypeName
* @return
* @param mappingConfig Global mapping configuration
* @param packageName Package name of the generated class which will be ignored
* @param objectTypeName Object type: Query/Mutation/Subscription
* @return all imports required for a generated class
*/
static Set<String> getImportsForFieldDefinition(MappingConfig mappingConfig, String packageName, String objectTypeName) {
final Set<String> imports = getImports(mappingConfig, packageName);
......@@ -179,15 +179,28 @@ public class MapperUtils {
return imports;
}
/**
* Returns imports required for the fields resolvers class
*
* @param mappingConfig Global mapping configuration
* @param packageName Package name of the generated class which will be ignored
* @return all imports required for a generated class
*/
static Set<String> getImportsForFieldResolvers(MappingConfig mappingConfig, String packageName) {
Set<String> imports = getImports(mappingConfig, packageName);
imports.add("graphql.schema");
return imports;
}
/**
* Determines if the specified operation is an async query or mutation
*
* @param mappingConfig
* @param objectTypeName
* @param mappingConfig Global mapping configuration
* @param objectTypeName Parent object type (Query/Mutation)
* @return true if the given operation is an async query or mutation, false otherwise
*/
static boolean isAsyncQueryOrMutation(MappingConfig mappingConfig, String objectTypeName) {
boolean isAsyncApi = mappingConfig.getGenerateAsyncApi() != null && mappingConfig.getGenerateAsyncApi().booleanValue();
boolean isAsyncApi = mappingConfig.getGenerateAsyncApi() != null && mappingConfig.getGenerateAsyncApi();
return isAsyncApi && (Operation.QUERY.name().equalsIgnoreCase(objectTypeName) || Operation.MUTATION.name()
.equalsIgnoreCase(objectTypeName));
......
......@@ -6,4 +6,5 @@ public class DefaultMappingConfigValues {
public static final boolean DEFAULT_GENERATE_APIS = true;
public static final boolean DEFAULT_EQUALS_AND_HASHCODE = false;
public static final boolean DEFAULT_TO_STRING = false;
public static final boolean DEFAULT_GENERATE_PARAMETERIZED_FIELDS_RESOLVERS = true;
}
package com.kobylynskyi.graphql.codegen.model;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* Freemarker-understandable format of parametrized field.
* <p>
* Example schema:
* <code>
* type Person {
* name: String!
* height(unit: Unit): Int!
* }
* </code>
* <p>
* Here:
* <p>
* name = "height"
* type = "Integer"
* parameters = [Person person, Unit unit, DataFetchingEnvironment env]
* <p>
* So that resulting interface will have:
* <code>
* Integer height(Person person, Unit unit, DataFetchingEnvironment env);
* </code>
*
* @author kobylynskyi
*/
@Data
public class FieldResolverDefinition {
private String name;
private String type;
private List<ParameterDefinition> parameters = new ArrayList<>();
}
package com.kobylynskyi.graphql.codegen.model;
import lombok.Data;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import lombok.Data;
import java.util.Set;
/**
* The type Mapping config.
......@@ -38,22 +40,14 @@ public class MappingConfig implements Combinable<MappingConfig> {
private Boolean generateEqualsAndHashCode;
private Boolean generateToString;
private Boolean generateAsyncApi;
private Boolean generateParameterizedFieldsResolvers;
/**
* Put custom type mapping if absent.
*
* @param from the from
* @param to the to
* Fields that require Resolvers should be defined here in format: TypeName.fieldName
* E.g.: "Person.friends"
* If just type is specified, then all fields of this type will
*/
public void putCustomTypeMappingIfAbsent(String from, String to) {
if (customTypesMapping == null) {
customTypesMapping = new HashMap<>();
}
if (!customTypesMapping.containsKey(from)) {
customTypesMapping.put(from, to);
}
}
private Set<String> fieldsResolvers = new HashSet<>();
@Override
public void combine(MappingConfig source) {
......@@ -77,9 +71,30 @@ public class MappingConfig implements Combinable<MappingConfig> {
this.modelNamePrefix = source.modelNamePrefix != null ? source.modelNamePrefix : this.modelNamePrefix;
this.modelNameSuffix = source.modelNameSuffix != null ? source.modelNameSuffix : this.modelNameSuffix;
this.modelValidationAnnotation = source.modelValidationAnnotation != null ? source.modelValidationAnnotation : this.modelValidationAnnotation;
this.subscriptionReturnType = source.subscriptionReturnType != null ? source.subscriptionReturnType : this.subscriptionReturnType;
this.subscriptionReturnType = source.subscriptionReturnType != null ? source.subscriptionReturnType : this.subscriptionReturnType;
this.generateEqualsAndHashCode = source.generateEqualsAndHashCode != null ? source.generateEqualsAndHashCode : this.generateEqualsAndHashCode;
this.generateToString = source.generateToString != null ? source.generateToString : this.generateToString;
this.generateAsyncApi = source.generateAsyncApi != null? source.generateAsyncApi : this.generateAsyncApi;
this.generateAsyncApi = source.generateAsyncApi != null ? source.generateAsyncApi : this.generateAsyncApi;
this.generateParameterizedFieldsResolvers = source.generateParameterizedFieldsResolvers != null ? source.generateParameterizedFieldsResolvers : this.generateParameterizedFieldsResolvers;
if (this.fieldsResolvers != null && source.fieldsResolvers != null) {
this.fieldsResolvers.addAll(source.fieldsResolvers);
} else if (this.fieldsResolvers == null) {
this.fieldsResolvers = source.fieldsResolvers;
}
}
/**
* Put custom type mapping if absent.
*
* @param from the from
* @param to the to
*/
public void putCustomTypeMappingIfAbsent(String from, String to) {
if (customTypesMapping == null) {
customTypesMapping = new HashMap<>();
}
if (!customTypesMapping.containsKey(from)) {
customTypesMapping.put(from, to);
}
}
}
package com.kobylynskyi.graphql.codegen.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
......@@ -11,6 +13,8 @@ import java.util.List;
* @author kobylynskyi
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ParameterDefinition {
private String type;
......
......@@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import graphql.language.OperationDefinition;
......@@ -37,14 +38,23 @@ public final class Utils {
* @return capitalized string
*/
public static String capitalize(String aString) {
if (Utils.isBlank(aString)) {
return aString;
}
char[] chars = aString.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
}
/**
* Uncapitalize a string. Make first letter as lowercase
*
* @param aString string to uncapitalize
* @return uncapitalized string
*/
public static String uncapitalize(String aString) {
char[] chars = aString.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
/**
* Basically copy of org.apache.commons.lang3.StringUtils.isBlank(CharSequence cs)
*
......@@ -114,5 +124,14 @@ public final class Utils {
}
}
/**
* Check if collection is empty.
*
* @param collection that will be checked for emptiness
* @return true if collection is null or empty
*/
public static boolean isEmpty(Collection<?> collection) {
return collection == null || collection.isEmpty();
}
}
<#if package?has_content>
package ${package};
</#if>
<#list imports as import>
import ${import}.*;
</#list>
public interface ${className} {
<#list fields as field>
${field.type} ${field.name}(<#list field.parameters as param>${param.type} ${param.name}<#if param_has_next>, </#if></#list>) throws Exception;
</#list>
}
\ No newline at end of file
package com.kobylynskyi.graphql.codegen;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.utils.Utils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Objects;
import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent;
import static java.util.Collections.singletonMap;
class GraphqlCodegenFieldsResolversTest {
private GraphqlCodegen generator;
private final File outputBuildDir = new File("build/generated");
private final File outputJavaClassesDir = new File("build/generated/com/github/graphql");
private final MappingConfig mappingConfig = new MappingConfig();
@BeforeEach
void init() {
mappingConfig.setPackageName("com.github.graphql");
generator = new GraphqlCodegen(Collections.singletonList("src/test/resources/schemas/github.graphqls"),
outputBuildDir, mappingConfig);
}
@AfterEach
void cleanup() throws IOException {
Utils.deleteDir(new File("build/generated"));
}
@Test
void generate_ParametrizedFields() throws Exception {
mappingConfig.setGenerateParameterizedFieldsResolvers(true);
mappingConfig.setCustomAnnotationsMapping(new HashMap<>(singletonMap(
"Commit.blame", "com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.example.json.DateTimeScalarDeserializer.class)")));
generator.generate();
File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
assertSameTrimmedContent(new File("src/test/resources/expected-classes/Commit_noParametrizedFields.java.txt"),
getGeneratedFile(files, "Commit.java"));
assertSameTrimmedContent(new File("src/test/resources/expected-classes/CommitResolver.java.txt"),
getGeneratedFile(files, "CommitResolver.java"));
}
@Test
void generate_CustomFieldsResolvers() throws Exception {
mappingConfig.setFieldsResolvers(Collections.singleton("AcceptTopicSuggestionPayload.topic"));
generator.generate();
File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
assertSameTrimmedContent(new File("src/test/resources/expected-classes/AcceptTopicSuggestionPayload.java.txt"),
getGeneratedFile(files, "AcceptTopicSuggestionPayload.java"));
assertSameTrimmedContent(new File("src/test/resources/expected-classes/AcceptTopicSuggestionPayloadResolver.java.txt"),
getGeneratedFile(files, "AcceptTopicSuggestionPayloadResolver.java"));
}
private static File getGeneratedFile(File[] files, String fileName) throws FileNotFoundException {
return Arrays.stream(files)
.filter(f -> f.getName().equalsIgnoreCase(fileName))
.findFirst()
.orElseThrow(FileNotFoundException::new);
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package com.kobylynskyi.graphql.codegen;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.utils.Utils;
import org.hamcrest.core.StringContains;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
......@@ -26,12 +27,13 @@ class GraphqlCodegenGitHubTest {
@BeforeEach
void init() {
mappingConfig.setGenerateParameterizedFieldsResolvers(false);
mappingConfig.setPackageName("com.github.graphql");
generator = new GraphqlCodegen(Collections.singletonList("src/test/resources/schemas/github.graphqls"),
outputBuildDir, mappingConfig);
}
//@AfterEach
@AfterEach
void cleanup() throws IOException {
Utils.deleteDir(new File("build/generated"));
}
......
package com.kobylynskyi.graphql.codegen.model;
import static java.util.Collections.singletonMap;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import java.util.*;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import static java.util.Collections.*;
import static org.junit.jupiter.api.Assertions.*;
@SuppressWarnings("unchecked")
class MappingConfigTest {
......@@ -48,6 +43,9 @@ class MappingConfigTest {
assertEquals("ModelPackageName", mappingConfig.getModelPackageName());
assertEquals("ModelValidationAnnotation", mappingConfig.getModelValidationAnnotation());
assertEquals("PackageName", mappingConfig.getPackageName());
assertFalse(mappingConfig.getGenerateAsyncApi());
assertTrue(mappingConfig.getGenerateParameterizedFieldsResolvers());
assertEquals(singleton("5"), mappingConfig.getFieldsResolvers());
}
@Test
......@@ -68,6 +66,8 @@ class MappingConfigTest {
assertEquals("PackageName", mappingConfig.getPackageName());
assertEquals("SubscriptionsReturnType", mappingConfig.getSubscriptionReturnType());
assertFalse(mappingConfig.getGenerateAsyncApi());
assertTrue(mappingConfig.getGenerateParameterizedFieldsResolvers());
assertEquals(singleton("5"), mappingConfig.getFieldsResolvers());
}
@Test
......@@ -90,6 +90,8 @@ class MappingConfigTest {
assertEquals("PackageName2", mappingConfig.getPackageName());
assertEquals("SubscriptionsReturnType2", mappingConfig.getSubscriptionReturnType());
assertTrue(mappingConfig.getGenerateAsyncApi());
assertFalse(mappingConfig.getGenerateParameterizedFieldsResolvers());
assertEquals(new HashSet<>(Arrays.asList("5", "55")), mappingConfig.getFieldsResolvers());
}
private static Map<String, String> hashMap(AbstractMap.SimpleEntry<String, String>... entries) {
......@@ -112,6 +114,8 @@ class MappingConfigTest {
config.setPackageName("PackageName");
config.setSubscriptionReturnType("SubscriptionsReturnType");
config.setGenerateAsyncApi(false);
config.setGenerateParameterizedFieldsResolvers(true);
config.setFieldsResolvers(new HashSet<>(singletonList("5")));
return config;
}
......@@ -130,6 +134,8 @@ class MappingConfigTest {
config.setPackageName("PackageName2");
config.setSubscriptionReturnType("SubscriptionsReturnType2");
config.setGenerateAsyncApi(true);
config.setGenerateParameterizedFieldsResolvers(false);
config.setFieldsResolvers(singleton("55"));
return config;
}
......@@ -137,6 +143,7 @@ class MappingConfigTest {
MappingConfig mappingConfig = new MappingConfig();
mappingConfig.setCustomTypesMapping(null);
mappingConfig.setCustomAnnotationsMapping(null);
mappingConfig.setFieldsResolvers(null);
return mappingConfig;
}
......
package com.github.graphql;
import java.util.*;
public class AcceptTopicSuggestionPayload {
private String clientMutationId;
public AcceptTopicSuggestionPayload() {
}
public AcceptTopicSuggestionPayload(String clientMutationId) {
this.clientMutationId = clientMutationId;
}
public String getClientMutationId() {
return clientMutationId;
}
public void setClientMutationId(String clientMutationId) {
this.clientMutationId = clientMutationId;
}
}
package com.github.graphql;
import java.util.*;
import graphql.schema.*;
public interface AcceptTopicSuggestionPayloadResolver {
Topic topic(AcceptTopicSuggestionPayload acceptTopicSuggestionPayload, DataFetchingEnvironment env) throws Exception;
}
\ No newline at end of file
package com.github.graphql;
import java.util.*;
import graphql.schema.*;
public interface CommitResolver {
PullRequestConnection associatedPullRequests(Commit commit, String after, String before, Integer first, Integer last, PullRequestOrder orderBy, DataFetchingEnvironment env) throws Exception;
Blame blame(Commit commit, String path, DataFetchingEnvironment env) throws Exception;
CommitCommentConnection comments(Commit commit, String after, String before, Integer first, Integer last, DataFetchingEnvironment env) throws Exception;
DeploymentConnection deployments(Commit commit, String after, String before, Collection<String> environments, Integer first, Integer last, DeploymentOrder orderBy, DataFetchingEnvironment env) throws Exception;
CommitHistoryConnection history(Commit commit, String after, CommitAuthor author, String before, Integer first, Integer last, String path, String since, String until, DataFetchingEnvironment env) throws Exception;
CommitConnection parents(Commit commit, String after, String before, Integer first, Integer last, DataFetchingEnvironment env) throws Exception;
}
\ No newline at end of file
package com.github.graphql;
import java.util.*;
public class Commit implements Closer, IssueTimelineItem, PullRequestTimelineItem, GitObject, Node, Subscribable, UniformResourceLocatable{
@javax.validation.constraints.NotNull
private String abbreviatedOid;
@javax.validation.constraints.NotNull
private Integer additions;
private GitActor author;
@javax.validation.constraints.NotNull
private Boolean authoredByCommitter;
@javax.validation.constraints.NotNull
private String authoredDate;
@javax.validation.constraints.NotNull
private Integer changedFiles;
@javax.validation.constraints.NotNull
private String commitResourcePath;
@javax.validation.constraints.NotNull
private String commitUrl;
@javax.validation.constraints.NotNull
private String committedDate;
@javax.validation.constraints.NotNull
private Boolean committedViaWeb;
private GitActor committer;
@javax.validation.constraints.NotNull
private Integer deletions;
@javax.validation.constraints.NotNull
private String id;
@javax.validation.constraints.NotNull
private String message;
@javax.validation.constraints.NotNull
private String messageBody;
@javax.validation.constraints.NotNull
private String messageBodyHTML;
@javax.validation.constraints.NotNull
private String messageHeadline;
@javax.validation.constraints.NotNull
private String messageHeadlineHTML;
@javax.validation.constraints.NotNull
private String oid;
private String pushedDate;
@javax.validation.constraints.NotNull
private Repository repository;
@javax.validation.constraints.NotNull
private String resourcePath;
private GitSignature signature;
private Status status;
@javax.validation.constraints.NotNull
private String tarballUrl;
@javax.validation.constraints.NotNull
private Tree tree;
@javax.validation.constraints.NotNull
private String treeResourcePath;
@javax.validation.constraints.NotNull
private String treeUrl;
@javax.validation.constraints.NotNull
private String url;
@javax.validation.constraints.NotNull
private Boolean viewerCanSubscribe;
private SubscriptionState viewerSubscription;
@javax.validation.constraints.NotNull
private String zipballUrl;
public Commit() {
}
public Commit(String abbreviatedOid, Integer additions, GitActor author, Boolean authoredByCommitter, String authoredDate, Integer changedFiles, String commitResourcePath, String commitUrl, String committedDate, Boolean committedViaWeb, GitActor committer, Integer deletions, String id, String message, String messageBody, String messageBodyHTML, String messageHeadline, String messageHeadlineHTML, String oid, String pushedDate, Repository repository, String resourcePath, GitSignature signature, Status status, String tarballUrl, Tree tree, String treeResourcePath, String treeUrl, String url, Boolean viewerCanSubscribe, SubscriptionState viewerSubscription, String zipballUrl) {
this.abbreviatedOid = abbreviatedOid;
this.additions = additions;
this.author = author;
this.authoredByCommitter = authoredByCommitter;
this.authoredDate = authoredDate;
this.changedFiles = changedFiles;
this.commitResourcePath = commitResourcePath;
this.commitUrl = commitUrl;
this.committedDate = committedDate;
this.committedViaWeb = committedViaWeb;
this.committer = committer;
this.deletions = deletions;
this.id = id;
this.message = message;
this.messageBody = messageBody;
this.messageBodyHTML = messageBodyHTML;
this.messageHeadline = messageHeadline;
this.messageHeadlineHTML = messageHeadlineHTML;
this.oid = oid;
this.pushedDate = pushedDate;
this.repository = repository;
this.resourcePath = resourcePath;
this.signature = signature;
this.status = status;
this.tarballUrl = tarballUrl;
this.tree = tree;
this.treeResourcePath = treeResourcePath;
this.treeUrl = treeUrl;
this.url = url;
this.viewerCanSubscribe = viewerCanSubscribe;
this.viewerSubscription = viewerSubscription;
this.zipballUrl = zipballUrl;
}
public String getAbbreviatedOid() {
return abbreviatedOid;
}
public void setAbbreviatedOid(String abbreviatedOid) {
this.abbreviatedOid = abbreviatedOid;
}
public Integer getAdditions() {
return additions;
}
public void setAdditions(Integer additions) {
this.additions = additions;
}
public GitActor getAuthor() {
return author;
}
public void setAuthor(GitActor author) {
this.author = author;
}
public Boolean getAuthoredByCommitter() {
return authoredByCommitter;
}
public void setAuthoredByCommitter(Boolean authoredByCommitter) {
this.authoredByCommitter = authoredByCommitter;
}
public String getAuthoredDate() {
return authoredDate;
}
public void setAuthoredDate(String authoredDate) {
this.authoredDate = authoredDate;
}
public Integer getChangedFiles() {
return changedFiles;
}
public void setChangedFiles(Integer changedFiles) {
this.changedFiles = changedFiles;
}
public String getCommitResourcePath() {
return commitResourcePath;
}
public void setCommitResourcePath(String commitResourcePath) {
this.commitResourcePath = commitResourcePath;
}
public String getCommitUrl() {
return commitUrl;
}
public void setCommitUrl(String commitUrl) {
this.commitUrl = commitUrl;
}
public String getCommittedDate() {
return committedDate;
}
public void setCommittedDate(String committedDate) {
this.committedDate = committedDate;
}
public Boolean getCommittedViaWeb() {
return committedViaWeb;
}
public void setCommittedViaWeb(Boolean committedViaWeb) {
this.committedViaWeb = committedViaWeb;
}
public GitActor getCommitter() {
return committer;
}
public void setCommitter(GitActor committer) {
this.committer = committer;
}
public Integer getDeletions() {
return deletions;
}
public void setDeletions(Integer deletions) {
this.deletions = deletions;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessageBody() {
return messageBody;
}
public void setMessageBody(String messageBody) {
this.messageBody = messageBody;
}
public String getMessageBodyHTML() {
return messageBodyHTML;
}
public void setMessageBodyHTML(String messageBodyHTML) {
this.messageBodyHTML = messageBodyHTML;
}
public String getMessageHeadline() {
return messageHeadline;
}
public void setMessageHeadline(String messageHeadline) {
this.messageHeadline = messageHeadline;
}
public String getMessageHeadlineHTML() {
return messageHeadlineHTML;
}
public void setMessageHeadlineHTML(String messageHeadlineHTML) {
this.messageHeadlineHTML = messageHeadlineHTML;
}
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public String getPushedDate() {
return pushedDate;
}
public void setPushedDate(String pushedDate) {
this.pushedDate = pushedDate;
}
public Repository getRepository() {
return repository;
}
public void setRepository(Repository repository) {
this.repository = repository;
}
public String getResourcePath() {
return resourcePath;
}
public void setResourcePath(String resourcePath) {
this.resourcePath = resourcePath;
}
public GitSignature getSignature() {
return signature;
}
public void setSignature(GitSignature signature) {
this.signature = signature;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public String getTarballUrl() {
return tarballUrl;
}
public void setTarballUrl(String tarballUrl) {
this.tarballUrl = tarballUrl;
}
public Tree getTree() {
return tree;
}
public void setTree(Tree tree) {
this.tree = tree;
}
public String getTreeResourcePath() {
return treeResourcePath;
}
public void setTreeResourcePath(String treeResourcePath) {
this.treeResourcePath = treeResourcePath;
}
public String getTreeUrl() {
return treeUrl;
}
public void setTreeUrl(String treeUrl) {
this.treeUrl = treeUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Boolean getViewerCanSubscribe() {
return viewerCanSubscribe;
}
public void setViewerCanSubscribe(Boolean viewerCanSubscribe) {
this.viewerCanSubscribe = viewerCanSubscribe;
}
public SubscriptionState getViewerSubscription() {
return viewerSubscription;
}
public void setViewerSubscription(SubscriptionState viewerSubscription) {
this.viewerSubscription = viewerSubscription;
}
public String getZipballUrl() {
return zipballUrl;
}
public void setZipballUrl(String zipballUrl) {
this.zipballUrl = zipballUrl;
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册