Skip to content
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

support placeholder at apiReturnListType and apiReturnType #1200

Merged
merged 8 commits into from
May 15, 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.GraphQLTypeMapper;
import com.kobylynskyi.graphql.codegen.model.MappingConfigConstants;
import com.kobylynskyi.graphql.codegen.model.MappingContext;
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
Expand All @@ -10,6 +11,8 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.Arrays.asList;

Expand All @@ -19,6 +22,7 @@
public class JavaGraphQLTypeMapper extends GraphQLTypeMapper {

public static final String JAVA_UTIL_LIST = "java.util.List";
public static final Pattern JAVA_UTIL_LIST_ELEMENT_REGEX = Pattern.compile("java\\.util\\.List<(.+)>");
private static final String JAVA_UTIL_OPTIONAL = "java.util.Optional";
private static final Set<String> JAVA_PRIMITIVE_TYPES = new HashSet<>(asList(
"byte", "short", "int", "long", "float", "double", "char", "boolean"));
Expand Down Expand Up @@ -65,11 +69,28 @@ public String wrapApiReturnTypeIfRequired(MappingContext mappingContext,
if (computedTypeName.startsWith(JAVA_UTIL_LIST) &&
Utils.isNotBlank(mappingContext.getApiReturnListType())) {
// in case it is query/mutation, return type is list and apiReturnListType is set
return computedTypeName.replace(JAVA_UTIL_LIST, mappingContext.getApiReturnListType());
if (mappingContext.getApiReturnListType().contains(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER)) {
Matcher matcher = JAVA_UTIL_LIST_ELEMENT_REGEX.matcher(computedTypeName);
if (matcher.find()) {
String listElement = matcher.group(1);
return mappingContext.getApiReturnListType().replace(
MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER,
listElement);
} else {
throw new IllegalStateException();
}
} else {
return computedTypeName.replace(JAVA_UTIL_LIST, mappingContext.getApiReturnListType());
}
}
if (Utils.isNotBlank(mappingContext.getApiReturnType())) {
// in case it is query/mutation and apiReturnType is set
return getGenericsString(mappingContext, mappingContext.getApiReturnType(), computedTypeName);
if (mappingContext.getApiReturnType().contains(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER)) {
return mappingContext.getApiReturnType()
.replace(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER, computedTypeName);
} else {
return getGenericsString(mappingContext, mappingContext.getApiReturnType(), computedTypeName);
}
}
return getTypeConsideringPrimitive(mappingContext, namedDefinition, computedTypeName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.GraphQLTypeMapper;
import com.kobylynskyi.graphql.codegen.model.MappingConfigConstants;
import com.kobylynskyi.graphql.codegen.model.MappingContext;
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
import com.kobylynskyi.graphql.codegen.utils.Utils;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.Arrays.asList;

Expand All @@ -21,6 +24,7 @@
public class KotlinGraphQLTypeMapper extends GraphQLTypeMapper {

private static final String KOTLIN_UTIL_LIST = "List";
public static final Pattern KOTLIN_UTIL_LIST_ELEMENT_REGEX = Pattern.compile("List<(.+)>");
private static final String KOTLIN_UTIL_NULLABLE = "?";
// Char Boolean are not primitive type, but non null equivalent jvm primitive types.
private static final Set<String> KOTLIN_PRIMITIVE_TYPES = new HashSet<>(
Expand Down Expand Up @@ -92,11 +96,35 @@ public String wrapApiReturnTypeIfRequired(MappingContext mappingContext,
if (computedTypeName.startsWith(KOTLIN_UTIL_LIST) &&
Utils.isNotBlank(mappingContext.getApiReturnListType())) {
// in case it is query/mutation, return type is list and apiReturnListType is set
return computedTypeName.replace(KOTLIN_UTIL_LIST, mappingContext.getApiReturnListType());
if (mappingContext.getApiReturnListType().contains(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER)) {
boolean isNullable = computedTypeName.endsWith(KOTLIN_UTIL_NULLABLE);

Matcher matcher = KOTLIN_UTIL_LIST_ELEMENT_REGEX.matcher(computedTypeName);
if (matcher.find()) {
String listElement = matcher.group(1);
computedTypeName = mappingContext.getApiReturnListType()
.replace(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER, listElement);

if (isNullable) {
return computedTypeName + "?";
} else {
return computedTypeName;
}
} else {
throw new IllegalStateException();
}
} else {
return computedTypeName.replace(KOTLIN_UTIL_LIST, mappingContext.getApiReturnListType());
}
}
if (Utils.isNotBlank(mappingContext.getApiReturnType())) {
// in case it is query/mutation and apiReturnType is set
return getGenericsString(mappingContext, mappingContext.getApiReturnType(), computedTypeName);
if (mappingContext.getApiReturnType().contains(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER)) {
return mappingContext.getApiReturnType()
.replace(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER, computedTypeName);
} else {
return getGenericsString(mappingContext, mappingContext.getApiReturnType(), computedTypeName);
}
}
return getTypeConsideringPrimitive(mappingContext, namedDefinition, computedTypeName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class MappingConfigConstants {
public static final String DEFAULT_VALIDATION_ANNOTATION = "javax.validation.constraints.NotNull";
public static final String PARENT_INTERFACE_TYPE_PLACEHOLDER = "{{TYPE}}";
public static final String TYPE_NAME_PLACEHOLDER = "{{TYPE_NAME}}";
public static final String API_RETURN_NAME_PLACEHOLDER = "{{TYPE}}";

public static final boolean DEFAULT_GENERATE_APIS = true;
public static final String DEFAULT_GENERATE_APIS_STRING = "true";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.kobylynskyi.graphql.codegen.scala;

import com.kobylynskyi.graphql.codegen.mapper.GraphQLTypeMapper;
import com.kobylynskyi.graphql.codegen.model.MappingConfigConstants;
import com.kobylynskyi.graphql.codegen.model.MappingContext;
import com.kobylynskyi.graphql.codegen.model.NamedDefinition;
import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation;
import com.kobylynskyi.graphql.codegen.utils.Utils;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.kobylynskyi.graphql.codegen.java.JavaGraphQLTypeMapper.JAVA_UTIL_LIST;
import static java.util.Arrays.asList;
Expand All @@ -18,6 +21,7 @@
public class ScalaGraphQLTypeMapper extends GraphQLTypeMapper {

private static final String SCALA_UTIL_LIST = "scala.Seq";
private static final Pattern SCALA_UTIL_LIST_ELEMENT_REGEX = Pattern.compile("scala\\.Seq\\[(.+)]");
private static final String SCALA_UTIL_OPTIONAL = "scala.Option";
private static final Set<String> SCALA_PRIMITIVE_TYPES = new HashSet<>(asList(
"Byte", "Short", "Int", "Long", "Float", "Double", "Char", "Boolean"));
Expand Down Expand Up @@ -72,11 +76,28 @@ public String wrapApiReturnTypeIfRequired(MappingContext mappingContext,
if (computedTypeName.startsWith(SCALA_UTIL_LIST) &&
Utils.isNotBlank(mappingContext.getApiReturnListType())) {
// in case it is query/mutation, return type is list and apiReturnListType is set
return computedTypeName.replace(SCALA_UTIL_LIST, mappingContext.getApiReturnListType());
if (mappingContext.getApiReturnListType().contains(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER)) {
Matcher matcher = SCALA_UTIL_LIST_ELEMENT_REGEX.matcher(computedTypeName);
if (matcher.find()) {
String listElement = matcher.group(1);
return mappingContext.getApiReturnListType().replace(
MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER,
listElement);
} else {
throw new IllegalStateException();
}
} else {
return computedTypeName.replace(SCALA_UTIL_LIST, mappingContext.getApiReturnListType());
}
}
if (Utils.isNotBlank(mappingContext.getApiReturnType())) {
// in case it is query/mutation and apiReturnType is set
return getGenericsString(mappingContext, mappingContext.getApiReturnType(), computedTypeName);
if (mappingContext.getApiReturnType().contains(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER)) {
return mappingContext.getApiReturnType()
.replace(MappingConfigConstants.API_RETURN_NAME_PLACEHOLDER, computedTypeName);
} else {
return getGenericsString(mappingContext, mappingContext.getApiReturnType(), computedTypeName);
}
}
return getTypeConsideringPrimitive(mappingContext, namedDefinition, computedTypeName);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.kobylynskyi.graphql.codegen;

import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen;
import com.kobylynskyi.graphql.codegen.model.GeneratedLanguage;
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.IOException;
import java.util.Objects;

import static com.kobylynskyi.graphql.codegen.TestUtils.assertFileContainsElements;
import static java.util.Collections.singletonList;

class GraphQLCodegenApiReturnTypeTest {

private final File outputBuildDir = new File("build/generated");
private final File outputJavaClassesDir = new File("build/generated/com/kobylynskyi/graphql/test1");

private MappingConfig mappingConfig;

@BeforeEach
void init() {
mappingConfig = new MappingConfig();
mappingConfig.setPackageName("com.kobylynskyi.graphql.test1");
mappingConfig.setGeneratedLanguage(GeneratedLanguage.JAVA);
}

@AfterEach
void cleanup() {
Utils.deleteDir(outputBuildDir);
}

@Test
void generate_ApiReturnType_WithPlaceHolder() throws Exception {
mappingConfig.setApiReturnType(
"java.util.concurrent.CompletionStage<graphql.execution.DataFetcherResult<{{TYPE}}>>"
);

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

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

String requireChildText = getChildText(
"java.util.concurrent.CompletionStage<graphql.execution.DataFetcherResult" +
"<java.util.List<EventProperty>>>"
);
assertFileContainsElements(
files,
"EventPropertyResolver.java",
requireChildText
);

String requireParentText = getParentText(
"java.util.concurrent.CompletionStage<graphql.execution.DataFetcherResult<Event>>"
);
assertFileContainsElements(files, "EventPropertyResolver.java",
requireParentText
);
}

@Test
void generate_ApiReturnType_And_ApiReturnListType_WithPlaceHolder() throws Exception {
mappingConfig.setApiReturnType(
"java.util.concurrent.CompletionStage<graphql.execution.DataFetcherResult<{{TYPE}}>>"
);
mappingConfig.setApiReturnListType(
"reactor.core.publisher.Mono<graphql.execution.DataFetcherResult<{{TYPE}}>>"
);

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

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

assertFileContainsElements(
files,
"EventPropertyResolver.java",
getChildText(
"reactor.core.publisher.Mono<graphql.execution.DataFetcherResult<EventProperty>>"
)
);

assertFileContainsElements(
files,
"EventPropertyResolver.java",
getParentText(
"java.util.concurrent.CompletionStage<graphql.execution.DataFetcherResult<Event>>"
)
);
}

private String getChildText(String returnType) {
return returnType + " child(EventProperty eventProperty, Integer first, Integer last) throws Exception;";
}

private String getParentText(String returnType) {
return returnType +
" parent(EventProperty eventProperty, EventStatus withStatus, String createdAfter) throws Exception;";
}

private void generate(String path) throws IOException {
new JavaGraphQLCodegen(singletonList(path), outputBuildDir, mappingConfig,
TestUtils.getStaticGeneratedInfo(mappingConfig)).generate();
}

}
Loading