From a2c86bd21b6213f9831b87b31dabeac275412b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odin=20Asbj=C3=B8rnsen?= Date: Fri, 18 Apr 2025 20:38:50 +0200 Subject: [PATCH] Add GraphQLIgnore annotation Add GraphQLIgnore to be able to ignore fields, classes and interfaces --- .../execution/processor/ApolloProcessor.kt | 1 + .../processor/codegen/KotlinSymbols.kt | 1 + .../execution/processor/definitions.kt | 30 +++++++------------ .../execution/annotation/GraphQLIgnore.kt | 5 ++++ tests/federation/src/main/kotlin/graphql.kt | 11 +++++-- 5 files changed, 27 insertions(+), 21 deletions(-) create mode 100644 apollo-execution-runtime/src/commonMain/kotlin/com/apollographql/execution/annotation/GraphQLIgnore.kt diff --git a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/ApolloProcessor.kt b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/ApolloProcessor.kt index 177a6d54..4ac9c331 100644 --- a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/ApolloProcessor.kt +++ b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/ApolloProcessor.kt @@ -53,6 +53,7 @@ class ApolloProcessor( done = true val query = getRootSymbol(resolver, KotlinSymbols.GraphQLQuery.canonicalName) + if (query == null) { logger.error("No '@GraphQLQuery' class found") return emptyList() diff --git a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/KotlinSymbols.kt b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/KotlinSymbols.kt index 07621520..8c477cb3 100644 --- a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/KotlinSymbols.kt +++ b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/KotlinSymbols.kt @@ -21,6 +21,7 @@ internal object KotlinSymbols { val GraphQLQuery = ClassName(annotationPackageName, "GraphQLQuery") val GraphQLMutation = ClassName(annotationPackageName, "GraphQLMutation") val GraphQLSubscription = ClassName(annotationPackageName, "GraphQLSubscription") + val GraphQLIgnore = ClassName(annotationPackageName, "GraphQLIgnore") val AstDocument = ClassName(apolloAstPackageName, "GQLDocument") val AstScalarTypeDefinition = ClassName(apolloAstPackageName, "GQLScalarTypeDefinition") diff --git a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/definitions.kt b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/definitions.kt index 4e887581..49231e6f 100644 --- a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/definitions.kt +++ b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/definitions.kt @@ -1,6 +1,7 @@ package com.apollographql.execution.processor import com.apollographql.apollo.ast.* +import com.apollographql.execution.processor.codegen.KotlinSymbols.GraphQLIgnore import com.apollographql.execution.processor.sir.* import com.apollographql.execution.processor.sir.Instantiation import com.apollographql.execution.processor.sir.SirArgumentDefinition @@ -19,10 +20,7 @@ import com.apollographql.execution.processor.sir.SirObjectDefinition import com.apollographql.execution.processor.sir.SirType import com.apollographql.execution.processor.sir.SirTypeDefinition import com.apollographql.execution.processor.sir.SirUnionDefinition -import com.google.devtools.ksp.getAllSuperTypes -import com.google.devtools.ksp.getDeclaredProperties -import com.google.devtools.ksp.isConstructor -import com.google.devtools.ksp.isPublic +import com.google.devtools.ksp.* import com.google.devtools.ksp.processing.KSPLogger import com.google.devtools.ksp.symbol.* @@ -172,11 +170,6 @@ private class TypeDefinitionContext( } usedTypeNames.add(name) - if (declaration.typeParameters.isNotEmpty()) { - logger.error("Generic classes are not supported") - return null - } - if (declaration is KSTypeAlias) { return declaration.toSirScalarDefinition(qualifiedName) } @@ -378,10 +371,13 @@ private class TypeDefinitionContext( logger.error("Cannot map to a GraphQL output type", this) return null } - val usedNames = mutableSetOf() val allFields = declarations.filter { it.isPublic() }.mapNotNull { val name = it.graphqlName() + val hasIsIgnoreAnnotation = this.annotations.any { + it.annotationType.resolve().declaration.qualifiedName?.asString() == "com.apollographql.execution.annotation.GraphQLIgnore" + } + if (hasIsIgnoreAnnotation) return@mapNotNull null if (usedNames.contains(name)) { logger.error("Duplicate field '$name'. Either rename the declaration or use @GraphQLName.", it) return@mapNotNull null @@ -434,11 +430,6 @@ private class TypeDefinitionContext( } ClassKind.INTERFACE -> { - if (!modifiers.contains(Modifier.SEALED)) { - logger.error("Interfaces and unions must be sealed interfaces", this) - return null - } - getSealedSubclasses().forEach { /** * We go depth first on the superclasses but need to escape the callstack and @@ -503,10 +494,11 @@ private class TypeDefinitionContext( private fun KSClassDeclaration.interfaces(objectName: String?): List { return getAllSuperTypes().mapNotNull { val declaration = it.declaration - if (it.arguments.isNotEmpty()) { - logger.error("Generic interfaces are not supported", this) - null - } else if (declaration is KSClassDeclaration) { + val hasIsIgnoreAnnotation = this.annotations.any { + it.annotationType.resolve().declaration.qualifiedName?.asString() == "com.apollographql.execution.annotation.GraphQLIgnore" + } + if (hasIsIgnoreAnnotation) return@mapNotNull null + if (declaration is KSClassDeclaration) { if (declaration.asClassName().asString() == "kotlin.Any") { // kotlin.Any is a super type of everything, just ignore it null diff --git a/apollo-execution-runtime/src/commonMain/kotlin/com/apollographql/execution/annotation/GraphQLIgnore.kt b/apollo-execution-runtime/src/commonMain/kotlin/com/apollographql/execution/annotation/GraphQLIgnore.kt new file mode 100644 index 00000000..3bf09a16 --- /dev/null +++ b/apollo-execution-runtime/src/commonMain/kotlin/com/apollographql/execution/annotation/GraphQLIgnore.kt @@ -0,0 +1,5 @@ +package com.apollographql.execution.annotation + +@Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) +annotation class GraphQLIgnore diff --git a/tests/federation/src/main/kotlin/graphql.kt b/tests/federation/src/main/kotlin/graphql.kt index b09bed96..fe87c2e2 100644 --- a/tests/federation/src/main/kotlin/graphql.kt +++ b/tests/federation/src/main/kotlin/graphql.kt @@ -1,11 +1,18 @@ import com.apollographql.execution.annotation.GraphQLQuery +import com.apollographql.execution.annotation.GraphQLIgnore import com.apollographql.execution.subgraph.GraphQLKey +@GraphQLIgnore +interface SomeGenericInterface + @GraphQLQuery -class Query { +class Query : SomeGenericInterface{ fun products(): List { return products } + + @GraphQLIgnore + fun internalFields(): Int = 1 } class Product( @@ -23,4 +30,4 @@ class Product( val products = listOf( Product("1", "foo"), Product("2", "bar") -) \ No newline at end of file +)