diff --git a/.github/workflows/build-pull-request.yaml b/.github/workflows/build-pull-request.yaml index a5fd73ef..9e9646c5 100644 --- a/.github/workflows/build-pull-request.yaml +++ b/.github/workflows/build-pull-request.yaml @@ -11,5 +11,6 @@ jobs: - uses: gradle/actions/setup-gradle@dbbdc275be76ac10734476cc723d82dfe7ec6eda #v3.4.2 - run: | ./gradlew build + ./gradlew -p execution-tests build ./gradlew -p sample-ktor build ./gradlew -p sample-http4k build diff --git a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/SchemaDocumentBuilder.kt b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/SchemaDocumentBuilder.kt index e20f1b24..e2fb1fdb 100644 --- a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/SchemaDocumentBuilder.kt +++ b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/SchemaDocumentBuilder.kt @@ -1,6 +1,7 @@ package com.apollographql.execution.processor.codegen import com.apollographql.apollo.ast.* +import com.apollographql.execution.processor.codegen.KotlinSymbols.AstArgument import com.apollographql.execution.processor.codegen.KotlinSymbols.AstBooleanValue import com.apollographql.execution.processor.codegen.KotlinSymbols.AstDirective import com.apollographql.execution.processor.codegen.KotlinSymbols.AstDirectiveDefinition @@ -45,6 +46,7 @@ import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.joinToCode +import com.squareup.kotlinpoet.withIndent internal class SchemaDocumentBuilder( val context: KotlinExecutableSchemaContext, @@ -185,7 +187,7 @@ private fun SirDirectiveDefinition.codeBlock(): CodeBlock { } private fun GQLDirectiveLocation.codeBlock(): CodeBlock { - return CodeBlock.of("%T", ClassName("com.apollographql.apollo.ast", name)) + return CodeBlock.of("%T", ClassName("com.apollographql.apollo.ast", "GQLDirectiveLocation", name)) } private fun SirObjectDefinition.codeBlock(): CodeBlock { @@ -273,11 +275,34 @@ private fun buildCommon( } private fun SirDirective.codeBlock(): CodeBlock { + return buildCode { + add("%T(\n", AstDirective) + withIndent { + add("null,\n") + add("%S,\n", name) + add("listOf(\n") + withIndent { + arguments.forEach { + add("%L,\n", it.codeBlock()) + } + } + add(")\n") + } + add(")\n") + } return CodeBlock.of("%T(null, %S, %L)", AstDirective, name, arguments.map { it.codeBlock() }.joinToCode(prefix = "listOf(", suffix = ")")) } private fun SirArgument.codeBlock(): CodeBlock { - return value.codeBlock() + return buildCode { + add("%T(\n", AstArgument) + withIndent { + add("null,\n") + add("%S,\n", name) + add("%L,\n", value.codeBlock()) + } + add(")\n") + } } private fun GQLValue.codeBlock(): CodeBlock { diff --git a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/resolver.kt b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/resolver.kt index cf10f9f0..c6178f12 100644 --- a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/resolver.kt +++ b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/codegen/resolver.kt @@ -16,7 +16,7 @@ internal fun resolverBody(sirObjectDefinition: SirObjectDefinition, sirTargetFie if (sirTargetField.isFunction) { add("(\n") indent { - add(sirTargetField.arguments.map { argumentCodeBlock(it) }.joinToCode(",\n", suffix = ",\n")) + add(sirTargetField.arguments.map { argumentCodeBlock(it) }.joinToCode(",\n")) } add(")\n") } 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 80e0ca04..9f499200 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 @@ -298,11 +298,11 @@ private class TypeDefinitionContext( private fun KSAnnotation.toSirDirective(directiveDefinition: SirDirectiveDefinition): SirDirective { return SirDirective( name = directiveDefinition.name, - arguments = arguments.mapNotNull { it.toSirArgument(directiveDefinition) } + arguments = arguments.mapNotNull { it.SirInputValueDefinition(directiveDefinition) } ) } - private fun KSValueArgument.toSirArgument(directiveDefinition: SirDirectiveDefinition): SirArgument? { + private fun KSValueArgument.SirInputValueDefinition(directiveDefinition: SirDirectiveDefinition): SirArgument? { val kotlinName = name?.asString() if (kotlinName == null) { logger.error("Arguments must be named", this) diff --git a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/sir/ServerIr.kt b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/sir/ServerIr.kt index 7504453c..b032ec83 100644 --- a/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/sir/ServerIr.kt +++ b/apollo-execution-processor/src/main/kotlin/com/apollographql/execution/processor/sir/ServerIr.kt @@ -84,6 +84,9 @@ internal class SirDirective( val arguments: List ) +/** + * The value of an argument in a directive + */ internal class SirArgument( val name: String, val value: GQLValue diff --git a/execution-tests/directives/graphql/schema.graphqls b/execution-tests/directives/graphql/schema.graphqls index c43ace9f..bd04c0e7 100644 --- a/execution-tests/directives/graphql/schema.graphqls +++ b/execution-tests/directives/graphql/schema.graphqls @@ -25,3 +25,157 @@ enum OptInLevel { Error } + +type __Schema { + description: String + + types: [__Type!]! + + queryType: __Type! + + mutationType: __Type + + subscriptionType: __Type + + directives: [__Directive!]! +} + +type __Type { + kind: __TypeKind! + + name: String + + description: String + + fields(includeDeprecated: Boolean = false): [__Field!] + + interfaces: [__Type!] + + possibleTypes: [__Type!] + + enumValues(includeDeprecated: Boolean = false): [__EnumValue!] + + inputFields(includeDeprecated: Boolean = false): [__InputValue!] + + ofType: __Type + + specifiedByURL: String +} + +enum __TypeKind { + SCALAR + + OBJECT + + INTERFACE + + UNION + + ENUM + + INPUT_OBJECT + + LIST + + NON_NULL +} + +type __Field { + name: String! + + description: String + + args(includeDeprecated: Boolean = false): [__InputValue!]! + + type: __Type! + + isDeprecated: Boolean! + + deprecationReason: String +} + +type __InputValue { + name: String! + + description: String + + type: __Type! + + defaultValue: String + + isDeprecated: Boolean! + + deprecationReason: String +} + +type __EnumValue { + name: String! + + description: String + + isDeprecated: Boolean! + + deprecationReason: String +} + +type __Directive { + name: String! + + description: String + + locations: [__DirectiveLocation!]! + + args(includeDeprecated: Boolean = false): [__InputValue!]! + + isRepeatable: Boolean! +} + +enum __DirectiveLocation { + QUERY + + MUTATION + + SUBSCRIPTION + + FIELD + + FRAGMENT_DEFINITION + + FRAGMENT_SPREAD + + INLINE_FRAGMENT + + VARIABLE_DEFINITION + + SCHEMA + + SCALAR + + OBJECT + + FIELD_DEFINITION + + ARGUMENT_DEFINITION + + INTERFACE + + UNION + + ENUM + + ENUM_VALUE + + INPUT_OBJECT + + INPUT_FIELD_DEFINITION +} + +directive @skip (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @include (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @deprecated (reason: String = "No longer supported") on FIELD_DEFINITION|ARGUMENT_DEFINITION|INPUT_FIELD_DEFINITION|ENUM_VALUE + +directive @defer (label: String, if: Boolean! = true) on FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @specifiedBy (url: String!) on SCALAR diff --git a/execution-tests/integration/build.gradle.kts b/execution-tests/integration/build.gradle.kts new file mode 100644 index 00000000..808b12e1 --- /dev/null +++ b/execution-tests/integration/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + alias(libs.plugins.kgp.jvm) + alias(libs.plugins.ksp) + alias(libs.plugins.apollo.execution) +} + +apolloExecution { + service("service") { + packageName.set("com.example") + } +} + +dependencies { + implementation(libs.apollo.execution.runtime) +} \ No newline at end of file diff --git a/execution-tests/integration/graphql/schema.graphqls b/execution-tests/integration/graphql/schema.graphqls new file mode 100644 index 00000000..1a84e8a1 --- /dev/null +++ b/execution-tests/integration/graphql/schema.graphqls @@ -0,0 +1,161 @@ +schema { + query: Query +} + +type Query { + field: String! +} + +type __Schema { + description: String + + types: [__Type!]! + + queryType: __Type! + + mutationType: __Type + + subscriptionType: __Type + + directives: [__Directive!]! +} + +type __Type { + kind: __TypeKind! + + name: String + + description: String + + fields(includeDeprecated: Boolean = false): [__Field!] + + interfaces: [__Type!] + + possibleTypes: [__Type!] + + enumValues(includeDeprecated: Boolean = false): [__EnumValue!] + + inputFields(includeDeprecated: Boolean = false): [__InputValue!] + + ofType: __Type + + specifiedByURL: String +} + +enum __TypeKind { + SCALAR + + OBJECT + + INTERFACE + + UNION + + ENUM + + INPUT_OBJECT + + LIST + + NON_NULL +} + +type __Field { + name: String! + + description: String + + args(includeDeprecated: Boolean = false): [__InputValue!]! + + type: __Type! + + isDeprecated: Boolean! + + deprecationReason: String +} + +type __InputValue { + name: String! + + description: String + + type: __Type! + + defaultValue: String + + isDeprecated: Boolean! + + deprecationReason: String +} + +type __EnumValue { + name: String! + + description: String + + isDeprecated: Boolean! + + deprecationReason: String +} + +type __Directive { + name: String! + + description: String + + locations: [__DirectiveLocation!]! + + args(includeDeprecated: Boolean = false): [__InputValue!]! + + isRepeatable: Boolean! +} + +enum __DirectiveLocation { + QUERY + + MUTATION + + SUBSCRIPTION + + FIELD + + FRAGMENT_DEFINITION + + FRAGMENT_SPREAD + + INLINE_FRAGMENT + + VARIABLE_DEFINITION + + SCHEMA + + SCALAR + + OBJECT + + FIELD_DEFINITION + + ARGUMENT_DEFINITION + + INTERFACE + + UNION + + ENUM + + ENUM_VALUE + + INPUT_OBJECT + + INPUT_FIELD_DEFINITION +} + +directive @skip (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @include (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @deprecated (reason: String = "No longer supported") on FIELD_DEFINITION|ARGUMENT_DEFINITION|INPUT_FIELD_DEFINITION|ENUM_VALUE + +directive @defer (label: String, if: Boolean! = true) on FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @specifiedBy (url: String!) on SCALAR diff --git a/execution-tests/integration/src/main/kotlin/graphql.kt b/execution-tests/integration/src/main/kotlin/graphql.kt new file mode 100644 index 00000000..47f0718e --- /dev/null +++ b/execution-tests/integration/src/main/kotlin/graphql.kt @@ -0,0 +1,6 @@ +import com.apollographql.execution.annotation.GraphQLQuery + +@GraphQLQuery +class Query { + fun field(): String = "hello" +} \ No newline at end of file diff --git a/execution-tests/settings.gradle.kts b/execution-tests/settings.gradle.kts index b20c93eb..fe7f8c34 100644 --- a/execution-tests/settings.gradle.kts +++ b/execution-tests/settings.gradle.kts @@ -14,4 +14,5 @@ dependencyResolutionManagement { } } -include(":directives") \ No newline at end of file +include(":directives") +include(":integration") \ No newline at end of file