diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt index e5221c6f9..85bd37747 100644 --- a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt @@ -74,6 +74,18 @@ class Kotlin2CodeGenTest { ) else -> emptyMap() }, + typePrefix = + when (testName) { + "dataClassWithPrefix" -> "Dgs" + "inputWithPrefix" -> "Dgs" + else -> "" + }, + typeSuffix = + when (testName) { + "dataClassWithSuffix" -> "Type" + "inputWithSuffix" -> "Type" + else -> "" + }, ), ).generate() diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/DgsClient.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/DgsClient.kt new file mode 100644 index 000000000..11f504c95 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/DgsClient.kt @@ -0,0 +1,14 @@ +package com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected + +import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface +import com.netflix.graphql.dgs.codegen.GraphQLProjection +import com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected.client.QueryProjection +import graphql.language.OperationDefinition +import kotlin.String + +public object DgsClient { + public fun buildQuery(inputValueSerializer: InputValueSerializerInterface? = null, + _projection: QueryProjection.() -> QueryProjection): String = + GraphQLProjection.asQuery(OperationDefinition.Operation.QUERY, + QueryProjection(inputValueSerializer), _projection) +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/DgsConstants.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/DgsConstants.kt new file mode 100644 index 000000000..a1019e011 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/DgsConstants.kt @@ -0,0 +1,29 @@ +package com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected + +import kotlin.String + +public object DgsConstants { + public const val QUERY_TYPE: String = "Query" + + public object QUERY { + public const val TYPE_NAME: String = "Query" + + public const val Search: String = "search" + + public object SEARCH_INPUT_ARGUMENT { + public const val MovieFilter: String = "movieFilter" + } + } + + public object MOVIE { + public const val TYPE_NAME: String = "Movie" + + public const val Title: String = "title" + } + + public object MOVIEFILTER { + public const val TYPE_NAME: String = "MovieFilter" + + public const val TitleFilter: String = "titleFilter" + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/client/MovieProjection.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/client/MovieProjection.kt new file mode 100644 index 000000000..5bf95a6b8 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/client/MovieProjection.kt @@ -0,0 +1,14 @@ +package com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected.client + +import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface +import com.netflix.graphql.dgs.codegen.GraphQLProjection + +public class MovieProjection( + inputValueSerializer: InputValueSerializerInterface? = null, +) : GraphQLProjection(inputValueSerializer) { + public val title: MovieProjection + get() { + field("title") + return this + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/client/QueryProjection.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/client/QueryProjection.kt new file mode 100644 index 000000000..165c9adae --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/client/QueryProjection.kt @@ -0,0 +1,20 @@ +package com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected.client + +import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface +import com.netflix.graphql.dgs.codegen.GraphQLProjection +import com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected.types.DgsMovieFilter +import kotlin.String + +public class QueryProjection( + inputValueSerializer: InputValueSerializerInterface? = null, +) : GraphQLProjection(inputValueSerializer) { + public fun search( + movieFilter: DgsMovieFilter, + _alias: String? = null, + _projection: MovieProjection.() -> MovieProjection, + ): QueryProjection { + field(_alias, "search", MovieProjection(inputValueSerializer), _projection, "movieFilter" to + movieFilter) + return this + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsMovie.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsMovie.kt new file mode 100644 index 000000000..6fbbe5103 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsMovie.kt @@ -0,0 +1,46 @@ +package com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected.types + +import com.fasterxml.jackson.`annotation`.JsonIgnoreProperties +import com.fasterxml.jackson.`annotation`.JsonProperty +import com.fasterxml.jackson.`annotation`.JsonTypeInfo +import com.fasterxml.jackson.databind.`annotation`.JsonDeserialize +import com.fasterxml.jackson.databind.`annotation`.JsonPOJOBuilder +import java.lang.IllegalStateException +import kotlin.String +import kotlin.jvm.JvmName + +/** + * Movies are fun to watch. + * They also work well as examples in GraphQL. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) +@JsonDeserialize(builder = DgsMovie.Builder::class) +public class DgsMovie( + title: () -> String? = titleDefault, +) { + private val __title: () -> String? = title + + @get:JvmName("getTitle") + public val title: String? + get() = __title.invoke() + + public companion object { + private val titleDefault: () -> String? = + { throw IllegalStateException("Field `title` was not requested") } + } + + @JsonPOJOBuilder + @JsonIgnoreProperties("__typename") + public class Builder { + private var title: () -> String? = titleDefault + + @JsonProperty("title") + public fun withTitle(title: String?): Builder = this.apply { + this.title = { title } + } + + public fun build(): DgsMovie = DgsMovie( + title = title, + ) + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsMovieFilter.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsMovieFilter.kt new file mode 100644 index 000000000..29a54aac3 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsMovieFilter.kt @@ -0,0 +1,21 @@ +package com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected.types + +import com.fasterxml.jackson.`annotation`.JsonCreator +import com.fasterxml.jackson.`annotation`.JsonProperty +import com.netflix.graphql.dgs.codegen.GraphQLInput +import kotlin.Any +import kotlin.Pair +import kotlin.String +import kotlin.collections.List + +/** + * Example filter for Movies. + * + * It takes a title and such. + */ +public data class DgsMovieFilter @JsonCreator constructor( + @JsonProperty("titleFilter") + public val titleFilter: String? = default("titleFilter", null), +) : GraphQLInput() { + override fun fields(): List> = listOf("titleFilter" to titleFilter) +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsQuery.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsQuery.kt new file mode 100644 index 000000000..4251afc66 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/expected/types/DgsQuery.kt @@ -0,0 +1,41 @@ +package com.netflix.graphql.dgs.codegen.cases.dataClassWithPrefix.expected.types + +import com.fasterxml.jackson.`annotation`.JsonIgnoreProperties +import com.fasterxml.jackson.`annotation`.JsonProperty +import com.fasterxml.jackson.`annotation`.JsonTypeInfo +import com.fasterxml.jackson.databind.`annotation`.JsonDeserialize +import com.fasterxml.jackson.databind.`annotation`.JsonPOJOBuilder +import java.lang.IllegalStateException +import kotlin.jvm.JvmName + +@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) +@JsonDeserialize(builder = DgsQuery.Builder::class) +public class DgsQuery( + search: () -> DgsMovie? = searchDefault, +) { + private val __search: () -> DgsMovie? = search + + @get:JvmName("getSearch") + public val search: DgsMovie? + get() = __search.invoke() + + public companion object { + private val searchDefault: () -> DgsMovie? = + { throw IllegalStateException("Field `search` was not requested") } + } + + @JsonPOJOBuilder + @JsonIgnoreProperties("__typename") + public class Builder { + private var search: () -> DgsMovie? = searchDefault + + @JsonProperty("search") + public fun withSearch(search: DgsMovie?): Builder = this.apply { + this.search = { search } + } + + public fun build(): DgsQuery = DgsQuery( + search = search, + ) + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/schema.graphql b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/schema.graphql new file mode 100644 index 000000000..09e4f5f93 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/dataClassWithPrefix/schema.graphql @@ -0,0 +1,20 @@ +type Query { + search(movieFilter: MovieFilter!): Movie +} + +""" +Movies are fun to watch. +They also work well as examples in GraphQL. +""" +type Movie { + title: String +} + +""" +Example filter for Movies. + +It takes a title and such. +""" +input MovieFilter { + titleFilter: String +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/DgsClient.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/DgsClient.kt new file mode 100644 index 000000000..1d9f69de7 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/DgsClient.kt @@ -0,0 +1,14 @@ +package com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected + +import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface +import com.netflix.graphql.dgs.codegen.GraphQLProjection +import com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected.client.QueryProjection +import graphql.language.OperationDefinition +import kotlin.String + +public object DgsClient { + public fun buildQuery(inputValueSerializer: InputValueSerializerInterface? = null, + _projection: QueryProjection.() -> QueryProjection): String = + GraphQLProjection.asQuery(OperationDefinition.Operation.QUERY, + QueryProjection(inputValueSerializer), _projection) +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/DgsConstants.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/DgsConstants.kt new file mode 100644 index 000000000..87ac309c0 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/DgsConstants.kt @@ -0,0 +1,23 @@ +package com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected + +import kotlin.String + +public object DgsConstants { + public const val QUERY_TYPE: String = "Query" + + public object QUERY { + public const val TYPE_NAME: String = "Query" + + public const val Movies: String = "movies" + + public object MOVIES_INPUT_ARGUMENT { + public const val Filter: String = "filter" + } + } + + public object MOVIEFILTER { + public const val TYPE_NAME: String = "MovieFilter" + + public const val Genre: String = "genre" + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/client/QueryProjection.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/client/QueryProjection.kt new file mode 100644 index 000000000..e67995eb6 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/client/QueryProjection.kt @@ -0,0 +1,15 @@ +package com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected.client + +import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface +import com.netflix.graphql.dgs.codegen.GraphQLProjection +import com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected.types.DgsMovieFilter + +public class QueryProjection( + inputValueSerializer: InputValueSerializerInterface? = null, +) : GraphQLProjection(inputValueSerializer) { + public fun movies(filter: DgsMovieFilter? = default("filter")): + QueryProjection { + field("movies", "filter" to filter) + return this + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/types/DgsMovieFilter.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/types/DgsMovieFilter.kt new file mode 100644 index 000000000..b6cefadb5 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/types/DgsMovieFilter.kt @@ -0,0 +1,16 @@ +package com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected.types + +import com.fasterxml.jackson.`annotation`.JsonCreator +import com.fasterxml.jackson.`annotation`.JsonProperty +import com.netflix.graphql.dgs.codegen.GraphQLInput +import kotlin.Any +import kotlin.Pair +import kotlin.String +import kotlin.collections.List + +public data class DgsMovieFilter @JsonCreator constructor( + @JsonProperty("genre") + public val genre: String? = default("genre", null), +) : GraphQLInput() { + override fun fields(): List> = listOf("genre" to genre) +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/types/DgsQuery.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/types/DgsQuery.kt new file mode 100644 index 000000000..a9c67afde --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/expected/types/DgsQuery.kt @@ -0,0 +1,43 @@ +package com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected.types + +import com.fasterxml.jackson.`annotation`.JsonIgnoreProperties +import com.fasterxml.jackson.`annotation`.JsonProperty +import com.fasterxml.jackson.`annotation`.JsonTypeInfo +import com.fasterxml.jackson.databind.`annotation`.JsonDeserialize +import com.fasterxml.jackson.databind.`annotation`.JsonPOJOBuilder +import java.lang.IllegalStateException +import kotlin.String +import kotlin.collections.List +import kotlin.jvm.JvmName + +@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) +@JsonDeserialize(builder = DgsQuery.Builder::class) +public class DgsQuery( + movies: () -> List? = moviesDefault, +) { + private val __movies: () -> List? = movies + + @get:JvmName("getMovies") + public val movies: List? + get() = __movies.invoke() + + public companion object { + private val moviesDefault: () -> List? = + { throw IllegalStateException("Field `movies` was not requested") } + } + + @JsonPOJOBuilder + @JsonIgnoreProperties("__typename") + public class Builder { + private var movies: () -> List? = moviesDefault + + @JsonProperty("movies") + public fun withMovies(movies: List?): Builder = this.apply { + this.movies = { movies } + } + + public fun build(): DgsQuery = DgsQuery( + movies = movies, + ) + } +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/schema.graphql b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/schema.graphql new file mode 100644 index 000000000..9c42d7dc2 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/schema.graphql @@ -0,0 +1,7 @@ +type Query { + movies(filter: MovieFilter): [String] +} + +input MovieFilter { + genre: String +} diff --git a/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/test/QueryTest.kt b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/test/QueryTest.kt new file mode 100644 index 000000000..ce2546428 --- /dev/null +++ b/graphql-dgs-codegen-core/src/integTest/kotlin/com/netflix/graphql/dgs/codegen/cases/inputWithPrefix/test/QueryTest.kt @@ -0,0 +1,112 @@ +/* + * + * Copyright 2020 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.test + +import com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected.DgsClient +import com.netflix.graphql.dgs.codegen.cases.inputWithPrefix.expected.types.DgsMovieFilter +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class QueryTest { + + @Test + fun testQueryWithNoFilter() { + val query = DgsClient.buildQuery { + movies() + } + + Assertions.assertEquals( + """{ + | __typename + | movies + |} + | + """.trimMargin(), + query + ) + } + + @Test + fun testQueryWithEmptyFilter() { + val query = DgsClient.buildQuery { + movies(filter = DgsMovieFilter()) + } + + Assertions.assertEquals( + """{ + | __typename + | movies(filter: {}) + |} + | + """.trimMargin(), + query + ) + } + + @Test + fun testQueryWithNullFilter() { + val query = DgsClient.buildQuery { + movies(filter = DgsMovieFilter(genre = null)) + } + + Assertions.assertEquals( + """{ + | __typename + | movies(filter: {genre : null}) + |} + | + """.trimMargin(), + query + ) + } + + @Test + fun testQueryWithFilter() { + val query = DgsClient.buildQuery { + movies(filter = DgsMovieFilter(genre = "horror")) + } + + Assertions.assertEquals( + """{ + | __typename + | movies(filter: {genre : "horror"}) + |} + | + """.trimMargin(), + query + ) + } + + @Test + fun testQueryWithNewline() { + val query = DgsClient.buildQuery { + movies(filter = DgsMovieFilter(genre = "horror\ncomedy")) + } + + Assertions.assertEquals( + """{ + | __typename + | movies(filter: {genre : "horror\ncomedy"}) + |} + | + """.trimMargin(), + query + ) + } +} diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt index 9a28512b4..2c48e6719 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGen.kt @@ -582,6 +582,8 @@ class CodeGenConfig( var addDeprecatedAnnotation: Boolean = false, var trackInputFieldSet: Boolean = false, var generateJSpecifyAnnotations: Boolean = false, + var typePrefix: String = "", + var typeSuffix: String = "", ) { val packageNameClient: String = "$packageName.$subPackageNameClient" diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGenCli.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGenCli.kt index 514fd94b8..3567a9246 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGenCli.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/CodeGenCli.kt @@ -70,6 +70,8 @@ class CodeGenCli : CliktCommand("Generate Java sources for SCHEMA file(s)") { private val shortProjectionNames by option("--short-projection-names").flag() private val generateInterfaceSetters by option("--generate-interface-setters").flag() private val generateDocs by option("--generate-docs").flag() + private val typePrefix by option("--type-prefix").default("") + private val typeSuffix by option("--type-suffix").default("") override fun run() { val inputSchemas = @@ -108,6 +110,8 @@ class CodeGenCli : CliktCommand("Generate Java sources for SCHEMA file(s)") { generateInterfaces = generateInterfaces, generateInterfaceSetters = generateInterfaceSetters, generateDocs = generateDocs, + typePrefix = typePrefix, + typeSuffix = typeSuffix, ) } else { CodeGenConfig( @@ -129,6 +133,8 @@ class CodeGenCli : CliktCommand("Generate Java sources for SCHEMA file(s)") { generateInterfaces = generateInterfaces, generateInterfaceSetters = generateInterfaceSetters, generateDocs = generateDocs, + typePrefix = typePrefix, + typeSuffix = typeSuffix, ) }, ).generate() diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt index b68e10b41..7d04c5acf 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/java/DataTypeGenerator.kt @@ -18,9 +18,12 @@ package com.netflix.graphql.dgs.codegen.generators.java -import com.netflix.graphql.dgs.codegen.* +import com.netflix.graphql.dgs.codegen.CodeGenConfig +import com.netflix.graphql.dgs.codegen.CodeGenResult +import com.netflix.graphql.dgs.codegen.filterSkipped import com.netflix.graphql.dgs.codegen.generators.shared.SiteTarget import com.netflix.graphql.dgs.codegen.generators.shared.applyDirectivesJava +import com.netflix.graphql.dgs.codegen.shouldSkip import com.palantir.javapoet.ClassName import com.palantir.javapoet.CodeBlock import com.palantir.javapoet.FieldSpec @@ -81,7 +84,7 @@ class DataTypeGenerator( logger.info("Generating data type {}", definition.name) - val name = definition.name + val name = config.typePrefix + definition.name + config.typeSuffix val unionTypes = document .getDefinitionsOfType(UnionTypeDefinition::class.java) diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt index 6da680fd5..ebd723764 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinDataTypeGenerator.kt @@ -186,9 +186,11 @@ abstract class AbstractKotlinDataTypeGenerator( description: Description? = null, directives: List = emptyList(), ): CodeGenResult { + val typeName = config.typePrefix + name + config.typeSuffix + val kotlinType = TypeSpec - .classBuilder(name) + .classBuilder(typeName) .addOptionalGeneratedAnnotation(config) if (config.implementSerializable) { diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinTypeUtils.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinTypeUtils.kt index 0bf282184..b2668ff37 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinTypeUtils.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin/KotlinTypeUtils.kt @@ -157,6 +157,8 @@ class KotlinTypeUtils( return commonScalars.getValue(name) } + val typeName = config.typePrefix + name + config.typeSuffix + return when (name) { STRING.simpleName -> STRING "StringValue" -> STRING @@ -168,7 +170,7 @@ class KotlinTypeUtils( "BooleanValue" -> BOOLEAN "ID" -> STRING "IDValue" -> STRING - else -> "${config.packageNameTypes}.$name".toKtTypeName() + else -> "${config.packageNameTypes}.$typeName".toKtTypeName() } } diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt index c7adcf46a..40daefa18 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2DataTypes.kt @@ -99,6 +99,7 @@ fun generateKotlin2DataTypes( val fields = fieldDefinitions.map(::KotlinFieldInfo) fun type(field: KotlinFieldInfo) = typeLookup.findReturnType(config.packageNameTypes, field.definition.type) + val typeName = config.typePrefix + typeDefinition.name + config.typeSuffix // get a list of fields to override val overrideFields = typeLookup.overrideFields(implementedInterfaces) @@ -129,7 +130,7 @@ fun generateKotlin2DataTypes( ).build() // create a builder for this class; default to lambda that throws if accessed - val builderClassName = ClassName(config.packageNameTypes, typeDefinition.name, "Builder") + val builderClassName = ClassName(config.packageNameTypes, typeName, "Builder") val builder = TypeSpec .classBuilder("Builder") @@ -166,13 +167,13 @@ fun generateKotlin2DataTypes( .addFunction( FunSpec .builder("build") - .returns(typeDefinition.name.toKtTypeName()) + .returns(typeName.toKtTypeName()) .addCode( fields.let { fs -> val builder = CodeBlock.builder().add( "return %T(\n", - ClassName(config.packageNameTypes, typeDefinition.name), + ClassName(config.packageNameTypes, typeName), ) fs.forEach { f -> builder.add(" %N = %N,\n", f.kotlinName, f.kotlinName) } builder.add(")").build() @@ -183,7 +184,7 @@ fun generateKotlin2DataTypes( // create the data class val typeSpec = TypeSpec - .classBuilder(typeDefinition.name) + .classBuilder(typeName) .addOptionalGeneratedAnnotation(config) // add docs if available .apply { diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt index 8280c9c57..2b22b9df4 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/GenerateKotlin2InputTypes.kt @@ -71,7 +71,8 @@ fun generateKotlin2InputTypes( fun type(field: InputValueDefinition) = typeLookup.findReturnType(config.packageNameTypes, field.type) - val typeName = ClassName(config.packageNameTypes, inputDefinition.name) + val name = config.typePrefix + inputDefinition.name + config.typeSuffix + val typeName = ClassName(config.packageNameTypes, name) // create the input class val typeSpec = diff --git a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/Kotlin2TypeLookup.kt b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/Kotlin2TypeLookup.kt index 6d8f2d885..66bdd3007 100644 --- a/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/Kotlin2TypeLookup.kt +++ b/graphql-dgs-codegen-core/src/main/kotlin/com/netflix/graphql/dgs/codegen/generators/kotlin2/Kotlin2TypeLookup.kt @@ -69,6 +69,9 @@ class Kotlin2TypeLookup( "Subscription" to OperationDefinition.Operation.SUBSCRIPTION, ) + private val typePrefix = config.typePrefix + private val typeSuffix = config.typeSuffix + /** * A set of object type names defined in the document */ @@ -301,6 +304,8 @@ class Kotlin2TypeLookup( return builtinType } - return "$packageName.${typeName.name}".toKtTypeName() + val name = typePrefix + typeName.name + typeSuffix + + return "$packageName.$name".toKtTypeName() } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt index 135e98a6a..aaab8ada5 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/CodeGenTest.kt @@ -7061,4 +7061,38 @@ It takes a title and such. dataTypes[0].writeTo(System.out) assertCompilesJava(dataTypes) } + + @Test + fun `Generate Java data types with prefix and suffix`() { + val schema = + """ + type Query { + person: Person + } + + type Person { + name: String + age: Int + } + """.trimIndent() + + val config = + CodeGenConfig( + schemas = setOf(schema), + packageName = "com.netflix.test", + language = Language.JAVA, + typePrefix = "My", + typeSuffix = "Type", + ) + + val codeGen = CodeGen(config) + val result = codeGen.generate() + + val dataTypes = result.javaDataTypes + assertThat(dataTypes).hasSize(1) + + val personFile = dataTypes.find { it.typeSpec().name() == "MyPersonType" } + assertThat(personFile).isNotNull + assertThat(personFile!!.toString()).contains("public class MyPersonType") + } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt index 9b20f0efc..0903e5f83 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/Kotlin2CodeGenTest.kt @@ -140,4 +140,46 @@ class Kotlin2CodeGenTest { assertCompilesKotlin(result.kotlinEnumTypes) } + + @Test + fun `Generate data types with prefix and suffix`() { + val schema = + """ + type Query { + person: Person + } + + type Person { + firstname: String + lastname: String + } + """.trimIndent() + + val config = + CodeGenConfig( + schemas = setOf(schema), + packageName = BASE_PACKAGE_NAME, + language = Language.KOTLIN, + typePrefix = "My", + typeSuffix = "Type", + generateKotlinNullableClasses = true, + ) + + val codeGen = CodeGen(config) + val result = codeGen.generate() + + val dataTypes = result.kotlinDataTypes + assertThat(dataTypes.size).isEqualTo(2) + + val personType = dataTypes.find { it.name == "MyPersonType" } + assertThat(personType).isNotNull + assertThat(personType!!.name).isEqualTo("MyPersonType") + assertThat(personType.packageName).isEqualTo(TYPES_PACKAGE_NAME) + val type = personType.members[0] as TypeSpec + + assertThat(type.propertySpecs.size).isEqualTo(4) + assertThat(type.propertySpecs).extracting("name").contains("firstname", "lastname") + + assertCompilesKotlin(dataTypes) + } } diff --git a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt index cf7659ce9..3975d17ab 100644 --- a/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt +++ b/graphql-dgs-codegen-core/src/test/kotlin/com/netflix/graphql/dgs/codegen/KotlinCodeGenTest.kt @@ -5110,4 +5110,43 @@ It takes a title and such. assertCompilesKotlin(dataTypes) } + + @Test + fun `Generate Kotlin data types with prefix and suffix`() { + val schema = + """ + type Query { + person: Person + } + + type Person { + firstname: String + lastname: String + } + """.trimIndent() + + val config = + CodeGenConfig( + schemas = setOf(schema), + packageName = BASE_PACKAGE_NAME, + language = Language.KOTLIN, + typePrefix = "My", + typeSuffix = "Type", + ) + + val codeGen = CodeGen(config) + val result = codeGen.generate() + + val dataTypes = result.kotlinDataTypes + assertThat(dataTypes.size).isEqualTo(1) + assertThat(dataTypes[0].name).isEqualTo("MyPersonType") + assertThat(dataTypes[0].packageName).isEqualTo(TYPES_PACKAGE_NAME) + val type = dataTypes[0].members[0] as TypeSpec + + assertThat(type.modifiers).contains(KModifier.DATA) + assertThat(type.propertySpecs.size).isEqualTo(2) + assertThat(type.propertySpecs).extracting("name").contains("firstname", "lastname") + + assertCompilesKotlin(dataTypes) + } }