Skip to content

Commit

Permalink
add support for default Currnecy value
Browse files Browse the repository at this point in the history
  • Loading branch information
dwilkolek committed Sep 8, 2024
1 parent 57b2e1e commit 4cef9e5
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
package com.netflix.graphql.dgs.codegen

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Assertions.fail
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import java.nio.file.Files
Expand Down Expand Up @@ -62,6 +64,9 @@ class Kotlin2CodeGenTest {
"inputWithDefaultBigDecimal" -> mapOf(
"Decimal" to "java.math.BigDecimal"
)
"inputWithDefaultCurrency" -> mapOf(
"Currency" to "java.util.Currency"
)
else -> emptyMap()
}
)
Expand Down Expand Up @@ -101,6 +106,11 @@ class Kotlin2CodeGenTest {
assertCompilesKotlin(codeGenResult)
}

@Test
fun `assert updateExpected is false`() {
Assertions.assertFalse(updateExpected)
}

companion object {

@Suppress("unused")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.netflix.graphql.dgs.codegen.cases.inputWithDefaultCurrency.expected

import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface
import com.netflix.graphql.dgs.codegen.GraphQLProjection
import com.netflix.graphql.dgs.codegen.cases.inputWithDefaultCurrency.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)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.netflix.graphql.dgs.codegen.cases.inputWithDefaultCurrency.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 Orders: String = "orders"

public object ORDERS_INPUT_ARGUMENT {
public const val Filter: String = "filter"
}
}

public object ORDERFILTER {
public const val TYPE_NAME: String = "OrderFilter"

public const val Value: String = "value"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.netflix.graphql.dgs.codegen.cases.inputWithDefaultCurrency.expected.client

import com.netflix.graphql.dgs.client.codegen.InputValueSerializerInterface
import com.netflix.graphql.dgs.codegen.GraphQLProjection
import com.netflix.graphql.dgs.codegen.cases.inputWithDefaultCurrency.expected.types.OrderFilter

public class QueryProjection(
inputValueSerializer: InputValueSerializerInterface? = null,
) : GraphQLProjection(inputValueSerializer) {
public fun orders(filter: OrderFilter? = default<QueryProjection, OrderFilter?>("filter")):
QueryProjection {
field("orders", "filter" to filter)
return this
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.netflix.graphql.dgs.codegen.cases.inputWithDefaultCurrency.expected.types

import com.fasterxml.jackson.`annotation`.JsonCreator
import com.fasterxml.jackson.`annotation`.JsonProperty
import com.netflix.graphql.dgs.codegen.GraphQLInput
import java.util.Currency
import kotlin.Any
import kotlin.Pair
import kotlin.String
import kotlin.collections.List

public class OrderFilter @JsonCreator constructor(
@JsonProperty("value")
public val `value`: Currency = default<OrderFilter, Currency>("value",
java.util.Currency.getInstance("USD")),
) : GraphQLInput() {
override fun fields(): List<Pair<String, Any?>> = listOf("value" to `value`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.netflix.graphql.dgs.codegen.cases.inputWithDefaultCurrency.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

@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonDeserialize(builder = Query.Builder::class)
public class Query(
orders: () -> String? = ordersDefault,
) {
private val __orders: () -> String? = orders

@get:JvmName("getOrders")
public val orders: String?
get() = __orders.invoke()

public companion object {
private val ordersDefault: () -> String? =
{ throw IllegalStateException("Field `orders` was not requested") }
}

@JsonPOJOBuilder
@JsonIgnoreProperties("__typename")
public class Builder {
private var orders: () -> String? = ordersDefault

@JsonProperty("orders")
public fun withOrders(orders: String?): Builder = this.apply {
this.orders = { orders }
}

public fun build(): Query = Query(
orders = orders,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
scalar Currency

type Query {
orders(filter: OrderFilter): String
}

input OrderFilter {
value: Currency! = "USD"
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import java.io.Serializable
import java.math.BigDecimal
import java.util.Arrays
import java.util.Collections
import java.util.Currency
import java.util.Locale
import java.util.Objects
import javax.lang.model.element.Modifier
Expand Down Expand Up @@ -155,6 +156,7 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy
private val logger: Logger = LoggerFactory.getLogger(InputTypeGenerator::class.java)
private val LOCALE: ClassName = ClassName.get(Locale::class.java)
private val BIG_DECIMAL: ClassName = ClassName.get(BigDecimal::class.java)
private val CURRENCY: ClassName = ClassName.get(Currency::class.java)
}

fun generate(
Expand Down Expand Up @@ -191,11 +193,19 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy
type: JavaTypeName,
inputTypeDefinitions: List<InputObjectTypeDefinition>
): CodeBlock {
if (type == LOCALE) {
return localeCodeBlock(value, type)
} else if (type == BIG_DECIMAL) {
return bigDecimalCodeBlock(value, type)
return when (type) {
LOCALE -> localeCodeBlock(value, type)
BIG_DECIMAL -> bigDecimalCodeBlock(value, type)
CURRENCY -> currencyCodeBlock(value, type)
else -> defaultCodeBlock(value, type, inputTypeDefinitions)
}
}

private fun defaultCodeBlock(
value: Value<out Value<*>>,
type: JavaTypeName,
inputTypeDefinitions: List<InputObjectTypeDefinition>
): CodeBlock {
return when (value) {
is BooleanValue -> CodeBlock.of("\$L", value.isValue)
is IntValue -> CodeBlock.of("\$L", value.value)
Expand Down Expand Up @@ -256,6 +266,13 @@ class InputTypeGenerator(config: CodeGenConfig, document: Document) : BaseDataTy
}
}

private fun currencyCodeBlock(value: Value<out Value<*>>, type: JavaTypeName): CodeBlock {
return when (value) {
is StringValue -> CodeBlock.of("\$T.getInstance(\$S)", CURRENCY, value.value)
else -> error("$type cannot be created from $value, expected String value")
}
}

private val JavaTypeName.className: ClassName
get() = when (this) {
is ClassName -> this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ fun generateKotlinCode(
): CodeBlock {
return checkAndGetLocaleCodeBlock(value, type)
?: checkAndGetBigDecimalCodeBlock(value, type)
?: checkAndGetCurrencyCodeBlock(value, type)
?: when (value) {
is BooleanValue -> CodeBlock.of("%L", value.isValue)
is IntValue -> CodeBlock.of("%L", value.value)
Expand Down Expand Up @@ -105,6 +106,15 @@ private fun checkAndGetBigDecimalCodeBlock(value: Value<Value<*>>, type: TypeNam
} else null
}

private fun checkAndGetCurrencyCodeBlock(value: Value<Value<*>>, type: TypeName): CodeBlock? {
return if (type.className.canonicalName == "java.util.Currency") {
when (value) {
is StringValue -> CodeBlock.of("%L", "java.util.Currency.getInstance(\"${value.value}\")")
else -> error("$type cannot be created from $value, expected String value")
}
} else null
}

private val TypeName.className: ClassName
get() = when (this) {
is ClassName -> this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5040,4 +5040,50 @@ It takes a title and such.
).generate()
assertThat(result.javaDataTypes[0].typeSpec.fieldSpecs[1].type.toString() == "java.lang.String")
}

@Test
fun `The default value for Currency should be overridden and wrapped`() {
val schema = """
scalar Currency
input MyInput {
currency: Currency! = "USD"
}
""".trimIndent()

val codeGenResult = CodeGen(
CodeGenConfig(
schemas = setOf(schema),
packageName = basePackageName,
generateClientApi = true,
typeMapping = mapOf("Decimal" to "java.math.BigDecimal")
)
).generate()

val dataTypes = codeGenResult.javaDataTypes
assertThat(dataTypes[0].typeSpec.fieldSpecs[0].initializer.toString()).isEqualTo("java.util.Currency.getInstance(\"USD\")")
assertCompilesJava(dataTypes)
}

@Test
fun `Codegen should fail with nice message given unsupported default value provided for Currency`() {
val schema = """
scalar Currency
input MyInput {
currency: Currency! = 1
}
""".trimIndent()

assertThatThrownBy {
CodeGen(
CodeGenConfig(
schemas = setOf(schema),
packageName = basePackageName,
generateClientApi = true,
typeMapping = mapOf("Currency" to "java.util.Currency")
)
).generate()
}.hasMessage("java.util.Currency cannot be created from IntValue{value=1}, expected String value")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4176,4 +4176,51 @@ It takes a title and such.
assertThat(superinterfaces).contains("com.netflix.graphql.dgs.codegen.tests.generated.types.A")
assertThat(superinterfaces).contains("com.netflix.graphql.dgs.codegen.tests.generated.types.B")
}

@Test
fun `The default value for Currency should be overridden and wrapped`() {
val schema = """
scalar Currency
input MyInput {
currency: Currency! = "USD"
}
""".trimIndent()

val codeGenResult = CodeGen(
CodeGenConfig(
schemas = setOf(schema),
packageName = basePackageName,
language = Language.KOTLIN,
typeMapping = mapOf("Currency" to "java.util.Currency")
)
).generate()

val dataTypes = codeGenResult.kotlinDataTypes
val typeSpec = dataTypes[0].members[0] as TypeSpec
assertThat(typeSpec.primaryConstructor!!.parameters[0].defaultValue.toString()).isEqualTo("java.util.Currency.getInstance(\"USD\")")
assertCompilesKotlin(dataTypes)
}

@Test
fun `Codegen should fail with nice message given unsupported default value provided for Currency`() {
val schema = """
scalar Currency
input MyInput {
currency: Currency! = 1
}
""".trimIndent()

assertThatThrownBy {
CodeGen(
CodeGenConfig(
schemas = setOf(schema),
packageName = basePackageName,
language = Language.KOTLIN,
typeMapping = mapOf("Currency" to "java.util.Currency")
)
).generate()
}.hasMessage("java.util.Currency cannot be created from IntValue{value=1}, expected String value")
}
}

0 comments on commit 4cef9e5

Please sign in to comment.