From 213005a711ec54f4bfc93b7d14fd982d4e9a63fa Mon Sep 17 00:00:00 2001 From: Steven Barker Date: Thu, 27 Jun 2024 09:26:52 +1200 Subject: [PATCH 1/6] trying to add deferred executions to rename transform --- .../transform/NadelDeepRenameTransform.kt | 1 + .../engine/transform/NadelRenameTransform.kt | 1 + .../nadel/engine/transform/query/NFUtil.kt | 13 ++++++ .../DeferredFieldIsRenamedTestSnapshot.kt | 46 ++++++++++++++++--- .../MultipleDeferDirectivesTestSnapshot.kt | 12 ++--- ...eDeferWithDifferentServiceCallsSnapshot.kt | 8 ++-- 6 files changed, 65 insertions(+), 16 deletions(-) diff --git a/lib/src/main/java/graphql/nadel/engine/transform/NadelDeepRenameTransform.kt b/lib/src/main/java/graphql/nadel/engine/transform/NadelDeepRenameTransform.kt index 9dde4cb02..13db288b7 100644 --- a/lib/src/main/java/graphql/nadel/engine/transform/NadelDeepRenameTransform.kt +++ b/lib/src/main/java/graphql/nadel/engine/transform/NadelDeepRenameTransform.kt @@ -253,6 +253,7 @@ internal class NadelDeepRenameTransform : NadelTransform { queryPathToField = NadelQueryPath(listOf(rename.underlyingName)), fieldArguments = field.normalizedArguments, fieldChildren = transformer.transform(field.children), + deferredExecutions = field.deferredExecutions ) ) } diff --git a/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt b/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt index a945d530a..46d165271 100644 --- a/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt +++ b/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt @@ -2,11 +2,13 @@ package graphql.nadel.engine.transform.query import graphql.normalized.ExecutableNormalizedField import graphql.normalized.NormalizedInputValue +import graphql.normalized.incremental.NormalizedDeferredExecution import graphql.schema.GraphQLInterfaceType import graphql.schema.GraphQLObjectType import graphql.schema.GraphQLOutputType import graphql.schema.GraphQLSchema import graphql.schema.GraphQLTypeUtil +import kotlin.collections.LinkedHashSet object NFUtil { // Exists for IntelliJ search everywhere purposes, DO NOT INVOKE @@ -18,6 +20,7 @@ object NFUtil { pathToField: NadelQueryPath, fieldArguments: Map, fieldChildren: List, + deferredExecutions: LinkedHashSet = LinkedHashSet(), ): List { return createFieldRecursively( schema, @@ -26,6 +29,7 @@ object NFUtil { fieldArguments, fieldChildren, pathToFieldIndex = 0, + deferredExecutions ) } @@ -35,6 +39,7 @@ object NFUtil { queryPathToField: NadelQueryPath, fieldArguments: Map, fieldChildren: List, + deferredExecutions: LinkedHashSet = LinkedHashSet(), ): ExecutableNormalizedField { return createParticularField( schema, @@ -43,6 +48,7 @@ object NFUtil { fieldArguments, fieldChildren, pathToFieldIndex = 0, + deferredExecutions ) } @@ -53,6 +59,7 @@ object NFUtil { fieldArguments: Map, fieldChildren: List, pathToFieldIndex: Int, + deferredExecutions: LinkedHashSet, ): List { // Note: remember that we are creating fields that do not exist in the original NF // Thus, we need to handle interfaces and object types @@ -65,6 +72,7 @@ object NFUtil { fieldArguments, fieldChildren, pathToFieldIndex, + deferredExecutions ) } is GraphQLObjectType -> listOf( @@ -75,6 +83,7 @@ object NFUtil { fieldArguments, fieldChildren, pathToFieldIndex, + deferredExecutions ) ) else -> error("Unsupported type '${parentType.javaClass.name}'") @@ -88,6 +97,7 @@ object NFUtil { fieldArguments: Map, fieldChildren: List, pathToFieldIndex: Int, + deferredExecutions: LinkedHashSet, ): ExecutableNormalizedField { val fieldName = queryPathToField.segments[pathToFieldIndex] val fieldDef = parentType.getFieldDefinition(fieldName) @@ -96,6 +106,8 @@ object NFUtil { return ExecutableNormalizedField.newNormalizedField() .objectTypeNames(listOf(parentType.name)) .fieldName(fieldName) + //.deferredExecutions() // <-- add defer execution + .deferredExecutions(deferredExecutions) .also { builder -> if (pathToFieldIndex == queryPathToField.segments.lastIndex) { builder.normalizedArguments(fieldArguments) @@ -112,6 +124,7 @@ object NFUtil { fieldArguments, fieldChildren, pathToFieldIndex = pathToFieldIndex + 1, + deferredExecutions ) } ) diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferredFieldIsRenamedTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferredFieldIsRenamedTestSnapshot.kt index f27698c7a..5e3561481 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferredFieldIsRenamedTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferredFieldIsRenamedTestSnapshot.kt @@ -23,8 +23,10 @@ public class DeferredFieldIsRenamedTestSnapshot : TestSnapshot() { | { | defer { | hello - | rename__overallString__underlyingString: underlyingString | __typename__rename__overallString: __typename + | ... @defer { + | rename__overallString__underlyingString: underlyingString + | } | } | } """.trimMargin(), @@ -34,13 +36,28 @@ public class DeferredFieldIsRenamedTestSnapshot : TestSnapshot() { | "data": { | "defer": { | "hello": "hello there", - | "rename__overallString__underlyingString": "string for the deferred renamed field", | "__typename__rename__overallString": "DeferApi" | } - | } + | }, + | "hasNext": true | } """.trimMargin(), delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "rename__overallString__underlyingString": "string for the deferred renamed field" + | } + | } + | ] + | } + """.trimMargin(), ), ), ) @@ -51,7 +68,8 @@ public class DeferredFieldIsRenamedTestSnapshot : TestSnapshot() { * "data": { * "defer": { * "hello": "hello there", - * "overallString": "string for the deferred renamed field" + * "overallString": null, + * "rename__overallString__underlyingString": "string for the deferred renamed field" * } * } * } @@ -63,12 +81,28 @@ public class DeferredFieldIsRenamedTestSnapshot : TestSnapshot() { | "data": { | "defer": { | "hello": "hello there", - | "overallString": "string for the deferred renamed field" + | "overallString": null | } - | } + | }, + | "hasNext": true | } """.trimMargin(), delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "rename__overallString__underlyingString": "string for the deferred renamed field" + | } + | } + | ] + | } + """.trimMargin(), ), ) } diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt index 2dd653088..b9d5affa2 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt @@ -53,7 +53,7 @@ public class MultipleDeferDirectivesTestSnapshot : TestSnapshot() { | "defer" | ], | "data": { - | "slowField": "slowString" + | "anotherSlowField": 123456789 | } | } | ] @@ -68,7 +68,7 @@ public class MultipleDeferDirectivesTestSnapshot : TestSnapshot() { | "defer" | ], | "data": { - | "anotherSlowField": 123456789 + | "slowField": "slowString" | } | } | ] @@ -84,8 +84,8 @@ public class MultipleDeferDirectivesTestSnapshot : TestSnapshot() { * "data": { * "defer": { * "fastField": "123", - * "anotherSlowField": 123456789, - * "slowField": "slowString" + * "slowField": "slowString", + * "anotherSlowField": 123456789 * } * } * } @@ -112,7 +112,7 @@ public class MultipleDeferDirectivesTestSnapshot : TestSnapshot() { | "defer" | ], | "data": { - | "slowField": "slowString" + | "anotherSlowField": 123456789 | } | } | ] @@ -127,7 +127,7 @@ public class MultipleDeferDirectivesTestSnapshot : TestSnapshot() { | "defer" | ], | "data": { - | "anotherSlowField": 123456789 + | "slowField": "slowString" | } | } | ] diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt index 7081a2c43..eb5fdd2bf 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt @@ -138,10 +138,10 @@ public class MultipleDeferWithDifferentServiceCallsSnapshot : TestSnapshot() { | "incremental": [ | { | "path": [ - | "user" + | "product" | ], | "data": { - | "profilePicture": "https://examplesite.com/user/profile_picture.jpg" + | "productImage": null | } | } | ] @@ -153,10 +153,10 @@ public class MultipleDeferWithDifferentServiceCallsSnapshot : TestSnapshot() { | "incremental": [ | { | "path": [ - | "product" + | "user" | ], | "data": { - | "productImage": null + | "profilePicture": "https://examplesite.com/user/profile_picture.jpg" | } | } | ] From 0d1d3cff2b9705caf42183a839f3f99199360178 Mon Sep 17 00:00:00 2001 From: sbarker2 <109047597+sbarker2@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:44:19 +1200 Subject: [PATCH 2/6] [READY] Initial defer implementation (#553) * nextgen engine changes for defer * adding defer tests * adding more stuff to defer tests * Ignore failing tests (defer queries with multiple service call) * ignore location field in defer test errors (#554) * fix error locations bug (#555) * changing defer tests * remove @ignore on previously failing tests * update test snapshots * cleaning up defer tests --- .../main/java/graphql/nadel/NextgenEngine.kt | 7 + .../nadel/tests/next/NadelIntegrationTest.kt | 8 +- ...siveDeferQueryWithDifferentServiceCalls.kt | 118 +++++++++ ...rQueryWithDifferentServiceCallsSnapshot.kt | 223 ++++++++++++++++++ .../next/fixtures/defer/DeferOnListItems.kt | 72 ++++++ .../defer/DeferOnListItemsTestSnapshot.kt | 166 +++++++++++++ .../fixtures/defer/DeferThrowsErrorTest.kt | 62 +++++ .../defer/DeferThrowsErrorTestSnapshot.kt | 161 +++++++++++++ .../fixtures/defer/DeferWithIfFalseTest.kt | 62 +++++ .../defer/DeferWithIfFalseTestSnapshot.kt | 72 ++++++ .../next/fixtures/defer/DeferWithLabelTest.kt | 62 +++++ .../defer/DeferWithLabelTestSnapshot.kt | 106 +++++++++ .../fixtures/defer/DeferWithoutLabelTest.kt | 57 +++++ .../defer/DeferWithoutLabelTestSnapshot.kt | 104 ++++++++ .../defer/MultipleDeferDirectivesTest.kt | 71 ++++++ .../MultipleDeferDirectivesTestSnapshot.kt | 138 +++++++++++ .../MultipleDeferWithDifferentServiceCalls.kt | 99 ++++++++ ...eDeferWithDifferentServiceCallsSnapshot.kt | 167 +++++++++++++ ...ipleFieldsinMultipleDeferDirectivesTest.kt | 82 +++++++ ...dsinMultipleDeferDirectivesTestSnapshot.kt | 146 ++++++++++++ ...ultipleFieldsinSingleDeferDirectiveTest.kt | 68 ++++++ ...ieldsinSingleDeferDirectiveTestSnapshot.kt | 108 +++++++++ .../next/fixtures/defer/NestedDefersTest.kt | 67 ++++++ .../defer/NestedDefersTestSnapshot.kt | 142 +++++++++++ 24 files changed, 2366 insertions(+), 2 deletions(-) create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCalls.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItems.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCalls.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt diff --git a/lib/src/main/java/graphql/nadel/NextgenEngine.kt b/lib/src/main/java/graphql/nadel/NextgenEngine.kt index 0de29dcb2..1c2914e68 100644 --- a/lib/src/main/java/graphql/nadel/NextgenEngine.kt +++ b/lib/src/main/java/graphql/nadel/NextgenEngine.kt @@ -62,6 +62,7 @@ import kotlinx.coroutines.future.asCompletableFuture import kotlinx.coroutines.future.asDeferred import kotlinx.coroutines.future.await import kotlinx.coroutines.launch +import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.reactive.asPublisher import java.util.concurrent.CompletableFuture import graphql.normalized.ExecutableNormalizedOperationFactory.Options.defaultOptions as executableNormalizedOperationFactoryOptions @@ -358,6 +359,12 @@ internal class NextgenEngine( ) } + if (serviceExecResult is NadelIncrementalServiceExecutionResult) { + executionContext.incrementalResultSupport.defer( + serviceExecResult.incrementalItemPublisher.asFlow() + ) + } + return serviceExecResult.copy( data = serviceExecResult.data.let { data -> data.takeIf { transformedQuery.resultKey in data } diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/NadelIntegrationTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/NadelIntegrationTest.kt index 4f3377c94..81b11d02e 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/NadelIntegrationTest.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/NadelIntegrationTest.kt @@ -126,11 +126,15 @@ abstract class NadelIntegrationTest( // Maybe this won't hold out longer term, but e.g. it's ok for the deferred errors to add a path assertJsonEquals( expected = mapOf( - "errors" to noDeferResultMap["errors"], + "errors" to (noDeferResultMap["errors"] as? List>)?.map { errorMap -> + errorMap.filterKeys { it != "locations" } + }, "extensions" to noDeferResultMap["extensions"], ), actual = mapOf( - "errors" to combinedDeferResultMap["errors"], + "errors" to (combinedDeferResultMap["errors"] as? List>)?.map { errorMap -> + errorMap.filterKeys { it != "locations" } + }, "extensions" to combinedDeferResultMap["extensions"], ), mode = JSONCompareMode.LENIENT, diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCalls.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCalls.kt new file mode 100644 index 000000000..ebb5ee0c8 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCalls.kt @@ -0,0 +1,118 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest +import kotlin.test.Ignore + +open class ComprehensiveDeferQueryWithDifferentServiceCalls : NadelIntegrationTest( + query = """ + query { + user { + name + ... @defer { + profilePicture + } + ... @defer(label: "team-details") { + teamName + teamMembers + } + } + product { + productName + ... @defer { + productImage + } + ... @defer(if: false) { + productDescription + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "shared", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + """.trimIndent(), + runtimeWiring = { wiring -> + }, + ), + Service( + name = "users", + overallSchema = """ + type Query { + user: UserApi + } + type UserApi { + name: String + profilePicture: String + teamName: String + teamMembers: [String] + } + """.trimIndent(), + runtimeWiring = { wiring -> + wiring + .type("Query") { type -> + type + .dataFetcher("user") { env -> + Any() + } + } + .type("UserApi") { type -> + type + .dataFetcher("name") { env -> + "Steven" + } + .dataFetcher("profilePicture") { env -> + "https://examplesite.com/user/profile_picture.jpg" + } + .dataFetcher("teamName") { env -> + "The Unicorns" + } + .dataFetcher("teamMembers") { env -> + listOf("Felipe", "Franklin", "Juliano") + } + } + }, + ), + Service( + name = "product", + overallSchema = """ + type Query { + product: ProductApi + } + type ProductApi { + productName: String + productImage: String + productDescription: String + } + """.trimIndent(), + runtimeWiring = { wiring -> + wiring + .type("Query") { type -> + type + .dataFetcher("product") { env -> + Any() + } + } + .type("ProductApi") { type -> + type + .dataFetcher("productName") { env -> + "Awesome Product" + } + .dataFetcher("profilePicture") { env -> + "https://examplesite.com/product/product_image.jpg" + } + .dataFetcher("profilePicture") { env -> + "This is a really awesome product with really awesome features." + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt new file mode 100644 index 000000000..6389bf028 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt @@ -0,0 +1,223 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "product", + query = """ + | { + | product { + | productName + | productDescription + | ... @defer { + | productImage + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "product": { + | "productName": "Awesome Product", + | "productDescription": null + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "product" + | ], + | "data": { + | "productImage": null + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ExpectedServiceCall( + service = "users", + query = """ + | { + | user { + | name + | ... @defer { + | profilePicture + | } + | ... @defer(label: "team-details") { + | teamName + | teamMembers + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "user": { + | "name": "Steven" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "user" + | ], + | "label": "team-details", + | "data": { + | "teamName": "The Unicorns", + | "teamMembers": [ + | "Felipe", + | "Franklin", + | "Juliano" + | ] + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "user" + | ], + | "data": { + | "profilePicture": "https://examplesite.com/user/profile_picture.jpg" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "user": { + * "name": "Steven", + * "profilePicture": "https://examplesite.com/user/profile_picture.jpg", + * "teamName": "The Unicorns", + * "teamMembers": [ + * "Felipe", + * "Franklin", + * "Juliano" + * ] + * }, + * "product": { + * "productName": "Awesome Product", + * "productDescription": null, + * "productImage": null + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "user": { + | "name": "Steven" + | }, + | "product": { + | "productName": "Awesome Product", + | "productDescription": null + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "user" + | ], + | "label": "team-details", + | "data": { + | "teamName": "The Unicorns", + | "teamMembers": [ + | "Felipe", + | "Franklin", + | "Juliano" + | ] + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "product" + | ], + | "data": { + | "productImage": null + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "user" + | ], + | "data": { + | "profilePicture": "https://examplesite.com/user/profile_picture.jpg" + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItems.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItems.kt new file mode 100644 index 000000000..366933151 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItems.kt @@ -0,0 +1,72 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest + +open class DeferOnListItemsTest : NadelIntegrationTest( + query = """ + query { + defer { + list { + fast + ... @defer { + slow + } + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + list: [Test] + } + + type Test { + fast: String + slow: String + } + + """.trimIndent(), + runtimeWiring = { wiring -> + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("list") { env -> + listOf( + mapOf(), + mapOf(), + ) + } + } + .type("Test") { type -> + type + .dataFetcher("fast") { env -> + "fastString" + } + .dataFetcher("slow") { env -> + "slowString" + } + } + } + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt new file mode 100644 index 000000000..ce1b5ce10 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt @@ -0,0 +1,166 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class DeferOnListItemsTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | list { + | fast + | ... @defer { + | slow + | } + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "list": [ + | { + | "fast": "fastString" + | }, + | { + | "fast": "fastString" + | } + | ] + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer", + | "list", + | 1 + | ], + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer", + | "list", + | 0 + | ], + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "list": [ + * { + * "fast": "fastString", + * "slow": "slowString" + * }, + * { + * "fast": "fastString", + * "slow": "slowString" + * } + * ] + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "list": [ + | { + | "fast": "fastString" + | }, + | { + | "fast": "fastString" + | } + | ] + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer", + | "list", + | 1 + | ], + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer", + | "list", + | 0 + | ], + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTest.kt new file mode 100644 index 000000000..7d5592dcd --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTest.kt @@ -0,0 +1,62 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest + +open class DeferThrowsErrorTest : NadelIntegrationTest( + query = """ + query { + defer { + hello + ... @defer(label: "slow-defer") { + slow + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + hello: String + slow: String + } + + """.trimIndent(), + runtimeWiring = { wiring -> + data class DeferApi( + val hello: String, + val slow: String, + ) + + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("hello") { env -> + "helloString" + } + .dataFetcher("slow") { env -> + throw RuntimeException("An error occurred while fetching 'slow'") + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt new file mode 100644 index 000000000..5b8e08b62 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt @@ -0,0 +1,161 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class DeferThrowsErrorTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | hello + | ... @defer(label: "slow-defer") { + | slow + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "slow-defer", + | "errors": [ + | { + | "message": "Exception while fetching data (/defer/slow) : An error occurred while fetching 'slow'", + | "locations": [ + | { + | "line": 5, + | "column": 7 + | } + | ], + | "path": [ + | "defer", + | "slow" + | ], + | "extensions": { + | "classification": "DataFetchingException" + | } + | } + | ], + | "data": { + | "slow": null + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "hello": "helloString", + * "slow": null + * } + * }, + * "errors": [ + * { + * "message": "Exception while fetching data (/defer/slow) : An error occurred while + * fetching 'slow'", + * "locations": [ + * { + * "line": 5, + * "column": 7 + * } + * ], + * "path": [ + * "defer", + * "slow" + * ], + * "extensions": { + * "classification": "DataFetchingException" + * } + * } + * ] + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "slow-defer", + | "errors": [ + | { + | "message": "Exception while fetching data (/defer/slow) : An error occurred while fetching 'slow'", + | "locations": [ + | { + | "line": 5, + | "column": 7 + | } + | ], + | "path": [ + | "defer", + | "slow" + | ], + | "extensions": { + | "classification": "DataFetchingException" + | } + | } + | ], + | "data": { + | "slow": null + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTest.kt new file mode 100644 index 000000000..ad0a086ce --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTest.kt @@ -0,0 +1,62 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest + +open class DeferWithIfFalseTest : NadelIntegrationTest( + query = """ + query { + defer { + hello + ... @defer(if: false) { + slow + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + hello: String + slow: String + } + + """.trimIndent(), + runtimeWiring = { wiring -> + data class DeferApi( + val hello: String, + val slow: String, + ) + + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("hello") { env -> + "helloString" + } + .dataFetcher("slow") { env -> + "slowString" + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt new file mode 100644 index 000000000..8bd741911 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt @@ -0,0 +1,72 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class DeferWithIfFalseTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | hello + | slow + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString", + | "slow": "slowString" + | } + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "hello": "helloString", + * "slow": "slowString" + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString", + | "slow": "slowString" + | } + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTest.kt new file mode 100644 index 000000000..16067ea4c --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTest.kt @@ -0,0 +1,62 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest + +open class DeferWithLabelTest : NadelIntegrationTest( + query = """ + query { + defer { + hello + ... @defer(label: "slow-defer") { + slow + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + hello: String + slow: String + } + + """.trimIndent(), + runtimeWiring = { wiring -> + data class DeferApi( + val hello: String, + val slow: String, + ) + + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("hello") { env -> + "helloString" + } + .dataFetcher("slow") { env -> + "slowString" + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt new file mode 100644 index 000000000..04055650e --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt @@ -0,0 +1,106 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class DeferWithLabelTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | hello + | ... @defer(label: "slow-defer") { + | slow + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "slow-defer", + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "hello": "helloString", + * "slow": "slowString" + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "slow-defer", + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTest.kt new file mode 100644 index 000000000..2e519a6eb --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTest.kt @@ -0,0 +1,57 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest + +open class DeferWithoutLabelTest : NadelIntegrationTest( + query = """ + query { + defer { + hello + ... @defer { + slow + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + hello: String + slow: String + } + + """.trimIndent(), + runtimeWiring = { wiring -> + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("hello") { env -> + "helloString" + } + .dataFetcher("slow") { env -> + "slowString" + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt new file mode 100644 index 000000000..6a148fd81 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt @@ -0,0 +1,104 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class DeferWithoutLabelTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | hello + | ... @defer { + | slow + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "hello": "helloString", + * "slow": "slowString" + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "hello": "helloString" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slow": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTest.kt new file mode 100644 index 000000000..507dcf539 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTest.kt @@ -0,0 +1,71 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest +import kotlin.test.Ignore + +open class MultipleDeferDirectivesTest : NadelIntegrationTest( + query = """ + query { + defer { + fastField + ... @defer { + slowField + } + ... @defer { + anotherSlowField + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + fastField: ID + slowField: String + anotherSlowField: Int + } + + """.trimIndent(), + runtimeWiring = { wiring -> + data class DeferApi( + val fastField: Int, + val slowField: String, + val anotherSlowField: Int + ) + + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("fastField") { env -> + 123 + } + .dataFetcher("slowField") { env -> + "slowString" + } + .dataFetcher("anotherSlowField") { env -> + 123456789 + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt new file mode 100644 index 000000000..b9d5affa2 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt @@ -0,0 +1,138 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class MultipleDeferDirectivesTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | fastField + | ... @defer { + | slowField + | } + | ... @defer { + | anotherSlowField + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "fastField": "123" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "anotherSlowField": 123456789 + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "fastField": "123", + * "slowField": "slowString", + * "anotherSlowField": 123456789 + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "fastField": "123" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "anotherSlowField": 123456789 + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField": "slowString" + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCalls.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCalls.kt new file mode 100644 index 000000000..8019ddb9d --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCalls.kt @@ -0,0 +1,99 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest +import kotlin.test.Ignore + +open class MultipleDeferWithDifferentServiceCalls : NadelIntegrationTest( + query = """ + query { + user { + name + ... @defer { + profilePicture + } + } + product { + productName + ... @defer { + productImage + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "shared", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + """.trimIndent(), + runtimeWiring = { wiring -> + }, + ), + Service( + name = "users", + overallSchema = """ + type Query { + user: UserApi + } + type UserApi { + name: String + profilePicture: String + } + """.trimIndent(), + runtimeWiring = { wiring -> + wiring + .type("Query") { type -> + type + .dataFetcher("user") { env -> + Any() + } + } + .type("UserApi") { type -> + type + .dataFetcher("name") { env -> + "Steven" + } + .dataFetcher("profilePicture") { env -> + "https://examplesite.com/user/profile_picture.jpg" + } + } + }, + ), + Service( + name = "product", + overallSchema = """ + type Query { + product: ProductApi + } + type ProductApi { + productName: String + productImage: String + } + """.trimIndent(), + runtimeWiring = { wiring -> + wiring + .type("Query") { type -> + type + .dataFetcher("product") { env -> + Any() + } + } + .type("ProductApi") { type -> + type + .dataFetcher("productName") { env -> + "Awesome Product" + } + .dataFetcher("productImage") { env -> + "https://examplesite.com/product/product_image.jpg" + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt new file mode 100644 index 000000000..f8f5f3dcc --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt @@ -0,0 +1,167 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class MultipleDeferWithDifferentServiceCallsSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "product", + query = """ + | { + | product { + | productName + | ... @defer { + | productImage + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "product": { + | "productName": "Awesome Product" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "product" + | ], + | "data": { + | "productImage": "https://examplesite.com/product/product_image.jpg" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ExpectedServiceCall( + service = "users", + query = """ + | { + | user { + | name + | ... @defer { + | profilePicture + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "user": { + | "name": "Steven" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "user" + | ], + | "data": { + | "profilePicture": "https://examplesite.com/user/profile_picture.jpg" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "user": { + * "name": "Steven", + * "profilePicture": "https://examplesite.com/user/profile_picture.jpg" + * }, + * "product": { + * "productName": "Awesome Product", + * "productImage": "https://examplesite.com/product/product_image.jpg" + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "user": { + | "name": "Steven" + | }, + | "product": { + | "productName": "Awesome Product" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "product" + | ], + | "data": { + | "productImage": "https://examplesite.com/product/product_image.jpg" + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "user" + | ], + | "data": { + | "profilePicture": "https://examplesite.com/user/profile_picture.jpg" + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTest.kt new file mode 100644 index 000000000..2539dc846 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTest.kt @@ -0,0 +1,82 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest + +open class MultipleFieldsinMultipleDeferDirectivesTest : NadelIntegrationTest( + query = """ + query { + defer { + fastField + ... @defer { + slowField + slowField2 + } + ... @defer { + slowField3 + slowField4 + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + fastField: ID + slowField: String + slowField2: String + slowField3: String + slowField4: String + } + + """.trimIndent(), + runtimeWiring = { wiring -> + data class DeferApi( + val fastField: Int, + val slowField: String, + val slowField2: String, + val slowField3: String, + val slowField4: String, + ) + + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("fastField") { env -> + 123 + } + .dataFetcher("slowField") { env -> + "slowString" + } + .dataFetcher("slowField2") { env -> + "slowString2" + } + .dataFetcher("slowField3") { env -> + "slowString3" + } + .dataFetcher("slowField4") { env -> + "slowString4" + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt new file mode 100644 index 000000000..b3d0df19e --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt @@ -0,0 +1,146 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class MultipleFieldsinMultipleDeferDirectivesTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | fastField + | ... @defer { + | slowField + | slowField2 + | } + | ... @defer { + | slowField3 + | slowField4 + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "fastField": "123" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField": "slowString", + | "slowField2": "slowString2" + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField4": "slowString4", + | "slowField3": "slowString3" + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "fastField": "123", + * "slowField4": "slowString4", + * "slowField3": "slowString3", + * "slowField": "slowString", + * "slowField2": "slowString2" + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "fastField": "123" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField": "slowString", + | "slowField2": "slowString2" + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField4": "slowString4", + | "slowField3": "slowString3" + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTest.kt new file mode 100644 index 000000000..fb15332f2 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTest.kt @@ -0,0 +1,68 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest + +open class MultipleFieldsinSingleDeferDirectiveTest : NadelIntegrationTest( + query = """ + query { + defer { + fastField + ... @defer { + slowField + anotherSlowField + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + fastField: ID + slowField: String + anotherSlowField: Int + } + + """.trimIndent(), + runtimeWiring = { wiring -> + data class DeferApi( + val fastField: Int, + val slowField: String, + val anotherSlowField: Int + ) + + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("fastField") { env -> + 123 + } + .dataFetcher("slowField") { env -> + "slowString" + } + .dataFetcher("anotherSlowField") { env -> + 123456789 + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt new file mode 100644 index 000000000..8a7c0c191 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt @@ -0,0 +1,108 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class MultipleFieldsinSingleDeferDirectiveTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | fastField + | ... @defer { + | slowField + | anotherSlowField + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "fastField": "123" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField": "slowString", + | "anotherSlowField": 123456789 + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "fastField": "123", + * "slowField": "slowString", + * "anotherSlowField": 123456789 + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "fastField": "123" + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "data": { + | "slowField": "slowString", + | "anotherSlowField": 123456789 + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTest.kt new file mode 100644 index 000000000..7f02fb928 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTest.kt @@ -0,0 +1,67 @@ +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.NadelExecutionHints +import graphql.nadel.tests.next.NadelIntegrationTest +import kotlin.test.Ignore + +@Ignore("Ignored for now as test is failing. This will be implemented later. It may be a problem with ExecutableNormalisedFields in graphql-java") +open class NestedDefersTest : NadelIntegrationTest( + query = """ + query { + defer { + fastField + ... @defer(label: "outer defer") { + slowField1 + ... @defer(label: "inner defer") { + slowField2 + } + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "defer", + overallSchema = """ + directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + + type Query { + defer: DeferApi + } + type DeferApi { + fastField: String + slowField1: String + slowField2: String + } + + """.trimIndent(), + runtimeWiring = { wiring -> + wiring + .type("Query") { type -> + type + .dataFetcher("defer") { env -> + Any() + } + } + .type("DeferApi") { type -> + type + .dataFetcher("hello") { env -> + "helloString" + } + .dataFetcher("slow1") { env -> + Thread.sleep(1_000) // wait for 1 second + "slowString 1" + } + .dataFetcher("slow2") { env -> + "slowString 2" + } + } + }, + ), + ), +) { + override fun makeExecutionHints(): NadelExecutionHints.Builder { + return super.makeExecutionHints() + .deferSupport { true } + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt new file mode 100644 index 000000000..e9b8bc83f --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt @@ -0,0 +1,142 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.defer + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class NestedDefersTestSnapshot : TestSnapshot() { + override val calls: List = listOf( + ExpectedServiceCall( + service = "defer", + query = """ + | { + | defer { + | fastField + | ... @defer(label: "outer defer") { + | slowField1 + | } + | ... @defer(label: "inner defer") { + | slowField2 + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "defer": { + | "fastField": null + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "outer defer", + | "data": { + | "slowField1": null + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "inner defer", + | "data": { + | "slowField2": null + | } + | } + | ] + | } + """.trimMargin(), + ), + ), + ) + + /** + * ```json + * { + * "data": { + * "defer": { + * "fastField": null, + * "slowField2": null, + * "slowField1": null + * } + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "defer": { + | "fastField": null + | } + | }, + | "hasNext": true + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + """ + | { + | "hasNext": false, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "outer defer", + | "data": { + | "slowField1": null + | } + | } + | ] + | } + """.trimMargin(), + """ + | { + | "hasNext": true, + | "incremental": [ + | { + | "path": [ + | "defer" + | ], + | "label": "inner defer", + | "data": { + | "slowField2": null + | } + | } + | ] + | } + """.trimMargin(), + ), + ) +} From 596626d2f815ec58428671edd9de5cf2829afa90 Mon Sep 17 00:00:00 2001 From: Franklin Wang <9077461+gnawf@users.noreply.github.com> Date: Thu, 4 Jul 2024 08:45:27 +1000 Subject: [PATCH 3/6] Bump GraphQL Java (#560) * Bump GraphQL Java Should pull in Fix builder return type and expose generic toSpecification #3642 https://github.com/graphql-java/graphql-java/pull/3642 * Fix build * Fix test expected errors --- lib/build.gradle.kts | 2 +- .../hydration/defer/HydrationDeferInRenamedField.kt | 2 +- .../hydration/defer/HydrationDeferIsDisabled.kt | 4 ++-- .../oneOf/one-of-fails-when-2-values-are-passed.yml | 11 ++++++++--- ...ne-of-fails-when-invalid-variables-are-passed.yml | 12 +++++++++--- .../oneOf/one-of-fails-when-no-values-are-passed.yml | 11 ++++++++--- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 2cf6a16d2..fbe07a171 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -7,7 +7,7 @@ plugins { id("com.bnorm.power.kotlin-power-assert") } -val graphqlJavaVersion = "0.0.0-2024-04-30T01-25-21-2f5ff3c" +val graphqlJavaVersion = "0.0.0-2024-06-28T04-37-51-99ec596" val slf4jVersion = "1.7.25" dependencies { diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedField.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedField.kt index ff460d2f5..27a2335a0 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedField.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedField.kt @@ -121,7 +121,7 @@ abstract class BaseHydrationDeferInRenamedFieldTest( issuesByKey[env.getArgument("key")] } .dataFetcher("getIssueById") { env -> - issuesById[env.getArgument("id").toIntOrNull()] + issuesById[env.getArgument("id")!!.toIntOrNull()] } } }, diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabled.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabled.kt index 5b7e2085a..28eeb316f 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabled.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabled.kt @@ -174,14 +174,14 @@ abstract class HydrationDeferIsDisabled( .type("Issue") { type -> type .dataFetcher("related") { env -> - env.getSource() + env.getSource()!! .relatedKeys .map { issuesByKey[it]!! } } .dataFetcher("parent") { env -> - issuesByKey[env.getSource().parentKey] + issuesByKey[env.getSource()!!.parentKey] } } }, diff --git a/test/src/test/resources/fixtures/oneOf/one-of-fails-when-2-values-are-passed.yml b/test/src/test/resources/fixtures/oneOf/one-of-fails-when-2-values-are-passed.yml index c4c9b6974..1f02707b8 100644 --- a/test/src/test/resources/fixtures/oneOf/one-of-fails-when-2-values-are-passed.yml +++ b/test/src/test/resources/fixtures/oneOf/one-of-fails-when-2-values-are-passed.yml @@ -33,11 +33,16 @@ response: |- "data": null, "errors": [ { - "message": "Exactly one key must be specified for OneOf type 'SearchInput'.", + "message": "Validation error (WrongType@[search]) : Exactly one key must be specified for OneOf type 'SearchInput'.", + "locations": [ + { + "line": 2, + "column": 10 + } + ], "extensions": { "classification": "ValidationError" } } - ], - "extensions": {} + ] } diff --git a/test/src/test/resources/fixtures/oneOf/one-of-fails-when-invalid-variables-are-passed.yml b/test/src/test/resources/fixtures/oneOf/one-of-fails-when-invalid-variables-are-passed.yml index 67422957f..71dbd08d6 100644 --- a/test/src/test/resources/fixtures/oneOf/one-of-fails-when-invalid-variables-are-passed.yml +++ b/test/src/test/resources/fixtures/oneOf/one-of-fails-when-invalid-variables-are-passed.yml @@ -34,11 +34,17 @@ response: |- "data": null, "errors": [ { - "message": "Exactly one key must be specified for OneOf type 'SearchInput'.", + "message": "Validation error (WrongType@[search]) : Exactly one key must be specified for OneOf type 'SearchInput'.", + "locations": [ + { + "line": 2, + "column": 10 + } + ], "extensions": { "classification": "ValidationError" } } - ], - "extensions": {} + ] } + diff --git a/test/src/test/resources/fixtures/oneOf/one-of-fails-when-no-values-are-passed.yml b/test/src/test/resources/fixtures/oneOf/one-of-fails-when-no-values-are-passed.yml index 824e874b9..62e25b6fc 100644 --- a/test/src/test/resources/fixtures/oneOf/one-of-fails-when-no-values-are-passed.yml +++ b/test/src/test/resources/fixtures/oneOf/one-of-fails-when-no-values-are-passed.yml @@ -33,11 +33,16 @@ response: |- "data": null, "errors": [ { - "message": "Exactly one key must be specified for OneOf type 'SearchInput'.", + "message": "Validation error (WrongType@[search]) : Exactly one key must be specified for OneOf type 'SearchInput'.", + "locations": [ + { + "line": 2, + "column": 10 + } + ], "extensions": { "classification": "ValidationError" } } - ], - "extensions": {} + ] } From fe0267661620fbdf01bafc015845a42211830440 Mon Sep 17 00:00:00 2001 From: Franklin Wang <9077461+gnawf@users.noreply.github.com> Date: Fri, 5 Jul 2024 14:37:00 +1000 Subject: [PATCH 4/6] Individual update snapshot func (#561) * Add individual update snapshot functions * Update tests * Make private --- .../nadel/tests/next/UpdateTestSnapshots.kt | 22 ++++++++++++++++++- .../basic/BasicObjectSchemaTestSnapshot.kt | 4 ++++ .../next/fixtures/basic/EchoTestSnapshot.kt | 4 ++++ ...rQueryWithDifferentServiceCallsSnapshot.kt | 4 ++++ .../defer/DeferOnListItemsTestSnapshot.kt | 4 ++++ .../defer/DeferThrowsErrorTestSnapshot.kt | 4 ++++ .../defer/DeferWithIfFalseTestSnapshot.kt | 4 ++++ .../defer/DeferWithLabelTestSnapshot.kt | 4 ++++ .../defer/DeferWithoutLabelTestSnapshot.kt | 4 ++++ .../MultipleDeferDirectivesTestSnapshot.kt | 4 ++++ ...eDeferWithDifferentServiceCallsSnapshot.kt | 4 ++++ ...dsinMultipleDeferDirectivesTestSnapshot.kt | 4 ++++ ...ieldsinSingleDeferDirectiveTestSnapshot.kt | 4 ++++ .../defer/NestedDefersTestSnapshot.kt | 4 ++++ .../hydration/HydrationTestSnapshot.kt | 4 ++++ .../HydrationDeferFlagOffTestSnapshot.kt | 4 ++++ ...medFieldAndNestedHydrationsTestSnapshot.kt | 4 ++++ ...ydrationDeferInRenamedFieldTestSnapshot.kt | 4 ++++ ...namedFieldUsingRenamedFieldTestSnapshot.kt | 4 ++++ ...DisabledForNestedHydrationsTestSnapshot.kt | 4 ++++ ...rIsDisabledForRelatedIssuesTestSnapshot.kt | 4 ++++ ...RelatedIssuesForParentIssueTestSnapshot.kt | 4 ++++ .../HydrationDeferIsDisabledTestSnapshot.kt | 4 ++++ .../defer/HydrationDeferTestSnapshot.kt | 4 ++++ ...nExecuteOnCompleteOnFailureTestSnapshot.kt | 4 ++++ ...nExecuteOnCompleteOnSuccessTestSnapshot.kt | 4 ++++ ...xecutionOnCompleteOnFailureTestSnapshot.kt | 4 ++++ ...xecutionOnCompleteOnSuccessTestSnapshot.kt | 4 ++++ 28 files changed, 129 insertions(+), 1 deletion(-) diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/UpdateTestSnapshots.kt b/test/src/test/kotlin/graphql/nadel/tests/next/UpdateTestSnapshots.kt index fdc1d0319..c3ad1d579 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/UpdateTestSnapshots.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/UpdateTestSnapshots.kt @@ -5,6 +5,7 @@ import com.squareup.kotlinpoet.AnnotationSpec import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FileSpec +import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy @@ -25,7 +26,15 @@ import kotlin.reflect.KClass // For navigation so you can search up UpdateTestSnapshots private typealias UpdateTestSnapshots = Unit -suspend fun main() { +suspend inline fun update() { + return update(T::class) +} + +suspend fun update(klass: KClass) { + main(klass.qualifiedName!!) +} + +private suspend fun main(vararg args: String) { val sourceRoot = File("test/src/test/kotlin/") require(sourceRoot.exists() && sourceRoot.isDirectory) @@ -33,6 +42,9 @@ suspend fun main() { .onEach { klass -> println("Loading ${klass.qualifiedName}") } + .filter { + args.isEmpty() || args.contains(it.qualifiedName) + } .map { it to it.newInstanceNoArgConstructor() } @@ -45,6 +57,7 @@ suspend fun main() { val outputFile = FileSpec.builder(ClassName.bestGuess(klass.qualifiedName!! + "Snapshot")) .indent(' '.toString().repeat(4)) .addFileComment("@formatter:off") + .addFunction(makeUpdateSnapshotFunction(klass)) .addType(makeTestSnapshotClass(klass, captured)) .build() .writeTo(sourceRoot) @@ -65,6 +78,13 @@ suspend fun main() { } } +fun makeUpdateSnapshotFunction(klass: KClass): FunSpec { + return FunSpec.builder("main") + .addModifiers(KModifier.PRIVATE, KModifier.SUSPEND) + .addCode("graphql.nadel.tests.next.update<%T>()", klass) + .build() +} + private fun getTestClassSequence(): Sequence> { return ClassPath.from(ClassLoader.getSystemClassLoader()) .getTopLevelClassesRecursive("graphql.nadel.tests") diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/BasicObjectSchemaTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/BasicObjectSchemaTestSnapshot.kt index 688443ff2..43fa7c402 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/BasicObjectSchemaTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/BasicObjectSchemaTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/EchoTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/EchoTestSnapshot.kt index 584bc5522..c53104b8e 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/EchoTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/basic/EchoTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt index 6389bf028..2c0a05453 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/ComprehensiveDeferQueryWithDifferentServiceCallsSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt index ce1b5ce10..1cdb6a537 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferOnListItemsTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt index 5b8e08b62..9bfa7ab30 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferThrowsErrorTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt index 8bd741911..863def571 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithIfFalseTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt index 04055650e..0b1c9cb58 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithLabelTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt index 6a148fd81..100b7de1c 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/DeferWithoutLabelTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt index b9d5affa2..d2be14f54 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferDirectivesTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt index f8f5f3dcc..8b8aba2fd 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleDeferWithDifferentServiceCallsSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt index b3d0df19e..88001acff 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinMultipleDeferDirectivesTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt index 8a7c0c191..7f18c5bbe 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/MultipleFieldsinSingleDeferDirectiveTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt index e9b8bc83f..c7a979750 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/defer/NestedDefersTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/HydrationTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/HydrationTestSnapshot.kt index 04575dfd0..dc83d324d 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/HydrationTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/HydrationTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferFlagOffTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferFlagOffTestSnapshot.kt index b307671d0..afc9d8810 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferFlagOffTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferFlagOffTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldAndNestedHydrationsTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldAndNestedHydrationsTestSnapshot.kt index b12632cd7..ec934a0a7 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldAndNestedHydrationsTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldAndNestedHydrationsTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldTestSnapshot.kt index be6e76620..7c9e86d50 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldUsingRenamedFieldTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldUsingRenamedFieldTestSnapshot.kt index 8cba6b521..5c3bb1005 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldUsingRenamedFieldTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferInRenamedFieldUsingRenamedFieldTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForNestedHydrationsTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForNestedHydrationsTestSnapshot.kt index e950786bb..b6f4cff4e 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForNestedHydrationsTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForNestedHydrationsTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForRelatedIssuesTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForRelatedIssuesTestSnapshot.kt index 6b67ce5ec..530bdd4d7 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForRelatedIssuesTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledForRelatedIssuesTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledInListOfRelatedIssuesForParentIssueTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledInListOfRelatedIssuesForParentIssueTestSnapshot.kt index 15e6703f3..bec6840db 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledInListOfRelatedIssuesForParentIssueTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledInListOfRelatedIssuesForParentIssueTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledTestSnapshot.kt index cdedc3b0d..f8ba4a777 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferIsDisabledTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferTestSnapshot.kt index bc7193527..64c05d162 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/hydration/defer/HydrationDeferTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnFailureTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnFailureTestSnapshot.kt index 626929a82..43ef28783 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnFailureTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnFailureTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnSuccessTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnSuccessTestSnapshot.kt index 127be8583..0c41794e2 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnSuccessTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginExecuteOnCompleteOnSuccessTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnFailureTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnFailureTestSnapshot.kt index 52bac40f9..55204e525 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnFailureTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnFailureTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnSuccessTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnSuccessTestSnapshot.kt index b532645ea..aed6732a6 100644 --- a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnSuccessTestSnapshot.kt +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/instrumentation/InstrumentationBeginQueryExecutionOnCompleteOnSuccessTestSnapshot.kt @@ -9,6 +9,10 @@ import kotlin.Suppress import kotlin.collections.List import kotlin.collections.listOf +private suspend fun main() { + graphql.nadel.tests.next.update() +} + /** * This class is generated. Do NOT modify. * From 53f4a437461fbecaf15fd85ce8d6a24dc784ba3f Mon Sep 17 00:00:00 2001 From: Franklin Wang <9077461+gnawf@users.noreply.github.com> Date: Mon, 5 Aug 2024 11:34:01 +1000 Subject: [PATCH 5/6] Enable union validation (#567) * Enable union validation * Add more tests around omitted union members * Let's sunset this behavior, it introduces complexity without consumers * Add unit tests for union validation * Wording * More tests --- .../nadel/validation/NadelUnionValidation.kt | 72 ++-- .../validation/NadelTypeValidationTest.kt | 44 --- .../validation/NadelUnionValidationTest.kt | 332 ++++++++++++++++++ ...AllUnionTypeConditionsUnionTestSnapshot.kt | 121 +++++++ .../execution/BasicUnionExecutionTest.kt | 113 ++++++ ...nUnionMembersInlineFragmentTestSnapshot.kt | 90 +++++ ...enUnionMembersNamedFragmentTestSnapshot.kt | 91 +++++ .../HiddenUnionMembersTypenameTestSnapshot.kt | 102 ++++++ .../HiddenUnionMembersVisibleMemberTest.kt | 116 ++++++ ...enUnionMembersVisibleMemberTestSnapshot.kt | 104 ++++++ ...ialUnionTypeConditionsUnionTestSnapshot.kt | 109 ++++++ .../TypenameInUnionSelectionTestSnapshot.kt | 106 ++++++ .../UnionAliasToSameResultKeyTestSnapshot.kt | 124 +++++++ .../UnionWithInterfacesExecutionTest.kt | 81 +++++ ...nionWithInterfacesExecutionTestSnapshot.kt | 122 +++++++ .../deep-rename-not-asked-for-with-unions.yml | 2 +- .../deep-rename-with-more-unions.yml | 2 +- .../deep renames/deep-rename-with-unions.yml | 2 +- 18 files changed, 1652 insertions(+), 81 deletions(-) create mode 100644 lib/src/test/kotlin/graphql/nadel/validation/NadelUnionValidationTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/AllUnionTypeConditionsUnionTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/BasicUnionExecutionTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersInlineFragmentTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersNamedFragmentTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersTypenameTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/PartialUnionTypeConditionsUnionTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/TypenameInUnionSelectionTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionAliasToSameResultKeyTestSnapshot.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTest.kt create mode 100644 test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTestSnapshot.kt diff --git a/lib/src/main/java/graphql/nadel/validation/NadelUnionValidation.kt b/lib/src/main/java/graphql/nadel/validation/NadelUnionValidation.kt index 0869bed66..c4c62da76 100644 --- a/lib/src/main/java/graphql/nadel/validation/NadelUnionValidation.kt +++ b/lib/src/main/java/graphql/nadel/validation/NadelUnionValidation.kt @@ -1,45 +1,49 @@ package graphql.nadel.validation +import graphql.nadel.validation.NadelSchemaValidationError.UnionHasExtraType +import graphql.nadel.validation.util.NadelSchemaUtil +import graphql.schema.GraphQLObjectType +import graphql.schema.GraphQLUnionType + internal class NadelUnionValidation( private val typeValidation: NadelTypeValidation, ) { fun validate( schemaElement: NadelServiceSchemaElement, ): List { - return emptyList() + return if (schemaElement.overall is GraphQLUnionType && schemaElement.underlying is GraphQLUnionType) { + schemaElement.overall.types + .flatMap { memberOverallType -> + val memberUnderlyingType = + NadelSchemaUtil.getUnderlyingType(memberOverallType, schemaElement.service) - // return if (schemaElement.overall is GraphQLUnionType && schemaElement.underlying is GraphQLUnionType) { - // schemaElement.overall.types - // .flatMap { unionOverallType -> - // val unionUnderlyingType = NadelSchemaUtil.getUnderlyingType(unionOverallType, schemaElement.service) - // - // if (!schemaElement.underlying.types.contains(unionUnderlyingType)) { - // listOf( - // UnionHasExtraType( - // service = schemaElement.service, - // unionType = schemaElement.overall, - // extraType = unionOverallType as GraphQLObjectType, - // ), - // ) - // } else if (unionUnderlyingType == null) { - // listOf( - // MissingUnderlyingType( - // service = schemaElement.service, - // overallType = unionOverallType, - // ), - // ) - // } else { - // typeValidation.validate( - // NadelServiceSchemaElement( - // service = schemaElement.service, - // overall = unionOverallType, - // underlying = unionUnderlyingType, - // ), - // ) - // } - // } - // } else { - // emptyList() - // } + if (memberUnderlyingType == null) { + listOf( + NadelSchemaValidationError.MissingUnderlyingType( + service = schemaElement.service, + overallType = memberOverallType, + ), + ) + } else if (!schemaElement.underlying.types.contains(memberUnderlyingType)) { + listOf( + UnionHasExtraType( + service = schemaElement.service, + unionType = schemaElement.overall, + extraType = memberOverallType as GraphQLObjectType, + ), + ) + } else { + typeValidation.validate( + NadelServiceSchemaElement( + service = schemaElement.service, + overall = memberOverallType, + underlying = memberUnderlyingType, + ), + ) + } + } + } else { + emptyList() + } } } diff --git a/lib/src/test/kotlin/graphql/nadel/validation/NadelTypeValidationTest.kt b/lib/src/test/kotlin/graphql/nadel/validation/NadelTypeValidationTest.kt index 5832f58e0..51fd395de 100644 --- a/lib/src/test/kotlin/graphql/nadel/validation/NadelTypeValidationTest.kt +++ b/lib/src/test/kotlin/graphql/nadel/validation/NadelTypeValidationTest.kt @@ -474,50 +474,6 @@ class NadelTypeValidationTest : DescribeSpec({ assert(error.overallField.name == "nextgenSpecific") } - it("ignores extension union members declared by other services") { - val fixture = NadelValidationTestFixture( - overallSchema = mapOf( - "users" to """ - type Query { - stuff: Stuff - } - union Stuff = User - type User { - id: ID! - } - """.trimIndent(), - "issues" to """ - extend union Stuff = | Issue - type Issue { - id: ID! - } - """.trimIndent(), - ), - underlyingSchema = mapOf( - "users" to """ - type Query { - stuff: Stuff - } - union Stuff = User - type User { - id: ID! - } - """.trimIndent(), - "issues" to """ - type Query { - echo: String - } - type Issue { - id: ID! - } - """.trimIndent(), - ), - ) - - val errors = validate(fixture) - assert(errors.map { it.message }.isEmpty()) - } - it("validates extension union member if defined by own service") { val fixture = NadelValidationTestFixture( overallSchema = mapOf( diff --git a/lib/src/test/kotlin/graphql/nadel/validation/NadelUnionValidationTest.kt b/lib/src/test/kotlin/graphql/nadel/validation/NadelUnionValidationTest.kt new file mode 100644 index 000000000..bcbd2bf57 --- /dev/null +++ b/lib/src/test/kotlin/graphql/nadel/validation/NadelUnionValidationTest.kt @@ -0,0 +1,332 @@ +package graphql.nadel.validation + +import graphql.nadel.validation.util.assertSingleOfType +import org.junit.jupiter.api.Test +import kotlin.test.assertTrue + +class NadelUnionValidationTest { + @Test + fun `no errors for valid schema`() { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog + type Human { + id: ID! + } + type Dog { + name: String + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog + type Human { + id: ID! + } + type Dog { + name: String + } + """.trimIndent(), + ), + ) + + val errors = validate(fixture) + assertTrue(errors.map { it.message }.isEmpty()) + } + + @Test + fun `union in overall schema can have fewer members than underlying schema`() { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Dog + type Human { + id: ID! + } + type Dog { + name: String + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog + type Human { + id: ID! + } + type Dog { + name: String + } + """.trimIndent(), + ), + ) + + val errors = validate(fixture) + assertTrue(errors.map { it.message }.isEmpty()) + } + + @Test + fun `passes valid schema where union member was renamed`() { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Dog + type Human @renamed(from: "Homo") { + id: ID! + } + type Dog { + name: String + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Homo | Dog + type Homo { + id: ID! + } + type Dog { + name: String + } + """.trimIndent(), + ), + ) + + val errors = validate(fixture) + assertTrue(errors.map { it.message }.isEmpty()) + } + + @Test + fun `fails if irrelevant union member was renamed to same name of valid union member`() { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human + type Human @renamed(from: "Issue") { + id: ID! + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog + type Human { + id: ID! + } + type Dog { + name: String + } + type Issue { + id: ID! + } + """.trimIndent(), + ), + ) + + val errors = validate(fixture) + assertTrue(errors.map { it.message }.isNotEmpty()) + + val error = errors.assertSingleOfType() + assertTrue(error.service.name == "entities") + assertTrue(error.unionType.name == "Entity") + assertTrue(error.extraType.name == "Human") + } + + @Test + fun `errors if union in overall schema declares members not in underlying schema union`() { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog | Tree + type Human { + id: ID! + } + type Dog { + name: String + } + type Tree { + location: String + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog + type Human { + id: ID! + } + type Dog { + name: String + } + type Tree { + location: String + } + """.trimIndent(), + ), + ) + + val errors = validate(fixture) + assertTrue(errors.map { it.message }.isNotEmpty()) + + val error = errors.assertSingleOfType() + assertTrue(error.service.name == "entities") + assertTrue(error.unionType.name == "Entity") + assertTrue(error.extraType.name == "Tree") + } + + @Test + fun `cannot add types not defined in service`() { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "issues" to /* language=GraphQL */ """ + type Issue { + id: ID! + } + """.trimIndent(), + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog | Issue + type Human { + id: ID! + } + type Dog { + name: String + } + type Tree { + location: String + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "issues" to /* language=GraphQL */ """ + type Query { + echo: String + } + type Issue { + id: ID! + } + """.trimIndent(), + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog + type Human { + id: ID! + } + type Dog { + name: String + } + type Tree { + location: String + } + """.trimIndent(), + ), + ) + + val errors = validate(fixture) + assertTrue(errors.map { it.message }.isNotEmpty()) + + val error = errors.assertSingleOfType() + assertTrue(error.service.name == "entities") + assertTrue(error.overallType.name == "Issue") + } + + @Test + fun `runs type validation on unions members`() { + val fixture = NadelValidationTestFixture( + overallSchema = mapOf( + "issues" to /* language=GraphQL */ """ + type Issue { + id: ID! + } + """.trimIndent(), + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog | Issue + type Human { + id: ID! + } + type Dog { + name: String + } + type Tree { + location: String + } + """.trimIndent(), + ), + underlyingSchema = mapOf( + "issues" to /* language=GraphQL */ """ + type Query { + echo: String + } + type Issue { + id: ID! + } + """.trimIndent(), + "entities" to /* language=GraphQL */ """ + type Query { + entity(id: ID!): Entity + } + union Entity = Human | Dog + type Human { + id: ID! + } + type Dog { + name: String + } + type Tree { + location: String + } + type Issue { + key: ID! + } + """.trimIndent(), + ), + ) + + val errors = validate(fixture) + assertTrue(errors.map { it.message }.isNotEmpty()) + + val error = errors.assertSingleOfType() + assertTrue(error.service.name == "entities") + assertTrue(error.parentType.overall.name == "Issue") + assertTrue(error.overallField.name == "id") + } +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/AllUnionTypeConditionsUnionTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/AllUnionTypeConditionsUnionTestSnapshot.kt new file mode 100644 index 000000000..82700d336 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/AllUnionTypeConditionsUnionTestSnapshot.kt @@ -0,0 +1,121 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class AllUnionTypeConditionsUnionTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * ... on Issue { + * __typename + * key + * } + * ... on User { + * name + * } + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ExpectedServiceCall( + service = "abstract", + query = """ + | { + | abstract { + | ... on Issue { + | __typename + | key + | } + | ... on User { + | name + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "abstract": [ + | { + | "name": "Hello" + | }, + | { + | "__typename": "Issue", + | "key": "HEL" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * Combined Result + * + * ```json + * { + * "data": { + * "abstract": [ + * { + * "name": "Hello" + * }, + * { + * "__typename": "Issue", + * "key": "HEL" + * } + * ] + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "abstract": [ + | { + | "name": "Hello" + | }, + | { + | "__typename": "Issue", + | "key": "HEL" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/BasicUnionExecutionTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/BasicUnionExecutionTest.kt new file mode 100644 index 000000000..d7fd00644 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/BasicUnionExecutionTest.kt @@ -0,0 +1,113 @@ +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.NadelIntegrationTest +import org.intellij.lang.annotations.Language + +class TypenameInUnionSelectionTest : BasicUnionExecutionTestBase( + query = """ + query { + abstract { + __typename + } + } + """.trimIndent(), +) + +class PartialUnionTypeConditionsUnionTest : BasicUnionExecutionTestBase( + query = """ + query { + abstract { + ... on Issue { + __typename + key + } + } + } + """.trimIndent(), +) + +class AllUnionTypeConditionsUnionTest : BasicUnionExecutionTestBase( + query = """ + query { + abstract { + ... on Issue { + __typename + key + } + ... on User { + name + } + } + } + """.trimIndent(), +) + + +class UnionAliasToSameResultKeyTest : BasicUnionExecutionTestBase( + query = """ + query { + abstract { + __typename + ... on Issue { + id: key + } + ... on User { + id: name + } + } + } + """.trimIndent(), +) + +abstract class BasicUnionExecutionTestBase( + @Language("GraphQL") query: String, +) : NadelIntegrationTest( + query = query, + services = listOf( + Service( + name = "abstract", + overallSchema = """ + type Query { + abstract: [Abstract] + } + union Abstract = User | Issue + type User { + name: String + } + type Issue { + key: String + } + """.trimIndent(), + runtimeWiring = { wiring -> + data class User( + val name: String, + ) + + data class Issue( + val key: String, + ) + + wiring + .type("Abstract") { type -> + type + .typeResolver { env -> + env.schema.getObjectType(env.getObject().javaClass.simpleName) + } + } + .type("Query") { type -> + type + .dataFetcher("abstract") { env -> + listOf( + User( + name = "Hello", + ), + Issue( + key = "HEL", + ), + ) + } + } + }, + ), + ), +) diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersInlineFragmentTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersInlineFragmentTestSnapshot.kt new file mode 100644 index 000000000..68c789415 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersInlineFragmentTestSnapshot.kt @@ -0,0 +1,90 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class HiddenUnionMembersInlineFragmentTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * ... on Issue { + * key + * } + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ) + + /** + * Combined Result + * + * ```json + * { + * "errors": [ + * { + * "message": "Validation error (InvalidFragmentType@[abstract]) : Fragment cannot be + * spread here as objects of type 'Abstract' can never be of type 'Issue'", + * "locations": [ + * { + * "line": 3, + * "column": 5 + * } + * ], + * "extensions": { + * "classification": "ValidationError" + * } + * } + * ] + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "errors": [ + | { + | "message": "Validation error (InvalidFragmentType@[abstract]) : Fragment cannot be spread here as objects of type 'Abstract' can never be of type 'Issue'", + | "locations": [ + | { + | "line": 3, + | "column": 5 + | } + | ], + | "extensions": { + | "classification": "ValidationError" + | } + | } + | ] + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersNamedFragmentTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersNamedFragmentTestSnapshot.kt new file mode 100644 index 000000000..34f17b2ac --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersNamedFragmentTestSnapshot.kt @@ -0,0 +1,91 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class HiddenUnionMembersNamedFragmentTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * ...Frag + * } + * } + * fragment Frag on Issue { + * key + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ) + + /** + * Combined Result + * + * ```json + * { + * "errors": [ + * { + * "message": "Validation error (InvalidFragmentType@[abstract]) : Fragment 'Frag' cannot + * be spread here as objects of type 'Abstract' can never be of type 'Issue'", + * "locations": [ + * { + * "line": 3, + * "column": 5 + * } + * ], + * "extensions": { + * "classification": "ValidationError" + * } + * } + * ] + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "errors": [ + | { + | "message": "Validation error (InvalidFragmentType@[abstract]) : Fragment 'Frag' cannot be spread here as objects of type 'Abstract' can never be of type 'Issue'", + | "locations": [ + | { + | "line": 3, + | "column": 5 + | } + | ], + | "extensions": { + | "classification": "ValidationError" + | } + | } + | ] + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersTypenameTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersTypenameTestSnapshot.kt new file mode 100644 index 000000000..894e592ce --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersTypenameTestSnapshot.kt @@ -0,0 +1,102 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class HiddenUnionMembersTypenameTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * __typename + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ExpectedServiceCall( + service = "abstract", + query = """ + | { + | abstract { + | ... on User { + | __typename + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "abstract": [ + | { + | "__typename": "User" + | }, + | {} + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * Combined Result + * + * ```json + * { + * "data": { + * "abstract": [ + * { + * "__typename": "User" + * }, + * {} + * ] + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "abstract": [ + | { + | "__typename": "User" + | }, + | {} + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTest.kt new file mode 100644 index 000000000..f38e5fdc8 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTest.kt @@ -0,0 +1,116 @@ +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.NadelIntegrationTest +import org.intellij.lang.annotations.Language + +class HiddenUnionMembersTypenameTest : HiddenUnionMembersTestBase( + query = """ + query { + abstract { + __typename + } + } + """.trimIndent(), +) + +class HiddenUnionMembersInlineFragmentTest : HiddenUnionMembersTestBase( + query = """ + query { + abstract { + ... on Issue { + key + } + } + } + """.trimIndent(), +) + +class HiddenUnionMembersNamedFragmentTest : HiddenUnionMembersTestBase( + query = """ + query { + abstract { + ...Frag + } + } + fragment Frag on Issue { + key + } + """.trimIndent(), +) + +class HiddenUnionMembersVisibleMemberTest : HiddenUnionMembersTestBase( + query = """ + query { + abstract { + ... on User { + name + } + } + } + """.trimIndent(), +) + +abstract class HiddenUnionMembersTestBase( + @Language("GraphQL") query: String, +) : NadelIntegrationTest( + query = query, + services = listOf( + Service( + name = "abstract", + overallSchema = """ + type Query { + abstract: [Abstract] + } + union Abstract = User + type User { + name: String + } + type Issue { + key: String + } + """.trimIndent(), + underlyingSchema = """ + type Query { + abstract: [Abstract] + } + union Abstract = User | Issue + type User { + name: String + } + type Issue { + key: String + } + """.trimIndent(), + runtimeWiring = { wiring -> + data class User( + val name: String, + ) + + data class Issue( + val key: String, + ) + + wiring + .type("Abstract") { type -> + type + .typeResolver { env -> + env.schema.getObjectType(env.getObject().javaClass.simpleName) + } + } + .type("Query") { type -> + type + .dataFetcher("abstract") { env -> + listOf( + User( + name = "Hello", + ), + Issue( + key = "HEL", + ), + ) + } + } + }, + ), + ), +) diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTestSnapshot.kt new file mode 100644 index 000000000..c99d15a85 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/HiddenUnionMembersVisibleMemberTestSnapshot.kt @@ -0,0 +1,104 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class HiddenUnionMembersVisibleMemberTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * ... on User { + * name + * } + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ExpectedServiceCall( + service = "abstract", + query = """ + | { + | abstract { + | ... on User { + | name + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "abstract": [ + | { + | "name": "Hello" + | }, + | {} + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * Combined Result + * + * ```json + * { + * "data": { + * "abstract": [ + * { + * "name": "Hello" + * }, + * {} + * ] + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "abstract": [ + | { + | "name": "Hello" + | }, + | {} + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/PartialUnionTypeConditionsUnionTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/PartialUnionTypeConditionsUnionTestSnapshot.kt new file mode 100644 index 000000000..67a9863ac --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/PartialUnionTypeConditionsUnionTestSnapshot.kt @@ -0,0 +1,109 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class PartialUnionTypeConditionsUnionTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * ... on Issue { + * __typename + * key + * } + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ExpectedServiceCall( + service = "abstract", + query = """ + | { + | abstract { + | ... on Issue { + | __typename + | key + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "abstract": [ + | {}, + | { + | "__typename": "Issue", + | "key": "HEL" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * Combined Result + * + * ```json + * { + * "data": { + * "abstract": [ + * {}, + * { + * "__typename": "Issue", + * "key": "HEL" + * } + * ] + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "abstract": [ + | {}, + | { + | "__typename": "Issue", + | "key": "HEL" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/TypenameInUnionSelectionTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/TypenameInUnionSelectionTestSnapshot.kt new file mode 100644 index 000000000..04d4f5a02 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/TypenameInUnionSelectionTestSnapshot.kt @@ -0,0 +1,106 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class TypenameInUnionSelectionTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * __typename + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ExpectedServiceCall( + service = "abstract", + query = """ + | { + | abstract { + | __typename + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "abstract": [ + | { + | "__typename": "User" + | }, + | { + | "__typename": "Issue" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * Combined Result + * + * ```json + * { + * "data": { + * "abstract": [ + * { + * "__typename": "User" + * }, + * { + * "__typename": "Issue" + * } + * ] + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "abstract": [ + | { + | "__typename": "User" + | }, + | { + | "__typename": "Issue" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionAliasToSameResultKeyTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionAliasToSameResultKeyTestSnapshot.kt new file mode 100644 index 000000000..0cf6d66ff --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionAliasToSameResultKeyTestSnapshot.kt @@ -0,0 +1,124 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class UnionAliasToSameResultKeyTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * abstract { + * __typename + * ... on Issue { + * id: key + * } + * ... on User { + * id: name + * } + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ExpectedServiceCall( + service = "abstract", + query = """ + | { + | abstract { + | __typename + | ... on Issue { + | id: key + | } + | ... on User { + | id: name + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "abstract": [ + | { + | "__typename": "User", + | "id": "Hello" + | }, + | { + | "__typename": "Issue", + | "id": "HEL" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * Combined Result + * + * ```json + * { + * "data": { + * "abstract": [ + * { + * "__typename": "User", + * "id": "Hello" + * }, + * { + * "__typename": "Issue", + * "id": "HEL" + * } + * ] + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "abstract": [ + | { + | "__typename": "User", + | "id": "Hello" + | }, + | { + | "__typename": "Issue", + | "id": "HEL" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTest.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTest.kt new file mode 100644 index 000000000..e175dd0cd --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTest.kt @@ -0,0 +1,81 @@ +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.NadelIntegrationTest + +class UnionWithInterfacesExecutionTest : NadelIntegrationTest( + query = """ + query { + union { + __typename + ... on Interface { + id + } + ... on User { + name + } + } + } + """.trimIndent(), + services = listOf( + Service( + name = "abstract", + overallSchema = """ + type Query { + union: [Union] + } + interface Interface { + id: ID! + } + union Union = User | Issue + type User implements Interface { + id: ID! + name: String + } + type Issue { + id: ID! + key: String + } + """.trimIndent(), + runtimeWiring = { wiring -> + data class User( + val id: String, + val name: String, + ) + + data class Issue( + val id: String, + val key: String, + ) + + wiring + .type("Union") { type -> + type + .typeResolver { env -> + env.schema.getObjectType(env.getObject().javaClass.simpleName) + } + } + .type("Interface") { type -> + type + .typeResolver { env -> + env.schema.getObjectType(env.getObject().javaClass.simpleName) + } + } + .type("Query") { type -> + type + .dataFetcher("union") { env -> + listOf( + User( + id = "user/1", + name = "Hello", + ), + Issue( + id = "issue/1", + key = "HEL", + ), + ) + } + } + }, + ), + ), +) diff --git a/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTestSnapshot.kt b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTestSnapshot.kt new file mode 100644 index 000000000..f56eb9c81 --- /dev/null +++ b/test/src/test/kotlin/graphql/nadel/tests/next/fixtures/execution/UnionWithInterfacesExecutionTestSnapshot.kt @@ -0,0 +1,122 @@ +// @formatter:off +package graphql.nadel.tests.next.fixtures.execution + +import graphql.nadel.tests.next.ExpectedNadelResult +import graphql.nadel.tests.next.ExpectedServiceCall +import graphql.nadel.tests.next.TestSnapshot +import graphql.nadel.tests.next.listOfJsonStrings +import kotlin.Suppress +import kotlin.collections.List +import kotlin.collections.listOf + +private suspend fun main() { + graphql.nadel.tests.next.update() +} + +/** + * This class is generated. Do NOT modify. + * + * Refer to [graphql.nadel.tests.next.UpdateTestSnapshots + */ +@Suppress("unused") +public class UnionWithInterfacesExecutionTestSnapshot : TestSnapshot() { + /** + * Query + * + * ```graphql + * query { + * union { + * __typename + * ... on Interface { + * id + * } + * ... on User { + * name + * } + * } + * } + * ``` + * + * Variables + * + * ```json + * {} + * ``` + */ + override val calls: List = listOf( + ExpectedServiceCall( + service = "abstract", + query = """ + | { + | union { + | __typename + | ... on User { + | id + | name + | } + | } + | } + """.trimMargin(), + variables = "{}", + result = """ + | { + | "data": { + | "union": [ + | { + | "__typename": "User", + | "id": "user/1", + | "name": "Hello" + | }, + | { + | "__typename": "Issue" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ), + ) + + /** + * Combined Result + * + * ```json + * { + * "data": { + * "union": [ + * { + * "__typename": "User", + * "id": "user/1", + * "name": "Hello" + * }, + * { + * "__typename": "Issue" + * } + * ] + * } + * } + * ``` + */ + override val result: ExpectedNadelResult = ExpectedNadelResult( + result = """ + | { + | "data": { + | "union": [ + | { + | "__typename": "User", + | "id": "user/1", + | "name": "Hello" + | }, + | { + | "__typename": "Issue" + | } + | ] + | } + | } + """.trimMargin(), + delayedResults = listOfJsonStrings( + ), + ) +} diff --git a/test/src/test/resources/fixtures/deep renames/deep-rename-not-asked-for-with-unions.yml b/test/src/test/resources/fixtures/deep renames/deep-rename-not-asked-for-with-unions.yml index 54594b3ae..71b7b7da4 100644 --- a/test/src/test/resources/fixtures/deep renames/deep-rename-not-asked-for-with-unions.yml +++ b/test/src/test/resources/fixtures/deep renames/deep-rename-not-asked-for-with-unions.yml @@ -22,7 +22,7 @@ overallSchema: # language=GraphQL underlyingSchema: Issues: | - union HasName = Issue | Edible + union HasName = Issue | Edible | Troll | User type Query { names: [HasName] } diff --git a/test/src/test/resources/fixtures/deep renames/deep-rename-with-more-unions.yml b/test/src/test/resources/fixtures/deep renames/deep-rename-with-more-unions.yml index ffeab4044..0c0d0adb3 100644 --- a/test/src/test/resources/fixtures/deep renames/deep-rename-with-more-unions.yml +++ b/test/src/test/resources/fixtures/deep renames/deep-rename-with-more-unions.yml @@ -22,7 +22,7 @@ overallSchema: # language=GraphQL underlyingSchema: Issues: | - union HasName = Issue | Edible + union HasName = Issue | Edible | Troll | User type Query { names: [HasName] } diff --git a/test/src/test/resources/fixtures/deep renames/deep-rename-with-unions.yml b/test/src/test/resources/fixtures/deep renames/deep-rename-with-unions.yml index e7e747823..bdde39b75 100644 --- a/test/src/test/resources/fixtures/deep renames/deep-rename-with-unions.yml +++ b/test/src/test/resources/fixtures/deep renames/deep-rename-with-unions.yml @@ -22,7 +22,7 @@ overallSchema: # language=GraphQL underlyingSchema: Issues: | - union HasName = Issue | Edible + union HasName = Issue | Edible | Troll | User type Query { names: [HasName] } From 4b6962323d08977e4cf6d34b53401fb7ad8bb12b Mon Sep 17 00:00:00 2001 From: Steven Barker Date: Mon, 5 Aug 2024 16:06:28 +1200 Subject: [PATCH 6/6] stashed changes --- .../main/java/graphql/nadel/NextgenEngine.kt | 23 +++++++- .../nadel/engine/transform/query/NFUtil.kt | 1 - .../result/NadelResultTransformer.kt | 53 ++++++++++++++++--- 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/lib/src/main/java/graphql/nadel/NextgenEngine.kt b/lib/src/main/java/graphql/nadel/NextgenEngine.kt index 1c2914e68..111abbfe4 100644 --- a/lib/src/main/java/graphql/nadel/NextgenEngine.kt +++ b/lib/src/main/java/graphql/nadel/NextgenEngine.kt @@ -58,6 +58,7 @@ import kotlinx.coroutines.awaitAll import kotlinx.coroutines.cancel import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.map import kotlinx.coroutines.future.asCompletableFuture import kotlinx.coroutines.future.asDeferred import kotlinx.coroutines.future.await @@ -269,7 +270,10 @@ internal class NextgenEngine( service = service, transformedQuery = transformedQuery, executionContext = executionContext, + executionPlan = executionPlan, executionHydrationDetails = executionContext.hydrationDetails, + artificialFields = queryTransform.artificialFields, + overallToUnderlyingFields = queryTransform.overallToUnderlyingFields, ) } val transformedResult: ServiceExecutionResult = when { @@ -293,7 +297,10 @@ internal class NextgenEngine( service: Service, transformedQuery: ExecutableNormalizedField, executionContext: NadelExecutionContext, + executionPlan: NadelExecutionPlan, executionHydrationDetails: ServiceExecutionHydrationDetails? = null, + artificialFields: List, + overallToUnderlyingFields: Map>, ): ServiceExecutionResult { val timer = executionContext.timer @@ -361,7 +368,21 @@ internal class NextgenEngine( if (serviceExecResult is NadelIncrementalServiceExecutionResult) { executionContext.incrementalResultSupport.defer( - serviceExecResult.incrementalItemPublisher.asFlow() + serviceExecResult.incrementalItemPublisher + .asFlow() + .map { + // Transform + resultTransformer + .transform( + executionContext = executionContext, + executionPlan = executionPlan, + artificialFields = artificialFields, + overallToUnderlyingFields = overallToUnderlyingFields, + service = service, + result = serviceExecResult + ) + it + } ) } diff --git a/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt b/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt index 46d165271..829faae78 100644 --- a/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt +++ b/lib/src/main/java/graphql/nadel/engine/transform/query/NFUtil.kt @@ -106,7 +106,6 @@ object NFUtil { return ExecutableNormalizedField.newNormalizedField() .objectTypeNames(listOf(parentType.name)) .fieldName(fieldName) - //.deferredExecutions() // <-- add defer execution .deferredExecutions(deferredExecutions) .also { builder -> if (pathToFieldIndex == queryPathToField.segments.lastIndex) { diff --git a/lib/src/main/java/graphql/nadel/engine/transform/result/NadelResultTransformer.kt b/lib/src/main/java/graphql/nadel/engine/transform/result/NadelResultTransformer.kt index e13f25e91..6cf1bf8b6 100644 --- a/lib/src/main/java/graphql/nadel/engine/transform/result/NadelResultTransformer.kt +++ b/lib/src/main/java/graphql/nadel/engine/transform/result/NadelResultTransformer.kt @@ -1,10 +1,13 @@ package graphql.nadel.engine.transform.result +import graphql.incremental.DelayedIncrementalPartialResultImpl +import graphql.nadel.NadelIncrementalServiceExecutionResult import graphql.nadel.Service import graphql.nadel.ServiceExecutionResult import graphql.nadel.engine.NadelExecutionContext import graphql.nadel.engine.blueprint.NadelOverallExecutionBlueprint import graphql.nadel.engine.plan.NadelExecutionPlan +import graphql.nadel.engine.transform.query.NadelQueryPath import graphql.nadel.engine.transform.result.json.JsonNodes import graphql.nadel.engine.util.JsonMap import graphql.nadel.engine.util.MutableJsonMap @@ -14,6 +17,8 @@ import kotlinx.coroutines.Deferred import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.reactive.asFlow internal class NadelResultTransformer(private val executionBlueprint: NadelOverallExecutionBlueprint) { suspend fun transform( @@ -24,11 +29,47 @@ internal class NadelResultTransformer(private val executionBlueprint: NadelOvera service: Service, result: ServiceExecutionResult, ): ServiceExecutionResult { + //NadelIncrementalServiceExecutionResult -> IncrementalItemPublisher.map (apply transforms to every itme in publisher) + //result + if (result is NadelIncrementalServiceExecutionResult) { + result.incrementalItemPublisher.asFlow() + .map { + val incremental = it.incremental + ?.map { + + } + DelayedIncrementalPartialResultImpl.newIncrementalExecutionResult() + + .extensions(it.extensions) + .build() + } + } + // maybe here or in NextGenEngine val nodes = JsonNodes(result.data) - - val deferredInstructions = ArrayList>>() - + nodes.getNodesAt(NadelQueryPath(listOf("issue", "user"))) + + val asyncInstructions = ArrayList>>() + + // issue { + // ... @defer { + // user { + // name # @renamed(from: "asdfaiowjefwef") + // } + // } + // key # @renamed(from: "asdf") + // } + // "incremtanl": [ + // { + // "data": { + // "user": { + // name: "Steven" + // } + // } + // "path": [issue] + // } + // ] coroutineScope { + // transform step of field [issue -> user -> name] for ((field, steps) in executionPlan.transformationSteps) { // This can be null if we did not end up sending the field e.g. for hydration val underlyingFields = overallToUnderlyingFields[field] @@ -37,7 +78,7 @@ internal class NadelResultTransformer(private val executionBlueprint: NadelOvera } for (step in steps) { - deferredInstructions.add( + asyncInstructions.add( async { step.transform.getResultInstructions( executionContext, @@ -54,14 +95,14 @@ internal class NadelResultTransformer(private val executionBlueprint: NadelOvera } } - deferredInstructions.add( + asyncInstructions.add( async { getRemoveArtificialFieldInstructions(artificialFields, nodes) }, ) } - val instructions = deferredInstructions + val instructions = asyncInstructions .awaitAll() .flatten()