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

Add support for default Currency value #742

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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 @@ -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`() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice add! ⭐

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")
}
}
Loading