Skip to content

Commit

Permalink
Merge branch 'ExpediaGroup:master' into ktor-version-3
Browse files Browse the repository at this point in the history
  • Loading branch information
ronjunevaldoz authored Nov 14, 2024
2 parents 6935a22 + 275e2ab commit 60bf100
Show file tree
Hide file tree
Showing 19 changed files with 310 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Expedia, Inc
* Copyright 2024 Expedia, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,18 +14,10 @@
* limitations under the License.
*/

package com.expediagroup.graphql.dataloader.instrumentation.extensions
package com.expediagroup.graphql.generator.annotations

import graphql.execution.FieldValueInfo

internal fun List<FieldValueInfo>.getExpectedStrategyCalls(): Int {
var count = 0
this.forEach { fieldValueInfo ->
when (fieldValueInfo.completeValueType) {
FieldValueInfo.CompleteValueType.OBJECT -> count++
FieldValueInfo.CompleteValueType.LIST -> count += fieldValueInfo.fieldValueInfos.getExpectedStrategyCalls()
else -> count += 0
}
}
return count
}
/**
* Do not add "Input" Suffix for input types.
*/
@Target(AnnotationTarget.CLASS)
annotation class GraphQLSkipInputSuffix
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.expediagroup.graphql.generator.internal.extensions

import com.expediagroup.graphql.generator.annotations.GraphQLSkipInputSuffix
import com.expediagroup.graphql.generator.exceptions.CouldNotGetNameOfKClassException
import com.expediagroup.graphql.generator.hooks.SchemaGeneratorHooks
import com.expediagroup.graphql.generator.internal.filters.functionFilters
Expand All @@ -28,6 +29,7 @@ import kotlin.reflect.KProperty
import kotlin.reflect.KVisibility
import kotlin.reflect.full.declaredMemberFunctions
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.findParameterByName
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.memberFunctions
Expand Down Expand Up @@ -84,12 +86,13 @@ internal fun KClass<*>.isListType(isDirective: Boolean = false): Boolean = this.

@Throws(CouldNotGetNameOfKClassException::class)
internal fun KClass<*>.getSimpleName(isInputClass: Boolean = false): String {
val skipSuffix = this.findAnnotation<GraphQLSkipInputSuffix>() != null
val name = this.getGraphQLName()
?: this.simpleName
?: throw CouldNotGetNameOfKClassException(this)

return when {
isInputClass -> if (name.endsWith(INPUT_SUFFIX, true)) name else "$name$INPUT_SUFFIX"
isInputClass && !skipSuffix -> if (name.endsWith(INPUT_SUFFIX, true)) name else "$name$INPUT_SUFFIX"
else -> name
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.expediagroup.graphql.generator.internal.extensions

import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
import com.expediagroup.graphql.generator.annotations.GraphQLName
import com.expediagroup.graphql.generator.annotations.GraphQLSkipInputSuffix
import com.expediagroup.graphql.generator.annotations.GraphQLUnion
import com.expediagroup.graphql.generator.exceptions.CouldNotGetNameOfKClassException
import com.expediagroup.graphql.generator.hooks.NoopSchemaGeneratorHooks
Expand Down Expand Up @@ -74,6 +75,9 @@ open class KClassExtensionsTest {

class MyClassInput

@GraphQLSkipInputSuffix
class MyTestClassSkipSuffix

@GraphQLName("MyClassRenamedInput")
class MyClassCustomNameInput

Expand Down Expand Up @@ -330,6 +334,11 @@ open class KClassExtensionsTest {
assertEquals("MyClassInput", MyClassInput::class.getSimpleName(true))
}

@Test
fun `test input class name with skipped suffix`() {
assertEquals("MyTestClassSkipSuffix", MyTestClassSkipSuffix::class.getSimpleName(true))
}

@Test
fun `test input class name with GraphQLName`() {
assertEquals("MyTestClassRenamedInput", MyTestClassCustomName::class.getSimpleName(true))
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ graphql-java = "22.1"
graalvm = "0.10.2"
jackson = "2.17.1"
# kotlin version has to match the compile-testing compiler version
kotlin = "1.9.24"
kotlin = "2.0.0"
kotlinx-benchmark = "0.4.11"
kotlinx-coroutines = "1.8.1"
# TODO kotlin 1.9 upgrade: fix GraphQLTestUtils and GenerateKotlinxClientIT
Expand All @@ -29,7 +29,7 @@ spring-boot = "3.2.7"
commons-codec = { strictly = "[1.13, 2[", prefer = "1.16.0" }

# test dependencies
compile-testing = "0.5.0"
compile-testing = "0.5.1"
icu = "75.1"
junit = "5.10.2"
logback = "1.5.6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,21 @@ class GraphQLClientGenerator(
operationTypeSpec.addType(graphQLResponseTypeSpec)

val polymorphicTypes = mutableListOf<ClassName>()
// prevent colocating duplicated type specs in the same packageName
val typeSpecByPackageName = mutableSetOf<String>()
for ((superClassName, implementations) in context.polymorphicTypes) {
polymorphicTypes.add(superClassName)
val polymorphicTypeSpec = FileSpec.builder(superClassName.packageName, superClassName.simpleName)
for (implementation in implementations) {
polymorphicTypes.add(implementation)
context.typeSpecs[implementation]?.let { typeSpec ->
polymorphicTypeSpec.addType(typeSpec)
if (
typeSpec.name != null &&
!typeSpecByPackageName.contains("${superClassName.packageName}.${typeSpec.name}")
) {
polymorphicTypeSpec.addType(typeSpec)
typeSpecByPackageName.add("${superClassName.packageName}.${typeSpec.name}")
}
}
}
fileSpecs.add(polymorphicTypeSpec.build())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,11 @@ private fun updateImplementationTypeSpecWithSuperInformation(
} else {
property
}
builder.addProperty(updatedProperty)

// add the property to the type builder only if the property was actually uptaded.
if (updatedProperty != property) {
builder.addProperty(updatedProperty)
}
constructor.addParameter(updatedProperty.name, updatedProperty.type)
}
builder.primaryConstructor(constructor.build())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
query UnionSameSelections {
message1 {
__typename
... on ProductRatingLink {
link {
text
}
action {
text
}
}
... on EGDSPlainText {
text
}
}
message2 {
__typename
... on EGDSParagraph {
text
}
... on EGDSPlainText {
text
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.expediagroup.graphql.generated

import com.expediagroup.graphql.client.Generated
import com.expediagroup.graphql.client.types.GraphQLClientRequest
import com.expediagroup.graphql.generated.unionsameselections.ProductRatingSupportingMessage
import com.expediagroup.graphql.generated.unionsameselections.ProductSupportingMessage
import com.fasterxml.jackson.`annotation`.JsonProperty
import kotlin.String
import kotlin.collections.List
import kotlin.reflect.KClass

public const val UNION_SAME_SELECTIONS: String =
"query UnionSameSelections {\n message1 {\n __typename\n ... on ProductRatingLink {\n link {\n text\n }\n action {\n text\n }\n }\n ... on EGDSPlainText {\n text\n }\n }\n message2 {\n __typename\n ... on EGDSParagraph {\n text\n }\n ... on EGDSPlainText {\n text\n }\n }\n}"

@Generated
public class UnionSameSelections : GraphQLClientRequest<UnionSameSelections.Result> {
override val query: String = UNION_SAME_SELECTIONS

override val operationName: String = "UnionSameSelections"

override fun responseType(): KClass<UnionSameSelections.Result> =
UnionSameSelections.Result::class

@Generated
public data class Result(
@get:JsonProperty(value = "message1")
public val message1: List<ProductRatingSupportingMessage>,
@get:JsonProperty(value = "message2")
public val message2: List<ProductSupportingMessage>,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.expediagroup.graphql.generated.unionsameselections

import com.expediagroup.graphql.client.Generated
import com.fasterxml.jackson.`annotation`.JsonProperty
import kotlin.String

@Generated
public data class EGDSProductRatingShowTextAction(
@get:JsonProperty(value = "text")
public val text: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.expediagroup.graphql.generated.unionsameselections

import com.expediagroup.graphql.client.Generated
import com.fasterxml.jackson.`annotation`.JsonProperty
import kotlin.String

@Generated
public data class EGDSStandardLink(
@get:JsonProperty(value = "text")
public val text: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.expediagroup.graphql.generated.unionsameselections

import com.expediagroup.graphql.client.Generated
import com.fasterxml.jackson.`annotation`.JsonProperty
import com.fasterxml.jackson.`annotation`.JsonSubTypes
import com.fasterxml.jackson.`annotation`.JsonTypeInfo
import com.fasterxml.jackson.`annotation`.JsonTypeInfo.As.PROPERTY
import com.fasterxml.jackson.`annotation`.JsonTypeInfo.Id.NAME
import kotlin.String

@Generated
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "__typename",
defaultImpl = DefaultProductRatingSupportingMessageImplementation::class,
)
@JsonSubTypes(value = [com.fasterxml.jackson.annotation.JsonSubTypes.Type(value =
ProductRatingLink::class,
name="ProductRatingLink"),com.fasterxml.jackson.annotation.JsonSubTypes.Type(value =
EGDSPlainText::class, name="EGDSPlainText")])
public interface ProductRatingSupportingMessage

@Generated
public data class ProductRatingLink(
@get:JsonProperty(value = "link")
public val link: EGDSStandardLink,
@get:JsonProperty(value = "action")
public val action: EGDSProductRatingShowTextAction,
) : ProductRatingSupportingMessage

@Generated
public data class EGDSPlainText(
@get:JsonProperty(value = "text")
public val text: String,
) : ProductRatingSupportingMessage,
ProductSupportingMessage

/**
* Fallback ProductRatingSupportingMessage implementation that will be used when unknown/unhandled
* type is encountered.
*/
@Generated
public class DefaultProductRatingSupportingMessageImplementation() : ProductRatingSupportingMessage
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.expediagroup.graphql.generated.unionsameselections

import com.expediagroup.graphql.client.Generated
import com.fasterxml.jackson.`annotation`.JsonProperty
import com.fasterxml.jackson.`annotation`.JsonSubTypes
import com.fasterxml.jackson.`annotation`.JsonTypeInfo
import com.fasterxml.jackson.`annotation`.JsonTypeInfo.As.PROPERTY
import com.fasterxml.jackson.`annotation`.JsonTypeInfo.Id.NAME
import kotlin.String

@Generated
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "__typename",
defaultImpl = DefaultProductSupportingMessageImplementation::class,
)
@JsonSubTypes(value = [com.fasterxml.jackson.annotation.JsonSubTypes.Type(value =
EGDSParagraph::class,
name="EGDSParagraph"),com.fasterxml.jackson.annotation.JsonSubTypes.Type(value =
EGDSPlainText::class, name="EGDSPlainText")])
public interface ProductSupportingMessage

@Generated
public data class EGDSParagraph(
@get:JsonProperty(value = "text")
public val text: String,
) : ProductSupportingMessage

/**
* Fallback ProductSupportingMessage implementation that will be used when unknown/unhandled type is
* encountered.
*/
@Generated
public class DefaultProductSupportingMessageImplementation() : ProductSupportingMessage
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ type Query {
unionQuery: BasicUnion!
"Query to test doc strings"
docQuery: DocObject!
message1: [ProductRatingSupportingMessage!]!
message2: [ProductSupportingMessage!]!
}
"Wrapper that holds all supported scalar types"
type ScalarWrapper {
Expand Down Expand Up @@ -213,3 +215,26 @@ input ScalarWrapperInput {
"List of custom scalar Locales"
listLocale: [Locale!]!
}

interface EGDSText {
text: String!
}
type EGDSPlainText implements EGDSText {
text: String!
}
type ProductRatingLink {
action: EGDSProductRatingShowTextAction!
link: EGDSStandardLink!
}
type EGDSProductRatingShowTextAction {
text: String!
}
type EGDSStandardLink implements EGDSText {
text: String!
}
union ProductRatingSupportingMessage = EGDSPlainText | ProductRatingLink
union ProductSupportingMessage = EGDSParagraph | EGDSPlainText

type EGDSParagraph implements EGDSText {
text: String!
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ internal class MetadataCapturingDataFetcherFactoryProvider(val scanResult: ScanR
// we need to capture enums
private val additionalTypes: MutableSet<String> = HashSet()

@OptIn(ExperimentalStdlibApi::class)
override fun functionDataFetcherFactory(target: Any?, kClass: KClass<*>, kFunction: KFunction<*>): DataFetcherFactory<Any?> {
val methodName = kFunction.javaMethod!!.name
val classMetadata = reflectMetadataMap.getOrPut(kClass.java.name) { MutableClassMetadata(name = kClass.java.name, methods = ArrayList()) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import com.expediagroup.graphql.plugin.graalvm.MetadataCapturingDataFetcherFactoryProvider
import com.expediagroup.graphql.plugin.graalvm.enums.EnumQuery
import io.github.classgraph.ClassGraph
import io.github.classgraph.ScanResult
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import kotlin.reflect.KFunction

class MetadataCapturingDataFetcherFactoryProviderTest {

private lateinit var scanResult: ScanResult
private lateinit var provider: MetadataCapturingDataFetcherFactoryProvider

@BeforeEach
fun setup() {
scanResult = ClassGraph().enableAllInfo().acceptPackages("com.expediagroup.graphql.plugin.graalvm").scan()
provider = MetadataCapturingDataFetcherFactoryProvider(scanResult, listOf("com.expediagroup.graphql.plugin.graalvm"))

val kClass = EnumQuery::class
val kFunction = kClass.members.find { it.name == "enumArgQuery" } as KFunction<*>
provider.functionDataFetcherFactory(null, kClass, kFunction)
}

@Test
fun `reflectMetadata should not be empty`() {
val metadata = provider.reflectMetadata()

Assertions.assertNotNull(metadata)
Assertions.assertTrue(metadata.isNotEmpty(), "Reflect metadata should not be empty")
Assertions.assertEquals(listOf("com.expediagroup.graphql.plugin.graalvm"), provider.supportedPackages)
}
}
Loading

0 comments on commit 60bf100

Please sign in to comment.