From d02c67f42d81feb904fd64b92beb77b570c9b351 Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Fri, 6 Sep 2024 12:25:03 +0300 Subject: [PATCH 1/7] Replace using @Name to @Namespace on GraphQLApi and GraphQLClientApi --- .../VertxTypesafeGraphQLClientProxy.java | 2 +- .../client/impl/typesafe/QueryBuilder.java | 25 +++-- .../client/impl/typesafe/ResultBuilder.java | 9 +- .../typesafe/reflection/MethodInvocation.java | 33 ++++--- .../graphql/client/model/Annotations.java | 1 + .../client/model/ClientModelBuilder.java | 10 ++ .../graphql/client/model/QueryBuilder.java | 24 +++-- .../client/model/helper/OperationModel.java | 37 ++++---- .../client/model/ClientModelBuilderTest.java | 31 ++++--- .../graphql/typesafe/AnnotationBehavior.java | 14 +-- .../tck/graphql/typesafe/ArrayBehavior.java | 30 +++--- .../tck/graphql/typesafe/EnumBehavior.java | 8 +- .../tck/graphql/typesafe/ErrorBehavior.java | 20 ++-- .../tck/graphql/typesafe/HeaderBehavior.java | 10 +- .../graphql/typesafe/InterfaceBehavior.java | 6 +- .../graphql/typesafe/MutationBehavior.java | 20 ++-- .../tck/graphql/typesafe/NestedBehavior.java | 36 +++---- .../typesafe/NestedParameterBehavior.java | 10 +- .../graphql/typesafe/OptionalBehavior.java | 38 ++++---- .../graphql/typesafe/ParametersBehavior.java | 82 ++++++++-------- .../tck/graphql/typesafe/ScalarBehavior.java | 90 +++++++++--------- .../typesafe/TypesafeResponseBehavior.java | 2 +- .../tck/graphql/typesafe/UnionBehavior.java | 8 +- .../smallrye/graphql/schema/Annotations.java | 1 + .../graphql/schema/SchemaBuilder.java | 59 ++++++++---- .../graphql/schema/helper/GroupHelper.java | 25 ++--- .../graphql/index/app/BookGraphQLApi.java | 5 +- .../smallrye/graphql/schema/model/Group.java | 22 ++--- .../graphql/schema/model/GroupContainer.java | 93 +++++++++++++++++++ .../smallrye/graphql/schema/model/Schema.java | 86 ++++++++--------- .../io/smallrye/graphql/api/Namespace.java | 17 ++++ .../graphql/entry/http/IndexInitializer.java | 2 + .../smallrye/graphql/bootstrap/Bootstrap.java | 82 +++++++++++----- .../execution/FederatedNamespaceTest.java | 1 - .../graphql/test/grouping/BookGraphQLApi.java | 5 +- .../test/namespace/NamedNamespaceTestApi.java | 5 +- .../NamedNamespaceWithGroupingKeyTestApi.java | 5 +- .../namespace/SourceNamespaceTestApi.java | 22 +---- .../client/typesafe/directives/ServerApi.java | 2 +- 39 files changed, 582 insertions(+), 396 deletions(-) create mode 100644 common/schema-model/src/main/java/io/smallrye/graphql/schema/model/GroupContainer.java create mode 100644 server/api/src/main/java/io/smallrye/graphql/api/Namespace.java diff --git a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java index 649f0684a..f9fe262d9 100644 --- a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java +++ b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java @@ -309,7 +309,7 @@ private JsonObject request(MethodInvocation method) { } request.add("query", query); request.add("variables", variables(method)); - request.add("operationName", method.getName()); + request.add("operationName", method.getOperationName()); JsonObject result = request.build(); log.tracef("full graphql request: %s", result.toString()); return result; diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java index 8e1cf14f1..b64969470 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java @@ -24,14 +24,19 @@ public QueryBuilder(MethodInvocation method) { public String build() { StringBuilder request = new StringBuilder(method.getOperationTypeAsString()); request.append(" "); - request.append(method.getName()); - if (method.hasValueParameters()) + + request.append(method.getOperationName()); // operation name + + if (method.hasValueParameters()) { request.append(method.valueParameters().map(this::declare).collect(joining(", ", "(", ")"))); + } - String groupName = method.getGroupName(); - if (groupName != null) { - request.append(" { "); - request.append(groupName); + List namespaces = method.getNamespaces(); + if (!namespaces.isEmpty()) { + namespaces.forEach(value -> { + request.append(" { "); + request.append(value); + }); } if (method.isSingle()) { @@ -45,11 +50,13 @@ public String build() { request.append(fields(method.getReturnType())); - if (method.isSingle()) + if (method.isSingle()) { request.append(" }"); + } - if (groupName != null) - request.append(" } "); + if (!namespaces.isEmpty()) { + request.append(" } ".repeat(namespaces.size())); + } return request.toString(); } diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java index 30e02bd4f..4f4dc6f90 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java @@ -92,10 +92,11 @@ public Object read() { private JsonObject readData() { if (!response.containsKey("data") || response.isNull("data")) return null; - String groupName = method.getGroupName(); - JsonObject data = groupName != null - ? response.getJsonObject("data").getJsonObject(groupName) - : response.getJsonObject("data"); + + JsonObject data = response.getJsonObject("data"); + for (String namespace : method.getNamespaces()) { + data = data.getJsonObject(namespace); + } if (method.isSingle() && !data.containsKey(method.getName())) throw new InvalidResponseException("No data for '" + method.getName() + "'"); return data; diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java index 1a8a49504..d2992a5e2 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java @@ -1,5 +1,6 @@ package io.smallrye.graphql.client.impl.typesafe.reflection; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import java.io.Closeable; @@ -10,10 +11,12 @@ import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -23,6 +26,7 @@ import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; +import io.smallrye.graphql.api.Namespace; import io.smallrye.graphql.api.Subscription; import io.smallrye.graphql.client.core.OperationType; import io.smallrye.graphql.client.model.MethodKey; @@ -36,14 +40,14 @@ public static MethodInvocation of(Method method, Object... args) { private final TypeInfo type; private final Method method; private final Object[] parameterValues; - private final String groupName; + private final List namespaces; private List parameters; private MethodInvocation(TypeInfo type, Method method, Object[] parameterValues) { this.type = type; this.method = method; this.parameterValues = parameterValues; - this.groupName = readGroupName(method); + this.namespaces = readNamespace(method); } @Override @@ -262,18 +266,25 @@ public String getOperationTypeAsString() { } } - public String getGroupName() { - return groupName; + public List getNamespaces() { + return namespaces; } - private String readGroupName(Method method) { - Name annotation = method.getDeclaringClass().getAnnotation(Name.class); + private List readNamespace(Method method) { + Namespace annotation = method.getDeclaringClass().getAnnotation(Namespace.class); if (annotation != null) { - String groupName = annotation.value().trim(); - if (!groupName.isEmpty()) { - return groupName; - } + return Arrays.stream(annotation.value().split("/")) + .map(String::trim) + .collect(Collectors.toList()); } - return null; + return List.of(); + } + + public String getOperationName() { + return namespaces.stream().map(this::prettyString).collect(joining()) + prettyString(getName()); + } + + private String prettyString(String value) { + return value.substring(0, 1).toUpperCase() + value.substring(1); } } diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java index 9fe7aff72..22e97a731 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java @@ -545,6 +545,7 @@ private static Map getAnnotationsWithFilter(Type ty public static final DotName TYPE = DotName.createSimple("org.eclipse.microprofile.graphql.Type"); public static final DotName INTERFACE = DotName.createSimple("org.eclipse.microprofile.graphql.Interface"); public static final DotName UNION = DotName.createSimple("io.smallrye.graphql.api.Union"); + public static final DotName NAMESPACE = DotName.createSimple("io.smallrye.graphql.api.Namespace"); public static final DotName MULTIPLE = DotName.createSimple("io.smallrye.graphql.client.typesafe.api.Multiple"); diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java index 17ce35ede..f30f34cf6 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java @@ -1,6 +1,7 @@ package io.smallrye.graphql.client.model; import static io.smallrye.graphql.client.model.Annotations.GRAPHQL_CLIENT_API; +import static io.smallrye.graphql.client.model.Annotations.NAME; import static io.smallrye.graphql.client.model.ScanningContext.getIndex; import java.util.ArrayList; @@ -8,6 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.ClassInfo; @@ -56,6 +58,14 @@ private ClientModels generateClientModels() { Collection graphQLApiAnnotations = getIndex() .getAnnotations(GRAPHQL_CLIENT_API); + List errors = graphQLApiAnnotations.stream() + .filter(annotationInstance -> annotationInstance.target().asClass().hasDeclaredAnnotation(NAME)) + .map(apiClass -> "Use @Namespace instead of @Name on interface " + apiClass.target().asClass().name()) + .collect(Collectors.toList()); + if (!errors.isEmpty()) { + throw new RuntimeException(String.join("\n", errors)); + } + graphQLApiAnnotations.forEach(graphQLApiAnnotation -> { ClientModel operationMap = new ClientModel(); ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java index 4470c877b..0d8e79baa 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java @@ -3,6 +3,8 @@ import static io.smallrye.graphql.client.model.helper.OperationModel.of; import static java.util.stream.Collectors.joining; +import java.util.List; + import org.jboss.jandex.MethodInfo; import io.smallrye.graphql.client.model.helper.DirectiveInstance; @@ -34,15 +36,19 @@ public QueryBuilder(MethodInfo method) { public String build() { StringBuilder request = new StringBuilder(method.getOperationTypeAsString()); request.append(" "); - request.append(method.getName()); // operationName + + request.append(method.getOperationName()); // operation name + if (method.hasValueParameters()) { request.append(method.valueParameters().stream().map(method::declare).collect(joining(", ", "(", ")"))); } - String groupName = method.getGroupName(); - if (groupName != null) { - request.append(" { "); - request.append(groupName); + List namespaces = method.getNamespaces(); + if (!namespaces.isEmpty()) { + namespaces.forEach(value -> { + request.append(" { "); + request.append(value); + }); } if (method.isSingle()) { @@ -61,11 +67,13 @@ public String build() { request.append(method.fields(method.getReturnType())); - if (method.isSingle()) + if (method.isSingle()) { request.append(" }"); + } - if (groupName != null) - request.append(" } "); + if (!namespaces.isEmpty()) { + request.append(" } ".repeat(namespaces.size())); + } return request.toString(); } diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java index cbfc70218..ad90dde5d 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java @@ -3,12 +3,14 @@ import static io.smallrye.graphql.client.model.Annotations.MULTIPLE; import static io.smallrye.graphql.client.model.Annotations.MUTATION; import static io.smallrye.graphql.client.model.Annotations.NAME; +import static io.smallrye.graphql.client.model.Annotations.NAMESPACE; import static io.smallrye.graphql.client.model.Annotations.QUERY; import static io.smallrye.graphql.client.model.Annotations.SUBCRIPTION; import static io.smallrye.graphql.client.model.ScanningContext.getIndex; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.Stack; @@ -36,7 +38,7 @@ public class OperationModel implements NamedElement { private final Stack expressionStack = new Stack<>(); private Stack rawParametrizedTypes = new Stack<>(); private final List directives; - private final String groupName; + private final List namespaces; /** * Creates a new {@code OperationModel} instance based on the provided Jandex {@link MethodInfo}. @@ -50,7 +52,7 @@ public class OperationModel implements NamedElement { getDirectiveLocation(), AnnotationTarget.Kind.METHOD) .map(DirectiveInstance::of) .collect(toList()); - this.groupName = readGroupName(method); + this.namespaces = readNamespace(method); } /** @@ -391,22 +393,25 @@ private boolean isRawParametrizedType(TypeModel type) { return type.isCustomParametrizedType() && !type.getFirstRawType().isTypeVariable(); } - public String getGroupName() { - return groupName; + public List getNamespaces() { + return namespaces; } - private String readGroupName(MethodInfo method) { - List annotationInstances = method.declaringClass().annotations(NAME); - for (AnnotationInstance annotationInstance : annotationInstances) { - if (annotationInstance.target().kind() == AnnotationTarget.Kind.CLASS) { - if (annotationInstance.target().asClass().name().equals(method.declaringClass().name())) { - String groupName = annotationInstance.value().asString().trim(); - if (!groupName.isEmpty()) { - return groupName; - } - } - } + private List readNamespace(MethodInfo method) { + AnnotationInstance annotationInstance = method.declaringClass().declaredAnnotation(NAMESPACE); + if (annotationInstance != null) { + return Arrays.stream(annotationInstance.value().asString().split("/")) + .map(String::trim) + .collect(Collectors.toList()); } - return null; + return List.of(); + } + + public String getOperationName() { + return namespaces.stream().map(this::prettyString).collect(joining()) + prettyString(getName()); + } + + private String prettyString(String value) { + return value.substring(0, 1).toUpperCase() + value.substring(1); } } diff --git a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java index a03e7a415..4afec8f1f 100644 --- a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java +++ b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java @@ -16,6 +16,7 @@ import org.jboss.jandex.Index; import org.junit.jupiter.api.Test; +import io.smallrye.graphql.api.Namespace; import io.smallrye.graphql.api.Subscription; import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi; @@ -47,15 +48,15 @@ void sclarClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("returnInteger", new Class[] { Integer.class }), - "query returnInteger($someNumber: Int) { returnInteger(someNumber: $someNumber) }"); + "query ReturnInteger($someNumber: Int) { returnInteger(someNumber: $someNumber) }"); assertOperation(clientModel, new MethodKey("returnString", new Class[] { String.class }), - "mutation returnString($someString: String) { returnString(someString: $someString) }"); + "mutation ReturnString($someString: String) { returnString(someString: $someString) }"); assertOperation(clientModel, new MethodKey("returnNonNullFloat", new Class[] { float.class }), - "subscription returnNonNullFloat($someFloat: Float!) { returnNonNullFloat(someFloat: $someFloat) }"); + "subscription ReturnNonNullFloat($someFloat: Float!) { returnNonNullFloat(someFloat: $someFloat) }"); } @GraphQLClientApi(configKey = "collection") @@ -79,15 +80,15 @@ void collectionClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("returnIntegerCollection", new Class[] { Integer[].class }), - "query returnIntegerCollection($someNumbers: [Int]) { returnIntegerCollection(someNumbers: $someNumbers) }"); + "query ReturnIntegerCollection($someNumbers: [Int]) { returnIntegerCollection(someNumbers: $someNumbers) }"); assertOperation(clientModel, new MethodKey("returnStringList", new Class[] { Set.class }), - "mutation returnStringList($someStrings: [String]) { returnStringList(someStrings: $someStrings) }"); + "mutation ReturnStringList($someStrings: [String]) { returnStringList(someStrings: $someStrings) }"); assertOperation(clientModel, new MethodKey("returnFloatArrayList", new Class[] { HashSet.class }), - "subscription returnFloatArrayList($someFloats: [Float]) { returnFloatArrayList(someFloats: $someFloats) }"); + "subscription ReturnFloatArrayList($someFloats: [Float]) { returnFloatArrayList(someFloats: $someFloats) }"); } @Test @@ -101,7 +102,7 @@ void simpleObjectClientModelTest() throws IOException { assertOperation(clientModel, new MethodKey("returnSomeObject", new Class[] { SimpleObjectClientApi.SomeObject.class }), - "query returnSomeObject($someObject: SomeObjectInput) { returnSomeObject(someObject: $someObject) {name innerObject {someInt}} }"); + "query ReturnSomeObject($someObject: SomeObjectInput) { returnSomeObject(someObject: $someObject) {name innerObject {someInt}} }"); } @GraphQLClientApi(configKey = "simple-object") @@ -134,7 +135,7 @@ void complexObjectClientModelTest() throws IOException { assertEquals(1, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("returnSomeGenericObject", new Class[] { List.class }), - "query returnSomeGenericObject($someObject: [SomeGenericClassInput])" + + "query ReturnSomeGenericObject($someObject: [SomeGenericClassInput])" + " { returnSomeGenericObject(someObject: $someObject) {somethingParent {number}" + " field1 {number} field2 {innerField {number} something {someObject {someThingElse" + " {string}}}}} }"); @@ -202,16 +203,16 @@ void inheritedOperationsClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("allStrings", new Class[0]), - "query strings { strings }"); + "query Strings { strings }"); assertOperation(clientModel, new MethodKey("allStrings2", new Class[0]), - "query allStrings2 { allStrings2 }"); + "query AllStrings2 { allStrings2 }"); assertOperation(clientModel, new MethodKey("allStrings0", new Class[0]), - "query allStrings0 { allStrings0 }"); + "query AllStrings0 { allStrings0 }"); } - @Name("named") + @Namespace("named") @GraphQLClientApi(configKey = "string-api") interface NamedClientApi { @Query("findAll") @@ -235,13 +236,13 @@ void namedClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("findAllStringsQuery", new Class[0]), - "query findAll { named { findAll } } "); + "query NamedFindAll { named { findAll } } "); assertOperation(clientModel, new MethodKey("findAllStringsName", new Class[0]), - "query findAll { named { findAll } } "); + "query NamedFindAll { named { findAll } } "); assertOperation(clientModel, new MethodKey("update", new Class[] { String.class }), - "mutation update($s: String) { named { update(s: $s) } } "); + "mutation NamedUpdate($s: String) { named { update(s: $s) } } "); } private void assertOperation(ClientModel clientModel, MethodKey methodKey, String expectedQuery) { diff --git a/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java index fbe1804ed..44f8acfc0 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java @@ -30,7 +30,7 @@ void shouldQueryRenamedString() { String greeting = api.foo(); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(greeting).isEqualTo("dummy-greeting"); } @@ -46,7 +46,7 @@ void shouldQueryNamedParam() { String greeting = api.greeting("foo"); - then(fixture.query()).isEqualTo("query greeting($foo: String) { greeting(who: $foo) }"); + then(fixture.query()).isEqualTo("query Greeting($foo: String) { greeting(who: $foo) }"); then(fixture.variables()).isEqualTo("{'foo':'foo'}"); then(greeting).isEqualTo("hi, foo"); } @@ -64,7 +64,7 @@ void shouldQueryRenamedMethod() { String greeting = api.someOtherMethodName(); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(fixture.variables()).isEqualTo("{}"); then(greeting).isEqualTo("hi, foo"); } @@ -88,7 +88,7 @@ void shouldQueryObjectWithRenamedFields() { RenamedGreeting greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting {text:foo code:key} }"); + then(fixture.query()).isEqualTo("query Greeting { greeting {text:foo code:key} }"); then(greeting.text).isEqualTo("foo"); then(greeting.code).isEqualTo(5); } @@ -120,7 +120,7 @@ void shouldQueryObjectWithFieldsWithIgnore() { GreetingWithIgnore greeting = api.greeting(new GreetingWithIgnore("foo", "the-code")); - then(fixture.query()).isEqualTo("query greeting($in: GreetingWithIgnoreInput) { greeting(in: $in) {text} }"); + then(fixture.query()).isEqualTo("query Greeting($in: GreetingWithIgnoreInput) { greeting(in: $in) {text} }"); then(greeting.text).isEqualTo("foo"); then(greeting.ignore).isNull(); } @@ -162,7 +162,7 @@ void shouldCallMultipleWithoutParamsDifferentType() { HeroAndVillain heroAndVillain = api.heroAndVillain(); - then(fixture.query()).isEqualTo("query heroAndVillain {hero {name good} villain {name}}"); + then(fixture.query()).isEqualTo("query HeroAndVillain {hero {name good} villain {name}}"); then(fixture.variables()).isEqualTo("{}"); then(heroAndVillain.hero.name).isEqualTo("Spider-Man"); then(heroAndVillain.hero.good).isTrue(); @@ -176,7 +176,7 @@ void shouldCallMultipleWithoutParamsSameType() { HeroPair pair = api.randomHeroPair(); - then(fixture.query()).isEqualTo("query randomHeroPair {left:hero {name good} right:hero {name good}}"); + then(fixture.query()).isEqualTo("query RandomHeroPair {left:hero {name good} right:hero {name good}}"); then(fixture.variables()).isEqualTo("{}"); then(pair.left.name).isEqualTo("Spider-Man"); then(pair.left.good).isTrue(); diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java index 2a2a060e5..44ade168d 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java @@ -21,7 +21,7 @@ void shouldCallBoolArrayQuery() { boolean[] bool = api.bool(new boolean[] { true, false }); - then(fixture.query()).isEqualTo("query bool($in: [Boolean!]) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query Bool($in: [Boolean!]) { bool(in: $in) }"); then(bool[0]).isTrue(); then(bool[1]).isFalse(); } @@ -33,7 +33,7 @@ void shouldCallEmptyBoolArrayQuery() { boolean[] bool = api.bool(new boolean[0]); - then(fixture.query()).isEqualTo("query bool($in: [Boolean!]) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query Bool($in: [Boolean!]) { bool(in: $in) }"); then(bool).isEmpty(); } @@ -49,7 +49,7 @@ void shouldCallBooleanArrayQuery() { Boolean[] bool = api.bool(new Boolean[] { true, false }); - then(fixture.query()).isEqualTo("query bool($in: [Boolean]) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query Bool($in: [Boolean]) { bool(in: $in) }"); then(bool[0]).isTrue(); then(bool[1]).isFalse(); } @@ -68,7 +68,7 @@ void shouldCallCharArrayQuery() { char[] chars = api.chars(new char[] { 'a', 'b', 'c' }); - then(fixture.query()).isEqualTo("query chars($in: [String!]) { chars(in: $in) }"); + then(fixture.query()).isEqualTo("query Chars($in: [String!]) { chars(in: $in) }"); then(chars).containsExactly('a', 'b', 'c'); } @@ -84,7 +84,7 @@ void shouldCallCharacterArrayQuery() { Character[] chars = api.chars(new Character[] { 'a', 'b', 'c' }); - then(fixture.query()).isEqualTo("query chars($in: [String]) { chars(in: $in) }"); + then(fixture.query()).isEqualTo("query Chars($in: [String]) { chars(in: $in) }"); then(chars).containsExactly('a', 'b', 'c'); } @@ -102,7 +102,7 @@ void shouldCallShortArrayQuery() { short[] shorts = api.shorts(new short[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query shorts($in: [Int!]) { shorts(in: $in) }"); + then(fixture.query()).isEqualTo("query Shorts($in: [Int!]) { shorts(in: $in) }"); then(shorts).containsExactly(1, 2, 3); } @@ -118,7 +118,7 @@ void shouldCallPrimitiveShortArrayQuery() { Short[] shorts = api.shorts(new Short[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query shorts($in: [Int]) { shorts(in: $in) }"); + then(fixture.query()).isEqualTo("query Shorts($in: [Int]) { shorts(in: $in) }"); then(shorts).containsExactly((short) 1, (short) 2, (short) 3); } @@ -136,7 +136,7 @@ void shouldCallIntArrayQuery() { int[] ints = api.integer(new int[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query integer($in: [Int!]) { integer(in: $in) }"); + then(fixture.query()).isEqualTo("query Integer($in: [Int!]) { integer(in: $in) }"); then(ints).containsExactly(1, 2, 3); } @@ -152,7 +152,7 @@ void shouldCallIntegerArrayQuery() { Integer[] ints = api.ints(new Integer[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query ints($in: [Int]) { ints(in: $in) }"); + then(fixture.query()).isEqualTo("query Ints($in: [Int]) { ints(in: $in) }"); then(ints).containsExactly(1, 2, 3); } @@ -170,7 +170,7 @@ void shouldCallPrimitiveLongArrayQuery() { long[] longs = api.longs(new long[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query longs($in: [BigInteger!]) { longs(in: $in) }"); + then(fixture.query()).isEqualTo("query Longs($in: [BigInteger!]) { longs(in: $in) }"); then(longs).containsExactly(1, 2, 3); } @@ -186,7 +186,7 @@ void shouldCallLongArrayQuery() { Long[] longs = api.longs(new Long[] { 1L, 2L, 3L }); - then(fixture.query()).isEqualTo("query longs($in: [BigInteger]) { longs(in: $in) }"); + then(fixture.query()).isEqualTo("query Longs($in: [BigInteger]) { longs(in: $in) }"); then(longs).containsExactly(1L, 2L, 3L); } @@ -204,7 +204,7 @@ void shouldCallPrimitiveFloatArrayQuery() { float[] floats = api.floats(new float[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query floats($in: [Float!]) { floats(in: $in) }"); + then(fixture.query()).isEqualTo("query Floats($in: [Float!]) { floats(in: $in) }"); then(floats).containsExactly(1, 2, 3); } @@ -220,7 +220,7 @@ void shouldCallFloatArrayQuery() { Float[] floats = api.floats(new Float[] { 1F, 2F, 3F }); - then(fixture.query()).isEqualTo("query floats($in: [Float]) { floats(in: $in) }"); + then(fixture.query()).isEqualTo("query Floats($in: [Float]) { floats(in: $in) }"); then(floats).containsExactly(1F, 2F, 3F); } @@ -238,7 +238,7 @@ void shouldCallPrimitiveDoubleArrayQuery() { double[] doubles = api.doubles(new double[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query doubles($in: [Float!]) { doubles(in: $in) }"); + then(fixture.query()).isEqualTo("query Doubles($in: [Float!]) { doubles(in: $in) }"); then(doubles).containsExactly(1, 2, 3); } @@ -254,7 +254,7 @@ void shouldCallDoubleArrayQuery() { Double[] doubles = api.doubles(new Double[] { 1D, 2D, 3D }); - then(fixture.query()).isEqualTo("query doubles($in: [Float]) { doubles(in: $in) }"); + then(fixture.query()).isEqualTo("query Doubles($in: [Float]) { doubles(in: $in) }"); then(doubles).containsExactly(1D, 2D, 3D); } } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java index 5da2dda8f..654041057 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java @@ -57,7 +57,7 @@ void shouldCallEnumQuery() { Episode episode = api.episode(); - then(fixture.query()).isEqualTo("query episode { episode }"); + then(fixture.query()).isEqualTo("query Episode { episode }"); then(episode).isEqualTo(JEDI); } @@ -73,7 +73,7 @@ void shouldCallEnumListQuery() { List episode = api.episodes(); - then(fixture.query()).isEqualTo("query episodes { episodes }"); + then(fixture.query()).isEqualTo("query Episodes { episodes }"); then(episode).containsExactly(NEWHOPE, EMPIRE, JEDI); } @@ -89,7 +89,7 @@ void shouldCallEnumFilterQuery() { List characters = api.characters(JEDI); - then(fixture.query()).isEqualTo("query characters($episode: Episode) { characters(episode: $episode) }"); + then(fixture.query()).isEqualTo("query Characters($episode: Episode) { characters(episode: $episode) }"); then(fixture.variables()).isEqualTo("{'episode':'JEDI'}"); then(characters).containsExactly("Luke", "Darth"); } @@ -106,7 +106,7 @@ void shouldCallGenericQuery() { DescribedValue episode = api.describedEpisode(); - then(fixture.query()).isEqualTo("query describedEpisode { describedEpisode {value description} }"); + then(fixture.query()).isEqualTo("query DescribedEpisode { describedEpisode {value description} }"); then(episode.description).isEqualTo("Episode 4"); then(episode.value).isEqualTo(NEWHOPE); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java index ac656854e..b8ac88752 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java @@ -239,7 +239,7 @@ void shouldIgnoreEmptyError() { String greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(greeting).isEqualTo("dummy-greeting"); } @@ -265,7 +265,7 @@ void shouldFetchErrorOrPresent() { ErrorOr> response = api.teams(); - then(fixture.query()).isEqualTo("query teams { teams {name} }"); + then(fixture.query()).isEqualTo("query Teams { teams {name} }"); then(response.isPresent()).isTrue(); then(response.hasErrors()).isFalse(); then(catchThrowable(response::getErrors)).isInstanceOf(NoSuchElementException.class); @@ -292,7 +292,7 @@ void shouldFetchErrorOrAbsent() { ErrorOr> response = api.teams(); - then(fixture.query()).isEqualTo("query teams { teams {name} }"); + then(fixture.query()).isEqualTo("query Teams { teams {name} }"); then(response).hasExactlyOneErrorWhich() .hasMessage("currently can't search for teams") .hasPath("teams") @@ -319,7 +319,7 @@ void shouldFetchErrorOnNullData() { GraphQLClientException throwable = catchThrowableOfType(api::teams, GraphQLClientException.class); - then(fixture.query()).isEqualTo("query teams { teams {name} }"); + then(fixture.query()).isEqualTo("query Teams { teams {name} }"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("currently can't search for teams") .hasPath("teams") @@ -354,7 +354,7 @@ void shouldFetchErrorOrWithTwoErrors() { ErrorOr> response = api.teams(); - then(fixture.query()).isEqualTo("query teams { teams {name} }"); + then(fixture.query()).isEqualTo("query Teams { teams {name} }"); List errors = response.getErrors(); then(errors).hasSize(2); then(errors.get(0)) @@ -388,7 +388,7 @@ void shouldFetchErrorOrAbsentWithoutPath() { GraphQLClientException throwable = catchThrowableOfType(api::teams, GraphQLClientException.class); - then(fixture.query()).isEqualTo("query teams { teams {name} }"); + then(fixture.query()).isEqualTo("query Teams { teams {name} }"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("currently can't search for teams") .hasNoPath() @@ -411,7 +411,7 @@ void shouldFetchErrorOrWithNullInPath() { GraphQLClientException throwable = catchThrowableOfType(api::teams, GraphQLClientException.class); - then(fixture.query()).isEqualTo("query teams { teams {name} }"); + then(fixture.query()).isEqualTo("query Teams { teams {name} }"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("can't get team name") .hasPath("teams", "name") @@ -441,7 +441,7 @@ void shouldFetchFullWrapper() { Wrapper response = api.find(); - then(fixture.query()).isEqualTo("query find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); + then(fixture.query()).isEqualTo("query Find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); { then(response.superHeroes).hasSize(1); ErrorOr superHero = response.superHeroes.get(0); @@ -476,7 +476,7 @@ void shouldFetchPartialWrapper() { Wrapper response = api.find(); - then(fixture.query()).isEqualTo("query find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); + then(fixture.query()).isEqualTo("query Find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); then(response.superHeroes).hasSize(1); then(response.superHeroes.get(0).get().name).isEqualTo("Wolverine"); then(response.teams.hasErrors()).isTrue(); @@ -534,7 +534,7 @@ void shouldFetchComplexError() { GraphQLClientException throwable = catchThrowableOfType(() -> api.order("o1"), GraphQLClientException.class); then(fixture.query()) - .isEqualTo("query order($id: String!) { order(id: $id) {id orderDate items {product {id name}}} }"); + .isEqualTo("query Order($id: String!) { order(id: $id) {id orderDate items {product {id name}}} }"); then(fixture.variables()).isEqualTo("{'id':'o1'}"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("System error") diff --git a/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java index 2b846f3c8..6f4d8d8e4 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java @@ -478,7 +478,7 @@ void shouldAddParamHeader() { api.greeting("bar"); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(fixture.sentHeader("foo")).isEqualTo("bar"); } @@ -590,7 +590,7 @@ void shouldAddDefaultHeaders() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Content-Type")).hasToString("application/json;charset=utf-8"); then(fixture.sentHeader("Accept")).hasToString("application/json;charset=utf-8"); @@ -603,7 +603,7 @@ void shouldAddManuallyBuildDefaultHeader() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Custom-Header")).hasToString("Custom-Header-Value"); } @@ -618,7 +618,7 @@ void shouldManuallyOverrideDefaultHeaders() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Content-Type")).hasToString("application/xxx"); then(fixture.sentHeader("Accept")).hasToString("application/yyy"); @@ -631,7 +631,7 @@ void shouldAddManuallyBuildDefaultHeaders() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Custom-Header")).hasToString("Custom-Header-Value"); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java index 367187f76..e3a40fce6 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java @@ -64,7 +64,7 @@ void shouldInterfaceFindBatman() { var response = api.find("Batman"); - then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + "__typename " + "... on MainCharacter {name superPower} " + "... on SideKick {name mainCharacter}} }"); @@ -81,7 +81,7 @@ void shouldInterfaceFindRobin() { var response = api.find("Robin"); - then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + "__typename " + "... on MainCharacter {name superPower} " + "... on SideKick {name mainCharacter}} }"); @@ -101,7 +101,7 @@ void shouldInterfaceFindAll() { var response = api.all(); - then(fixture.query()).isEqualTo("query all { all{" + + then(fixture.query()).isEqualTo("query All { all{" + "__typename " + "... on MainCharacter {name superPower} " + "... on SideKick {name mainCharacter}} }"); diff --git a/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java index 875c1ed75..690716631 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java @@ -28,7 +28,7 @@ void shouldCallStringMutation() { String greeting = api.createSome("input"); - then(fixture.query()).isEqualTo("mutation createSome($thing: String) { createSome(thing: $thing) }"); + then(fixture.query()).isEqualTo("mutation CreateSome($thing: String) { createSome(thing: $thing) }"); then(fixture.variables()).isEqualTo("{'thing':'input'}"); then(greeting).isEqualTo("output"); } @@ -40,7 +40,7 @@ void shouldCallNullStringMutation() { String greeting = api.createSome(null); - then(fixture.query()).isEqualTo("mutation createSome($thing: String) { createSome(thing: $thing) }"); + then(fixture.query()).isEqualTo("mutation CreateSome($thing: String) { createSome(thing: $thing) }"); then(fixture.variables()).isEqualTo("{'thing':null}"); then(greeting).isEqualTo("output"); } @@ -87,7 +87,7 @@ void shouldCallGreetingMutation() { Greeting greeting = api.say(new Greeting("hi", 5)); - then(fixture.query()).isEqualTo("mutation say($greet: GreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("mutation Say($greet: GreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -99,7 +99,7 @@ void shouldCallGreetingMutationWithNullValue() { Greeting greeting = api.say(new Greeting(null, 5)); - then(fixture.query()).isEqualTo("mutation say($greet: GreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("mutation Say($greet: GreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'count':5}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -120,7 +120,7 @@ void shouldCallMutationWithListWithNullValue() { null, new Greeting("three", 5))); - then(fixture.query()).isEqualTo("mutation say($greets: [GreetingInput]) { say(greets: $greets) {text count} }"); + then(fixture.query()).isEqualTo("mutation Say($greets: [GreetingInput]) { say(greets: $greets) {text count} }"); then(fixture.variables()).isEqualTo("{'greets':[" + "{'text':'one','count':5}," + "null," + @@ -174,7 +174,7 @@ void shouldCallMutationWithNestedValue() { Greeting greeting = api.say(new GreetingContainer(new Greeting("one", 5), now)); then(fixture.query()) - .isEqualTo("mutation say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); + .isEqualTo("mutation Say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); then(fixture.variables()).isEqualTo("{'greeting':{" + "'greeting':{'text':'one','count':5}," + "'when':'" + now + "'}}"); @@ -189,7 +189,7 @@ void shouldCallMutationWithNestedNullValue() { Greeting greeting = api.say(new GreetingContainer(new Greeting(null, 5), null)); then(fixture.query()) - .isEqualTo("mutation say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); + .isEqualTo("mutation Say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); then(fixture.variables()).isEqualTo("{'greeting':{'greeting':{'count':5}}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -228,7 +228,7 @@ void shouldCallMutationWithEnum() { Greeting greeting = api.say(new GreetingEnum("one", SomeEnum.ONE)); - then(fixture.query()).isEqualTo("mutation say($greeting: GreetingEnumInput) { say(greeting: $greeting) {text count} }"); + then(fixture.query()).isEqualTo("mutation Say($greeting: GreetingEnumInput) { say(greeting: $greeting) {text count} }"); then(fixture.variables()).isEqualTo("{'greeting':{'text':'one','someEnum':'ONE'}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -279,7 +279,7 @@ void shouldCallMutationWithPrimitives() { String result = api.run(new PrimitiveTypes()); - then(fixture.query()).isEqualTo("mutation run($primitives: PrimitiveTypesInput) { run(primitives: $primitives) }"); + then(fixture.query()).isEqualTo("mutation Run($primitives: PrimitiveTypesInput) { run(primitives: $primitives) }"); then(fixture.variables()) .isEqualTo("{'primitives':{'b':true,'c':'a','y':7,'s':255,'i':123456,'l':987654321,'f':1.0,'d':56.78}}"); then(result).isEqualTo("okay"); @@ -332,7 +332,7 @@ void shouldCallMutationWithPrimitiveWrappers() { String result = api.run(new PrimitiveWrapperTypes()); then(fixture.query()) - .isEqualTo("mutation run($primitives: PrimitiveWrapperTypesInput) { run(primitives: $primitives) }"); + .isEqualTo("mutation Run($primitives: PrimitiveWrapperTypesInput) { run(primitives: $primitives) }"); then(fixture.variables()) .isEqualTo("{'primitives':{'b':true,'c':'a','y':7,'s':255,'i':123456,'l':987654321,'f':1.0,'d':56.78}}"); then(result).isEqualTo("okay"); diff --git a/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java index 89f3dbb0e..1eec083c4 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java @@ -31,7 +31,7 @@ void shouldCallStringSetQuery() { Set greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings }"); + then(fixture.query()).isEqualTo("query Greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -91,7 +91,7 @@ void shouldCallStringCollectionQuery() { Collection greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings }"); + then(fixture.query()).isEqualTo("query Greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -107,7 +107,7 @@ void shouldCallStringArrayListQuery() { ArrayList greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings }"); + then(fixture.query()).isEqualTo("query Greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -123,7 +123,7 @@ void shouldCallStringListQuery() { List greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings }"); + then(fixture.query()).isEqualTo("query Greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -134,7 +134,7 @@ void shouldCallStringListQueryWithNull() { List greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings }"); + then(fixture.query()).isEqualTo("query Greetings { greetings }"); then(greetings).containsExactly("a", null); } @@ -167,7 +167,7 @@ void shouldCallStringArrayQuery() { String[] greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings }"); + then(fixture.query()).isEqualTo("query Greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -214,7 +214,7 @@ void shouldCallObjectQuery() { Greeting greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting {text code successful} }"); + then(fixture.query()).isEqualTo("query Greeting { greeting {text code successful} }"); then(greeting).isEqualTo(new Greeting("foo", 5, true)); } @@ -266,7 +266,7 @@ void shouldCallObjectListQuery() { List greeting = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings {text code successful} }"); + then(fixture.query()).isEqualTo("query Greetings { greetings {text code successful} }"); then(greeting).containsExactly( new Greeting("a", 1, null), new Greeting("b", 2, true), @@ -312,7 +312,7 @@ void shouldCallNestedStringQuery() { StringContainer container = api.container(); - then(fixture.query()).isEqualTo("query container { container {greeting count} }"); + then(fixture.query()).isEqualTo("query Container { container {greeting count} }"); then(container.greeting).isEqualTo("hi"); then(container.count).isEqualTo(5); } @@ -359,7 +359,7 @@ void shouldCallNestedObjectQuery() { GreetingContainer container = api.container(); then(fixture.query()) - .isEqualTo("query container { container {greeting {text code successful} count} }"); + .isEqualTo("query Container { container {greeting {text code successful} count} }"); then(container).isEqualTo(new GreetingContainer( new Greeting("a", 1, null), 3)); } @@ -408,7 +408,7 @@ void shouldCallNestedListQuery() { GreetingsContainer container = api.container(); then(fixture.query()) - .isEqualTo("query container { container {greetings {text code successful} count} }"); + .isEqualTo("query Container { container {greetings {text code successful} count} }"); then(container).isEqualTo(new GreetingsContainer( asList(new Greeting("a", 1, null), new Greeting("b", 2, null)), 3)); } @@ -485,7 +485,7 @@ void shouldCallWrappedGreetingQuery() { WrappedGreetingContainer container = api.container(); then(fixture.query()) - .isEqualTo("query container { container {greeting {value {text code successful}} count} }"); + .isEqualTo("query Container { container {greeting {value {text code successful}} count} }"); then(container).isEqualTo(new WrappedGreetingContainer( new Wrapper<>(new Greeting("a", 1, null)), 3)); } @@ -531,7 +531,7 @@ void shouldCallWrappedByteQuery() { WrappedByteContainer container = api.container(); - then(fixture.query()).isEqualTo("query container { container {code {value} count} }"); + then(fixture.query()).isEqualTo("query Container { container {code {value} count} }"); then(container).isEqualTo(new WrappedByteContainer( new Wrapper<>((byte) 123), 3)); } @@ -588,7 +588,7 @@ void shouldCallWrappedListByteQuery() { WrappedListByteContainer container = api.container(); - then(fixture.query()).isEqualTo("query container { container {codes count} }"); + then(fixture.query()).isEqualTo("query Container { container {codes count} }"); then(container).isEqualTo(new WrappedListByteContainer( asList((byte) 'a', (byte) 'b', (byte) 'c'), 3)); } @@ -626,7 +626,7 @@ void shouldCallObjectQueryWithSpecialFields() { ClassWithTransientAndStaticFields foo = api.foo(); - then(fixture.query()).isEqualTo("query foo { foo {text code} }"); + then(fixture.query()).isEqualTo("query Foo { foo {text code} }"); then(foo.text).isEqualTo("foo"); then(foo.code).isEqualTo(5); then(foo.ignoreMe).isFalse(); @@ -655,7 +655,7 @@ void shouldCallInheritedGreetingQuery() { Sub sub = api.call(); then(fixture.query()) - .isEqualTo("query call { call {greeting {text code successful} count} }"); + .isEqualTo("query Call { call {greeting {text code successful} count} }"); then(sub.greeting).isEqualTo(new Greeting("a", 1, null)); then(sub.count).isEqualTo(3); } @@ -680,7 +680,7 @@ void shouldCreateObjectPrivateDefaultConstructor() { ObjectPrivateDefaultConstructor call = api.call(); - then(fixture.query()).isEqualTo("query call { call {foo} }"); + then(fixture.query()).isEqualTo("query Call { call {foo} }"); then(call.foo).isEqualTo("a"); } @@ -731,7 +731,7 @@ void shouldCallWithMissingNullableField() { MissingNullableField result = api.call(); - then(fixture.query()).isEqualTo("query call { call {foo bar} }"); + then(fixture.query()).isEqualTo("query Call { call {foo bar} }"); then(result.foo).isEqualTo("a"); then(result.bar).isNull(); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java index dcf5681fc..649db302d 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java @@ -51,7 +51,7 @@ void shouldCallNestedParameterQuery() { Team team = api.team("endgame", 3); then(fixture.query()) - .isEqualTo("query team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + + .isEqualTo("query Team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + "{headQuarters {name} members(limit: $limit) {name}} }"); then(fixture.variables()).isEqualTo("{'teamName':'endgame','limit':3}"); then(team.headQuarters.stream().map(HeadQuarter::getName)).containsExactly("Earth"); @@ -72,7 +72,7 @@ void shouldCallMultipleNestedParameterQuery() { Team team = api.team("endgame", 3); then(fixture.query()) - .isEqualTo("query team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + + .isEqualTo("query Team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + "{headQuarters(limit: $limit) {name} members(limit: $limit) {name}} }"); then(fixture.variables()).isEqualTo("{'teamName':'endgame','limit':3}"); then(team.headQuarters).isEmpty(); @@ -101,7 +101,7 @@ void shouldCallDeeplyNestedParameterQuery() { Universe universe = api.universeWithTeam("endgame", 32, 3); then(fixture.query()) - .isEqualTo("query universeWithTeam($teamName: String, $offset: Int, $limit: Int) { universeWithTeam " + + .isEqualTo("query UniverseWithTeam($teamName: String, $offset: Int, $limit: Int) { universeWithTeam " + "{name teams(teamName: $teamName) {headQuarters {name} members(offset: $offset, limit: $limit) {name}}} }"); then(fixture.variables()).isEqualTo("{'teamName':'endgame','offset':32,'limit':3}"); then(universe.name).isEqualTo("Marvel"); @@ -138,7 +138,7 @@ void shouldCallMultipleWithParams() { HeroPair pair = api.heroPairByNames("Spider-Man", "Venom"); then(fixture.query()) - .isEqualTo("query heroPairByNames($leftName: String, $rightName: String) {" + + .isEqualTo("query HeroPairByNames($leftName: String, $rightName: String) {" + "left:hero(name: $leftName) {name good} right:hero(name: $rightName) {name good}}"); then(fixture.variables()).isEqualTo("{'leftName':'Spider-Man','rightName':'Venom'}"); then(pair.left.name).isEqualTo("Spider-Man"); @@ -176,7 +176,7 @@ void shouldCallMultipleMutations() { MultiUpdate result = api.multiUpdate("new-loc", "new-team", "new-name"); then(fixture.query()).isEqualTo("" + - "mutation multiUpdate($location: String, $teamName: String, $name: String) {" + + "mutation MultiUpdate($location: String, $teamName: String, $name: String) {" + "updateLocation(location: $location) " + "addTeam(teamName: $teamName) " + "updateName(name: $name) {name good}" + diff --git a/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java index c351ae0bc..e09040ddd 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java @@ -28,7 +28,7 @@ void shouldCallNullOptionalStringQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(greeting).isEmpty(); } @@ -39,7 +39,7 @@ void shouldCallOptionalStringQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(greeting).contains("hi"); } @@ -84,7 +84,7 @@ void shouldCallOptionalGreetingQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); then(greeting).contains(new Greeting("hi", 5)); } @@ -95,7 +95,7 @@ void shouldCallNullOptionalGreetingQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); then(greeting).isEmpty(); } @@ -111,7 +111,7 @@ void shouldCallOptionalGreetingListQuery() { Optional> greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); assert greeting.isPresent(); then(greeting.get()).contains(new Greeting("hi", 5), new Greeting("ho", 7)); } @@ -123,7 +123,7 @@ void shouldCallEmptyOptionalGreetingListQuery() { Optional> greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); assert greeting.isPresent(); then(greeting.get()).isEmpty(); } @@ -140,7 +140,7 @@ void shouldCallListOfOptionalGreetingsQuery() { List> greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings {text code} }"); + then(fixture.query()).isEqualTo("query Greetings { greetings {text code} }"); then(greetings).containsExactly( Optional.of(new Greeting("hi", 5)), Optional.of(new Greeting("ho", 7))); @@ -153,7 +153,7 @@ void shouldCallEmptyListOfOptionalGreetingsQuery() { List> greetings = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings {text code} }"); + then(fixture.query()).isEqualTo("query Greetings { greetings {text code} }"); then(greetings).isEmpty(); } @@ -169,7 +169,7 @@ void shouldCallOptionalOptionalStringQuery() { Optional> greeting = api.greeting(); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(greeting).contains(Optional.of("hi")); } @@ -180,7 +180,7 @@ void optionalIntOutputTest() { AnimalApi api = fixture.build(AnimalApi.class); List listOfAnimalLegs = api.allAnimalLegs(); - then(fixture.query()).isEqualTo("query allAnimalLegs { allAnimalLegs {name numberOfLegs" + + then(fixture.query()).isEqualTo("query AllAnimalLegs { allAnimalLegs {name numberOfLegs" + " numberOfTeeth price} }"); then(listOfAnimalLegs).containsExactly( new Animal("Lion", OptionalInt.of(4)), @@ -194,7 +194,7 @@ void optionalLongOutputTest() { " {'name': 'Centipedes', 'numberOfTeeth':0 }, {'name': 'Snake', 'numberOfTeeth':100}]"); AnimalApi api = fixture.build(AnimalApi.class); List listOfAnimalTeeth = api.allAnimalTeeth(); - then(fixture.query()).isEqualTo("query allAnimalTeeth { allAnimalTeeth {name numberOfLegs" + + then(fixture.query()).isEqualTo("query AllAnimalTeeth { allAnimalTeeth {name numberOfLegs" + " numberOfTeeth price} }"); then(listOfAnimalTeeth).containsExactly( new Animal("Lion", OptionalLong.of(30)), @@ -208,7 +208,7 @@ void optionalDoubleOutputTest() { " {'name': 'Centipedes', 'price':241.62 }, {'name': 'Snake', 'price':1648.28}]"); AnimalApi api = fixture.build(AnimalApi.class); List listOfAnimalPrice = api.allAnimalPrice(); - then(fixture.query()).isEqualTo("query allAnimalPrice { allAnimalPrice {name numberOfLegs" + + then(fixture.query()).isEqualTo("query AllAnimalPrice { allAnimalPrice {name numberOfLegs" + " numberOfTeeth price} }"); then(listOfAnimalPrice).containsExactly( new Animal("Lion", OptionalDouble.of(355655.74)), @@ -222,7 +222,7 @@ void optionalIntParameterQuery() { "{'name':'Snake', 'numberOfLegs':0, 'numberOfTeeth':100, 'price':1648.28}]"); AnimalApi api = fixture.build(AnimalApi.class); List animals = api.getAnimalsByLegs(OptionalInt.of(0)); - then(fixture.query()).isEqualTo("query animalsByLegs($numberOfLegs: Int) { " + + then(fixture.query()).isEqualTo("query AnimalsByLegs($numberOfLegs: Int) { " + "animalsByLegs(numberOfLegs: $numberOfLegs) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'numberOfLegs':0}"); then(animals).containsExactly( @@ -237,7 +237,7 @@ void optionalIntMutationTest() { fixture.returnsData("'newAnimal':{'name':'Pig', 'numberOfLegs':4}"); AnimalApi api = fixture.build(AnimalApi.class); Animal animal = api.newAnimal(new Animal("Pig", OptionalInt.of(4))); - then(fixture.query()).isEqualTo("mutation newAnimal($animal: AnimalInput) " + + then(fixture.query()).isEqualTo("mutation NewAnimal($animal: AnimalInput) " + "{ newAnimal(animal: $animal) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'animal':{'name':'Pig','numberOfLegs':" + "4}}"); @@ -252,7 +252,7 @@ void optionalLongParameterQuery() { "{'name':'Rhino', 'numberOfLegs':4, 'numberOfTeeth':30, 'price':2215390.3}]"); AnimalApi api = fixture.build(AnimalApi.class); List animals = api.getAnimalsByTeeth(OptionalLong.of(30)); - then(fixture.query()).isEqualTo("query animalsByTeeth($numberOfTeeth: BigInteger) { " + + then(fixture.query()).isEqualTo("query AnimalsByTeeth($numberOfTeeth: BigInteger) { " + "animalsByTeeth(numberOfTeeth: $numberOfTeeth) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'numberOfTeeth':30}"); then(animals).containsExactly( @@ -275,7 +275,7 @@ void optionalLongMutationTest() { fixture.returnsData("'newAnimal':{'name':'Bat', 'numberOfTeeth':20}"); AnimalApi api = fixture.build(AnimalApi.class); Animal animal = api.newAnimal(new Animal("Bat", OptionalLong.of(20))); - then(fixture.query()).isEqualTo("mutation newAnimal($animal: AnimalInput) " + + then(fixture.query()).isEqualTo("mutation NewAnimal($animal: AnimalInput) " + "{ newAnimal(animal: $animal) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'animal':{'name':'Bat','numberOfTeeth':" + "20}}"); @@ -289,7 +289,7 @@ void optionalDoubleParameterQuery() { " {'name':'Rhino', 'numberOfLegs':4, 'numberOfTeeth':30, 'price':2215390.3}]"); AnimalApi api = fixture.build(AnimalApi.class); List animals = api.getAnimalsByPrice(OptionalDouble.of(2215390.3)); - then(fixture.query()).isEqualTo("query animalsByPrice($price: Float) { " + + then(fixture.query()).isEqualTo("query AnimalsByPrice($price: Float) { " + "animalsByPrice(price: $price) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'price':2215390.3}"); then(animals).containsExactly( @@ -308,7 +308,7 @@ void optionalDoubleMutationTest() { fixture.returnsData("'newAnimal':{'name':'Labrador', 'price':6610.50}"); AnimalApi api = fixture.build(AnimalApi.class); Animal animal = api.newAnimal(new Animal("Labrador", OptionalDouble.of(6610.50))); - then(fixture.query()).isEqualTo("mutation newAnimal($animal: AnimalInput) " + + then(fixture.query()).isEqualTo("mutation NewAnimal($animal: AnimalInput) " + "{ newAnimal(animal: $animal) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'animal':{'name':'Labrador','price':" + "6610.5}}"); @@ -359,7 +359,7 @@ void optionalNumberNull() { fixture.returnsData("'randomCar':{'boo':[null, 3, null]}"); CarApi api = fixture.build(CarApi.class); Car car = api.getRandomCar(); - then(fixture.query()).isEqualTo("query randomCar { randomCar {boo} }"); + then(fixture.query()).isEqualTo("query RandomCar { randomCar {boo} }"); then(car).isEqualTo(new Car(List.of( OptionalLong.empty(), OptionalLong.of(3), diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java index 3093fe3c8..412348352 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java @@ -33,9 +33,9 @@ void shouldQueryWithStringParam() { String greeting = api.greeting("foo"); - then(fixture.query()).isEqualTo("query greeting($who: String) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: String) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':'foo'}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -53,9 +53,9 @@ void shouldQueryWithNonNullStringParam() { String greeting = api.greeting("foo"); - then(fixture.query()).isEqualTo("query greeting($who: String!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: String!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':'foo'}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -66,9 +66,9 @@ void shouldQueryWithJakartaNonNullStringParam() { String greeting = api.jakartaGreeting("foo"); - then(fixture.query()).isEqualTo("query jakartaGreeting($who: String!) { jakartaGreeting(who: $who) }"); + then(fixture.query()).isEqualTo("query JakartaGreeting($who: String!) { jakartaGreeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':'foo'}"); - then(fixture.operationName()).isEqualTo("jakartaGreeting"); + then(fixture.operationName()).isEqualTo("JakartaGreeting"); then(greeting).isEqualTo("hi, foo"); } @@ -79,7 +79,7 @@ void shouldEscapeParamScalarQuery() { String greeting = api.greeting("foo\"bar'\n"); - then(fixture.query()).isEqualTo("query greeting($who: String) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: String) { greeting(who: $who) }"); then(fixture.rawVariables()).isEqualTo("{\"who\":\"foo\\\"bar'\\n\"}"); then(greeting).isEqualTo("hi, foo"); } @@ -96,7 +96,7 @@ void shouldQueryWithTwoParams() { String greeting = api.greeting("foo", 3); - then(fixture.query()).isEqualTo("query greeting($who: String, $count: Int!) { greeting(who: $who, count: $count) }"); + then(fixture.query()).isEqualTo("query Greeting($who: String, $count: Int!) { greeting(who: $who, count: $count) }"); then(fixture.variables()).isEqualTo("{'who':'foo','count':3}"); then(greeting).isEqualTo("hi, foo 3"); } @@ -127,7 +127,7 @@ void shouldQueryWithObjectParam() { Greeting greeting = api.say(new Greeting("hi", 5)); - then(fixture.query()).isEqualTo("query say($greet: GreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query Say($greet: GreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -160,7 +160,7 @@ void shouldQueryWithRenamedObjectParam() { RenamedGreeting greeting = api.say(new RenamedGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query say($greet: Greeting) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query Say($greet: Greeting) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -193,7 +193,7 @@ void shouldQueryWithNamedInputObjectParam() { NamedInputGreeting greeting = api.say(new NamedInputGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query say($greet: Greet) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query Say($greet: Greet) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -226,7 +226,7 @@ void shouldQueryWithEmptyInputObjectParam() { EmptyInputGreeting greeting = api.say(new EmptyInputGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query say($greet: EmptyInputGreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query Say($greet: EmptyInputGreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -259,7 +259,7 @@ void shouldQueryWithNamedTypeObjectParam() { NamedTypeGreeting greeting = api.say(new NamedTypeGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query say($greet: NamedTypeGreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query Say($greet: NamedTypeGreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -293,7 +293,7 @@ void shouldQueryWithTypeAndInputObjectParam() { TypeAndInputGreeting greeting = api.say(new TypeAndInputGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query say($greet: Greet) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query Say($greet: Greet) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -311,7 +311,7 @@ void shouldQueryWithArrayParam() { boolean success = api.greetings(new String[] { "hi", "ho" }); - then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -328,7 +328,7 @@ void shouldQueryWithListParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -345,7 +345,7 @@ void shouldQueryWithNonNullListParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query greetings($greets: [String]!) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [String]!) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -362,7 +362,7 @@ void shouldQueryWithListOfNonNullParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query greetings($greets: [String!]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [String!]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -379,7 +379,7 @@ void shouldQueryWithSetParam() { boolean success = api.greetings(new HashSet<>(asList("hi", "ho"))); - then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -396,7 +396,7 @@ void shouldQueryWithQueueParam() { boolean success = api.greetings(new ArrayDeque<>(asList("hi", "ho"))); - then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -413,7 +413,7 @@ void shouldQueryWithCollectionParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -430,7 +430,7 @@ void shouldQueryWithObjectListParam() { boolean success = api.greetings(asList(new Greeting("hi", 5), new Greeting("ho", 3))); - then(fixture.query()).isEqualTo("query greetings($greets: [GreetingInput]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query Greetings($greets: [GreetingInput]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':[{'text':'hi','count':5},{'text':'ho','count':3}]}"); then(success).isTrue(); } @@ -457,7 +457,7 @@ void shouldQueryWithListObjectParam() { boolean success = api.foo(new ListObject(asList("hi", "ho"), 3)); - then(fixture.query()).isEqualTo("query foo($bar: ListObjectInput) { foo(bar: $bar) }"); + then(fixture.query()).isEqualTo("query Foo($bar: ListObjectInput) { foo(bar: $bar) }"); then(fixture.variables()).isEqualTo("{'bar':{'texts':['hi','ho'],'count':3}}"); then(success).isTrue(); } @@ -474,9 +474,9 @@ void shouldQueryWithBoolean() { String greeting = api.greeting(true); - then(fixture.query()).isEqualTo("query greeting($who: Boolean) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: Boolean) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':true}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -492,9 +492,9 @@ void shouldQueryWithPrimitiveBoolean() { String greeting = api.greeting(false); - then(fixture.query()).isEqualTo("query greeting($who: Boolean!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: Boolean!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':false}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -510,9 +510,9 @@ void shouldQueryWithNonNullBoolean() { String greeting = api.greeting(true); - then(fixture.query()).isEqualTo("query greeting($who: Boolean!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: Boolean!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':true}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -528,9 +528,9 @@ void shouldQueryWithInteger() { String greeting = api.greeting(123); - then(fixture.query()).isEqualTo("query greeting($who: Int) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: Int) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -546,9 +546,9 @@ void shouldQueryWithPrimitiveInteger() { String greeting = api.greeting(-12); - then(fixture.query()).isEqualTo("query greeting($who: Int!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: Int!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':-12}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -564,9 +564,9 @@ void shouldQueryWithNonNullInteger() { String greeting = api.greeting(456); - then(fixture.query()).isEqualTo("query greeting($who: Int!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: Int!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':456}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -582,9 +582,9 @@ void shouldQueryWithLong() { String greeting = api.greeting(123L); - then(fixture.query()).isEqualTo("query greeting($who: BigInteger) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: BigInteger) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -600,9 +600,9 @@ void shouldQueryWithPrimitiveLong() { String greeting = api.greeting(123L); - then(fixture.query()).isEqualTo("query greeting($who: BigInteger!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: BigInteger!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -618,9 +618,9 @@ void shouldQueryWithNonNullLong() { String greeting = api.greeting(123L); - then(fixture.query()).isEqualTo("query greeting($who: BigInteger!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query Greeting($who: BigInteger!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("greeting"); + then(fixture.operationName()).isEqualTo("Greeting"); then(greeting).isEqualTo("hi, foo"); } } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java index 3eb2983b3..2a44d3cea 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java @@ -49,7 +49,7 @@ void shouldCallBoolQuery() { boolean bool = api.bool(true); - then(fixture.query()).isEqualTo("query bool($in: Boolean!) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query Bool($in: Boolean!) { bool(in: $in) }"); then(bool).isTrue(); } @@ -110,7 +110,7 @@ void shouldCallBooleanQuery() { Boolean bool = api.bool(true); - then(fixture.query()).isEqualTo("query bool($in: Boolean) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query Bool($in: Boolean) { bool(in: $in) }"); then(bool).isTrue(); } } @@ -134,7 +134,7 @@ void shouldCallByteQuery() { Byte code = api.code((byte) 1); - then(fixture.query()).isEqualTo("query code($in: Int) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: Int) { code(in: $in) }"); then(code).isEqualTo((byte) 5); } @@ -145,7 +145,7 @@ void shouldCallPrimitiveByteQuery() { byte code = api.code((byte) 1); - then(fixture.query()).isEqualTo("query code($in: Int!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: Int!) { code(in: $in) }"); then(code).isEqualTo((byte) 5); } @@ -191,7 +191,7 @@ void shouldCallCharacterFromStringQuery() { Character c = api.code('c'); - then(fixture.query()).isEqualTo("query code($in: String) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: String) { code(in: $in) }"); then(c).isEqualTo('a'); } @@ -212,7 +212,7 @@ void shouldCallCharacterFromNumberQuery() { Character c = api.code('c'); - then(fixture.query()).isEqualTo("query code($in: String) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: String) { code(in: $in) }"); then(c).isEqualTo('a'); } @@ -245,7 +245,7 @@ void shouldCallPrimitiveCharQuery() { char c = api.code('c'); - then(fixture.query()).isEqualTo("query code($in: String!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: String!) { code(in: $in) }"); then(c).isEqualTo('a'); } @@ -279,7 +279,7 @@ void shouldCallShortQuery() { Short code = api.code((short) 2); - then(fixture.query()).isEqualTo("query code($in: Int) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: Int) { code(in: $in) }"); then(code).isEqualTo((short) 5); } @@ -312,7 +312,7 @@ void shouldCallPrimitiveShortQuery() { short code = api.code((short) 2); - then(fixture.query()).isEqualTo("query code($in: Int!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: Int!) { code(in: $in) }"); then(code).isEqualTo((short) 5); } } @@ -336,7 +336,7 @@ void shouldCallIntegerQuery() { Integer code = api.code(3); - then(fixture.query()).isEqualTo("query code($in: Int) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: Int) { code(in: $in) }"); then(code).isEqualTo(5); } @@ -380,7 +380,7 @@ void shouldCallIntQuery() { int code = api.code(3); - then(fixture.query()).isEqualTo("query code($in: Int!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: Int!) { code(in: $in) }"); then(code).isEqualTo(5); } } @@ -404,7 +404,7 @@ void shouldCallLongQuery() { Long code = api.code(7L); - then(fixture.query()).isEqualTo("query code($in: BigInteger) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: BigInteger) { code(in: $in) }"); then(code).isEqualTo(5L); } @@ -437,7 +437,7 @@ void shouldCallPrimitiveLongQuery() { long code = api.code(7L); - then(fixture.query()).isEqualTo("query code($in: BigInteger!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query Code($in: BigInteger!) { code(in: $in) }"); then(code).isEqualTo(5L); } } @@ -461,7 +461,7 @@ void shouldCallFloatQuery() { Float number = api.number(7.8f); - then(fixture.query()).isEqualTo("query number($in: Float) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: Float) { number(in: $in) }"); then(number).isEqualTo(123.456f); } @@ -472,7 +472,7 @@ void shouldCallPrimitiveFloatQuery() { float number = api.number(7.8f); - then(fixture.query()).isEqualTo("query number($in: Float!) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: Float!) { number(in: $in) }"); then(number).isEqualTo(123.456f); } } @@ -496,7 +496,7 @@ void shouldCallDoubleQuery() { Double number = api.number(4.5); - then(fixture.query()).isEqualTo("query number($in: Float) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: Float) { number(in: $in) }"); then(number).isEqualTo(123.456D); } @@ -507,7 +507,7 @@ void shouldCallPrimitiveDoubleQuery() { double number = api.number(4.5); - then(fixture.query()).isEqualTo("query number($in: Float!) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: Float!) { number(in: $in) }"); then(number).isEqualTo(123.456D); } } @@ -527,7 +527,7 @@ void shouldCallReallyLongIntegerQuery() { BigInteger number = api.number(BigInteger.TEN); - then(fixture.query()).isEqualTo("query number($in: BigInteger) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: BigInteger) { number(in: $in) }"); then(number).isEqualTo(reallyLongInteger); } @@ -539,7 +539,7 @@ void shouldCallNotSoLongIntegerQuery() { BigInteger number = api.number(BigInteger.TEN); - then(fixture.query()).isEqualTo("query number($in: BigInteger) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: BigInteger) { number(in: $in) }"); then(number).isEqualTo(notSoLongInteger); } } @@ -559,7 +559,7 @@ void shouldCallReallyLongDecimalQuery() { BigDecimal number = api.number(BigDecimal.valueOf(12.34)); - then(fixture.query()).isEqualTo("query number($in: BigDecimal) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: BigDecimal) { number(in: $in) }"); then(number).isEqualTo(reallyLongDecimal); } @@ -571,7 +571,7 @@ void shouldCallNotSoLongDecimalQuery() { BigDecimal number = api.number(BigDecimal.valueOf(12.34)); - then(fixture.query()).isEqualTo("query number($in: BigDecimal) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query Number($in: BigDecimal) { number(in: $in) }"); then(number).isEqualTo(notSoLongDecimal); } } @@ -717,7 +717,7 @@ void shouldCallStringQuery() { String greeting = api.greeting("in"); - then(fixture.query()).isEqualTo("query greeting($in: String) { greeting(in: $in) }"); + then(fixture.query()).isEqualTo("query Greeting($in: String) { greeting(in: $in) }"); then(greeting).isEqualTo("dummy-greeting"); } @@ -729,7 +729,7 @@ void shouldCallIdQuery() { String out = api.idea("stringId", singletonList("x"), singletonList("x"), singletonList("x"), singletonList("x"), 1L, 2, 3L, singletonList(5L), 4, UUID.randomUUID()); - then(fixture.query()).isEqualTo("query idea(" + + then(fixture.query()).isEqualTo("query Idea(" + "$stringId: ID, " + "$stringListId: [ID], " + "$stringListInnerNonNullId: [ID!], " + @@ -763,7 +763,7 @@ void shouldCallNonNullIdQuery() { String out = api.idea("stringId", 1L, 2, 3L, 4, UUID.randomUUID()); - then(fixture.query()).isEqualTo("query idea(" + + then(fixture.query()).isEqualTo("query Idea(" + "$stringId: ID!, " + "$primitiveLongId: ID!, " + "$primitiveIntId: ID!, " + @@ -787,7 +787,7 @@ void shouldCallScalarWithValueOfQuery() { Integer value = api.foo(); - then(fixture.query()).isEqualTo("query foo { foo }"); + then(fixture.query()).isEqualTo("query Foo { foo }"); then(value).isEqualTo(123456); } @@ -799,7 +799,7 @@ void shouldCallScalarWithParseQuery() { LocalDate value = api.now(); - then(fixture.query()).isEqualTo("query now { now }"); + then(fixture.query()).isEqualTo("query Now { now }"); then(value).isEqualTo(now); } @@ -810,7 +810,7 @@ void shouldCallNonScalarWithStringConstructorApiQuery() { NonScalarWithStringConstructor result = api.foo(); - then(fixture.query()).isEqualTo("query foo { foo {value} }"); + then(fixture.query()).isEqualTo("query Foo { foo {value} }"); then(result.value).isEqualTo("1234"); } @@ -832,7 +832,7 @@ void shouldCallScalarWithStringConstructorMethodQuery() { ScalarWithStringConstructorMethod value = api.foo(); - then(fixture.query()).isEqualTo("query foo { foo }"); + then(fixture.query()).isEqualTo("query Foo { foo }"); then(value.text).isEqualTo("bar"); } @@ -843,7 +843,7 @@ void shouldCallScalarWithOfConstructorMethodQuery() { ScalarWithOfConstructorMethod value = api.foo(); - then(fixture.query()).isEqualTo("query foo { foo }"); + then(fixture.query()).isEqualTo("query Foo { foo }"); then(value.text).isEqualTo("x-bar"); } } @@ -870,7 +870,7 @@ void shouldCallStringGetterQuery() { String value = api.getGreeting(); - then(fixture.query()).isEqualTo("query greeting { greeting }"); + then(fixture.query()).isEqualTo("query Greeting { greeting }"); then(value).isEqualTo("foo"); } @@ -881,7 +881,7 @@ void shouldCallJustGetQuery() { String value = api.get(); - then(fixture.query()).isEqualTo("query get { get }"); + then(fixture.query()).isEqualTo("query Get { get }"); then(value).isEqualTo("foo"); } @@ -892,7 +892,7 @@ void shouldCallOneCharGetterQuery() { String value = api.getG(); - then(fixture.query()).isEqualTo("query g { g }"); + then(fixture.query()).isEqualTo("query G { g }"); then(value).isEqualTo("foo"); } @@ -903,7 +903,7 @@ void shouldCallGetAndOneLowerCharQuery() { String value = api.gets(); - then(fixture.query()).isEqualTo("query gets { gets }"); + then(fixture.query()).isEqualTo("query Gets { gets }"); then(value).isEqualTo("foo"); } @@ -914,7 +914,7 @@ void shouldCallGetAndLowerCharsQuery() { String value = api.getting(); - then(fixture.query()).isEqualTo("query getting { getting }"); + then(fixture.query()).isEqualTo("query Getting { getting }"); then(value).isEqualTo("foo"); } } @@ -974,7 +974,7 @@ void shouldCallLocalDateQuery() { LocalDateApi api = fixture.builder().build(LocalDateApi.class); LocalDate value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($date: Date) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: Date) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -988,7 +988,7 @@ void shouldCallLocalTimeQuery() { LocalTime value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($date: Time) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: Time) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1002,7 +1002,7 @@ void shouldCallOffsetTimeQuery() { OffsetTime value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($date: Time) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: Time) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1016,7 +1016,7 @@ void shouldCallLocalDateTimeQuery() { LocalDateTime value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1030,7 +1030,7 @@ void shouldCallOffsetDateTimeQuery() { OffsetDateTime value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1044,7 +1044,7 @@ void shouldCallZonedDateTimeQuery() { ZonedDateTime value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1058,7 +1058,7 @@ void shouldCallInstantQuery() { Instant value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($instant: DateTime) { foo(instant: $instant) }"); + then(fixture.query()).isEqualTo("query Foo($instant: DateTime) { foo(instant: $instant) }"); then(fixture.variables()).isEqualTo("{'instant':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1072,7 +1072,7 @@ void shouldCallUtilDateQuery() { Date value = api.foo(Date.from(in)); - then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(Date.from(out)); } @@ -1089,7 +1089,7 @@ void shouldCallSqlDateQuery() { SqlDateApi api = fixture.builder().build(SqlDateApi.class); java.sql.Date value = api.foo(sqlIn); - then(fixture.query()).isEqualTo("query foo($date: Date) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query Foo($date: Date) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(sqlOut); } @@ -1122,7 +1122,7 @@ void shouldCallUuidQuery() { UUID value = api.foo(in1, in2); - then(fixture.query()).isEqualTo("query foo($uuid: String, $id: ID) { foo(uuid: $uuid, id: $id) }"); + then(fixture.query()).isEqualTo("query Foo($uuid: String, $id: ID) { foo(uuid: $uuid, id: $id) }"); then(fixture.variables()).isEqualTo("{'uuid':'" + in1 + "','id':'" + in2 + "'}"); then(value).isEqualTo(out); } @@ -1138,7 +1138,7 @@ void shouldCallNestedUuidIdQuery() { NestedUuidId value = api.foo(in); - then(fixture.query()).isEqualTo("query foo($uuid: NestedUuidIdInput) { foo(uuid: $uuid) {id} }"); + then(fixture.query()).isEqualTo("query Foo($uuid: NestedUuidIdInput) { foo(uuid: $uuid) {id} }"); then(fixture.variables()).isEqualTo("{'uuid':{'id':'" + in.id + "'}}"); then(value.id).isEqualTo(out.id); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java index 71ebacb3b..9fd7a8b48 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java @@ -50,7 +50,7 @@ void shouldParseExtensionsInTypesafeResponse() { StringApi api = fixture.build(StringApi.class); TypesafeResponse result = api.greetings(); - then(fixture.query()).isEqualTo("query greetings { greetings }"); + then(fixture.query()).isEqualTo("query Greetings { greetings }"); then(result.getExtensions()).isEqualTo(Json.createObjectBuilder() .add("pi", 3.14159) .add("extension", "bell") diff --git a/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java index f4e691d88..c43fa05c1 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java @@ -56,7 +56,7 @@ void shouldUnionFindSpiderMan() { var response = api.find("Spider-Man"); - then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); @@ -72,7 +72,7 @@ void shouldNotUnionFindFoo() { var response = api.find("Foo"); - then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); @@ -88,7 +88,7 @@ void shouldNotUnionFindSomethingUnexpected() { var throwable = catchThrowable(() -> api.find("Expect the unexpected")); - then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); @@ -107,7 +107,7 @@ void shouldUnionFindAll() { var response = api.findAll("Spider-Man"); - then(fixture.query()).isEqualTo("query findAll($name: String) { findAll(name: $name){" + + then(fixture.query()).isEqualTo("query FindAll($name: String) { findAll(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java index 3123a0d64..00b41ddc4 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java @@ -595,6 +595,7 @@ private static Map getAnnotationsWithFilter(org.jbo public static final DotName NULLABLE = DotName.createSimple("io.smallrye.graphql.api.Nullable"); public static final DotName KOTLIN_METADATA = DotName.createSimple("kotlin.Metadata"); public static final DotName ONE_OF = DotName.createSimple("io.smallrye.graphql.api.OneOf"); + public static final DotName NAMESPACE = DotName.createSimple("io.smallrye.graphql.api.Namespace"); // MicroProfile GraphQL Annotations public static final DotName GRAPHQL_API = DotName.createSimple("org.eclipse.microprofile.graphql.GraphQLApi"); diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java index 0d819a3f1..833eb9bb5 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java @@ -2,6 +2,7 @@ import static io.smallrye.graphql.schema.Annotations.CUSTOM_SCALAR; import static io.smallrye.graphql.schema.Annotations.DIRECTIVE; +import static io.smallrye.graphql.schema.Annotations.NAME; import static io.smallrye.graphql.schema.Annotations.ONE_OF; import java.util.ArrayList; @@ -143,11 +144,29 @@ private Schema generateSchema() { addCustomScalarTypes(schema); + List errors = graphQLApiAnnotations.stream() + .map(graphQLApiAnnotation -> graphQLApiAnnotation.target().asClass()) + .filter(apiClass -> apiClass.hasDeclaredAnnotation(NAME)) + .map(apiClass -> "Use @Namespace instead of @Name on class " + apiClass.name()) + .collect(Collectors.toList()); + if (!errors.isEmpty()) { + throw new RuntimeException(String.join("\n", errors)); + } + for (AnnotationInstance graphQLApiAnnotation : graphQLApiAnnotations) { ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); List methods = getAllMethodsIncludingFromSuperClasses(apiClass); - Optional group = GroupHelper.getGroup(graphQLApiAnnotation); - addOperations(group, schema, methods); + Optional namespace = GroupHelper.getGroup(graphQLApiAnnotation); + addNamespacedOperations(namespace, schema, methods); + } + + errors = schema.getQueries().stream() + .filter(operation -> schema.getNamespaceQueries().containsKey(operation.getName())) + .map(operation -> "Inconsistent schema state is query and there is a namespace with the same name. " + + "Class " + operation.getClassName() + ", method name = " + operation.getMethodName()) + .collect(Collectors.toList()); + if (!errors.isEmpty()) { + throw new RuntimeException(String.join("\n", errors)); } // The above queries and mutations reference some models (input / type / interfaces / enum), let's create those @@ -355,39 +374,41 @@ private boolean findOutstandingAndAddToSchema(ReferenceType referenceType, C return keepGoing; } - /** - * This inspect all method, looking for Query and Mutation annotations, - * to create those Operations. - * - * @param schema the schema to add the operation to. - * @param methodInfoList the java methods. - */ - private void addOperations(Optional group, Schema schema, List methodInfoList) { + private void addNamespacedOperations(Optional namespace, Schema schema, + List methodInfoList) { + List errors = new ArrayList<>(); + for (MethodInfo methodInfo : methodInfoList) { Annotations annotationsForMethod = Annotations.getAnnotationsForMethod(methodInfo); if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.QUERY)) { Operation query = operationCreator.createOperation(methodInfo, OperationType.QUERY, null); - if (group.isPresent()) { - schema.addGroupedQuery(group.get(), query); + if (namespace.isPresent()) { + schema.addNamespaceQuery(namespace.get(), query); } else { schema.addQuery(query); } } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.MUTATION)) { Operation mutation = operationCreator.createOperation(methodInfo, OperationType.MUTATION, null); - if (group.isPresent()) { - schema.addGroupedMutation(group.get(), mutation); + if (namespace.isPresent()) { + schema.addNamespaceMutation(namespace.get(), mutation); } else { schema.addMutation(mutation); } } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) { - Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null); - if (group.isPresent()) { - schema.addGroupedSubscription(group.get(), subscription); - } else { - schema.addSubscription(subscription); + if (namespace.isPresent()) { + errors.add("Subscriptions are not working in namespace. Move your subscription " + methodInfo.name() + + " from " + methodInfo.declaringClass().name() + " class " + + "to another @GraphQLApi class, not marked @Namespace"); + break; } + Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null); + schema.addSubscription(subscription); } } + + if (!errors.isEmpty()) { + throw new RuntimeException(String.join("\n", errors)); + } } private void setUpSchemaDirectivesAndDescription(Schema schema, diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java index 6235cdab3..9a1180423 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java @@ -21,11 +21,11 @@ private GroupHelper() { } public static Optional getGroup(AnnotationInstance graphQLApiAnnotation) { - Optional name = getName(graphQLApiAnnotation); - if (name.isPresent()) { + Optional> names = getNames(graphQLApiAnnotation); + if (names.isPresent()) { Optional description = getDescription(graphQLApiAnnotation); Group group = new Group(); - group.setName(name.get()); + group.setNames(names.get()); group.setDescription(description.orElse(null)); return Optional.of(group); } @@ -39,19 +39,12 @@ public static Optional getGroup(AnnotationInstance graphQLApiAnnotation) * @param graphQLApiAnnotation * @return */ - private static Optional getName(AnnotationInstance graphQLApiAnnotation) { - // Get the name - AnnotationValue value = graphQLApiAnnotation.value(); - if (value != null && value.asString() != null && !value.asString().isEmpty()) { - return Optional.of(value.asString()); - } else { - // Try the Name annotation - ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); - AnnotationInstance nameAnnotation = apiClass.classAnnotation(Annotations.NAME); - if (nameAnnotation != null && nameAnnotation.value() != null && nameAnnotation.value().asString() != null - && !nameAnnotation.value().asString().isEmpty()) { - return Optional.of(nameAnnotation.value().asString()); - } + private static Optional> getNames(AnnotationInstance graphQLApiAnnotation) { + ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); + AnnotationInstance nameAnnotation = apiClass.annotation(Annotations.NAMESPACE); + if (nameAnnotation != null && nameAnnotation.value() != null && nameAnnotation.value().asString() != null + && !nameAnnotation.value().asString().isEmpty()) { + return Optional.of(List.of(nameAnnotation.value().asString().split("/"))); } return Optional.empty(); } diff --git a/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java index 63744d96d..a29f5f9e6 100644 --- a/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java +++ b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java @@ -8,16 +8,17 @@ import java.util.Map; import org.eclipse.microprofile.graphql.GraphQLApi; -import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; +import io.smallrye.graphql.api.Namespace; + /** * Book API * * @author Phillip Kruger (phillip.kruger@redhat.com) */ @GraphQLApi -@Name("Books") +@Namespace("books") public class BookGraphQLApi { @Query diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java index 992c8855a..0827072e7 100644 --- a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java @@ -1,6 +1,7 @@ package io.smallrye.graphql.schema.model; import java.io.Serializable; +import java.util.List; import java.util.Objects; /** @@ -9,23 +10,18 @@ * @author Phillip Kruger (phillip.kruger@redhat.com) */ public class Group implements Serializable { - private String name; + private List names; private String description; public Group() { } - public Group(String name, String description) { - this.name = name; - this.description = description; - } - - public String getName() { - return name; + public List getNames() { + return names; } - public void setName(String name) { - this.name = name; + public void setNames(List names) { + this.names = names; } public String getDescription() { @@ -39,7 +35,7 @@ public void setDescription(String description) { @Override public int hashCode() { int hash = 7; - hash = 59 * hash + Objects.hashCode(this.name); + hash = 59 * hash + Objects.hashCode(this.names); return hash; } @@ -55,7 +51,7 @@ public boolean equals(Object obj) { return false; } final Group other = (Group) obj; - if (!Objects.equals(this.name, other.name)) { + if (!Objects.equals(this.names, other.names)) { return false; } return true; @@ -63,7 +59,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return "Group{" + "name=" + name + ", description=" + description + '}'; + return "Group{" + "names=" + names + ", description=" + description + '}'; } } diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/GroupContainer.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/GroupContainer.java new file mode 100644 index 000000000..95d4b8f7b --- /dev/null +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/GroupContainer.java @@ -0,0 +1,93 @@ +package io.smallrye.graphql.schema.model; + +import java.io.Serializable; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class GroupContainer implements Serializable { + private String name; + private String description; + private Set operations = new HashSet<>(); + private Map container = new HashMap<>(); + + public GroupContainer() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Set getOperations() { + return operations; + } + + public void setOperations(Set operations) { + this.operations = operations; + } + + public Map getContainer() { + return container; + } + + public void setContainer(Map container) { + this.container = container; + } + + public boolean hasOperations() { + return !operations.isEmpty() || container.values().stream().anyMatch(this::hasOperations); + } + + private boolean hasOperations(GroupContainer namespace) { + return !namespace.getOperations().isEmpty() + || namespace.container.values().stream().anyMatch(this::hasOperations); + } + + public void add(Collection names, String description, Operation operation) { + if (!names.isEmpty()) { + ArrayDeque queue = new ArrayDeque<>(names); + String name = queue.poll(); + add(name, description, queue, operation); + } else { + throw new RuntimeException("Namespaces can't be empty"); + } + } + + private void add(String name, String description, ArrayDeque queue, Operation operation) { + this.name = name; + + if (!queue.isEmpty()) { + String key = queue.poll(); + GroupContainer groupContainer = container.computeIfAbsent(key, s -> new GroupContainer()); + groupContainer.add(key, description, queue, operation); + } else { + this.description = description; + this.operations.add(operation); + } + } + + public List getAllOperations() { + List operations = new ArrayList<>(this.operations); + + container.values().forEach(groupContainer -> operations.addAll(groupContainer.getAllOperations())); + + return operations; + } +} diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java index 8575c949c..cf1a2b95e 100644 --- a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java @@ -2,11 +2,13 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Represents a GraphQL Schema. @@ -22,9 +24,8 @@ public final class Schema implements Serializable { private Set mutations = new HashSet<>(); private Set subscriptions = new HashSet<>(); - private Map> groupedQueries = new HashMap<>(); - private Map> groupedMutations = new HashMap<>(); - private Map> groupedSubscriptions = new HashMap<>(); + private Map namespaceQueries = new HashMap<>(); + private Map namespaceMutations = new HashMap<>(); private List customScalarTypes = new ArrayList<>(); private List directiveTypes = new ArrayList<>(); @@ -56,7 +57,7 @@ public void addQuery(Operation query) { } public boolean hasOperations() { - return hasQueries() || hasGroupedQueries() || hasMutations() || hasGroupedMutations(); + return hasQueries() || hasNamespaceQueries() || hasMutations() || hasNamespaceMutations(); } public boolean hasQueries() { @@ -96,51 +97,57 @@ public boolean hasSubscriptions() { } public Map> getGroupedQueries() { - return groupedQueries; + Set operations = namespaceQueries.values().stream() + .map(GroupContainer::getAllOperations) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + return Map.of(new Group(), operations); } - public void setGroupedQueries(Map> groupedQueries) { - this.groupedQueries = groupedQueries; - } - - public void addGroupedQuery(Group group, Operation query) { - addToOperationMap(this.groupedQueries, group, query); - } - - public boolean hasGroupedQueries() { - return !this.groupedQueries.isEmpty(); + public Map> getGroupedMutations() { + Set operations = namespaceMutations.values().stream() + .map(GroupContainer::getAllOperations) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + return Map.of(new Group(), operations); } - public Map> getGroupedMutations() { - return groupedMutations; + public Map getNamespaceQueries() { + return namespaceQueries; } - public void setGroupedMutations(Map> groupedMutations) { - this.groupedMutations = groupedMutations; + public void setNamespaceQueries(Map namespaceQueries) { + this.namespaceQueries = namespaceQueries; } - public void addGroupedMutation(Group group, Operation mutation) { - addToOperationMap(this.groupedMutations, group, mutation); + public boolean hasNamespaceQueries() { + return namespaceQueries.values().stream().anyMatch(GroupContainer::hasOperations); } - public boolean hasGroupedMutations() { - return !this.groupedMutations.isEmpty(); + public void addNamespaceQuery(Group group, Operation operation) { + GroupContainer groupContainer = namespaceQueries.computeIfAbsent( + group.getNames().get(0), + key -> new GroupContainer()); + groupContainer.add(group.getNames(), group.getDescription(), operation); } - public Map> getGroupedSubscriptions() { - return groupedSubscriptions; + public Map getNamespaceMutations() { + return namespaceMutations; } - public void setGroupedSubscriptions(Map> groupedSubscriptions) { - this.groupedSubscriptions = groupedSubscriptions; + public void setNamespaceMutations(Map namespaceMutations) { + this.namespaceMutations = namespaceMutations; } - public void addGroupedSubscription(Group group, Operation subscription) { - addToOperationMap(this.groupedSubscriptions, group, subscription); + public boolean hasNamespaceMutations() { + return namespaceMutations.values().stream().anyMatch(GroupContainer::hasOperations); } - public boolean hasGroupedSubscriptions() { - return !this.groupedSubscriptions.isEmpty(); + public void addNamespaceMutation(Group group, Operation operation) { + GroupContainer groupContainer = namespaceMutations.computeIfAbsent( + group.getNames().get(0), + key -> new GroupContainer()); + groupContainer.add(group.getNames(), group.getDescription(), operation); } public Map getInputs() { @@ -309,18 +316,6 @@ public List getBatchOperations() { return batchOperations; } - private void addToOperationMap(Map> map, Group group, Operation query) { - Set set; - - if (map.containsKey(group)) { - set = map.get(group); - } else { - set = new HashSet<>(); - } - set.add(query); - map.put(group, set); - } - public void addCustomScalarType(CustomScalarType customScalarType) { customScalarTypes.add(customScalarType); Scalars.registerCustomScalarInSchema( @@ -359,9 +354,8 @@ public String toString() { ", queries=" + queries + ", mutations=" + mutations + ", subscriptions=" + subscriptions + - ", groupedQueries=" + groupedQueries + - ", groupedMutations=" + groupedMutations + - ", groupedSubscriptions=" + groupedSubscriptions + + ", namespaceQueries=" + namespaceQueries + + ", namespaceMutations=" + namespaceMutations + ", directiveTypes=" + directiveTypes + ", customScalarTypes=" + customScalarTypes + ", inputs=" + inputs + diff --git a/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java b/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java new file mode 100644 index 000000000..30805c38e --- /dev/null +++ b/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java @@ -0,0 +1,17 @@ +package io.smallrye.graphql.api; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import io.smallrye.common.annotation.Experimental; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE }) +@Documented +@Experimental("Experimental namespaces on api class. Separate namespaces via '/' (example - admin/users)") +public @interface Namespace { + String value() default ""; +} diff --git a/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java b/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java index 92610c307..a40c16106 100644 --- a/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java +++ b/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java @@ -29,6 +29,7 @@ import org.jboss.jandex.Indexer; import io.smallrye.graphql.api.Entry; +import io.smallrye.graphql.api.Namespace; import io.smallrye.graphql.api.OneOf; import io.smallrye.graphql.api.federation.Authenticated; import io.smallrye.graphql.api.federation.ComposeDirective; @@ -126,6 +127,7 @@ private IndexView createCustomIndex() { indexer.index(convertClassToInputStream(Shareable.class)); indexer.index(convertClassToInputStream(Tag.class)); indexer.index(convertClassToInputStream(OneOf.class)); + indexer.index(convertClassToInputStream(Namespace.class)); } catch (IOException ex) { throw new RuntimeException(ex); } diff --git a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java index 1eaf74ff6..1f32b4f5f 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java @@ -81,7 +81,7 @@ import io.smallrye.graphql.schema.model.EnumType; import io.smallrye.graphql.schema.model.EnumValue; import io.smallrye.graphql.schema.model.Field; -import io.smallrye.graphql.schema.model.Group; +import io.smallrye.graphql.schema.model.GroupContainer; import io.smallrye.graphql.schema.model.InputType; import io.smallrye.graphql.schema.model.Operation; import io.smallrye.graphql.schema.model.Reference; @@ -334,8 +334,8 @@ private void addQueries(GraphQLSchema.Builder schemaBuilder) { if (schema.hasQueries()) { addRootObject(queryBuilder, schema.getQueries(), QUERY); } - if (schema.hasGroupedQueries()) { - addGroupedRootObject(queryBuilder, schema.getGroupedQueries(), QUERY); + if (schema.hasNamespaceQueries()) { + addNamespacedRootObject(queryBuilder, schema.getNamespaceQueries(), QUERY); } GraphQLObjectType query = queryBuilder.build(); @@ -350,8 +350,8 @@ private void addMutations(GraphQLSchema.Builder schemaBuilder) { if (schema.hasMutations()) { addRootObject(mutationBuilder, schema.getMutations(), MUTATION); } - if (schema.hasGroupedMutations()) { - addGroupedRootObject(mutationBuilder, schema.getGroupedMutations(), MUTATION); + if (schema.hasNamespaceMutations()) { + addNamespacedRootObject(mutationBuilder, schema.getNamespaceMutations(), MUTATION); } GraphQLObjectType mutation = mutationBuilder.build(); @@ -368,9 +368,6 @@ private void addSubscriptions(GraphQLSchema.Builder schemaBuilder) { if (schema.hasSubscriptions()) { addRootObject(subscriptionBuilder, schema.getSubscriptions(), SUBSCRIPTION); } - if (schema.hasGroupedSubscriptions()) { - addGroupedRootObject(subscriptionBuilder, schema.getGroupedSubscriptions(), SUBSCRIPTION); - } GraphQLObjectType subscription = subscriptionBuilder.build(); if (subscription.getFieldDefinitions() != null && !subscription.getFieldDefinitions().isEmpty()) { @@ -389,18 +386,30 @@ private void addRootObject(GraphQLObjectType.Builder rootBuilder, Set } } - private void addGroupedRootObject(GraphQLObjectType.Builder rootBuilder, - Map> operationMap, String rootName) { - Set>> operationsSet = operationMap.entrySet(); + private String prettyString(String value) { + return value.substring(0, 1).toUpperCase() + value.substring(1); + } + + private void addNamespacedRootObject(GraphQLObjectType.Builder mutationBuilder, + Map namespaceMutations, String mutation) { + namespaceMutations.values() + .forEach(groupContainer -> addNamespacedRootObject(mutationBuilder, groupContainer, "", mutation)); + } - for (Map.Entry> operationsEntry : operationsSet) { - Group group = operationsEntry.getKey(); - Set operations = operationsEntry.getValue(); + private List addNamespacedRootObject(GraphQLObjectType.Builder rootBuilder, + GroupContainer groupContainer, String rootName, String suffix) { + List graphQLFieldDefinitions = groupContainer.getContainer().isEmpty() + ? List.of() + : getGraphQLFieldDefinition(groupContainer, rootName, suffix); - GraphQLObjectType namedType = createNamedType(rootName, group, operations); + if (!groupContainer.getOperations().isEmpty() || !graphQLFieldDefinitions.isEmpty()) { + GraphQLObjectType namedType = createNamespaceType(rootName, suffix, groupContainer, + groupContainer.getOperations(), graphQLFieldDefinitions); - GraphQLFieldDefinition.Builder graphQLFieldDefinitionBuilder = GraphQLFieldDefinition.newFieldDefinition() - .name(group.getName()).description(group.getDescription()); + GraphQLFieldDefinition.Builder graphQLFieldDefinitionBuilder = GraphQLFieldDefinition + .newFieldDefinition() + .name(groupContainer.getName()) + .description(groupContainer.getDescription()); graphQLFieldDefinitionBuilder.type(namedType); @@ -409,28 +418,53 @@ private void addGroupedRootObject(GraphQLObjectType.Builder rootBuilder, GraphQLFieldDefinition namedField = graphQLFieldDefinitionBuilder.build(); this.codeRegistryBuilder.dataFetcherIfAbsent( - FieldCoordinates.coordinates(rootName, namedField.getName()), + FieldCoordinates.coordinates(rootName + suffix, namedField.getName()), dummyDataFetcher); - rootBuilder.field(namedField); + + return List.of(namedField); } + return List.of(); + } + + private List getGraphQLFieldDefinition(GroupContainer groupContainer, String rootName, + String suffix) { + String name = prettyString(groupContainer.getName()); + String namedTypeName = rootName + name + suffix; + + GraphQLObjectType.Builder wrapperBuilder = GraphQLObjectType.newObject() + .name(namedTypeName) + .description(groupContainer.getDescription()); + + return groupContainer + .getContainer() + .values() + .stream() + .map(namespace -> addNamespacedRootObject( + wrapperBuilder, namespace, rootName + prettyString(groupContainer.getName()), suffix)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); } - private GraphQLObjectType createNamedType(String parent, Group group, Set operations) { - String namedTypeName = group.getName() + parent; + private GraphQLObjectType createNamespaceType(String root, String suffix, GroupContainer namespace, + Set operations, List graphQLFieldDefinitions) { + String name = prettyString(namespace.getName()); + + String namedTypeName = root + name + suffix; GraphQLObjectType.Builder objectTypeBuilder = GraphQLObjectType.newObject() .name(namedTypeName) - .description(group.getDescription()); + .description(namespace.getDescription()); // Operations for (Operation operation : operations) { operation = eventEmitter.fireCreateOperation(operation); - GraphQLFieldDefinition graphQLFieldDefinition = createGraphQLFieldDefinitionFromOperation(namedTypeName, - operation); + GraphQLFieldDefinition graphQLFieldDefinition = createGraphQLFieldDefinitionFromOperation( + namedTypeName, operation); objectTypeBuilder = objectTypeBuilder.field(graphQLFieldDefinition); } + objectTypeBuilder.fields(graphQLFieldDefinitions); return objectTypeBuilder.build(); } diff --git a/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java b/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java index 7d6d8e1ec..118ddb297 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java @@ -57,7 +57,6 @@ static void beforeAll() { NamedNamespaceModel.class, NamedNamespaceTestApi.class, NamedNamespaceWIthGroupingKeyModel.class, NamedNamespaceWithGroupingKeyTestApi.class, SourceNamespaceModel.class, SourceNamespaceTestApi.class, - SourceNamespaceTestApi.First.class, SourceNamespaceTestApi.Second.class, UnamedModel.class, UnnamedTestApi.class); GraphQLSchema graphQLSchema = createGraphQLSchema(index); diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java index af3ce4b56..46fe20f96 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java @@ -10,16 +10,17 @@ import org.eclipse.microprofile.graphql.Description; import org.eclipse.microprofile.graphql.GraphQLApi; import org.eclipse.microprofile.graphql.Mutation; -import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; +import io.smallrye.graphql.api.Namespace; + /** * Book API * * @author Phillip Kruger (phillip.kruger@redhat.com) */ @GraphQLApi -@Name("books") +@Namespace("books") @Description("Allow all book releated APIs") public class BookGraphQLApi { diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java index 1a7c8c011..1358f243c 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java @@ -1,10 +1,11 @@ package io.smallrye.graphql.test.namespace; import org.eclipse.microprofile.graphql.GraphQLApi; -import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; -@Name("NamedNamespace") +import io.smallrye.graphql.api.Namespace; + +@Namespace("namedNamespace") @GraphQLApi public class NamedNamespaceTestApi { @Query diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java index 0c0f66b84..b9f7001cf 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java @@ -1,10 +1,11 @@ package io.smallrye.graphql.test.namespace; import org.eclipse.microprofile.graphql.GraphQLApi; -import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; -@Name("NamedNamespaceWithGroupingKey") +import io.smallrye.graphql.api.Namespace; + +@Namespace("namedNamespaceWithGroupingKey") @GraphQLApi public class NamedNamespaceWithGroupingKeyTestApi { @Query diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java index 2568cdec5..586163cc4 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java @@ -2,26 +2,14 @@ import org.eclipse.microprofile.graphql.GraphQLApi; import org.eclipse.microprofile.graphql.Query; -import org.eclipse.microprofile.graphql.Source; + +import io.smallrye.graphql.api.Namespace; @GraphQLApi +@Namespace("first/second") public class SourceNamespaceTestApi { - public static class First { - } - - public static class Second { - } - - @Query("first") - public First first() { - return new First(); - } - - public Second second(@Source First first) { - return new Second(); - } - - public SourceNamespaceModel getById(@Source Second second, String id) { + @Query + public SourceNamespaceModel getById(String id) { return new SourceNamespaceModel(id, id); } } diff --git a/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java b/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java index 143b48299..c0e25792d 100644 --- a/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java +++ b/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java @@ -11,7 +11,7 @@ @GraphQLApi public class ServerApi { - private final static String EXPECTED_QUERY = "query querySomeClass($someObject: SomeClassServerInput, $simpleType: Boolean! @variableDefinitionDirective @variableDefinitionDirective(fields: \"a\")) { querySomeClass(someObject: $someObject, simpleType: $simpleType) @fieldDirective(fields: [1]) @fieldDirective(fields: [2, 3]) {id @fieldDirective(fields: [4]) number} }"; + private final static String EXPECTED_QUERY = "query QuerySomeClass($someObject: SomeClassServerInput, $simpleType: Boolean! @variableDefinitionDirective @variableDefinitionDirective(fields: \"a\")) { querySomeClass(someObject: $someObject, simpleType: $simpleType) @fieldDirective(fields: [1]) @fieldDirective(fields: [2, 3]) {id @fieldDirective(fields: [4]) number} }"; @Inject SmallRyeContext context; From 10c16d20196ad285e6318372990492c7617c08d9 Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Thu, 12 Sep 2024 00:52:11 +0300 Subject: [PATCH 2/7] Return groups, separate logic between Name and Namespace, add some tests and update documentation --- .../VertxTypesafeGraphQLClientBuilder.java | 13 +- .../VertxTypesafeGraphQLClientProxy.java | 19 ++- .../client/impl/typesafe/QueryBuilder.java | 25 ++- .../client/impl/typesafe/ResultBuilder.java | 20 ++- .../typesafe/reflection/MethodInvocation.java | 53 ++++-- .../graphql/client/model/Annotations.java | 2 +- .../client/model/ClientModelBuilder.java | 25 ++- .../graphql/client/model/QueryBuilder.java | 24 ++- .../client/model/helper/OperationModel.java | 59 +++++-- .../client/model/ClientModelBuilderTest.java | 35 +++- .../graphql/schema/SchemaBuilder.java | 160 ++++++++++++++---- .../graphql/schema/helper/GroupHelper.java | 25 ++- .../schema/helper/NamespaceHelper.java | 63 +++++++ .../smallrye/graphql/index/NamespaceTest.java | 45 +++++ .../graphql/index/app/BookGraphQLApi.java | 5 +- .../index/app/namespace/ApiWithName.java | 14 ++ .../namespace/ApiWithNameAndNamespace.java | 17 ++ .../index/app/namespace/ApiWithNamespace.java | 15 ++ .../smallrye/graphql/schema/model/Group.java | 22 ++- .../graphql/schema/model/Namespace.java | 48 ++++++ .../schema/model/NamespaceContainer.java | 89 ++++++++++ .../smallrye/graphql/schema/model/Schema.java | 140 ++++++++++----- docs/namespaces-on-server-side.md | 71 +++++++- docs/typesafe-client-usage.md | 73 ++++++-- .../io/smallrye/graphql/api/Namespace.java | 7 +- .../graphql/entry/http/IndexInitializer.java | 1 - .../smallrye/graphql/bootstrap/Bootstrap.java | 120 +++++++++---- .../execution/ExperimentalNamespaceTest.java | 95 +++++++++++ .../execution/FederatedNamespaceTest.java | 1 + .../graphql/test/grouping/BookGraphQLApi.java | 5 +- .../namespace/ExperimentalNamespaceApi.java | 15 ++ .../ExperimentalNamespaceWithErrorApi.java | 17 ++ .../test/namespace/NamedNamespaceTestApi.java | 5 +- .../NamedNamespaceWithGroupingKeyTestApi.java | 5 +- .../namespace/SourceNamespaceTestApi.java | 22 ++- 35 files changed, 1121 insertions(+), 234 deletions(-) create mode 100644 common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java create mode 100644 common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java create mode 100644 common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithName.java create mode 100644 common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNameAndNamespace.java create mode 100644 common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNamespace.java create mode 100644 common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Namespace.java create mode 100644 common/schema-model/src/main/java/io/smallrye/graphql/schema/model/NamespaceContainer.java create mode 100644 server/implementation/src/test/java/io/smallrye/graphql/execution/ExperimentalNamespaceTest.java create mode 100644 server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java create mode 100644 server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java diff --git a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java index 948e04c57..a4dc50d2b 100644 --- a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java +++ b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java @@ -12,8 +12,10 @@ import java.util.List; import java.util.Map; +import org.eclipse.microprofile.graphql.Name; import org.jboss.logging.Logger; +import io.smallrye.graphql.api.Namespace; import io.smallrye.graphql.client.impl.ErrorMessageProvider; import io.smallrye.graphql.client.impl.GraphQLClientConfiguration; import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration; @@ -145,6 +147,14 @@ public VertxTypesafeGraphQLClientBuilder websocketInitializationTimeout(Integer @Override public T build(Class apiClass) { + Name nameAnnotation = apiClass.getAnnotation(Name.class); + Namespace namespaceAnnotation = apiClass.getAnnotation(Namespace.class); + + if (nameAnnotation != null && namespaceAnnotation != null) { + throw new RuntimeException("You can only use one of the annotations - @Name or @Namespace " + + "over the GraphQLClientApi interface. Please, fix next interface: " + apiClass.getName()); + } + if (this.options == null) { this.options = new WebClientOptions(); } @@ -185,7 +195,8 @@ public T build(Class apiClass) { endpoint, websocketUrl, executeSingleOperationsOverWebsocket, httpClient, webClient, subprotocols, websocketInitializationTimeout, - allowUnexpectedResponseFields); + allowUnexpectedResponseFields, + namespaceAnnotation != null); return apiClass.cast(Proxy.newProxyInstance(getClassLoader(apiClass), new Class[] { apiClass }, (proxy, method, args) -> invoke(graphQLClient, method, args))); diff --git a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java index f9fe262d9..f5017932d 100644 --- a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java +++ b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java @@ -81,6 +81,7 @@ class VertxTypesafeGraphQLClientProxy { private final ClientModel clientModel; private final boolean executeSingleOperationsOverWebsocket; private final boolean allowUnexpectedResponseFields; + private final boolean useNamespace; // Do NOT use this field directly, always retrieve by calling `webSocketHandler()`. // When a websocket connection is required, then this is populated with a Uni @@ -104,7 +105,8 @@ class VertxTypesafeGraphQLClientProxy { WebClient webClient, List subprotocols, Integer subscriptionInitializationTimeout, - boolean allowUnexpectedResponseFields) { + boolean allowUnexpectedResponseFields, + boolean useNamespace) { this.api = api; this.clientModel = clientModel; this.additionalHeaders = additionalHeaders; @@ -134,6 +136,7 @@ class VertxTypesafeGraphQLClientProxy { this.subprotocols = subprotocols; this.subscriptionInitializationTimeout = subscriptionInitializationTimeout; this.allowUnexpectedResponseFields = allowUnexpectedResponseFields; + this.useNamespace = useNamespace; } Object invoke(MethodInvocation method) { @@ -175,7 +178,7 @@ private Object executeSingleResultOperationOverHttpSync(MethodInvocation method, } return new ResultBuilder(method, response.bodyAsString(), response.statusCode(), response.statusMessage(), convertHeaders(allHeaders), - allowUnexpectedResponseFields).read(); + allowUnexpectedResponseFields, useNamespace).read(); } private Uni executeSingleResultOperationOverHttpAsync(MethodInvocation method, JsonObject request, @@ -193,7 +196,7 @@ private Uni executeSingleResultOperationOverHttpAsync(MethodInvocation m return Uni.createFrom().completionStage(postAsync(request.toString(), allHeaders)) .map(response -> new ResultBuilder(method, response.bodyAsString(), response.statusCode(), response.statusMessage(), convertHeaders(allHeaders), - allowUnexpectedResponseFields).read()); + allowUnexpectedResponseFields, useNamespace).read()); } else { // when all dynamic headers have been obtained, proceed with the request return Uni.combine().all().unis(unis) @@ -202,7 +205,7 @@ private Uni executeSingleResultOperationOverHttpAsync(MethodInvocation m .completionStage(postAsync(request.toString(), allHeaders)) .map(response -> new ResultBuilder(method, response.bodyAsString(), response.statusCode(), response.statusMessage(), convertHeaders(allHeaders), - allowUnexpectedResponseFields).read())); + allowUnexpectedResponseFields, useNamespace).read())); } } @@ -232,7 +235,7 @@ private Uni executeSingleResultOperationOverWebsocket(MethodInvocation m } }) .onItem().transform(data -> { - Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields).read(); + Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields, useNamespace).read(); if (object != null) { return object; } else { @@ -257,7 +260,7 @@ private Multi executeSubscriptionOverWebsocket(MethodInvocation method, handlerRef.get().cancelMulti(operationId.get()); }) .onItem().transform(data -> { - Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields).read(); + Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields, useNamespace).read(); if (object != null) { return object; } else { @@ -303,13 +306,13 @@ private JsonObject request(MethodInvocation method) { JsonObjectBuilder request = jsonObjectFactory.createObjectBuilder(); String query; if (clientModel == null) { - query = queryCache.computeIfAbsent(method.getKey(), key -> new QueryBuilder(method).build()); + query = queryCache.computeIfAbsent(method.getKey(), key -> new QueryBuilder(method).build(useNamespace)); } else { query = clientModel.getOperationMap().get(method.getMethodKey()); } request.add("query", query); request.add("variables", variables(method)); - request.add("operationName", method.getOperationName()); + request.add("operationName", method.getOperationName(useNamespace)); JsonObject result = request.build(); log.tracef("full graphql request: %s", result.toString()); return result; diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java index b64969470..f5d4d677d 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java @@ -21,22 +21,17 @@ public QueryBuilder(MethodInvocation method) { this.method = method; } - public String build() { + public String build(boolean useNamespace) { StringBuilder request = new StringBuilder(method.getOperationTypeAsString()); request.append(" "); - - request.append(method.getOperationName()); // operation name - - if (method.hasValueParameters()) { + request.append(method.getOperationName(useNamespace)); + if (method.hasValueParameters()) request.append(method.valueParameters().map(this::declare).collect(joining(", ", "(", ")"))); - } - List namespaces = method.getNamespaces(); - if (!namespaces.isEmpty()) { - namespaces.forEach(value -> { - request.append(" { "); - request.append(value); - }); + if (useNamespace) { + method.getNamespaces().forEach(namespace -> request.append(" { ").append(namespace)); + } else if (method.getGroupName() != null) { + request.append(" { ").append(method.getGroupName()); } if (method.isSingle()) { @@ -54,8 +49,10 @@ public String build() { request.append(" }"); } - if (!namespaces.isEmpty()) { - request.append(" } ".repeat(namespaces.size())); + if (useNamespace) { + request.append(" }".repeat(method.getNamespaces().size())); + } else if (method.getGroupName() != null) { + request.append(" }"); } return request.toString(); diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java index 4f4dc6f90..1f636bbc9 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java @@ -38,9 +38,11 @@ public class ResultBuilder { private JsonObject data; private JsonObject extensions; private Map> transportMeta; + private final boolean useNamespace; - public ResultBuilder(MethodInvocation method, String responseString, boolean allowUnexpectedResponseFields) { - this(method, responseString, null, null, null, allowUnexpectedResponseFields); + public ResultBuilder(MethodInvocation method, String responseString, boolean allowUnexpectedResponseFields, + boolean useNamespace) { + this(method, responseString, null, null, null, allowUnexpectedResponseFields, useNamespace); } public ResultBuilder(MethodInvocation method, @@ -48,13 +50,15 @@ public ResultBuilder(MethodInvocation method, Integer statusCode, String statusMessage, Map> transportMeta, - boolean allowUnexpectedResponseFields) { + boolean allowUnexpectedResponseFields, + boolean useNamespace) { this.method = method; this.statusCode = statusCode; this.statusMessage = statusMessage; this.responseString = responseString; this.transportMeta = transportMeta; this.response = ResponseReader.parseGraphQLResponse(responseString, allowUnexpectedResponseFields); + this.useNamespace = useNamespace; } public Object read() { @@ -94,9 +98,15 @@ private JsonObject readData() { return null; JsonObject data = response.getJsonObject("data"); - for (String namespace : method.getNamespaces()) { - data = data.getJsonObject(namespace); + + if (useNamespace) { + for (String namespace : method.getNamespaces()) { + data = data.getJsonObject(namespace); + } + } else if (method.getGroupName() != null) { + data = data.getJsonObject(method.getGroupName()); } + if (method.isSingle() && !data.containsKey(method.getName())) throw new InvalidResponseException("No data for '" + method.getName() + "'"); return data; diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java index d2992a5e2..f6495363f 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java @@ -40,14 +40,16 @@ public static MethodInvocation of(Method method, Object... args) { private final TypeInfo type; private final Method method; private final Object[] parameterValues; - private final List namespaces; + private final String groupName; + private List namespaces; + private String operationName; private List parameters; private MethodInvocation(TypeInfo type, Method method, Object[] parameterValues) { this.type = type; this.method = method; this.parameterValues = parameterValues; - this.namespaces = readNamespace(method); + this.groupName = readGroupName(method); } @Override @@ -266,25 +268,50 @@ public String getOperationTypeAsString() { } } - public List getNamespaces() { - return namespaces; + public String getGroupName() { + return groupName; } - private List readNamespace(Method method) { - Namespace annotation = method.getDeclaringClass().getAnnotation(Namespace.class); + private String readGroupName(Method method) { + Name annotation = method.getDeclaringClass().getAnnotation(Name.class); if (annotation != null) { - return Arrays.stream(annotation.value().split("/")) - .map(String::trim) - .collect(Collectors.toList()); + String groupName = annotation.value().trim(); + if (!groupName.isEmpty()) { + return groupName; + } } - return List.of(); + return null; } - public String getOperationName() { - return namespaces.stream().map(this::prettyString).collect(joining()) + prettyString(getName()); + public List getNamespaces() { + if (namespaces == null) { + Namespace annotation = method.getDeclaringClass().getAnnotation(Namespace.class); + if (annotation != null) { + namespaces = Arrays.stream(annotation.value().split("/")) + .map(String::trim) + .collect(Collectors.toList()); + } else { + namespaces = List.of(); + } + } + return namespaces; + } + + public String getOperationName(boolean useNamespace) { + if (operationName == null) { + if (useNamespace) { + operationName = getNamespaces().stream().map(this::makeFirstLetterUppercase).collect(joining()) + + makeFirstLetterUppercase(getName()); + } else { + operationName = getGroupName() == null + ? makeFirstLetterUppercase(getName()) + : makeFirstLetterUppercase(getGroupName()) + makeFirstLetterUppercase(getName()); + } + } + return operationName; } - private String prettyString(String value) { + private String makeFirstLetterUppercase(String value) { return value.substring(0, 1).toUpperCase() + value.substring(1); } } diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java index 22e97a731..561ae1a81 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/Annotations.java @@ -525,6 +525,7 @@ private static Map getAnnotationsWithFilter(Type ty public static final DotName NON_BLOCKING = DotName.createSimple("io.smallrye.common.annotation.NonBlocking"); // SmallRye GraphQL Annotations (Experimental) + public static final DotName NAMESPACE = DotName.createSimple("io.smallrye.graphql.api.Namespace"); public static final DotName TO_SCALAR = DotName.createSimple("io.smallrye.graphql.api.ToScalar"); // TODO: Remove public static final DotName ADAPT_TO_SCALAR = DotName.createSimple("io.smallrye.graphql.api.AdaptToScalar"); public static final DotName ADAPT_WITH = DotName.createSimple("io.smallrye.graphql.api.AdaptWith"); @@ -545,7 +546,6 @@ private static Map getAnnotationsWithFilter(Type ty public static final DotName TYPE = DotName.createSimple("org.eclipse.microprofile.graphql.Type"); public static final DotName INTERFACE = DotName.createSimple("org.eclipse.microprofile.graphql.Interface"); public static final DotName UNION = DotName.createSimple("io.smallrye.graphql.api.Union"); - public static final DotName NAMESPACE = DotName.createSimple("io.smallrye.graphql.api.Namespace"); public static final DotName MULTIPLE = DotName.createSimple("io.smallrye.graphql.client.typesafe.api.Multiple"); diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java index f30f34cf6..ebd48eab5 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java @@ -2,6 +2,7 @@ import static io.smallrye.graphql.client.model.Annotations.GRAPHQL_CLIENT_API; import static io.smallrye.graphql.client.model.Annotations.NAME; +import static io.smallrye.graphql.client.model.Annotations.NAMESPACE; import static io.smallrye.graphql.client.model.ScanningContext.getIndex; import java.util.ArrayList; @@ -58,20 +59,15 @@ private ClientModels generateClientModels() { Collection graphQLApiAnnotations = getIndex() .getAnnotations(GRAPHQL_CLIENT_API); - List errors = graphQLApiAnnotations.stream() - .filter(annotationInstance -> annotationInstance.target().asClass().hasDeclaredAnnotation(NAME)) - .map(apiClass -> "Use @Namespace instead of @Name on interface " + apiClass.target().asClass().name()) - .collect(Collectors.toList()); - if (!errors.isEmpty()) { - throw new RuntimeException(String.join("\n", errors)); - } + validateAnnotations(graphQLApiAnnotations); graphQLApiAnnotations.forEach(graphQLApiAnnotation -> { ClientModel operationMap = new ClientModel(); ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); + boolean useNamespace = apiClass.hasDeclaredAnnotation(NAMESPACE); List methods = getAllMethodsIncludingFromSuperClasses(apiClass); methods.forEach(method -> { - String query = new QueryBuilder(method).build(); + String query = new QueryBuilder(method).build(useNamespace); LOG.debugf("[%s] – Query created: %s", apiClass.name().toString(), query); operationMap.getOperationMap() .putIfAbsent(OperationModel.of(method).getMethodKey(), query); @@ -85,6 +81,19 @@ private ClientModels generateClientModels() { return clientModels; } + private void validateAnnotations(Collection graphQLApiAnnotations) { + List errorInterfaces = graphQLApiAnnotations.stream() + .map(annotation -> annotation.target().asClass()) + .filter(classInfo -> classInfo.hasDeclaredAnnotation(NAMESPACE) && classInfo.hasDeclaredAnnotation(NAME)) + .map(classInfo -> classInfo.name().toString()) + .collect(Collectors.toList()); + if (!errorInterfaces.isEmpty()) { + throw new RuntimeException("You can only use one of the annotations - @Name or @Namespace " + + "over the GraphQLClientApi interface. Please, fix next interfaces: " + + String.join(", ", errorInterfaces)); + } + } + /** * Retrieves all methods, including those from superclasses (interfaces). * diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java index 0d8e79baa..613946e55 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java @@ -3,8 +3,6 @@ import static io.smallrye.graphql.client.model.helper.OperationModel.of; import static java.util.stream.Collectors.joining; -import java.util.List; - import org.jboss.jandex.MethodInfo; import io.smallrye.graphql.client.model.helper.DirectiveInstance; @@ -33,22 +31,18 @@ public QueryBuilder(MethodInfo method) { * * @return The constructed GraphQL query string. */ - public String build() { + public String build(boolean useNamespace) { StringBuilder request = new StringBuilder(method.getOperationTypeAsString()); request.append(" "); - - request.append(method.getOperationName()); // operation name - + request.append(method.getOperationName(useNamespace)); if (method.hasValueParameters()) { request.append(method.valueParameters().stream().map(method::declare).collect(joining(", ", "(", ")"))); } - List namespaces = method.getNamespaces(); - if (!namespaces.isEmpty()) { - namespaces.forEach(value -> { - request.append(" { "); - request.append(value); - }); + if (useNamespace) { + method.getNamespaces().forEach(namespace -> request.append(" { ").append(namespace)); + } else if (method.getGroupName() != null) { + request.append(" { ").append(method.getGroupName()); } if (method.isSingle()) { @@ -71,8 +65,10 @@ public String build() { request.append(" }"); } - if (!namespaces.isEmpty()) { - request.append(" } ".repeat(namespaces.size())); + if (useNamespace) { + request.append(" }".repeat(method.getNamespaces().size())); + } else if (method.getGroupName() != null) { + request.append(" }"); } return request.toString(); diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java index ad90dde5d..66cf85823 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java @@ -38,7 +38,9 @@ public class OperationModel implements NamedElement { private final Stack expressionStack = new Stack<>(); private Stack rawParametrizedTypes = new Stack<>(); private final List directives; - private final List namespaces; + private final String groupName; + private String operationName; + private List namespaces; /** * Creates a new {@code OperationModel} instance based on the provided Jandex {@link MethodInfo}. @@ -52,7 +54,7 @@ public class OperationModel implements NamedElement { getDirectiveLocation(), AnnotationTarget.Kind.METHOD) .map(DirectiveInstance::of) .collect(toList()); - this.namespaces = readNamespace(method); + this.groupName = readGroupName(method); } /** @@ -393,25 +395,54 @@ private boolean isRawParametrizedType(TypeModel type) { return type.isCustomParametrizedType() && !type.getFirstRawType().isTypeVariable(); } - public List getNamespaces() { - return namespaces; + public String getGroupName() { + return groupName; + } + + private String readGroupName(MethodInfo method) { + List annotationInstances = method.declaringClass().annotations(NAME); + for (AnnotationInstance annotationInstance : annotationInstances) { + if (annotationInstance.target().kind() == AnnotationTarget.Kind.CLASS) { + if (annotationInstance.target().asClass().name().equals(method.declaringClass().name())) { + String groupName = annotationInstance.value().asString().trim(); + if (!groupName.isEmpty()) { + return groupName; + } + } + } + } + return null; } - private List readNamespace(MethodInfo method) { - AnnotationInstance annotationInstance = method.declaringClass().declaredAnnotation(NAMESPACE); - if (annotationInstance != null) { - return Arrays.stream(annotationInstance.value().asString().split("/")) - .map(String::trim) - .collect(Collectors.toList()); + public List getNamespaces() { + if (namespaces == null) { + AnnotationInstance annotationInstance = method.declaringClass().declaredAnnotation(NAMESPACE); + if (annotationInstance != null) { + namespaces = Arrays.stream(annotationInstance.value().asString().split("/")) + .map(String::trim) + .collect(Collectors.toList()); + } else { + namespaces = List.of(); + } } - return List.of(); + return namespaces; } - public String getOperationName() { - return namespaces.stream().map(this::prettyString).collect(joining()) + prettyString(getName()); + public String getOperationName(boolean useNamespace) { + if (operationName == null) { + if (useNamespace) { + operationName = getNamespaces().stream().map(this::makeFirstLetterUppercase).collect(joining()) + + makeFirstLetterUppercase(getName()); + } else { + operationName = getGroupName() == null + ? makeFirstLetterUppercase(getName()) + : makeFirstLetterUppercase(getGroupName()) + makeFirstLetterUppercase(getName()); + } + } + return operationName; } - private String prettyString(String value) { + private String makeFirstLetterUppercase(String value) { return value.substring(0, 1).toUpperCase() + value.substring(1); } } diff --git a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java index 4afec8f1f..8c151f1ac 100644 --- a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java +++ b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java @@ -212,7 +212,7 @@ void inheritedOperationsClientModelTest() throws IOException { "query AllStrings0 { allStrings0 }"); } - @Namespace("named") + @Name("named") @GraphQLClientApi(configKey = "string-api") interface NamedClientApi { @Query("findAll") @@ -236,13 +236,40 @@ void namedClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("findAllStringsQuery", new Class[0]), - "query NamedFindAll { named { findAll } } "); + "query NamedFindAll { named { findAll } }"); assertOperation(clientModel, new MethodKey("findAllStringsName", new Class[0]), - "query NamedFindAll { named { findAll } } "); + "query NamedFindAll { named { findAll } }"); assertOperation(clientModel, new MethodKey("update", new Class[] { String.class }), - "mutation NamedUpdate($s: String) { named { update(s: $s) } } "); + "mutation NamedUpdate($s: String) { named { update(s: $s) } }"); + } + + @Namespace("first/second") + @GraphQLClientApi(configKey = "namespaced-string-api") + interface NamespacedClientApi { + @Query("findAll") + List findAllStringsQuery(); + + @Mutation("update") + @Name("update") + String update(String s); + } + + @Test + void namespacedClientModelTest() throws IOException { + String configKey = "namespaced-string-api"; + ClientModels clientModels = ClientModelBuilder + .build(Index.of(NamespacedClientApi.class)); + assertNotNull(clientModels.getClientModelByConfigKey(configKey)); + ClientModel clientModel = clientModels.getClientModelByConfigKey(configKey); + assertEquals(2, clientModel.getOperationMap().size()); + assertOperation(clientModel, + new MethodKey("findAllStringsQuery", new Class[0]), + "query FirstSecondFindAll { first { second { findAll } } }"); + assertOperation(clientModel, + new MethodKey("update", new Class[] { String.class }), + "mutation FirstSecondUpdate($s: String) { first { second { update(s: $s) } } }"); } private void assertOperation(ClientModel clientModel, MethodKey methodKey, String expectedQuery) { diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java index 833eb9bb5..be7792404 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java @@ -2,13 +2,16 @@ import static io.smallrye.graphql.schema.Annotations.CUSTOM_SCALAR; import static io.smallrye.graphql.schema.Annotations.DIRECTIVE; +import static io.smallrye.graphql.schema.Annotations.GRAPHQL_API; import static io.smallrye.graphql.schema.Annotations.NAME; +import static io.smallrye.graphql.schema.Annotations.NAMESPACE; import static io.smallrye.graphql.schema.Annotations.ONE_OF; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Queue; import java.util.Set; @@ -42,11 +45,14 @@ import io.smallrye.graphql.schema.helper.DescriptionHelper; import io.smallrye.graphql.schema.helper.Directives; import io.smallrye.graphql.schema.helper.GroupHelper; +import io.smallrye.graphql.schema.helper.NamespaceHelper; import io.smallrye.graphql.schema.helper.RolesAllowedDirectivesHelper; import io.smallrye.graphql.schema.helper.TypeAutoNameStrategy; import io.smallrye.graphql.schema.model.DirectiveType; import io.smallrye.graphql.schema.model.ErrorInfo; import io.smallrye.graphql.schema.model.Group; +import io.smallrye.graphql.schema.model.Namespace; +import io.smallrye.graphql.schema.model.NamespaceContainer; import io.smallrye.graphql.schema.model.Operation; import io.smallrye.graphql.schema.model.OperationType; import io.smallrye.graphql.schema.model.Reference; @@ -120,10 +126,9 @@ private SchemaBuilder(TypeAutoNameStrategy autoNameStrategy) { } private Schema generateSchema() { - // Get all the @GraphQLAPI annotations Collection graphQLApiAnnotations = ScanningContext.getIndex() - .getAnnotations(Annotations.GRAPHQL_API); + .getAnnotations(GRAPHQL_API); final Schema schema = new Schema(); @@ -144,30 +149,22 @@ private Schema generateSchema() { addCustomScalarTypes(schema); - List errors = graphQLApiAnnotations.stream() - .map(graphQLApiAnnotation -> graphQLApiAnnotation.target().asClass()) - .filter(apiClass -> apiClass.hasDeclaredAnnotation(NAME)) - .map(apiClass -> "Use @Namespace instead of @Name on class " + apiClass.name()) - .collect(Collectors.toList()); - if (!errors.isEmpty()) { - throw new RuntimeException(String.join("\n", errors)); - } + validateAnnotations(graphQLApiAnnotations); + validateSubscriptions(graphQLApiAnnotations); for (AnnotationInstance graphQLApiAnnotation : graphQLApiAnnotations) { ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); List methods = getAllMethodsIncludingFromSuperClasses(apiClass); - Optional namespace = GroupHelper.getGroup(graphQLApiAnnotation); - addNamespacedOperations(namespace, schema, methods); + if (apiClass.hasDeclaredAnnotation(NAMESPACE)) { + Optional namespace = NamespaceHelper.getNamespace(graphQLApiAnnotation); + addNamespacedOperations(namespace, schema, methods); + } else { + Optional group = GroupHelper.getGroup(graphQLApiAnnotation); + addOperations(group, schema, methods); + } } - errors = schema.getQueries().stream() - .filter(operation -> schema.getNamespaceQueries().containsKey(operation.getName())) - .map(operation -> "Inconsistent schema state is query and there is a namespace with the same name. " + - "Class " + operation.getClassName() + ", method name = " + operation.getMethodName()) - .collect(Collectors.toList()); - if (!errors.isEmpty()) { - throw new RuntimeException(String.join("\n", errors)); - } + validateMethods(schema); // The above queries and mutations reference some models (input / type / interfaces / enum), let's create those addTypesToSchema(schema); @@ -187,6 +184,76 @@ private Schema generateSchema() { return schema; } + private List findNamespacedMethodsErrors(Map namespaces, Set operations) { + return operations.stream() + .filter(operation -> namespaces.containsKey(operation.getName())) + .map(operation -> "operation name: " + operation.getName() + ", class: " + operation.getClassName() + + ", method name: " + operation.getMethodName()) + .collect(Collectors.toList()); + } + + private List findGroupedMethodsErrors(Map> groups, Set operations) { + Set keys = groups.keySet().stream().map(Group::getName).collect(Collectors.toSet()); + + return operations.stream() + .filter(operation -> keys.contains(operation.getName())) + .map(operation -> "operation name: " + operation.getName() + ", class: " + operation.getClassName() + + ", method name: " + operation.getMethodName()) + .collect(Collectors.toList()); + } + + private void validateMethods(Schema schema) { + List queryErrors = new ArrayList<>(findNamespacedMethodsErrors(schema.getNamespacedQueries(), + schema.getQueries())); + queryErrors.addAll(findGroupedMethodsErrors(schema.getGroupedQueries(), schema.getQueries())); + + List mutationErrors = new ArrayList<>(findNamespacedMethodsErrors(schema.getNamespacedMutations(), + schema.getMutations())); + mutationErrors.addAll(findGroupedMethodsErrors(schema.getGroupedMutations(), schema.getMutations())); + + if (!queryErrors.isEmpty() || !mutationErrors.isEmpty()) { + throw new RuntimeException("Inconsistent schema. Operation names overlap with namespaces." + + queryErrors.stream().collect(Collectors.joining(", ", " queries - ", ";")) + + mutationErrors.stream().collect(Collectors.joining(", ", " mutations - ", ";"))); + } + } + + private void validateSubscriptions(Collection graphQLApiAnnotations) { + List errors = new ArrayList<>(); + + for (AnnotationInstance annotation : graphQLApiAnnotations) { + ClassInfo apiClass = annotation.target().asClass(); + if (apiClass.hasDeclaredAnnotation(NAMESPACE) || apiClass.hasDeclaredAnnotation(NAME)) { + List methods = getAllMethodsIncludingFromSuperClasses(apiClass); + for (MethodInfo methodInfo : methods) { + Annotations annotationsForMethod = Annotations.getAnnotationsForMethod(methodInfo); + if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) { + errors.add("class: " + apiClass.name().toString() + ", method: " + methodInfo.name()); + } + } + } + } + + if (!errors.isEmpty()) { + throw new RuntimeException("Subscriptions can't be nested. " + + "Move your subscriptions to another @GraphQLApi class, not marked @Namespace or @Name. " + + "Check next places: " + String.join("; ", errors)); + } + } + + private void validateAnnotations(Collection graphQLApiAnnotations) { + List errorClasses = graphQLApiAnnotations.stream() + .map(annotation -> annotation.target().asClass()) + .filter(classInfo -> classInfo.hasDeclaredAnnotation(NAMESPACE) && classInfo.hasDeclaredAnnotation(NAME)) + .map(classInfo -> classInfo.name().toString()) + .collect(Collectors.toList()); + if (!errorClasses.isEmpty()) { + throw new RuntimeException("You can only use one of the annotations - @Name or @Namespace " + + "over the GraphQLClientApi interface. Please, fix next classes: " + + String.join(", ", errorClasses)); + } + } + private List getAllMethodsIncludingFromSuperClasses(ClassInfo classInfo) { ClassInfo current = classInfo; IndexView index = ScanningContext.getIndex(); @@ -374,40 +441,65 @@ private boolean findOutstandingAndAddToSchema(ReferenceType referenceType, C return keepGoing; } - private void addNamespacedOperations(Optional namespace, Schema schema, + private void addNamespacedOperations(Optional namespace, Schema schema, List methodInfoList) { - List errors = new ArrayList<>(); - for (MethodInfo methodInfo : methodInfoList) { Annotations annotationsForMethod = Annotations.getAnnotationsForMethod(methodInfo); if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.QUERY)) { Operation query = operationCreator.createOperation(methodInfo, OperationType.QUERY, null); if (namespace.isPresent()) { - schema.addNamespaceQuery(namespace.get(), query); + schema.addNamespacedQuery(namespace.get(), query); } else { schema.addQuery(query); } } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.MUTATION)) { Operation mutation = operationCreator.createOperation(methodInfo, OperationType.MUTATION, null); if (namespace.isPresent()) { - schema.addNamespaceMutation(namespace.get(), mutation); + schema.addNamespacedMutation(namespace.get(), mutation); } else { schema.addMutation(mutation); } } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) { - if (namespace.isPresent()) { - errors.add("Subscriptions are not working in namespace. Move your subscription " + methodInfo.name() - + " from " + methodInfo.declaringClass().name() + " class " - + "to another @GraphQLApi class, not marked @Namespace"); - break; + if (namespace.isEmpty()) { + Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null); + schema.addSubscription(subscription); } - Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null); - schema.addSubscription(subscription); } } + } - if (!errors.isEmpty()) { - throw new RuntimeException(String.join("\n", errors)); + /** + * This inspect all method, looking for Query and Mutation annotations, + * to create those Operations. + * + * @param schema the schema to add the operation to. + * @param methodInfoList the java methods. + */ + private void addOperations(Optional group, Schema schema, List methodInfoList) { + for (MethodInfo methodInfo : methodInfoList) { + Annotations annotationsForMethod = Annotations.getAnnotationsForMethod(methodInfo); + if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.QUERY)) { + Operation query = operationCreator.createOperation(methodInfo, OperationType.QUERY, null); + if (group.isPresent()) { + schema.addGroupedQuery(group.get(), query); + } else { + schema.addQuery(query); + } + } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.MUTATION)) { + Operation mutation = operationCreator.createOperation(methodInfo, OperationType.MUTATION, null); + if (group.isPresent()) { + schema.addGroupedMutation(group.get(), mutation); + } else { + schema.addMutation(mutation); + } + } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) { + Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null); + if (group.isPresent()) { + schema.addGroupedSubscription(group.get(), subscription); + } else { + schema.addSubscription(subscription); + } + } } } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java index 9a1180423..6235cdab3 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java @@ -21,11 +21,11 @@ private GroupHelper() { } public static Optional getGroup(AnnotationInstance graphQLApiAnnotation) { - Optional> names = getNames(graphQLApiAnnotation); - if (names.isPresent()) { + Optional name = getName(graphQLApiAnnotation); + if (name.isPresent()) { Optional description = getDescription(graphQLApiAnnotation); Group group = new Group(); - group.setNames(names.get()); + group.setName(name.get()); group.setDescription(description.orElse(null)); return Optional.of(group); } @@ -39,12 +39,19 @@ public static Optional getGroup(AnnotationInstance graphQLApiAnnotation) * @param graphQLApiAnnotation * @return */ - private static Optional> getNames(AnnotationInstance graphQLApiAnnotation) { - ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); - AnnotationInstance nameAnnotation = apiClass.annotation(Annotations.NAMESPACE); - if (nameAnnotation != null && nameAnnotation.value() != null && nameAnnotation.value().asString() != null - && !nameAnnotation.value().asString().isEmpty()) { - return Optional.of(List.of(nameAnnotation.value().asString().split("/"))); + private static Optional getName(AnnotationInstance graphQLApiAnnotation) { + // Get the name + AnnotationValue value = graphQLApiAnnotation.value(); + if (value != null && value.asString() != null && !value.asString().isEmpty()) { + return Optional.of(value.asString()); + } else { + // Try the Name annotation + ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); + AnnotationInstance nameAnnotation = apiClass.classAnnotation(Annotations.NAME); + if (nameAnnotation != null && nameAnnotation.value() != null && nameAnnotation.value().asString() != null + && !nameAnnotation.value().asString().isEmpty()) { + return Optional.of(nameAnnotation.value().asString()); + } } return Optional.empty(); } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java new file mode 100644 index 000000000..8929cb5da --- /dev/null +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java @@ -0,0 +1,63 @@ +package io.smallrye.graphql.schema.helper; + +import java.util.List; +import java.util.Optional; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationValue; +import org.jboss.jandex.ClassInfo; + +import io.smallrye.graphql.schema.Annotations; +import io.smallrye.graphql.schema.model.Namespace; + +public class NamespaceHelper { + private NamespaceHelper() { + } + + public static Optional getNamespace(AnnotationInstance graphQLApiAnnotation) { + Optional> names = getNames(graphQLApiAnnotation); + if (names.isPresent()) { + Optional description = getDescription(graphQLApiAnnotation); + Namespace group = new Namespace(); + group.setNames(names.get()); + group.setDescription(description.orElse(null)); + return Optional.of(group); + } + return Optional.empty(); + } + + /** + * This gets the namespaces. + * This will allow grouping root queries under a logical name. + * + * @param graphQLApiAnnotation annotation on the class + * @return list of namespaces + */ + private static Optional> getNames(AnnotationInstance graphQLApiAnnotation) { + ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); + if (apiClass.hasDeclaredAnnotation(Annotations.NAMESPACE)) { + AnnotationValue value = apiClass.declaredAnnotation(Annotations.NAMESPACE).value(); + if (!value.asString().isEmpty()) { + return Optional.of(List.of(value.asString().split("/"))); + } + } + return Optional.empty(); + } + + /** + * Get the description on a class type + * + * @param graphQLApiAnnotation annotation on the class + * @return the optional description + */ + private static Optional getDescription(AnnotationInstance graphQLApiAnnotation) { + ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); + if (apiClass.hasDeclaredAnnotation(Annotations.DESCRIPTION)) { + AnnotationValue value = apiClass.declaredAnnotation(Annotations.DESCRIPTION).value(); + if (value != null && value.asString() != null && !value.asString().isEmpty()) { + return Optional.of(value.asString()); + } + } + return Optional.empty(); + } +} diff --git a/common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java b/common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java new file mode 100644 index 000000000..7f53b8950 --- /dev/null +++ b/common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java @@ -0,0 +1,45 @@ +package io.smallrye.graphql.index; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.jboss.jandex.Index; +import org.junit.jupiter.api.Test; + +import io.smallrye.graphql.index.app.namespace.ApiWithName; +import io.smallrye.graphql.index.app.namespace.ApiWithNameAndNamespace; +import io.smallrye.graphql.index.app.namespace.ApiWithNamespace; +import io.smallrye.graphql.schema.IndexCreator; +import io.smallrye.graphql.schema.SchemaBuilder; +import io.smallrye.graphql.schema.model.Schema; + +/** + * Test namespaces + */ +public class NamespaceTest { + @Test + public void apiWithNameTest() { + Index index = IndexCreator.indexWithPackage(ApiWithName.class); + Schema schema = SchemaBuilder.build(index); + + assertNotNull(schema); + assertEquals(schema.getGroupedQueries().values().size(), 1); + } + + @Test + public void apiWithNameTestWithEnabledUseNamespaces() { + Index index = IndexCreator.indexWithPackage(ApiWithNameAndNamespace.class); + + assertThrows(RuntimeException.class, () -> SchemaBuilder.build(index)); + } + + @Test + public void apiWithNamespaceTest() { + Index index = IndexCreator.indexWithPackage(ApiWithNamespace.class); + Schema schema = SchemaBuilder.build(index); + + assertNotNull(schema); + assertEquals(schema.getAllNamespacedQueryOperations().size(), 1); + } +} diff --git a/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java index a29f5f9e6..63744d96d 100644 --- a/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java +++ b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/BookGraphQLApi.java @@ -8,17 +8,16 @@ import java.util.Map; import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; -import io.smallrye.graphql.api.Namespace; - /** * Book API * * @author Phillip Kruger (phillip.kruger@redhat.com) */ @GraphQLApi -@Namespace("books") +@Name("Books") public class BookGraphQLApi { @Query diff --git a/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithName.java b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithName.java new file mode 100644 index 000000000..c137ecd50 --- /dev/null +++ b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithName.java @@ -0,0 +1,14 @@ +package io.smallrye.graphql.index.app.namespace; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Name; +import org.eclipse.microprofile.graphql.Query; + +@GraphQLApi +@Name("name") +public class ApiWithName { + @Query + public String query() { + return "query"; + } +} diff --git a/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNameAndNamespace.java b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNameAndNamespace.java new file mode 100644 index 000000000..7cfa4be90 --- /dev/null +++ b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNameAndNamespace.java @@ -0,0 +1,17 @@ +package io.smallrye.graphql.index.app.namespace; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Name; +import org.eclipse.microprofile.graphql.Query; + +import io.smallrye.graphql.api.Namespace; + +@GraphQLApi +@Name("name") +@Namespace("namespace") +public class ApiWithNameAndNamespace { + @Query + public String query() { + return "query"; + } +} diff --git a/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNamespace.java b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNamespace.java new file mode 100644 index 000000000..e5df861db --- /dev/null +++ b/common/schema-builder/src/test/java/io/smallrye/graphql/index/app/namespace/ApiWithNamespace.java @@ -0,0 +1,15 @@ +package io.smallrye.graphql.index.app.namespace; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Query; + +import io.smallrye.graphql.api.Namespace; + +@GraphQLApi +@Namespace("namespace") +public class ApiWithNamespace { + @Query + public String query() { + return "query"; + } +} diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java index 0827072e7..992c8855a 100644 --- a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java @@ -1,7 +1,6 @@ package io.smallrye.graphql.schema.model; import java.io.Serializable; -import java.util.List; import java.util.Objects; /** @@ -10,18 +9,23 @@ * @author Phillip Kruger (phillip.kruger@redhat.com) */ public class Group implements Serializable { - private List names; + private String name; private String description; public Group() { } - public List getNames() { - return names; + public Group(String name, String description) { + this.name = name; + this.description = description; + } + + public String getName() { + return name; } - public void setNames(List names) { - this.names = names; + public void setName(String name) { + this.name = name; } public String getDescription() { @@ -35,7 +39,7 @@ public void setDescription(String description) { @Override public int hashCode() { int hash = 7; - hash = 59 * hash + Objects.hashCode(this.names); + hash = 59 * hash + Objects.hashCode(this.name); return hash; } @@ -51,7 +55,7 @@ public boolean equals(Object obj) { return false; } final Group other = (Group) obj; - if (!Objects.equals(this.names, other.names)) { + if (!Objects.equals(this.name, other.name)) { return false; } return true; @@ -59,7 +63,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return "Group{" + "names=" + names + ", description=" + description + '}'; + return "Group{" + "name=" + name + ", description=" + description + '}'; } } diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Namespace.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Namespace.java new file mode 100644 index 000000000..2176c604f --- /dev/null +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Namespace.java @@ -0,0 +1,48 @@ +package io.smallrye.graphql.schema.model; + +import java.util.List; +import java.util.Objects; + +public class Namespace { + private List names; + private String description; + + public Namespace() { + } + + public List getNames() { + return names; + } + + public void setNames(List names) { + this.names = names; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Namespace namespace = (Namespace) o; + return Objects.equals(names, namespace.names) && Objects.equals(description, namespace.description); + } + + @Override + public int hashCode() { + return Objects.hash(names, description); + } + + @Override + public String toString() { + return "Namespace{" + "names=" + names + ", description=" + description + '}'; + } +} diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/NamespaceContainer.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/NamespaceContainer.java new file mode 100644 index 000000000..2552a0a6e --- /dev/null +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/NamespaceContainer.java @@ -0,0 +1,89 @@ +package io.smallrye.graphql.schema.model; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class NamespaceContainer { + private String name; + private String description; + private Set operations = new HashSet<>(); + private Map container = new HashMap<>(); + + public NamespaceContainer() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Set getOperations() { + return operations; + } + + public void setOperations(Set operations) { + this.operations = operations; + } + + public Map getContainer() { + return container; + } + + public void setContainer(Map container) { + this.container = container; + } + + public boolean hasOperations() { + return !operations.isEmpty() || container.values().stream().anyMatch(this::hasOperations); + } + + private boolean hasOperations(NamespaceContainer namespace) { + return !namespace.getOperations().isEmpty() + || namespace.container.values().stream().anyMatch(this::hasOperations); + } + + public void add(Collection names, String description, Operation operation) { + if (names.isEmpty()) { + throw new RuntimeException("Namespaces can't be empty"); + } + ArrayDeque queue = new ArrayDeque<>(names); + String name = queue.poll(); + add(name, description, queue, operation); + } + + private void add(String name, String description, ArrayDeque queue, Operation operation) { + this.name = name; + + if (queue.isEmpty()) { + this.description = description; + this.operations.add(operation); + } else { + String key = queue.poll(); + NamespaceContainer groupContainer = container.computeIfAbsent(key, s -> new NamespaceContainer()); + groupContainer.add(key, description, queue, operation); + } + } + + public List getAllOperations() { + List operations = new ArrayList<>(this.operations); + container.values().forEach(groupContainer -> operations.addAll(groupContainer.getAllOperations())); + return operations; + } +} diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java index cf1a2b95e..21ec48fd1 100644 --- a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java @@ -24,8 +24,12 @@ public final class Schema implements Serializable { private Set mutations = new HashSet<>(); private Set subscriptions = new HashSet<>(); - private Map namespaceQueries = new HashMap<>(); - private Map namespaceMutations = new HashMap<>(); + private Map> groupedQueries = new HashMap<>(); + private Map> groupedMutations = new HashMap<>(); + private Map> groupedSubscriptions = new HashMap<>(); + + private Map namespacedQueries = new HashMap<>(); + private Map namespacedMutations = new HashMap<>(); private List customScalarTypes = new ArrayList<>(); private List directiveTypes = new ArrayList<>(); @@ -44,6 +48,36 @@ public final class Schema implements Serializable { public Schema() { } + public Map getNamespacedQueries() { + return namespacedQueries; + } + + public void setNamespacedQueries(Map namespacedQueries) { + this.namespacedQueries = namespacedQueries; + } + + public Map getNamespacedMutations() { + return namespacedMutations; + } + + public Set getAllNamespacedQueryOperations() { + return namespacedQueries.values().stream() + .map(NamespaceContainer::getAllOperations) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + public Set getAllNamespacedMutationOperations() { + return namespacedMutations.values().stream() + .map(NamespaceContainer::getAllOperations) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + public void setNamespacedMutations(Map namespacedMutations) { + this.namespacedMutations = namespacedMutations; + } + public Set getQueries() { return queries; } @@ -57,7 +91,8 @@ public void addQuery(Operation query) { } public boolean hasOperations() { - return hasQueries() || hasNamespaceQueries() || hasMutations() || hasNamespaceMutations(); + return hasQueries() || hasGroupedQueries() || hasNamespaceQueries() + || hasMutations() || hasGroupedMutations() || hasNamespaceMutations(); } public boolean hasQueries() { @@ -97,57 +132,51 @@ public boolean hasSubscriptions() { } public Map> getGroupedQueries() { - Set operations = namespaceQueries.values().stream() - .map(GroupContainer::getAllOperations) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); - return Map.of(new Group(), operations); + return groupedQueries; } - public Map> getGroupedMutations() { - Set operations = namespaceMutations.values().stream() - .map(GroupContainer::getAllOperations) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); - return Map.of(new Group(), operations); + public void setGroupedQueries(Map> groupedQueries) { + this.groupedQueries = groupedQueries; } - public Map getNamespaceQueries() { - return namespaceQueries; + public void addGroupedQuery(Group group, Operation query) { + addToOperationMap(this.groupedQueries, group, query); } - public void setNamespaceQueries(Map namespaceQueries) { - this.namespaceQueries = namespaceQueries; + public boolean hasGroupedQueries() { + return !this.groupedQueries.isEmpty(); } - public boolean hasNamespaceQueries() { - return namespaceQueries.values().stream().anyMatch(GroupContainer::hasOperations); + public Map> getGroupedMutations() { + return groupedMutations; } - public void addNamespaceQuery(Group group, Operation operation) { - GroupContainer groupContainer = namespaceQueries.computeIfAbsent( - group.getNames().get(0), - key -> new GroupContainer()); - groupContainer.add(group.getNames(), group.getDescription(), operation); + public void setGroupedMutations(Map> groupedMutations) { + this.groupedMutations = groupedMutations; } - public Map getNamespaceMutations() { - return namespaceMutations; + public void addGroupedMutation(Group group, Operation mutation) { + addToOperationMap(this.groupedMutations, group, mutation); } - public void setNamespaceMutations(Map namespaceMutations) { - this.namespaceMutations = namespaceMutations; + public boolean hasGroupedMutations() { + return !this.groupedMutations.isEmpty(); } - public boolean hasNamespaceMutations() { - return namespaceMutations.values().stream().anyMatch(GroupContainer::hasOperations); + public Map> getGroupedSubscriptions() { + return groupedSubscriptions; } - public void addNamespaceMutation(Group group, Operation operation) { - GroupContainer groupContainer = namespaceMutations.computeIfAbsent( - group.getNames().get(0), - key -> new GroupContainer()); - groupContainer.add(group.getNames(), group.getDescription(), operation); + public void setGroupedSubscriptions(Map> groupedSubscriptions) { + this.groupedSubscriptions = groupedSubscriptions; + } + + public void addGroupedSubscription(Group group, Operation subscription) { + addToOperationMap(this.groupedSubscriptions, group, subscription); + } + + public boolean hasGroupedSubscriptions() { + return !this.groupedSubscriptions.isEmpty(); } public Map getInputs() { @@ -316,6 +345,18 @@ public List getBatchOperations() { return batchOperations; } + private void addToOperationMap(Map> map, Group group, Operation query) { + Set set; + + if (map.containsKey(group)) { + set = map.get(group); + } else { + set = new HashSet<>(); + } + set.add(query); + map.put(group, set); + } + public void addCustomScalarType(CustomScalarType customScalarType) { customScalarTypes.add(customScalarType); Scalars.registerCustomScalarInSchema( @@ -354,8 +395,9 @@ public String toString() { ", queries=" + queries + ", mutations=" + mutations + ", subscriptions=" + subscriptions + - ", namespaceQueries=" + namespaceQueries + - ", namespaceMutations=" + namespaceMutations + + ", groupedQueries=" + groupedQueries + + ", groupedMutations=" + groupedMutations + + ", groupedSubscriptions=" + groupedSubscriptions + ", directiveTypes=" + directiveTypes + ", customScalarTypes=" + customScalarTypes + ", inputs=" + inputs + @@ -383,4 +425,26 @@ public String getDescription() { public void setDescription(String description) { this.description = description; } + + public void addNamespacedQuery(Namespace namespace, Operation operation) { + NamespaceContainer groupContainer = namespacedQueries.computeIfAbsent( + namespace.getNames().get(0), + key -> new NamespaceContainer()); + groupContainer.add(namespace.getNames(), namespace.getDescription(), operation); + } + + public void addNamespacedMutation(Namespace namespace, Operation operation) { + NamespaceContainer groupContainer = namespacedMutations.computeIfAbsent( + namespace.getNames().get(0), + key -> new NamespaceContainer()); + groupContainer.add(namespace.getNames(), namespace.getDescription(), operation); + } + + public boolean hasNamespaceQueries() { + return namespacedQueries.values().stream().anyMatch(NamespaceContainer::hasOperations); + } + + public boolean hasNamespaceMutations() { + return namespacedMutations.values().stream().anyMatch(NamespaceContainer::hasOperations); + } } diff --git a/docs/namespaces-on-server-side.md b/docs/namespaces-on-server-side.md index 0fbf49dd2..2ba91eb4c 100644 --- a/docs/namespaces-on-server-side.md +++ b/docs/namespaces-on-server-side.md @@ -6,7 +6,11 @@ > However, read the documentation carefully, especially the limitations and possible problems. ## How use namespaces -There are 3 options how to use the name space - use the @Name annotation, @Source, or combine them. +There are 4 options how to use the name space - use the @Name annotation, @Source, or combine them. + +And modern @Namespace (new feature, read below). + +> [NOTE] You can only use one of the annotations - @Name or @Namespace over the GraphQLApi classes. ### Using @Name annotation The easiest way is that you can separate your API into namespace areas using the annotation @Name with @GraphQLApi. @@ -150,6 +154,71 @@ public class UserApi { } } ``` + +### Using @Namespace annotation + +The annotation accepts a string that contains namespaces separated by '/' + +```java +@GraphQLApi +@Namespace("admin/users") +public class ResourceApi { + @Query + public List findAll() { + // + } +} +``` + +Will be generated schema +``` +"Query root" +type Query { + admin: AdminQuery +} + +type AdminQuery { + users: AdminUsersQuery +} + +type AdminUsersQuery { + findAll: Info +} + +type User { + id: BigInteger + ... +} +``` + +And you will can send such request +``` +query { + admin { + users { + findAll { + id + } + } + } +} +``` + +You can use any nesting and also combine different levels +```java +@GraphQLApi +@Namespace("admin/users") +public class ResourceApi { + // +} + +@GraphQLApi +@Namespace("admin") +public class ResourceApi { + // +} +``` + ## Problems While dividing APIs into namespaces may seem convenient, it has several issues that are important to be aware of. diff --git a/docs/typesafe-client-usage.md b/docs/typesafe-client-usage.md index 1d9b38b71..199f6b1fd 100644 --- a/docs/typesafe-client-usage.md +++ b/docs/typesafe-client-usage.md @@ -1,9 +1,10 @@ +# Java code-first type-safe GraphQL Client API + A Java code-first type-safe GraphQL Client API suggestion for [Microprofile GraphQL Issue \#185](https://github.com/eclipse/microprofile-graphql/issues/185). -Basic Usage -=========== +## Basic Usage Creating the client-side counterpart of the GraphQL API: @@ -46,8 +47,7 @@ Contracts](https://martinfowler.com/articles/consumerDrivenContracts.html). If the server uses names different from yours, you can simply use annotations to do a mapping: -Name Mapping / Aliases -====================== +### Name Mapping / Aliases If the server defines a different field or parameter name, annotate it with `@Name`. If the server defines a different query name, annotate the @@ -75,8 +75,7 @@ If you rename a field or method, the real field or method name will be used as an alias, so you can select the same data twice (see `` and `` below). -Configuration -============= +### Configuration If the endpoint is always the same, e.g. a public API of a cloud service, you can add the URL to your API annotation, e.g.: @@ -116,8 +115,7 @@ key for the endpoint `superheroes/mp-graphql/url`. When using the builder, you can override the config key as well: `TypesafeGraphQLClientBuilder.newBuilder().configKey("superheroes")`. -NestedParameter -=============== +### NestedParameter Some APIs require parameters beyond the root level, e.g. for filtering or paginating nested lists. Say you have a schema like this: @@ -200,8 +198,63 @@ public interface ApiClient { } ``` -Namespaces -========== +## Namespaces + +There are several ways to work with namespaces in a type-safe client +1. Using @Name, or wrapping +2. Using @Namespace (new feature) + +> [NOTE] You can only use one of the annotations - @Name or @Namespace over the GraphQLApi classes. + +### Using @Namespace annotation + +The annotation accepts a string that contains namespaces separated by '/' + +If remove graphql api has next schema +``` +"Query root" +type Query { + admin: AdminQuery +} + +type AdminQuery { + users: AdminUsersQuery +} + +type AdminUsersQuery { + findAll: User +} + +type User { + id: BigInteger + ... +} +``` + +You can create next interface +```java +@Namespace("admin/users") +@GraphQLClientApi +public interface UsersClient { + List findAll(); +} +``` + +Here will be generated next query +``` +query AminUsersFindAll { + admin { + users { + findAll { + id + } + } + } +} +``` + +### Using @Name or type wrapping + > [NOTE] > We strongly unrecommended the use namespaces with a type-safe client. > It is possible to use the @Name annotation, with minimal changes to the code. diff --git a/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java b/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java index 30805c38e..5f045299a 100644 --- a/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java +++ b/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java @@ -11,7 +11,10 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) @Documented -@Experimental("Experimental namespaces on api class. Separate namespaces via '/' (example - admin/users)") +@Experimental("Grouping APIs by nested namespaces") public @interface Namespace { - String value() default ""; + /** + * @return Namespaces separated by '/' (example - admin/users) + */ + String value(); } diff --git a/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java b/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java index a40c16106..65491090e 100644 --- a/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java +++ b/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java @@ -126,7 +126,6 @@ private IndexView createCustomIndex() { indexer.index(convertClassToInputStream(ScopeItem.class)); indexer.index(convertClassToInputStream(Shareable.class)); indexer.index(convertClassToInputStream(Tag.class)); - indexer.index(convertClassToInputStream(OneOf.class)); indexer.index(convertClassToInputStream(Namespace.class)); } catch (IOException ex) { throw new RuntimeException(ex); diff --git a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java index 1f32b4f5f..575148fd5 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java @@ -81,8 +81,9 @@ import io.smallrye.graphql.schema.model.EnumType; import io.smallrye.graphql.schema.model.EnumValue; import io.smallrye.graphql.schema.model.Field; -import io.smallrye.graphql.schema.model.GroupContainer; +import io.smallrye.graphql.schema.model.Group; import io.smallrye.graphql.schema.model.InputType; +import io.smallrye.graphql.schema.model.NamespaceContainer; import io.smallrye.graphql.schema.model.Operation; import io.smallrye.graphql.schema.model.Reference; import io.smallrye.graphql.schema.model.ReferenceType; @@ -159,7 +160,9 @@ private void verifyInjectionIsAvailable() { schema.getQueries().stream().map(Operation::getClassName), schema.getMutations().stream().map(Operation::getClassName), schema.getGroupedQueries().values().stream().flatMap(Collection::stream).map(Operation::getClassName), - schema.getGroupedMutations().values().stream().flatMap(Collection::stream).map(Operation::getClassName)) + schema.getGroupedMutations().values().stream().flatMap(Collection::stream).map(Operation::getClassName), + schema.getAllNamespacedQueryOperations().stream().map(Operation::getClassName), + schema.getAllNamespacedMutationOperations().stream().map(Operation::getClassName)) .flatMap(stream -> stream) .distinct().forEach(beanClassName -> { // verify that the bean is injectable @@ -334,8 +337,11 @@ private void addQueries(GraphQLSchema.Builder schemaBuilder) { if (schema.hasQueries()) { addRootObject(queryBuilder, schema.getQueries(), QUERY); } + if (schema.hasGroupedQueries()) { + addGroupedRootObject(queryBuilder, schema.getGroupedQueries(), QUERY); + } if (schema.hasNamespaceQueries()) { - addNamespacedRootObject(queryBuilder, schema.getNamespaceQueries(), QUERY); + addNamespacedRootObject(queryBuilder, schema.getNamespacedQueries(), QUERY); } GraphQLObjectType query = queryBuilder.build(); @@ -350,8 +356,11 @@ private void addMutations(GraphQLSchema.Builder schemaBuilder) { if (schema.hasMutations()) { addRootObject(mutationBuilder, schema.getMutations(), MUTATION); } + if (schema.hasGroupedMutations()) { + addGroupedRootObject(mutationBuilder, schema.getGroupedMutations(), MUTATION); + } if (schema.hasNamespaceMutations()) { - addNamespacedRootObject(mutationBuilder, schema.getNamespaceMutations(), MUTATION); + addNamespacedRootObject(mutationBuilder, schema.getNamespacedMutations(), MUTATION); } GraphQLObjectType mutation = mutationBuilder.build(); @@ -368,6 +377,9 @@ private void addSubscriptions(GraphQLSchema.Builder schemaBuilder) { if (schema.hasSubscriptions()) { addRootObject(subscriptionBuilder, schema.getSubscriptions(), SUBSCRIPTION); } + if (schema.hasGroupedSubscriptions()) { + addGroupedRootObject(subscriptionBuilder, schema.getGroupedSubscriptions(), SUBSCRIPTION); + } GraphQLObjectType subscription = subscriptionBuilder.build(); if (subscription.getFieldDefinitions() != null && !subscription.getFieldDefinitions().isEmpty()) { @@ -386,50 +398,51 @@ private void addRootObject(GraphQLObjectType.Builder rootBuilder, Set } } - private String prettyString(String value) { + private String makeFirstLetterUppercase(String value) { return value.substring(0, 1).toUpperCase() + value.substring(1); } - private void addNamespacedRootObject(GraphQLObjectType.Builder mutationBuilder, - Map namespaceMutations, String mutation) { + private void addNamespacedRootObject(GraphQLObjectType.Builder rootBuilder, + Map namespaceMutations, String mutation) { namespaceMutations.values() - .forEach(groupContainer -> addNamespacedRootObject(mutationBuilder, groupContainer, "", mutation)); + .forEach(groupContainer -> addNamespacedRootObject(rootBuilder, groupContainer, "", mutation)); } private List addNamespacedRootObject(GraphQLObjectType.Builder rootBuilder, - GroupContainer groupContainer, String rootName, String suffix) { + NamespaceContainer groupContainer, String rootName, String suffix) { List graphQLFieldDefinitions = groupContainer.getContainer().isEmpty() ? List.of() : getGraphQLFieldDefinition(groupContainer, rootName, suffix); - if (!groupContainer.getOperations().isEmpty() || !graphQLFieldDefinitions.isEmpty()) { - GraphQLObjectType namedType = createNamespaceType(rootName, suffix, groupContainer, - groupContainer.getOperations(), graphQLFieldDefinitions); + if (groupContainer.getOperations().isEmpty() && graphQLFieldDefinitions.isEmpty()) { + return List.of(); + } - GraphQLFieldDefinition.Builder graphQLFieldDefinitionBuilder = GraphQLFieldDefinition - .newFieldDefinition() - .name(groupContainer.getName()) - .description(groupContainer.getDescription()); + GraphQLObjectType namedType = createNamespaceType(rootName, suffix, groupContainer, + groupContainer.getOperations(), graphQLFieldDefinitions); - graphQLFieldDefinitionBuilder.type(namedType); + GraphQLFieldDefinition.Builder graphQLFieldDefinitionBuilder = GraphQLFieldDefinition + .newFieldDefinition() + .name(groupContainer.getName()) + .description(groupContainer.getDescription()); - DataFetcher dummyDataFetcher = dfe -> namedType.getName(); + graphQLFieldDefinitionBuilder.type(namedType); - GraphQLFieldDefinition namedField = graphQLFieldDefinitionBuilder.build(); + DataFetcher dummyDataFetcher = dfe -> namedType.getName(); - this.codeRegistryBuilder.dataFetcherIfAbsent( - FieldCoordinates.coordinates(rootName + suffix, namedField.getName()), - dummyDataFetcher); - rootBuilder.field(namedField); + GraphQLFieldDefinition namedField = graphQLFieldDefinitionBuilder.build(); - return List.of(namedField); - } - return List.of(); + this.codeRegistryBuilder.dataFetcherIfAbsent( + FieldCoordinates.coordinates(rootName + suffix, namedField.getName()), + dummyDataFetcher); + rootBuilder.field(namedField); + + return List.of(namedField); } - private List getGraphQLFieldDefinition(GroupContainer groupContainer, String rootName, + private List getGraphQLFieldDefinition(NamespaceContainer groupContainer, String rootName, String suffix) { - String name = prettyString(groupContainer.getName()); + String name = makeFirstLetterUppercase(groupContainer.getName()); String namedTypeName = rootName + name + suffix; GraphQLObjectType.Builder wrapperBuilder = GraphQLObjectType.newObject() @@ -441,14 +454,14 @@ private List getGraphQLFieldDefinition(GroupContainer gr .values() .stream() .map(namespace -> addNamespacedRootObject( - wrapperBuilder, namespace, rootName + prettyString(groupContainer.getName()), suffix)) + wrapperBuilder, namespace, rootName + makeFirstLetterUppercase(groupContainer.getName()), suffix)) .flatMap(Collection::stream) .collect(Collectors.toList()); } - private GraphQLObjectType createNamespaceType(String root, String suffix, GroupContainer namespace, + private GraphQLObjectType createNamespaceType(String root, String suffix, NamespaceContainer namespace, Set operations, List graphQLFieldDefinitions) { - String name = prettyString(namespace.getName()); + String name = makeFirstLetterUppercase(namespace.getName()); String namedTypeName = root + name + suffix; GraphQLObjectType.Builder objectTypeBuilder = GraphQLObjectType.newObject() @@ -468,6 +481,51 @@ private GraphQLObjectType createNamespaceType(String root, String suffix, GroupC return objectTypeBuilder.build(); } + private void addGroupedRootObject(GraphQLObjectType.Builder rootBuilder, + Map> operationMap, String rootName) { + Set>> operationsSet = operationMap.entrySet(); + + for (Entry> operationsEntry : operationsSet) { + Group group = operationsEntry.getKey(); + Set operations = operationsEntry.getValue(); + + GraphQLObjectType namedType = createNamedType(rootName, group, operations); + + GraphQLFieldDefinition.Builder graphQLFieldDefinitionBuilder = GraphQLFieldDefinition.newFieldDefinition() + .name(group.getName()).description(group.getDescription()); + + graphQLFieldDefinitionBuilder.type(namedType); + + DataFetcher dummyDataFetcher = dfe -> namedType.getName(); + + GraphQLFieldDefinition namedField = graphQLFieldDefinitionBuilder.build(); + + this.codeRegistryBuilder.dataFetcherIfAbsent( + FieldCoordinates.coordinates(rootName, namedField.getName()), + dummyDataFetcher); + + rootBuilder.field(namedField); + } + } + + private GraphQLObjectType createNamedType(String parent, Group group, Set operations) { + String namedTypeName = group.getName() + parent; + GraphQLObjectType.Builder objectTypeBuilder = GraphQLObjectType.newObject() + .name(namedTypeName) + .description(group.getDescription()); + + // Operations + for (Operation operation : operations) { + operation = eventEmitter.fireCreateOperation(operation); + + GraphQLFieldDefinition graphQLFieldDefinition = createGraphQLFieldDefinitionFromOperation(namedTypeName, + operation); + objectTypeBuilder = objectTypeBuilder.field(graphQLFieldDefinition); + } + + return objectTypeBuilder.build(); + } + // Create all enums and map them private void createGraphQLEnumTypes() { if (schema.hasEnums()) { diff --git a/server/implementation/src/test/java/io/smallrye/graphql/execution/ExperimentalNamespaceTest.java b/server/implementation/src/test/java/io/smallrye/graphql/execution/ExperimentalNamespaceTest.java new file mode 100644 index 000000000..4c75555db --- /dev/null +++ b/server/implementation/src/test/java/io/smallrye/graphql/execution/ExperimentalNamespaceTest.java @@ -0,0 +1,95 @@ +package io.smallrye.graphql.execution; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.util.stream.Stream; + +import jakarta.json.JsonObject; + +import org.jboss.jandex.IndexView; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import graphql.schema.GraphQLSchema; +import io.smallrye.graphql.bootstrap.Bootstrap; +import io.smallrye.graphql.schema.SchemaBuilder; +import io.smallrye.graphql.schema.model.Schema; +import io.smallrye.graphql.test.namespace.ExperimentalNamespaceApi; +import io.smallrye.graphql.test.namespace.ExperimentalNamespaceWithErrorApi; + +/** + * Test for Federated namespaces + */ +public class ExperimentalNamespaceTest { + private static ExecutionService executionService; + + private static IndexView buildIndex(Class... classes) { + org.jboss.jandex.Indexer indexer = new org.jboss.jandex.Indexer(); + Stream.of(classes).forEach(cls -> index(indexer, cls)); + return indexer.complete(); + } + + private static InputStream getResourceStream(Class type) { + String name = type.getName().replace(".", "/") + ".class"; + return Thread.currentThread().getContextClassLoader().getResourceAsStream(name); + } + + private static void index(org.jboss.jandex.Indexer indexer, Class cls) { + try { + indexer.index(getResourceStream(cls)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static GraphQLSchema createGraphQLSchema(IndexView index) { + Schema schema = SchemaBuilder.build(index); + assertNotNull(schema, "Schema should not be null"); + GraphQLSchema graphQLSchema = Bootstrap.bootstrap(schema, true); + assertNotNull(graphQLSchema, "GraphQLSchema should not be null"); + return graphQLSchema; + } + + private static JsonObject executeAndGetResult(String graphQL) { + JsonObjectResponseWriter jsonObjectResponseWriter = new JsonObjectResponseWriter(graphQL); + jsonObjectResponseWriter.logInput(); + executionService.executeSync(jsonObjectResponseWriter.getInput(), jsonObjectResponseWriter); + jsonObjectResponseWriter.logOutput(); + return jsonObjectResponseWriter.getOutput(); + } + + @Test + public void experimentalNamespaceTest() { + IndexView index = buildIndex(ExperimentalNamespaceApi.class); + + GraphQLSchema graphQLSchema = createGraphQLSchema(index); + Schema schema = SchemaBuilder.build(index); + executionService = new ExecutionService(graphQLSchema, schema); + + JsonObject jsonObject = executeAndGetResult(NAMESPACED_QUERY); + assertNotNull(jsonObject); + + String result = jsonObject.getJsonObject("data") + .getJsonObject("admin") + .getJsonObject("users") + .getString("find"); + assertEquals(result, "AdminUsersFind"); + } + + @Test + public void experimentalNamespaceFailureWithUsingNameTest() { + IndexView index = buildIndex(ExperimentalNamespaceWithErrorApi.class); + Assertions.assertThrows(RuntimeException.class, () -> SchemaBuilder.build(index)); + } + + private static final String NAMESPACED_QUERY = "query AminUsersFind {\n" + + " admin {\n" + + " users {\n" + + " find \n" + + " }\n" + + " }\n" + + "}"; +} diff --git a/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java b/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java index 118ddb297..7d6d8e1ec 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/execution/FederatedNamespaceTest.java @@ -57,6 +57,7 @@ static void beforeAll() { NamedNamespaceModel.class, NamedNamespaceTestApi.class, NamedNamespaceWIthGroupingKeyModel.class, NamedNamespaceWithGroupingKeyTestApi.class, SourceNamespaceModel.class, SourceNamespaceTestApi.class, + SourceNamespaceTestApi.First.class, SourceNamespaceTestApi.Second.class, UnamedModel.class, UnnamedTestApi.class); GraphQLSchema graphQLSchema = createGraphQLSchema(index); diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java index 46fe20f96..af3ce4b56 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/grouping/BookGraphQLApi.java @@ -10,17 +10,16 @@ import org.eclipse.microprofile.graphql.Description; import org.eclipse.microprofile.graphql.GraphQLApi; import org.eclipse.microprofile.graphql.Mutation; +import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; -import io.smallrye.graphql.api.Namespace; - /** * Book API * * @author Phillip Kruger (phillip.kruger@redhat.com) */ @GraphQLApi -@Namespace("books") +@Name("books") @Description("Allow all book releated APIs") public class BookGraphQLApi { diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java new file mode 100644 index 000000000..1a328ebfb --- /dev/null +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java @@ -0,0 +1,15 @@ +package io.smallrye.graphql.test.namespace; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Query; + +import io.smallrye.graphql.api.Namespace; + +@GraphQLApi +@Namespace("admin/users") +public class ExperimentalNamespaceApi { + @Query + public String find() { + return "AdminUsersFind"; + } +} diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java new file mode 100644 index 000000000..d40fcbd2d --- /dev/null +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java @@ -0,0 +1,17 @@ +package io.smallrye.graphql.test.namespace; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Name; +import org.eclipse.microprofile.graphql.Query; + +import io.smallrye.graphql.api.Namespace; + +@GraphQLApi +@Name("users") +@Namespace("admin/users") +public class ExperimentalNamespaceWithErrorApi { + @Query + public String find() { + return "AdminUsersFind"; + } +} diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java index 1358f243c..1a7c8c011 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceTestApi.java @@ -1,11 +1,10 @@ package io.smallrye.graphql.test.namespace; import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; -import io.smallrye.graphql.api.Namespace; - -@Namespace("namedNamespace") +@Name("NamedNamespace") @GraphQLApi public class NamedNamespaceTestApi { @Query diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java index b9f7001cf..0c0f66b84 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/NamedNamespaceWithGroupingKeyTestApi.java @@ -1,11 +1,10 @@ package io.smallrye.graphql.test.namespace; import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Name; import org.eclipse.microprofile.graphql.Query; -import io.smallrye.graphql.api.Namespace; - -@Namespace("namedNamespaceWithGroupingKey") +@Name("NamedNamespaceWithGroupingKey") @GraphQLApi public class NamedNamespaceWithGroupingKeyTestApi { @Query diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java index 586163cc4..2568cdec5 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/SourceNamespaceTestApi.java @@ -2,14 +2,26 @@ import org.eclipse.microprofile.graphql.GraphQLApi; import org.eclipse.microprofile.graphql.Query; - -import io.smallrye.graphql.api.Namespace; +import org.eclipse.microprofile.graphql.Source; @GraphQLApi -@Namespace("first/second") public class SourceNamespaceTestApi { - @Query - public SourceNamespaceModel getById(String id) { + public static class First { + } + + public static class Second { + } + + @Query("first") + public First first() { + return new First(); + } + + public Second second(@Source First first) { + return new Second(); + } + + public SourceNamespaceModel getById(@Source Second second, String id) { return new SourceNamespaceModel(id, id); } } From 536955a111d2fa522317c5dc176b804d4db3f8a5 Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Thu, 12 Sep 2024 13:50:38 +0300 Subject: [PATCH 3/7] Without namespace make operationName without capitalize first letter, return test --- .../typesafe/reflection/MethodInvocation.java | 2 +- .../client/model/helper/OperationModel.java | 2 +- .../client/model/ClientModelBuilderTest.java | 22 ++--- .../graphql/typesafe/AnnotationBehavior.java | 14 +-- .../tck/graphql/typesafe/ArrayBehavior.java | 30 +++---- .../tck/graphql/typesafe/EnumBehavior.java | 8 +- .../tck/graphql/typesafe/ErrorBehavior.java | 20 ++--- .../tck/graphql/typesafe/HeaderBehavior.java | 10 +-- .../graphql/typesafe/InterfaceBehavior.java | 6 +- .../graphql/typesafe/MutationBehavior.java | 20 ++--- .../tck/graphql/typesafe/NestedBehavior.java | 36 ++++---- .../typesafe/NestedParameterBehavior.java | 10 +-- .../graphql/typesafe/OptionalBehavior.java | 38 ++++---- .../graphql/typesafe/ParametersBehavior.java | 82 ++++++++--------- .../tck/graphql/typesafe/ScalarBehavior.java | 90 +++++++++---------- .../typesafe/TypesafeResponseBehavior.java | 2 +- .../tck/graphql/typesafe/UnionBehavior.java | 8 +- .../client/typesafe/directives/ServerApi.java | 2 +- 18 files changed, 201 insertions(+), 201 deletions(-) diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java index f6495363f..4f9cbcbe6 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java @@ -304,7 +304,7 @@ public String getOperationName(boolean useNamespace) { + makeFirstLetterUppercase(getName()); } else { operationName = getGroupName() == null - ? makeFirstLetterUppercase(getName()) + ? getName() : makeFirstLetterUppercase(getGroupName()) + makeFirstLetterUppercase(getName()); } } diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java index aab415c46..b83592514 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java @@ -443,7 +443,7 @@ public String getOperationName(boolean useNamespace) { + makeFirstLetterUppercase(getName()); } else { operationName = getGroupName() == null - ? makeFirstLetterUppercase(getName()) + ? getName() : makeFirstLetterUppercase(getGroupName()) + makeFirstLetterUppercase(getName()); } } diff --git a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java index 8c151f1ac..8e2de88ef 100644 --- a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java +++ b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java @@ -48,15 +48,15 @@ void sclarClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("returnInteger", new Class[] { Integer.class }), - "query ReturnInteger($someNumber: Int) { returnInteger(someNumber: $someNumber) }"); + "query returnInteger($someNumber: Int) { returnInteger(someNumber: $someNumber) }"); assertOperation(clientModel, new MethodKey("returnString", new Class[] { String.class }), - "mutation ReturnString($someString: String) { returnString(someString: $someString) }"); + "mutation returnString($someString: String) { returnString(someString: $someString) }"); assertOperation(clientModel, new MethodKey("returnNonNullFloat", new Class[] { float.class }), - "subscription ReturnNonNullFloat($someFloat: Float!) { returnNonNullFloat(someFloat: $someFloat) }"); + "subscription returnNonNullFloat($someFloat: Float!) { returnNonNullFloat(someFloat: $someFloat) }"); } @GraphQLClientApi(configKey = "collection") @@ -80,15 +80,15 @@ void collectionClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("returnIntegerCollection", new Class[] { Integer[].class }), - "query ReturnIntegerCollection($someNumbers: [Int]) { returnIntegerCollection(someNumbers: $someNumbers) }"); + "query returnIntegerCollection($someNumbers: [Int]) { returnIntegerCollection(someNumbers: $someNumbers) }"); assertOperation(clientModel, new MethodKey("returnStringList", new Class[] { Set.class }), - "mutation ReturnStringList($someStrings: [String]) { returnStringList(someStrings: $someStrings) }"); + "mutation returnStringList($someStrings: [String]) { returnStringList(someStrings: $someStrings) }"); assertOperation(clientModel, new MethodKey("returnFloatArrayList", new Class[] { HashSet.class }), - "subscription ReturnFloatArrayList($someFloats: [Float]) { returnFloatArrayList(someFloats: $someFloats) }"); + "subscription returnFloatArrayList($someFloats: [Float]) { returnFloatArrayList(someFloats: $someFloats) }"); } @Test @@ -102,7 +102,7 @@ void simpleObjectClientModelTest() throws IOException { assertOperation(clientModel, new MethodKey("returnSomeObject", new Class[] { SimpleObjectClientApi.SomeObject.class }), - "query ReturnSomeObject($someObject: SomeObjectInput) { returnSomeObject(someObject: $someObject) {name innerObject {someInt}} }"); + "query returnSomeObject($someObject: SomeObjectInput) { returnSomeObject(someObject: $someObject) {name innerObject {someInt}} }"); } @GraphQLClientApi(configKey = "simple-object") @@ -135,7 +135,7 @@ void complexObjectClientModelTest() throws IOException { assertEquals(1, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("returnSomeGenericObject", new Class[] { List.class }), - "query ReturnSomeGenericObject($someObject: [SomeGenericClassInput])" + + "query returnSomeGenericObject($someObject: [SomeGenericClassInput])" + " { returnSomeGenericObject(someObject: $someObject) {somethingParent {number}" + " field1 {number} field2 {innerField {number} something {someObject {someThingElse" + " {string}}}}} }"); @@ -203,13 +203,13 @@ void inheritedOperationsClientModelTest() throws IOException { assertEquals(3, clientModel.getOperationMap().size()); assertOperation(clientModel, new MethodKey("allStrings", new Class[0]), - "query Strings { strings }"); + "query strings { strings }"); assertOperation(clientModel, new MethodKey("allStrings2", new Class[0]), - "query AllStrings2 { allStrings2 }"); + "query allStrings2 { allStrings2 }"); assertOperation(clientModel, new MethodKey("allStrings0", new Class[0]), - "query AllStrings0 { allStrings0 }"); + "query allStrings0 { allStrings0 }"); } @Name("named") diff --git a/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java index 44f8acfc0..fbe1804ed 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/AnnotationBehavior.java @@ -30,7 +30,7 @@ void shouldQueryRenamedString() { String greeting = api.foo(); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(greeting).isEqualTo("dummy-greeting"); } @@ -46,7 +46,7 @@ void shouldQueryNamedParam() { String greeting = api.greeting("foo"); - then(fixture.query()).isEqualTo("query Greeting($foo: String) { greeting(who: $foo) }"); + then(fixture.query()).isEqualTo("query greeting($foo: String) { greeting(who: $foo) }"); then(fixture.variables()).isEqualTo("{'foo':'foo'}"); then(greeting).isEqualTo("hi, foo"); } @@ -64,7 +64,7 @@ void shouldQueryRenamedMethod() { String greeting = api.someOtherMethodName(); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(fixture.variables()).isEqualTo("{}"); then(greeting).isEqualTo("hi, foo"); } @@ -88,7 +88,7 @@ void shouldQueryObjectWithRenamedFields() { RenamedGreeting greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting {text:foo code:key} }"); + then(fixture.query()).isEqualTo("query greeting { greeting {text:foo code:key} }"); then(greeting.text).isEqualTo("foo"); then(greeting.code).isEqualTo(5); } @@ -120,7 +120,7 @@ void shouldQueryObjectWithFieldsWithIgnore() { GreetingWithIgnore greeting = api.greeting(new GreetingWithIgnore("foo", "the-code")); - then(fixture.query()).isEqualTo("query Greeting($in: GreetingWithIgnoreInput) { greeting(in: $in) {text} }"); + then(fixture.query()).isEqualTo("query greeting($in: GreetingWithIgnoreInput) { greeting(in: $in) {text} }"); then(greeting.text).isEqualTo("foo"); then(greeting.ignore).isNull(); } @@ -162,7 +162,7 @@ void shouldCallMultipleWithoutParamsDifferentType() { HeroAndVillain heroAndVillain = api.heroAndVillain(); - then(fixture.query()).isEqualTo("query HeroAndVillain {hero {name good} villain {name}}"); + then(fixture.query()).isEqualTo("query heroAndVillain {hero {name good} villain {name}}"); then(fixture.variables()).isEqualTo("{}"); then(heroAndVillain.hero.name).isEqualTo("Spider-Man"); then(heroAndVillain.hero.good).isTrue(); @@ -176,7 +176,7 @@ void shouldCallMultipleWithoutParamsSameType() { HeroPair pair = api.randomHeroPair(); - then(fixture.query()).isEqualTo("query RandomHeroPair {left:hero {name good} right:hero {name good}}"); + then(fixture.query()).isEqualTo("query randomHeroPair {left:hero {name good} right:hero {name good}}"); then(fixture.variables()).isEqualTo("{}"); then(pair.left.name).isEqualTo("Spider-Man"); then(pair.left.good).isTrue(); diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java index 44ade168d..2a2a060e5 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ArrayBehavior.java @@ -21,7 +21,7 @@ void shouldCallBoolArrayQuery() { boolean[] bool = api.bool(new boolean[] { true, false }); - then(fixture.query()).isEqualTo("query Bool($in: [Boolean!]) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query bool($in: [Boolean!]) { bool(in: $in) }"); then(bool[0]).isTrue(); then(bool[1]).isFalse(); } @@ -33,7 +33,7 @@ void shouldCallEmptyBoolArrayQuery() { boolean[] bool = api.bool(new boolean[0]); - then(fixture.query()).isEqualTo("query Bool($in: [Boolean!]) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query bool($in: [Boolean!]) { bool(in: $in) }"); then(bool).isEmpty(); } @@ -49,7 +49,7 @@ void shouldCallBooleanArrayQuery() { Boolean[] bool = api.bool(new Boolean[] { true, false }); - then(fixture.query()).isEqualTo("query Bool($in: [Boolean]) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query bool($in: [Boolean]) { bool(in: $in) }"); then(bool[0]).isTrue(); then(bool[1]).isFalse(); } @@ -68,7 +68,7 @@ void shouldCallCharArrayQuery() { char[] chars = api.chars(new char[] { 'a', 'b', 'c' }); - then(fixture.query()).isEqualTo("query Chars($in: [String!]) { chars(in: $in) }"); + then(fixture.query()).isEqualTo("query chars($in: [String!]) { chars(in: $in) }"); then(chars).containsExactly('a', 'b', 'c'); } @@ -84,7 +84,7 @@ void shouldCallCharacterArrayQuery() { Character[] chars = api.chars(new Character[] { 'a', 'b', 'c' }); - then(fixture.query()).isEqualTo("query Chars($in: [String]) { chars(in: $in) }"); + then(fixture.query()).isEqualTo("query chars($in: [String]) { chars(in: $in) }"); then(chars).containsExactly('a', 'b', 'c'); } @@ -102,7 +102,7 @@ void shouldCallShortArrayQuery() { short[] shorts = api.shorts(new short[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query Shorts($in: [Int!]) { shorts(in: $in) }"); + then(fixture.query()).isEqualTo("query shorts($in: [Int!]) { shorts(in: $in) }"); then(shorts).containsExactly(1, 2, 3); } @@ -118,7 +118,7 @@ void shouldCallPrimitiveShortArrayQuery() { Short[] shorts = api.shorts(new Short[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query Shorts($in: [Int]) { shorts(in: $in) }"); + then(fixture.query()).isEqualTo("query shorts($in: [Int]) { shorts(in: $in) }"); then(shorts).containsExactly((short) 1, (short) 2, (short) 3); } @@ -136,7 +136,7 @@ void shouldCallIntArrayQuery() { int[] ints = api.integer(new int[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query Integer($in: [Int!]) { integer(in: $in) }"); + then(fixture.query()).isEqualTo("query integer($in: [Int!]) { integer(in: $in) }"); then(ints).containsExactly(1, 2, 3); } @@ -152,7 +152,7 @@ void shouldCallIntegerArrayQuery() { Integer[] ints = api.ints(new Integer[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query Ints($in: [Int]) { ints(in: $in) }"); + then(fixture.query()).isEqualTo("query ints($in: [Int]) { ints(in: $in) }"); then(ints).containsExactly(1, 2, 3); } @@ -170,7 +170,7 @@ void shouldCallPrimitiveLongArrayQuery() { long[] longs = api.longs(new long[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query Longs($in: [BigInteger!]) { longs(in: $in) }"); + then(fixture.query()).isEqualTo("query longs($in: [BigInteger!]) { longs(in: $in) }"); then(longs).containsExactly(1, 2, 3); } @@ -186,7 +186,7 @@ void shouldCallLongArrayQuery() { Long[] longs = api.longs(new Long[] { 1L, 2L, 3L }); - then(fixture.query()).isEqualTo("query Longs($in: [BigInteger]) { longs(in: $in) }"); + then(fixture.query()).isEqualTo("query longs($in: [BigInteger]) { longs(in: $in) }"); then(longs).containsExactly(1L, 2L, 3L); } @@ -204,7 +204,7 @@ void shouldCallPrimitiveFloatArrayQuery() { float[] floats = api.floats(new float[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query Floats($in: [Float!]) { floats(in: $in) }"); + then(fixture.query()).isEqualTo("query floats($in: [Float!]) { floats(in: $in) }"); then(floats).containsExactly(1, 2, 3); } @@ -220,7 +220,7 @@ void shouldCallFloatArrayQuery() { Float[] floats = api.floats(new Float[] { 1F, 2F, 3F }); - then(fixture.query()).isEqualTo("query Floats($in: [Float]) { floats(in: $in) }"); + then(fixture.query()).isEqualTo("query floats($in: [Float]) { floats(in: $in) }"); then(floats).containsExactly(1F, 2F, 3F); } @@ -238,7 +238,7 @@ void shouldCallPrimitiveDoubleArrayQuery() { double[] doubles = api.doubles(new double[] { 1, 2, 3 }); - then(fixture.query()).isEqualTo("query Doubles($in: [Float!]) { doubles(in: $in) }"); + then(fixture.query()).isEqualTo("query doubles($in: [Float!]) { doubles(in: $in) }"); then(doubles).containsExactly(1, 2, 3); } @@ -254,7 +254,7 @@ void shouldCallDoubleArrayQuery() { Double[] doubles = api.doubles(new Double[] { 1D, 2D, 3D }); - then(fixture.query()).isEqualTo("query Doubles($in: [Float]) { doubles(in: $in) }"); + then(fixture.query()).isEqualTo("query doubles($in: [Float]) { doubles(in: $in) }"); then(doubles).containsExactly(1D, 2D, 3D); } } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java index 654041057..5da2dda8f 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/EnumBehavior.java @@ -57,7 +57,7 @@ void shouldCallEnumQuery() { Episode episode = api.episode(); - then(fixture.query()).isEqualTo("query Episode { episode }"); + then(fixture.query()).isEqualTo("query episode { episode }"); then(episode).isEqualTo(JEDI); } @@ -73,7 +73,7 @@ void shouldCallEnumListQuery() { List episode = api.episodes(); - then(fixture.query()).isEqualTo("query Episodes { episodes }"); + then(fixture.query()).isEqualTo("query episodes { episodes }"); then(episode).containsExactly(NEWHOPE, EMPIRE, JEDI); } @@ -89,7 +89,7 @@ void shouldCallEnumFilterQuery() { List characters = api.characters(JEDI); - then(fixture.query()).isEqualTo("query Characters($episode: Episode) { characters(episode: $episode) }"); + then(fixture.query()).isEqualTo("query characters($episode: Episode) { characters(episode: $episode) }"); then(fixture.variables()).isEqualTo("{'episode':'JEDI'}"); then(characters).containsExactly("Luke", "Darth"); } @@ -106,7 +106,7 @@ void shouldCallGenericQuery() { DescribedValue episode = api.describedEpisode(); - then(fixture.query()).isEqualTo("query DescribedEpisode { describedEpisode {value description} }"); + then(fixture.query()).isEqualTo("query describedEpisode { describedEpisode {value description} }"); then(episode.description).isEqualTo("Episode 4"); then(episode.value).isEqualTo(NEWHOPE); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java index b8ac88752..ac656854e 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ErrorBehavior.java @@ -239,7 +239,7 @@ void shouldIgnoreEmptyError() { String greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(greeting).isEqualTo("dummy-greeting"); } @@ -265,7 +265,7 @@ void shouldFetchErrorOrPresent() { ErrorOr> response = api.teams(); - then(fixture.query()).isEqualTo("query Teams { teams {name} }"); + then(fixture.query()).isEqualTo("query teams { teams {name} }"); then(response.isPresent()).isTrue(); then(response.hasErrors()).isFalse(); then(catchThrowable(response::getErrors)).isInstanceOf(NoSuchElementException.class); @@ -292,7 +292,7 @@ void shouldFetchErrorOrAbsent() { ErrorOr> response = api.teams(); - then(fixture.query()).isEqualTo("query Teams { teams {name} }"); + then(fixture.query()).isEqualTo("query teams { teams {name} }"); then(response).hasExactlyOneErrorWhich() .hasMessage("currently can't search for teams") .hasPath("teams") @@ -319,7 +319,7 @@ void shouldFetchErrorOnNullData() { GraphQLClientException throwable = catchThrowableOfType(api::teams, GraphQLClientException.class); - then(fixture.query()).isEqualTo("query Teams { teams {name} }"); + then(fixture.query()).isEqualTo("query teams { teams {name} }"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("currently can't search for teams") .hasPath("teams") @@ -354,7 +354,7 @@ void shouldFetchErrorOrWithTwoErrors() { ErrorOr> response = api.teams(); - then(fixture.query()).isEqualTo("query Teams { teams {name} }"); + then(fixture.query()).isEqualTo("query teams { teams {name} }"); List errors = response.getErrors(); then(errors).hasSize(2); then(errors.get(0)) @@ -388,7 +388,7 @@ void shouldFetchErrorOrAbsentWithoutPath() { GraphQLClientException throwable = catchThrowableOfType(api::teams, GraphQLClientException.class); - then(fixture.query()).isEqualTo("query Teams { teams {name} }"); + then(fixture.query()).isEqualTo("query teams { teams {name} }"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("currently can't search for teams") .hasNoPath() @@ -411,7 +411,7 @@ void shouldFetchErrorOrWithNullInPath() { GraphQLClientException throwable = catchThrowableOfType(api::teams, GraphQLClientException.class); - then(fixture.query()).isEqualTo("query Teams { teams {name} }"); + then(fixture.query()).isEqualTo("query teams { teams {name} }"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("can't get team name") .hasPath("teams", "name") @@ -441,7 +441,7 @@ void shouldFetchFullWrapper() { Wrapper response = api.find(); - then(fixture.query()).isEqualTo("query Find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); + then(fixture.query()).isEqualTo("query find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); { then(response.superHeroes).hasSize(1); ErrorOr superHero = response.superHeroes.get(0); @@ -476,7 +476,7 @@ void shouldFetchPartialWrapper() { Wrapper response = api.find(); - then(fixture.query()).isEqualTo("query Find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); + then(fixture.query()).isEqualTo("query find { find {superHeroes:findHeroes {name location} teams:findTeams {name}} }"); then(response.superHeroes).hasSize(1); then(response.superHeroes.get(0).get().name).isEqualTo("Wolverine"); then(response.teams.hasErrors()).isTrue(); @@ -534,7 +534,7 @@ void shouldFetchComplexError() { GraphQLClientException throwable = catchThrowableOfType(() -> api.order("o1"), GraphQLClientException.class); then(fixture.query()) - .isEqualTo("query Order($id: String!) { order(id: $id) {id orderDate items {product {id name}}} }"); + .isEqualTo("query order($id: String!) { order(id: $id) {id orderDate items {product {id name}}} }"); then(fixture.variables()).isEqualTo("{'id':'o1'}"); then(throwable).hasExactlyOneErrorWhich() .hasMessage("System error") diff --git a/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java index 6f4d8d8e4..2b846f3c8 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/HeaderBehavior.java @@ -478,7 +478,7 @@ void shouldAddParamHeader() { api.greeting("bar"); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(fixture.sentHeader("foo")).isEqualTo("bar"); } @@ -590,7 +590,7 @@ void shouldAddDefaultHeaders() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Content-Type")).hasToString("application/json;charset=utf-8"); then(fixture.sentHeader("Accept")).hasToString("application/json;charset=utf-8"); @@ -603,7 +603,7 @@ void shouldAddManuallyBuildDefaultHeader() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Custom-Header")).hasToString("Custom-Header-Value"); } @@ -618,7 +618,7 @@ void shouldManuallyOverrideDefaultHeaders() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Content-Type")).hasToString("application/xxx"); then(fixture.sentHeader("Accept")).hasToString("application/yyy"); @@ -631,7 +631,7 @@ void shouldAddManuallyBuildDefaultHeaders() { api.greeting("foo"); - then(fixture.query()).isEqualTo("query Greeting($target: String) { greeting(target: $target) }"); + then(fixture.query()).isEqualTo("query greeting($target: String) { greeting(target: $target) }"); then(fixture.variables()).isEqualTo("{'target':'foo'}"); then(fixture.sentHeader("Custom-Header")).hasToString("Custom-Header-Value"); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java index e3a40fce6..367187f76 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/InterfaceBehavior.java @@ -64,7 +64,7 @@ void shouldInterfaceFindBatman() { var response = api.find("Batman"); - then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + "__typename " + "... on MainCharacter {name superPower} " + "... on SideKick {name mainCharacter}} }"); @@ -81,7 +81,7 @@ void shouldInterfaceFindRobin() { var response = api.find("Robin"); - then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + "__typename " + "... on MainCharacter {name superPower} " + "... on SideKick {name mainCharacter}} }"); @@ -101,7 +101,7 @@ void shouldInterfaceFindAll() { var response = api.all(); - then(fixture.query()).isEqualTo("query All { all{" + + then(fixture.query()).isEqualTo("query all { all{" + "__typename " + "... on MainCharacter {name superPower} " + "... on SideKick {name mainCharacter}} }"); diff --git a/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java index 690716631..875c1ed75 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/MutationBehavior.java @@ -28,7 +28,7 @@ void shouldCallStringMutation() { String greeting = api.createSome("input"); - then(fixture.query()).isEqualTo("mutation CreateSome($thing: String) { createSome(thing: $thing) }"); + then(fixture.query()).isEqualTo("mutation createSome($thing: String) { createSome(thing: $thing) }"); then(fixture.variables()).isEqualTo("{'thing':'input'}"); then(greeting).isEqualTo("output"); } @@ -40,7 +40,7 @@ void shouldCallNullStringMutation() { String greeting = api.createSome(null); - then(fixture.query()).isEqualTo("mutation CreateSome($thing: String) { createSome(thing: $thing) }"); + then(fixture.query()).isEqualTo("mutation createSome($thing: String) { createSome(thing: $thing) }"); then(fixture.variables()).isEqualTo("{'thing':null}"); then(greeting).isEqualTo("output"); } @@ -87,7 +87,7 @@ void shouldCallGreetingMutation() { Greeting greeting = api.say(new Greeting("hi", 5)); - then(fixture.query()).isEqualTo("mutation Say($greet: GreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("mutation say($greet: GreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -99,7 +99,7 @@ void shouldCallGreetingMutationWithNullValue() { Greeting greeting = api.say(new Greeting(null, 5)); - then(fixture.query()).isEqualTo("mutation Say($greet: GreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("mutation say($greet: GreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'count':5}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -120,7 +120,7 @@ void shouldCallMutationWithListWithNullValue() { null, new Greeting("three", 5))); - then(fixture.query()).isEqualTo("mutation Say($greets: [GreetingInput]) { say(greets: $greets) {text count} }"); + then(fixture.query()).isEqualTo("mutation say($greets: [GreetingInput]) { say(greets: $greets) {text count} }"); then(fixture.variables()).isEqualTo("{'greets':[" + "{'text':'one','count':5}," + "null," + @@ -174,7 +174,7 @@ void shouldCallMutationWithNestedValue() { Greeting greeting = api.say(new GreetingContainer(new Greeting("one", 5), now)); then(fixture.query()) - .isEqualTo("mutation Say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); + .isEqualTo("mutation say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); then(fixture.variables()).isEqualTo("{'greeting':{" + "'greeting':{'text':'one','count':5}," + "'when':'" + now + "'}}"); @@ -189,7 +189,7 @@ void shouldCallMutationWithNestedNullValue() { Greeting greeting = api.say(new GreetingContainer(new Greeting(null, 5), null)); then(fixture.query()) - .isEqualTo("mutation Say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); + .isEqualTo("mutation say($greeting: GreetingContainerInput) { say(greeting: $greeting) {text count} }"); then(fixture.variables()).isEqualTo("{'greeting':{'greeting':{'count':5}}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -228,7 +228,7 @@ void shouldCallMutationWithEnum() { Greeting greeting = api.say(new GreetingEnum("one", SomeEnum.ONE)); - then(fixture.query()).isEqualTo("mutation Say($greeting: GreetingEnumInput) { say(greeting: $greeting) {text count} }"); + then(fixture.query()).isEqualTo("mutation say($greeting: GreetingEnumInput) { say(greeting: $greeting) {text count} }"); then(fixture.variables()).isEqualTo("{'greeting':{'text':'one','someEnum':'ONE'}}"); then(greeting).isEqualTo(new Greeting("ho", 3)); } @@ -279,7 +279,7 @@ void shouldCallMutationWithPrimitives() { String result = api.run(new PrimitiveTypes()); - then(fixture.query()).isEqualTo("mutation Run($primitives: PrimitiveTypesInput) { run(primitives: $primitives) }"); + then(fixture.query()).isEqualTo("mutation run($primitives: PrimitiveTypesInput) { run(primitives: $primitives) }"); then(fixture.variables()) .isEqualTo("{'primitives':{'b':true,'c':'a','y':7,'s':255,'i':123456,'l':987654321,'f':1.0,'d':56.78}}"); then(result).isEqualTo("okay"); @@ -332,7 +332,7 @@ void shouldCallMutationWithPrimitiveWrappers() { String result = api.run(new PrimitiveWrapperTypes()); then(fixture.query()) - .isEqualTo("mutation Run($primitives: PrimitiveWrapperTypesInput) { run(primitives: $primitives) }"); + .isEqualTo("mutation run($primitives: PrimitiveWrapperTypesInput) { run(primitives: $primitives) }"); then(fixture.variables()) .isEqualTo("{'primitives':{'b':true,'c':'a','y':7,'s':255,'i':123456,'l':987654321,'f':1.0,'d':56.78}}"); then(result).isEqualTo("okay"); diff --git a/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java index 1eec083c4..89f3dbb0e 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/NestedBehavior.java @@ -31,7 +31,7 @@ void shouldCallStringSetQuery() { Set greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings }"); + then(fixture.query()).isEqualTo("query greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -91,7 +91,7 @@ void shouldCallStringCollectionQuery() { Collection greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings }"); + then(fixture.query()).isEqualTo("query greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -107,7 +107,7 @@ void shouldCallStringArrayListQuery() { ArrayList greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings }"); + then(fixture.query()).isEqualTo("query greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -123,7 +123,7 @@ void shouldCallStringListQuery() { List greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings }"); + then(fixture.query()).isEqualTo("query greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -134,7 +134,7 @@ void shouldCallStringListQueryWithNull() { List greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings }"); + then(fixture.query()).isEqualTo("query greetings { greetings }"); then(greetings).containsExactly("a", null); } @@ -167,7 +167,7 @@ void shouldCallStringArrayQuery() { String[] greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings }"); + then(fixture.query()).isEqualTo("query greetings { greetings }"); then(greetings).containsExactly("a", "b"); } @@ -214,7 +214,7 @@ void shouldCallObjectQuery() { Greeting greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting {text code successful} }"); + then(fixture.query()).isEqualTo("query greeting { greeting {text code successful} }"); then(greeting).isEqualTo(new Greeting("foo", 5, true)); } @@ -266,7 +266,7 @@ void shouldCallObjectListQuery() { List greeting = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings {text code successful} }"); + then(fixture.query()).isEqualTo("query greetings { greetings {text code successful} }"); then(greeting).containsExactly( new Greeting("a", 1, null), new Greeting("b", 2, true), @@ -312,7 +312,7 @@ void shouldCallNestedStringQuery() { StringContainer container = api.container(); - then(fixture.query()).isEqualTo("query Container { container {greeting count} }"); + then(fixture.query()).isEqualTo("query container { container {greeting count} }"); then(container.greeting).isEqualTo("hi"); then(container.count).isEqualTo(5); } @@ -359,7 +359,7 @@ void shouldCallNestedObjectQuery() { GreetingContainer container = api.container(); then(fixture.query()) - .isEqualTo("query Container { container {greeting {text code successful} count} }"); + .isEqualTo("query container { container {greeting {text code successful} count} }"); then(container).isEqualTo(new GreetingContainer( new Greeting("a", 1, null), 3)); } @@ -408,7 +408,7 @@ void shouldCallNestedListQuery() { GreetingsContainer container = api.container(); then(fixture.query()) - .isEqualTo("query Container { container {greetings {text code successful} count} }"); + .isEqualTo("query container { container {greetings {text code successful} count} }"); then(container).isEqualTo(new GreetingsContainer( asList(new Greeting("a", 1, null), new Greeting("b", 2, null)), 3)); } @@ -485,7 +485,7 @@ void shouldCallWrappedGreetingQuery() { WrappedGreetingContainer container = api.container(); then(fixture.query()) - .isEqualTo("query Container { container {greeting {value {text code successful}} count} }"); + .isEqualTo("query container { container {greeting {value {text code successful}} count} }"); then(container).isEqualTo(new WrappedGreetingContainer( new Wrapper<>(new Greeting("a", 1, null)), 3)); } @@ -531,7 +531,7 @@ void shouldCallWrappedByteQuery() { WrappedByteContainer container = api.container(); - then(fixture.query()).isEqualTo("query Container { container {code {value} count} }"); + then(fixture.query()).isEqualTo("query container { container {code {value} count} }"); then(container).isEqualTo(new WrappedByteContainer( new Wrapper<>((byte) 123), 3)); } @@ -588,7 +588,7 @@ void shouldCallWrappedListByteQuery() { WrappedListByteContainer container = api.container(); - then(fixture.query()).isEqualTo("query Container { container {codes count} }"); + then(fixture.query()).isEqualTo("query container { container {codes count} }"); then(container).isEqualTo(new WrappedListByteContainer( asList((byte) 'a', (byte) 'b', (byte) 'c'), 3)); } @@ -626,7 +626,7 @@ void shouldCallObjectQueryWithSpecialFields() { ClassWithTransientAndStaticFields foo = api.foo(); - then(fixture.query()).isEqualTo("query Foo { foo {text code} }"); + then(fixture.query()).isEqualTo("query foo { foo {text code} }"); then(foo.text).isEqualTo("foo"); then(foo.code).isEqualTo(5); then(foo.ignoreMe).isFalse(); @@ -655,7 +655,7 @@ void shouldCallInheritedGreetingQuery() { Sub sub = api.call(); then(fixture.query()) - .isEqualTo("query Call { call {greeting {text code successful} count} }"); + .isEqualTo("query call { call {greeting {text code successful} count} }"); then(sub.greeting).isEqualTo(new Greeting("a", 1, null)); then(sub.count).isEqualTo(3); } @@ -680,7 +680,7 @@ void shouldCreateObjectPrivateDefaultConstructor() { ObjectPrivateDefaultConstructor call = api.call(); - then(fixture.query()).isEqualTo("query Call { call {foo} }"); + then(fixture.query()).isEqualTo("query call { call {foo} }"); then(call.foo).isEqualTo("a"); } @@ -731,7 +731,7 @@ void shouldCallWithMissingNullableField() { MissingNullableField result = api.call(); - then(fixture.query()).isEqualTo("query Call { call {foo bar} }"); + then(fixture.query()).isEqualTo("query call { call {foo bar} }"); then(result.foo).isEqualTo("a"); then(result.bar).isNull(); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java index 649db302d..dcf5681fc 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/NestedParameterBehavior.java @@ -51,7 +51,7 @@ void shouldCallNestedParameterQuery() { Team team = api.team("endgame", 3); then(fixture.query()) - .isEqualTo("query Team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + + .isEqualTo("query team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + "{headQuarters {name} members(limit: $limit) {name}} }"); then(fixture.variables()).isEqualTo("{'teamName':'endgame','limit':3}"); then(team.headQuarters.stream().map(HeadQuarter::getName)).containsExactly("Earth"); @@ -72,7 +72,7 @@ void shouldCallMultipleNestedParameterQuery() { Team team = api.team("endgame", 3); then(fixture.query()) - .isEqualTo("query Team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + + .isEqualTo("query team($teamName: String, $limit: Int!) { team(teamName: $teamName) " + "{headQuarters(limit: $limit) {name} members(limit: $limit) {name}} }"); then(fixture.variables()).isEqualTo("{'teamName':'endgame','limit':3}"); then(team.headQuarters).isEmpty(); @@ -101,7 +101,7 @@ void shouldCallDeeplyNestedParameterQuery() { Universe universe = api.universeWithTeam("endgame", 32, 3); then(fixture.query()) - .isEqualTo("query UniverseWithTeam($teamName: String, $offset: Int, $limit: Int) { universeWithTeam " + + .isEqualTo("query universeWithTeam($teamName: String, $offset: Int, $limit: Int) { universeWithTeam " + "{name teams(teamName: $teamName) {headQuarters {name} members(offset: $offset, limit: $limit) {name}}} }"); then(fixture.variables()).isEqualTo("{'teamName':'endgame','offset':32,'limit':3}"); then(universe.name).isEqualTo("Marvel"); @@ -138,7 +138,7 @@ void shouldCallMultipleWithParams() { HeroPair pair = api.heroPairByNames("Spider-Man", "Venom"); then(fixture.query()) - .isEqualTo("query HeroPairByNames($leftName: String, $rightName: String) {" + + .isEqualTo("query heroPairByNames($leftName: String, $rightName: String) {" + "left:hero(name: $leftName) {name good} right:hero(name: $rightName) {name good}}"); then(fixture.variables()).isEqualTo("{'leftName':'Spider-Man','rightName':'Venom'}"); then(pair.left.name).isEqualTo("Spider-Man"); @@ -176,7 +176,7 @@ void shouldCallMultipleMutations() { MultiUpdate result = api.multiUpdate("new-loc", "new-team", "new-name"); then(fixture.query()).isEqualTo("" + - "mutation MultiUpdate($location: String, $teamName: String, $name: String) {" + + "mutation multiUpdate($location: String, $teamName: String, $name: String) {" + "updateLocation(location: $location) " + "addTeam(teamName: $teamName) " + "updateName(name: $name) {name good}" + diff --git a/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java index e09040ddd..c351ae0bc 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/OptionalBehavior.java @@ -28,7 +28,7 @@ void shouldCallNullOptionalStringQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(greeting).isEmpty(); } @@ -39,7 +39,7 @@ void shouldCallOptionalStringQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(greeting).contains("hi"); } @@ -84,7 +84,7 @@ void shouldCallOptionalGreetingQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); then(greeting).contains(new Greeting("hi", 5)); } @@ -95,7 +95,7 @@ void shouldCallNullOptionalGreetingQuery() { Optional greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); then(greeting).isEmpty(); } @@ -111,7 +111,7 @@ void shouldCallOptionalGreetingListQuery() { Optional> greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); assert greeting.isPresent(); then(greeting.get()).contains(new Greeting("hi", 5), new Greeting("ho", 7)); } @@ -123,7 +123,7 @@ void shouldCallEmptyOptionalGreetingListQuery() { Optional> greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting {text code} }"); + then(fixture.query()).isEqualTo("query greeting { greeting {text code} }"); assert greeting.isPresent(); then(greeting.get()).isEmpty(); } @@ -140,7 +140,7 @@ void shouldCallListOfOptionalGreetingsQuery() { List> greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings {text code} }"); + then(fixture.query()).isEqualTo("query greetings { greetings {text code} }"); then(greetings).containsExactly( Optional.of(new Greeting("hi", 5)), Optional.of(new Greeting("ho", 7))); @@ -153,7 +153,7 @@ void shouldCallEmptyListOfOptionalGreetingsQuery() { List> greetings = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings {text code} }"); + then(fixture.query()).isEqualTo("query greetings { greetings {text code} }"); then(greetings).isEmpty(); } @@ -169,7 +169,7 @@ void shouldCallOptionalOptionalStringQuery() { Optional> greeting = api.greeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(greeting).contains(Optional.of("hi")); } @@ -180,7 +180,7 @@ void optionalIntOutputTest() { AnimalApi api = fixture.build(AnimalApi.class); List listOfAnimalLegs = api.allAnimalLegs(); - then(fixture.query()).isEqualTo("query AllAnimalLegs { allAnimalLegs {name numberOfLegs" + + then(fixture.query()).isEqualTo("query allAnimalLegs { allAnimalLegs {name numberOfLegs" + " numberOfTeeth price} }"); then(listOfAnimalLegs).containsExactly( new Animal("Lion", OptionalInt.of(4)), @@ -194,7 +194,7 @@ void optionalLongOutputTest() { " {'name': 'Centipedes', 'numberOfTeeth':0 }, {'name': 'Snake', 'numberOfTeeth':100}]"); AnimalApi api = fixture.build(AnimalApi.class); List listOfAnimalTeeth = api.allAnimalTeeth(); - then(fixture.query()).isEqualTo("query AllAnimalTeeth { allAnimalTeeth {name numberOfLegs" + + then(fixture.query()).isEqualTo("query allAnimalTeeth { allAnimalTeeth {name numberOfLegs" + " numberOfTeeth price} }"); then(listOfAnimalTeeth).containsExactly( new Animal("Lion", OptionalLong.of(30)), @@ -208,7 +208,7 @@ void optionalDoubleOutputTest() { " {'name': 'Centipedes', 'price':241.62 }, {'name': 'Snake', 'price':1648.28}]"); AnimalApi api = fixture.build(AnimalApi.class); List listOfAnimalPrice = api.allAnimalPrice(); - then(fixture.query()).isEqualTo("query AllAnimalPrice { allAnimalPrice {name numberOfLegs" + + then(fixture.query()).isEqualTo("query allAnimalPrice { allAnimalPrice {name numberOfLegs" + " numberOfTeeth price} }"); then(listOfAnimalPrice).containsExactly( new Animal("Lion", OptionalDouble.of(355655.74)), @@ -222,7 +222,7 @@ void optionalIntParameterQuery() { "{'name':'Snake', 'numberOfLegs':0, 'numberOfTeeth':100, 'price':1648.28}]"); AnimalApi api = fixture.build(AnimalApi.class); List animals = api.getAnimalsByLegs(OptionalInt.of(0)); - then(fixture.query()).isEqualTo("query AnimalsByLegs($numberOfLegs: Int) { " + + then(fixture.query()).isEqualTo("query animalsByLegs($numberOfLegs: Int) { " + "animalsByLegs(numberOfLegs: $numberOfLegs) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'numberOfLegs':0}"); then(animals).containsExactly( @@ -237,7 +237,7 @@ void optionalIntMutationTest() { fixture.returnsData("'newAnimal':{'name':'Pig', 'numberOfLegs':4}"); AnimalApi api = fixture.build(AnimalApi.class); Animal animal = api.newAnimal(new Animal("Pig", OptionalInt.of(4))); - then(fixture.query()).isEqualTo("mutation NewAnimal($animal: AnimalInput) " + + then(fixture.query()).isEqualTo("mutation newAnimal($animal: AnimalInput) " + "{ newAnimal(animal: $animal) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'animal':{'name':'Pig','numberOfLegs':" + "4}}"); @@ -252,7 +252,7 @@ void optionalLongParameterQuery() { "{'name':'Rhino', 'numberOfLegs':4, 'numberOfTeeth':30, 'price':2215390.3}]"); AnimalApi api = fixture.build(AnimalApi.class); List animals = api.getAnimalsByTeeth(OptionalLong.of(30)); - then(fixture.query()).isEqualTo("query AnimalsByTeeth($numberOfTeeth: BigInteger) { " + + then(fixture.query()).isEqualTo("query animalsByTeeth($numberOfTeeth: BigInteger) { " + "animalsByTeeth(numberOfTeeth: $numberOfTeeth) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'numberOfTeeth':30}"); then(animals).containsExactly( @@ -275,7 +275,7 @@ void optionalLongMutationTest() { fixture.returnsData("'newAnimal':{'name':'Bat', 'numberOfTeeth':20}"); AnimalApi api = fixture.build(AnimalApi.class); Animal animal = api.newAnimal(new Animal("Bat", OptionalLong.of(20))); - then(fixture.query()).isEqualTo("mutation NewAnimal($animal: AnimalInput) " + + then(fixture.query()).isEqualTo("mutation newAnimal($animal: AnimalInput) " + "{ newAnimal(animal: $animal) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'animal':{'name':'Bat','numberOfTeeth':" + "20}}"); @@ -289,7 +289,7 @@ void optionalDoubleParameterQuery() { " {'name':'Rhino', 'numberOfLegs':4, 'numberOfTeeth':30, 'price':2215390.3}]"); AnimalApi api = fixture.build(AnimalApi.class); List animals = api.getAnimalsByPrice(OptionalDouble.of(2215390.3)); - then(fixture.query()).isEqualTo("query AnimalsByPrice($price: Float) { " + + then(fixture.query()).isEqualTo("query animalsByPrice($price: Float) { " + "animalsByPrice(price: $price) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'price':2215390.3}"); then(animals).containsExactly( @@ -308,7 +308,7 @@ void optionalDoubleMutationTest() { fixture.returnsData("'newAnimal':{'name':'Labrador', 'price':6610.50}"); AnimalApi api = fixture.build(AnimalApi.class); Animal animal = api.newAnimal(new Animal("Labrador", OptionalDouble.of(6610.50))); - then(fixture.query()).isEqualTo("mutation NewAnimal($animal: AnimalInput) " + + then(fixture.query()).isEqualTo("mutation newAnimal($animal: AnimalInput) " + "{ newAnimal(animal: $animal) {name numberOfLegs numberOfTeeth price} }"); then(fixture.variables()).isEqualTo("{'animal':{'name':'Labrador','price':" + "6610.5}}"); @@ -359,7 +359,7 @@ void optionalNumberNull() { fixture.returnsData("'randomCar':{'boo':[null, 3, null]}"); CarApi api = fixture.build(CarApi.class); Car car = api.getRandomCar(); - then(fixture.query()).isEqualTo("query RandomCar { randomCar {boo} }"); + then(fixture.query()).isEqualTo("query randomCar { randomCar {boo} }"); then(car).isEqualTo(new Car(List.of( OptionalLong.empty(), OptionalLong.of(3), diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java index 412348352..3093fe3c8 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ParametersBehavior.java @@ -33,9 +33,9 @@ void shouldQueryWithStringParam() { String greeting = api.greeting("foo"); - then(fixture.query()).isEqualTo("query Greeting($who: String) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: String) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':'foo'}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -53,9 +53,9 @@ void shouldQueryWithNonNullStringParam() { String greeting = api.greeting("foo"); - then(fixture.query()).isEqualTo("query Greeting($who: String!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: String!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':'foo'}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -66,9 +66,9 @@ void shouldQueryWithJakartaNonNullStringParam() { String greeting = api.jakartaGreeting("foo"); - then(fixture.query()).isEqualTo("query JakartaGreeting($who: String!) { jakartaGreeting(who: $who) }"); + then(fixture.query()).isEqualTo("query jakartaGreeting($who: String!) { jakartaGreeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':'foo'}"); - then(fixture.operationName()).isEqualTo("JakartaGreeting"); + then(fixture.operationName()).isEqualTo("jakartaGreeting"); then(greeting).isEqualTo("hi, foo"); } @@ -79,7 +79,7 @@ void shouldEscapeParamScalarQuery() { String greeting = api.greeting("foo\"bar'\n"); - then(fixture.query()).isEqualTo("query Greeting($who: String) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: String) { greeting(who: $who) }"); then(fixture.rawVariables()).isEqualTo("{\"who\":\"foo\\\"bar'\\n\"}"); then(greeting).isEqualTo("hi, foo"); } @@ -96,7 +96,7 @@ void shouldQueryWithTwoParams() { String greeting = api.greeting("foo", 3); - then(fixture.query()).isEqualTo("query Greeting($who: String, $count: Int!) { greeting(who: $who, count: $count) }"); + then(fixture.query()).isEqualTo("query greeting($who: String, $count: Int!) { greeting(who: $who, count: $count) }"); then(fixture.variables()).isEqualTo("{'who':'foo','count':3}"); then(greeting).isEqualTo("hi, foo 3"); } @@ -127,7 +127,7 @@ void shouldQueryWithObjectParam() { Greeting greeting = api.say(new Greeting("hi", 5)); - then(fixture.query()).isEqualTo("query Say($greet: GreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query say($greet: GreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -160,7 +160,7 @@ void shouldQueryWithRenamedObjectParam() { RenamedGreeting greeting = api.say(new RenamedGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query Say($greet: Greeting) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query say($greet: Greeting) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -193,7 +193,7 @@ void shouldQueryWithNamedInputObjectParam() { NamedInputGreeting greeting = api.say(new NamedInputGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query Say($greet: Greet) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query say($greet: Greet) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -226,7 +226,7 @@ void shouldQueryWithEmptyInputObjectParam() { EmptyInputGreeting greeting = api.say(new EmptyInputGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query Say($greet: EmptyInputGreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query say($greet: EmptyInputGreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -259,7 +259,7 @@ void shouldQueryWithNamedTypeObjectParam() { NamedTypeGreeting greeting = api.say(new NamedTypeGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query Say($greet: NamedTypeGreetingInput) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query say($greet: NamedTypeGreetingInput) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -293,7 +293,7 @@ void shouldQueryWithTypeAndInputObjectParam() { TypeAndInputGreeting greeting = api.say(new TypeAndInputGreeting("hi", 5)); - then(fixture.query()).isEqualTo("query Say($greet: Greet) { say(greet: $greet) {text count} }"); + then(fixture.query()).isEqualTo("query say($greet: Greet) { say(greet: $greet) {text count} }"); then(fixture.variables()).isEqualTo("{'greet':{'text':'hi','count':5}}"); then(greeting.text).isEqualTo("ho"); then(greeting.count).isEqualTo(3); @@ -311,7 +311,7 @@ void shouldQueryWithArrayParam() { boolean success = api.greetings(new String[] { "hi", "ho" }); - then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -328,7 +328,7 @@ void shouldQueryWithListParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -345,7 +345,7 @@ void shouldQueryWithNonNullListParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query Greetings($greets: [String]!) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [String]!) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -362,7 +362,7 @@ void shouldQueryWithListOfNonNullParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query Greetings($greets: [String!]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [String!]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -379,7 +379,7 @@ void shouldQueryWithSetParam() { boolean success = api.greetings(new HashSet<>(asList("hi", "ho"))); - then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -396,7 +396,7 @@ void shouldQueryWithQueueParam() { boolean success = api.greetings(new ArrayDeque<>(asList("hi", "ho"))); - then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -413,7 +413,7 @@ void shouldQueryWithCollectionParam() { boolean success = api.greetings(asList("hi", "ho")); - then(fixture.query()).isEqualTo("query Greetings($greets: [String]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [String]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':['hi','ho']}"); then(success).isTrue(); } @@ -430,7 +430,7 @@ void shouldQueryWithObjectListParam() { boolean success = api.greetings(asList(new Greeting("hi", 5), new Greeting("ho", 3))); - then(fixture.query()).isEqualTo("query Greetings($greets: [GreetingInput]) { greetings(greets: $greets) }"); + then(fixture.query()).isEqualTo("query greetings($greets: [GreetingInput]) { greetings(greets: $greets) }"); then(fixture.variables()).isEqualTo("{'greets':[{'text':'hi','count':5},{'text':'ho','count':3}]}"); then(success).isTrue(); } @@ -457,7 +457,7 @@ void shouldQueryWithListObjectParam() { boolean success = api.foo(new ListObject(asList("hi", "ho"), 3)); - then(fixture.query()).isEqualTo("query Foo($bar: ListObjectInput) { foo(bar: $bar) }"); + then(fixture.query()).isEqualTo("query foo($bar: ListObjectInput) { foo(bar: $bar) }"); then(fixture.variables()).isEqualTo("{'bar':{'texts':['hi','ho'],'count':3}}"); then(success).isTrue(); } @@ -474,9 +474,9 @@ void shouldQueryWithBoolean() { String greeting = api.greeting(true); - then(fixture.query()).isEqualTo("query Greeting($who: Boolean) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: Boolean) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':true}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -492,9 +492,9 @@ void shouldQueryWithPrimitiveBoolean() { String greeting = api.greeting(false); - then(fixture.query()).isEqualTo("query Greeting($who: Boolean!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: Boolean!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':false}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -510,9 +510,9 @@ void shouldQueryWithNonNullBoolean() { String greeting = api.greeting(true); - then(fixture.query()).isEqualTo("query Greeting($who: Boolean!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: Boolean!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':true}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -528,9 +528,9 @@ void shouldQueryWithInteger() { String greeting = api.greeting(123); - then(fixture.query()).isEqualTo("query Greeting($who: Int) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: Int) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -546,9 +546,9 @@ void shouldQueryWithPrimitiveInteger() { String greeting = api.greeting(-12); - then(fixture.query()).isEqualTo("query Greeting($who: Int!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: Int!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':-12}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -564,9 +564,9 @@ void shouldQueryWithNonNullInteger() { String greeting = api.greeting(456); - then(fixture.query()).isEqualTo("query Greeting($who: Int!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: Int!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':456}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -582,9 +582,9 @@ void shouldQueryWithLong() { String greeting = api.greeting(123L); - then(fixture.query()).isEqualTo("query Greeting($who: BigInteger) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: BigInteger) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -600,9 +600,9 @@ void shouldQueryWithPrimitiveLong() { String greeting = api.greeting(123L); - then(fixture.query()).isEqualTo("query Greeting($who: BigInteger!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: BigInteger!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } @@ -618,9 +618,9 @@ void shouldQueryWithNonNullLong() { String greeting = api.greeting(123L); - then(fixture.query()).isEqualTo("query Greeting($who: BigInteger!) { greeting(who: $who) }"); + then(fixture.query()).isEqualTo("query greeting($who: BigInteger!) { greeting(who: $who) }"); then(fixture.variables()).isEqualTo("{'who':123}"); - then(fixture.operationName()).isEqualTo("Greeting"); + then(fixture.operationName()).isEqualTo("greeting"); then(greeting).isEqualTo("hi, foo"); } } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java index 2a44d3cea..3eb2983b3 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/ScalarBehavior.java @@ -49,7 +49,7 @@ void shouldCallBoolQuery() { boolean bool = api.bool(true); - then(fixture.query()).isEqualTo("query Bool($in: Boolean!) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query bool($in: Boolean!) { bool(in: $in) }"); then(bool).isTrue(); } @@ -110,7 +110,7 @@ void shouldCallBooleanQuery() { Boolean bool = api.bool(true); - then(fixture.query()).isEqualTo("query Bool($in: Boolean) { bool(in: $in) }"); + then(fixture.query()).isEqualTo("query bool($in: Boolean) { bool(in: $in) }"); then(bool).isTrue(); } } @@ -134,7 +134,7 @@ void shouldCallByteQuery() { Byte code = api.code((byte) 1); - then(fixture.query()).isEqualTo("query Code($in: Int) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: Int) { code(in: $in) }"); then(code).isEqualTo((byte) 5); } @@ -145,7 +145,7 @@ void shouldCallPrimitiveByteQuery() { byte code = api.code((byte) 1); - then(fixture.query()).isEqualTo("query Code($in: Int!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: Int!) { code(in: $in) }"); then(code).isEqualTo((byte) 5); } @@ -191,7 +191,7 @@ void shouldCallCharacterFromStringQuery() { Character c = api.code('c'); - then(fixture.query()).isEqualTo("query Code($in: String) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: String) { code(in: $in) }"); then(c).isEqualTo('a'); } @@ -212,7 +212,7 @@ void shouldCallCharacterFromNumberQuery() { Character c = api.code('c'); - then(fixture.query()).isEqualTo("query Code($in: String) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: String) { code(in: $in) }"); then(c).isEqualTo('a'); } @@ -245,7 +245,7 @@ void shouldCallPrimitiveCharQuery() { char c = api.code('c'); - then(fixture.query()).isEqualTo("query Code($in: String!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: String!) { code(in: $in) }"); then(c).isEqualTo('a'); } @@ -279,7 +279,7 @@ void shouldCallShortQuery() { Short code = api.code((short) 2); - then(fixture.query()).isEqualTo("query Code($in: Int) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: Int) { code(in: $in) }"); then(code).isEqualTo((short) 5); } @@ -312,7 +312,7 @@ void shouldCallPrimitiveShortQuery() { short code = api.code((short) 2); - then(fixture.query()).isEqualTo("query Code($in: Int!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: Int!) { code(in: $in) }"); then(code).isEqualTo((short) 5); } } @@ -336,7 +336,7 @@ void shouldCallIntegerQuery() { Integer code = api.code(3); - then(fixture.query()).isEqualTo("query Code($in: Int) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: Int) { code(in: $in) }"); then(code).isEqualTo(5); } @@ -380,7 +380,7 @@ void shouldCallIntQuery() { int code = api.code(3); - then(fixture.query()).isEqualTo("query Code($in: Int!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: Int!) { code(in: $in) }"); then(code).isEqualTo(5); } } @@ -404,7 +404,7 @@ void shouldCallLongQuery() { Long code = api.code(7L); - then(fixture.query()).isEqualTo("query Code($in: BigInteger) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: BigInteger) { code(in: $in) }"); then(code).isEqualTo(5L); } @@ -437,7 +437,7 @@ void shouldCallPrimitiveLongQuery() { long code = api.code(7L); - then(fixture.query()).isEqualTo("query Code($in: BigInteger!) { code(in: $in) }"); + then(fixture.query()).isEqualTo("query code($in: BigInteger!) { code(in: $in) }"); then(code).isEqualTo(5L); } } @@ -461,7 +461,7 @@ void shouldCallFloatQuery() { Float number = api.number(7.8f); - then(fixture.query()).isEqualTo("query Number($in: Float) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: Float) { number(in: $in) }"); then(number).isEqualTo(123.456f); } @@ -472,7 +472,7 @@ void shouldCallPrimitiveFloatQuery() { float number = api.number(7.8f); - then(fixture.query()).isEqualTo("query Number($in: Float!) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: Float!) { number(in: $in) }"); then(number).isEqualTo(123.456f); } } @@ -496,7 +496,7 @@ void shouldCallDoubleQuery() { Double number = api.number(4.5); - then(fixture.query()).isEqualTo("query Number($in: Float) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: Float) { number(in: $in) }"); then(number).isEqualTo(123.456D); } @@ -507,7 +507,7 @@ void shouldCallPrimitiveDoubleQuery() { double number = api.number(4.5); - then(fixture.query()).isEqualTo("query Number($in: Float!) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: Float!) { number(in: $in) }"); then(number).isEqualTo(123.456D); } } @@ -527,7 +527,7 @@ void shouldCallReallyLongIntegerQuery() { BigInteger number = api.number(BigInteger.TEN); - then(fixture.query()).isEqualTo("query Number($in: BigInteger) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: BigInteger) { number(in: $in) }"); then(number).isEqualTo(reallyLongInteger); } @@ -539,7 +539,7 @@ void shouldCallNotSoLongIntegerQuery() { BigInteger number = api.number(BigInteger.TEN); - then(fixture.query()).isEqualTo("query Number($in: BigInteger) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: BigInteger) { number(in: $in) }"); then(number).isEqualTo(notSoLongInteger); } } @@ -559,7 +559,7 @@ void shouldCallReallyLongDecimalQuery() { BigDecimal number = api.number(BigDecimal.valueOf(12.34)); - then(fixture.query()).isEqualTo("query Number($in: BigDecimal) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: BigDecimal) { number(in: $in) }"); then(number).isEqualTo(reallyLongDecimal); } @@ -571,7 +571,7 @@ void shouldCallNotSoLongDecimalQuery() { BigDecimal number = api.number(BigDecimal.valueOf(12.34)); - then(fixture.query()).isEqualTo("query Number($in: BigDecimal) { number(in: $in) }"); + then(fixture.query()).isEqualTo("query number($in: BigDecimal) { number(in: $in) }"); then(number).isEqualTo(notSoLongDecimal); } } @@ -717,7 +717,7 @@ void shouldCallStringQuery() { String greeting = api.greeting("in"); - then(fixture.query()).isEqualTo("query Greeting($in: String) { greeting(in: $in) }"); + then(fixture.query()).isEqualTo("query greeting($in: String) { greeting(in: $in) }"); then(greeting).isEqualTo("dummy-greeting"); } @@ -729,7 +729,7 @@ void shouldCallIdQuery() { String out = api.idea("stringId", singletonList("x"), singletonList("x"), singletonList("x"), singletonList("x"), 1L, 2, 3L, singletonList(5L), 4, UUID.randomUUID()); - then(fixture.query()).isEqualTo("query Idea(" + + then(fixture.query()).isEqualTo("query idea(" + "$stringId: ID, " + "$stringListId: [ID], " + "$stringListInnerNonNullId: [ID!], " + @@ -763,7 +763,7 @@ void shouldCallNonNullIdQuery() { String out = api.idea("stringId", 1L, 2, 3L, 4, UUID.randomUUID()); - then(fixture.query()).isEqualTo("query Idea(" + + then(fixture.query()).isEqualTo("query idea(" + "$stringId: ID!, " + "$primitiveLongId: ID!, " + "$primitiveIntId: ID!, " + @@ -787,7 +787,7 @@ void shouldCallScalarWithValueOfQuery() { Integer value = api.foo(); - then(fixture.query()).isEqualTo("query Foo { foo }"); + then(fixture.query()).isEqualTo("query foo { foo }"); then(value).isEqualTo(123456); } @@ -799,7 +799,7 @@ void shouldCallScalarWithParseQuery() { LocalDate value = api.now(); - then(fixture.query()).isEqualTo("query Now { now }"); + then(fixture.query()).isEqualTo("query now { now }"); then(value).isEqualTo(now); } @@ -810,7 +810,7 @@ void shouldCallNonScalarWithStringConstructorApiQuery() { NonScalarWithStringConstructor result = api.foo(); - then(fixture.query()).isEqualTo("query Foo { foo {value} }"); + then(fixture.query()).isEqualTo("query foo { foo {value} }"); then(result.value).isEqualTo("1234"); } @@ -832,7 +832,7 @@ void shouldCallScalarWithStringConstructorMethodQuery() { ScalarWithStringConstructorMethod value = api.foo(); - then(fixture.query()).isEqualTo("query Foo { foo }"); + then(fixture.query()).isEqualTo("query foo { foo }"); then(value.text).isEqualTo("bar"); } @@ -843,7 +843,7 @@ void shouldCallScalarWithOfConstructorMethodQuery() { ScalarWithOfConstructorMethod value = api.foo(); - then(fixture.query()).isEqualTo("query Foo { foo }"); + then(fixture.query()).isEqualTo("query foo { foo }"); then(value.text).isEqualTo("x-bar"); } } @@ -870,7 +870,7 @@ void shouldCallStringGetterQuery() { String value = api.getGreeting(); - then(fixture.query()).isEqualTo("query Greeting { greeting }"); + then(fixture.query()).isEqualTo("query greeting { greeting }"); then(value).isEqualTo("foo"); } @@ -881,7 +881,7 @@ void shouldCallJustGetQuery() { String value = api.get(); - then(fixture.query()).isEqualTo("query Get { get }"); + then(fixture.query()).isEqualTo("query get { get }"); then(value).isEqualTo("foo"); } @@ -892,7 +892,7 @@ void shouldCallOneCharGetterQuery() { String value = api.getG(); - then(fixture.query()).isEqualTo("query G { g }"); + then(fixture.query()).isEqualTo("query g { g }"); then(value).isEqualTo("foo"); } @@ -903,7 +903,7 @@ void shouldCallGetAndOneLowerCharQuery() { String value = api.gets(); - then(fixture.query()).isEqualTo("query Gets { gets }"); + then(fixture.query()).isEqualTo("query gets { gets }"); then(value).isEqualTo("foo"); } @@ -914,7 +914,7 @@ void shouldCallGetAndLowerCharsQuery() { String value = api.getting(); - then(fixture.query()).isEqualTo("query Getting { getting }"); + then(fixture.query()).isEqualTo("query getting { getting }"); then(value).isEqualTo("foo"); } } @@ -974,7 +974,7 @@ void shouldCallLocalDateQuery() { LocalDateApi api = fixture.builder().build(LocalDateApi.class); LocalDate value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($date: Date) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: Date) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -988,7 +988,7 @@ void shouldCallLocalTimeQuery() { LocalTime value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($date: Time) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: Time) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1002,7 +1002,7 @@ void shouldCallOffsetTimeQuery() { OffsetTime value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($date: Time) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: Time) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1016,7 +1016,7 @@ void shouldCallLocalDateTimeQuery() { LocalDateTime value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1030,7 +1030,7 @@ void shouldCallOffsetDateTimeQuery() { OffsetDateTime value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1044,7 +1044,7 @@ void shouldCallZonedDateTimeQuery() { ZonedDateTime value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1058,7 +1058,7 @@ void shouldCallInstantQuery() { Instant value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($instant: DateTime) { foo(instant: $instant) }"); + then(fixture.query()).isEqualTo("query foo($instant: DateTime) { foo(instant: $instant) }"); then(fixture.variables()).isEqualTo("{'instant':'" + in + "'}"); then(value).isEqualTo(out); } @@ -1072,7 +1072,7 @@ void shouldCallUtilDateQuery() { Date value = api.foo(Date.from(in)); - then(fixture.query()).isEqualTo("query Foo($date: DateTime) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: DateTime) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(Date.from(out)); } @@ -1089,7 +1089,7 @@ void shouldCallSqlDateQuery() { SqlDateApi api = fixture.builder().build(SqlDateApi.class); java.sql.Date value = api.foo(sqlIn); - then(fixture.query()).isEqualTo("query Foo($date: Date) { foo(date: $date) }"); + then(fixture.query()).isEqualTo("query foo($date: Date) { foo(date: $date) }"); then(fixture.variables()).isEqualTo("{'date':'" + in + "'}"); then(value).isEqualTo(sqlOut); } @@ -1122,7 +1122,7 @@ void shouldCallUuidQuery() { UUID value = api.foo(in1, in2); - then(fixture.query()).isEqualTo("query Foo($uuid: String, $id: ID) { foo(uuid: $uuid, id: $id) }"); + then(fixture.query()).isEqualTo("query foo($uuid: String, $id: ID) { foo(uuid: $uuid, id: $id) }"); then(fixture.variables()).isEqualTo("{'uuid':'" + in1 + "','id':'" + in2 + "'}"); then(value).isEqualTo(out); } @@ -1138,7 +1138,7 @@ void shouldCallNestedUuidIdQuery() { NestedUuidId value = api.foo(in); - then(fixture.query()).isEqualTo("query Foo($uuid: NestedUuidIdInput) { foo(uuid: $uuid) {id} }"); + then(fixture.query()).isEqualTo("query foo($uuid: NestedUuidIdInput) { foo(uuid: $uuid) {id} }"); then(fixture.variables()).isEqualTo("{'uuid':{'id':'" + in.id + "'}}"); then(value.id).isEqualTo(out.id); } diff --git a/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java index 9fd7a8b48..71ebacb3b 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/TypesafeResponseBehavior.java @@ -50,7 +50,7 @@ void shouldParseExtensionsInTypesafeResponse() { StringApi api = fixture.build(StringApi.class); TypesafeResponse result = api.greetings(); - then(fixture.query()).isEqualTo("query Greetings { greetings }"); + then(fixture.query()).isEqualTo("query greetings { greetings }"); then(result.getExtensions()).isEqualTo(Json.createObjectBuilder() .add("pi", 3.14159) .add("extension", "bell") diff --git a/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java b/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java index c43fa05c1..f4e691d88 100644 --- a/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java +++ b/client/tck/src/main/java/tck/graphql/typesafe/UnionBehavior.java @@ -56,7 +56,7 @@ void shouldUnionFindSpiderMan() { var response = api.find("Spider-Man"); - then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); @@ -72,7 +72,7 @@ void shouldNotUnionFindFoo() { var response = api.find("Foo"); - then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); @@ -88,7 +88,7 @@ void shouldNotUnionFindSomethingUnexpected() { var throwable = catchThrowable(() -> api.find("Expect the unexpected")); - then(fixture.query()).isEqualTo("query Find($name: String) { find(name: $name){" + + then(fixture.query()).isEqualTo("query find($name: String) { find(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); @@ -107,7 +107,7 @@ void shouldUnionFindAll() { var response = api.findAll("Spider-Man"); - then(fixture.query()).isEqualTo("query FindAll($name: String) { findAll(name: $name){" + + then(fixture.query()).isEqualTo("query findAll($name: String) { findAll(name: $name){" + "__typename " + "... on SuperHero {name} " + "... on SuperHeroNotFound {message}} }"); diff --git a/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java b/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java index c0e25792d..143b48299 100644 --- a/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java +++ b/server/integration-tests/src/test/java/io/smallrye/graphql/tests/client/typesafe/directives/ServerApi.java @@ -11,7 +11,7 @@ @GraphQLApi public class ServerApi { - private final static String EXPECTED_QUERY = "query QuerySomeClass($someObject: SomeClassServerInput, $simpleType: Boolean! @variableDefinitionDirective @variableDefinitionDirective(fields: \"a\")) { querySomeClass(someObject: $someObject, simpleType: $simpleType) @fieldDirective(fields: [1]) @fieldDirective(fields: [2, 3]) {id @fieldDirective(fields: [4]) number} }"; + private final static String EXPECTED_QUERY = "query querySomeClass($someObject: SomeClassServerInput, $simpleType: Boolean! @variableDefinitionDirective @variableDefinitionDirective(fields: \"a\")) { querySomeClass(someObject: $someObject, simpleType: $simpleType) @fieldDirective(fields: [1]) @fieldDirective(fields: [2, 3]) {id @fieldDirective(fields: [4]) number} }"; @Inject SmallRyeContext context; From cc93826b3838713b2e087e90252cdd3f10b7b87b Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Thu, 19 Sep 2024 20:02:31 +0300 Subject: [PATCH 4/7] Remove group, refactor for working with namespaces --- .../VertxTypesafeGraphQLClientBuilder.java | 5 +- .../VertxTypesafeGraphQLClientProxy.java | 19 ++--- .../client/impl/typesafe/QueryBuilder.java | 16 +--- .../client/impl/typesafe/ResultBuilder.java | 19 ++--- .../typesafe/reflection/MethodInvocation.java | 65 ++++++-------- .../client/model/ClientModelBuilder.java | 3 +- .../graphql/client/model/QueryBuilder.java | 16 +--- .../client/model/helper/OperationModel.java | 68 ++++++--------- .../client/model/ClientModelBuilderTest.java | 2 +- .../graphql/schema/SchemaBuilder.java | 73 +++------------- .../graphql/schema/helper/GroupHelper.java | 82 ------------------ .../schema/helper/NamespaceHelper.java | 20 +++-- .../smallrye/graphql/index/NamespaceTest.java | 2 +- .../smallrye/graphql/schema/model/Group.java | 69 --------------- .../smallrye/graphql/schema/model/Schema.java | 84 ++++--------------- .../io/smallrye/graphql/api/Namespace.java | 4 +- .../smallrye/graphql/bootstrap/Bootstrap.java | 71 +--------------- .../namespace/ExperimentalNamespaceApi.java | 2 +- .../ExperimentalNamespaceWithErrorApi.java | 2 +- 19 files changed, 127 insertions(+), 495 deletions(-) delete mode 100644 common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java delete mode 100644 common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java diff --git a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java index a4dc50d2b..404c5a1b4 100644 --- a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java +++ b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java @@ -152,7 +152,7 @@ public T build(Class apiClass) { if (nameAnnotation != null && namespaceAnnotation != null) { throw new RuntimeException("You can only use one of the annotations - @Name or @Namespace " + - "over the GraphQLClientApi interface. Please, fix next interface: " + apiClass.getName()); + "over the GraphQLClientApi interface. Please, fix the interface: " + apiClass.getName()); } if (this.options == null) { @@ -195,8 +195,7 @@ public T build(Class apiClass) { endpoint, websocketUrl, executeSingleOperationsOverWebsocket, httpClient, webClient, subprotocols, websocketInitializationTimeout, - allowUnexpectedResponseFields, - namespaceAnnotation != null); + allowUnexpectedResponseFields); return apiClass.cast(Proxy.newProxyInstance(getClassLoader(apiClass), new Class[] { apiClass }, (proxy, method, args) -> invoke(graphQLClient, method, args))); diff --git a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java index f5017932d..f9fe262d9 100644 --- a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java +++ b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientProxy.java @@ -81,7 +81,6 @@ class VertxTypesafeGraphQLClientProxy { private final ClientModel clientModel; private final boolean executeSingleOperationsOverWebsocket; private final boolean allowUnexpectedResponseFields; - private final boolean useNamespace; // Do NOT use this field directly, always retrieve by calling `webSocketHandler()`. // When a websocket connection is required, then this is populated with a Uni @@ -105,8 +104,7 @@ class VertxTypesafeGraphQLClientProxy { WebClient webClient, List subprotocols, Integer subscriptionInitializationTimeout, - boolean allowUnexpectedResponseFields, - boolean useNamespace) { + boolean allowUnexpectedResponseFields) { this.api = api; this.clientModel = clientModel; this.additionalHeaders = additionalHeaders; @@ -136,7 +134,6 @@ class VertxTypesafeGraphQLClientProxy { this.subprotocols = subprotocols; this.subscriptionInitializationTimeout = subscriptionInitializationTimeout; this.allowUnexpectedResponseFields = allowUnexpectedResponseFields; - this.useNamespace = useNamespace; } Object invoke(MethodInvocation method) { @@ -178,7 +175,7 @@ private Object executeSingleResultOperationOverHttpSync(MethodInvocation method, } return new ResultBuilder(method, response.bodyAsString(), response.statusCode(), response.statusMessage(), convertHeaders(allHeaders), - allowUnexpectedResponseFields, useNamespace).read(); + allowUnexpectedResponseFields).read(); } private Uni executeSingleResultOperationOverHttpAsync(MethodInvocation method, JsonObject request, @@ -196,7 +193,7 @@ private Uni executeSingleResultOperationOverHttpAsync(MethodInvocation m return Uni.createFrom().completionStage(postAsync(request.toString(), allHeaders)) .map(response -> new ResultBuilder(method, response.bodyAsString(), response.statusCode(), response.statusMessage(), convertHeaders(allHeaders), - allowUnexpectedResponseFields, useNamespace).read()); + allowUnexpectedResponseFields).read()); } else { // when all dynamic headers have been obtained, proceed with the request return Uni.combine().all().unis(unis) @@ -205,7 +202,7 @@ private Uni executeSingleResultOperationOverHttpAsync(MethodInvocation m .completionStage(postAsync(request.toString(), allHeaders)) .map(response -> new ResultBuilder(method, response.bodyAsString(), response.statusCode(), response.statusMessage(), convertHeaders(allHeaders), - allowUnexpectedResponseFields, useNamespace).read())); + allowUnexpectedResponseFields).read())); } } @@ -235,7 +232,7 @@ private Uni executeSingleResultOperationOverWebsocket(MethodInvocation m } }) .onItem().transform(data -> { - Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields, useNamespace).read(); + Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields).read(); if (object != null) { return object; } else { @@ -260,7 +257,7 @@ private Multi executeSubscriptionOverWebsocket(MethodInvocation method, handlerRef.get().cancelMulti(operationId.get()); }) .onItem().transform(data -> { - Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields, useNamespace).read(); + Object object = new ResultBuilder(method, data, allowUnexpectedResponseFields).read(); if (object != null) { return object; } else { @@ -306,13 +303,13 @@ private JsonObject request(MethodInvocation method) { JsonObjectBuilder request = jsonObjectFactory.createObjectBuilder(); String query; if (clientModel == null) { - query = queryCache.computeIfAbsent(method.getKey(), key -> new QueryBuilder(method).build(useNamespace)); + query = queryCache.computeIfAbsent(method.getKey(), key -> new QueryBuilder(method).build()); } else { query = clientModel.getOperationMap().get(method.getMethodKey()); } request.add("query", query); request.add("variables", variables(method)); - request.add("operationName", method.getOperationName(useNamespace)); + request.add("operationName", method.getOperationName()); JsonObject result = request.build(); log.tracef("full graphql request: %s", result.toString()); return result; diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java index f5d4d677d..d15ddf51d 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/QueryBuilder.java @@ -21,18 +21,14 @@ public QueryBuilder(MethodInvocation method) { this.method = method; } - public String build(boolean useNamespace) { + public String build() { StringBuilder request = new StringBuilder(method.getOperationTypeAsString()); request.append(" "); - request.append(method.getOperationName(useNamespace)); + request.append(method.getOperationName()); if (method.hasValueParameters()) request.append(method.valueParameters().map(this::declare).collect(joining(", ", "(", ")"))); - if (useNamespace) { - method.getNamespaces().forEach(namespace -> request.append(" { ").append(namespace)); - } else if (method.getGroupName() != null) { - request.append(" { ").append(method.getGroupName()); - } + method.getNamespaces().forEach(namespace -> request.append(" { ").append(namespace)); if (method.isSingle()) { request.append(" { "); @@ -49,11 +45,7 @@ public String build(boolean useNamespace) { request.append(" }"); } - if (useNamespace) { - request.append(" }".repeat(method.getNamespaces().size())); - } else if (method.getGroupName() != null) { - request.append(" }"); - } + request.append(" }".repeat(method.getNamespaces().size())); return request.toString(); } diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java index 1f636bbc9..8506b2411 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/ResultBuilder.java @@ -38,11 +38,9 @@ public class ResultBuilder { private JsonObject data; private JsonObject extensions; private Map> transportMeta; - private final boolean useNamespace; - public ResultBuilder(MethodInvocation method, String responseString, boolean allowUnexpectedResponseFields, - boolean useNamespace) { - this(method, responseString, null, null, null, allowUnexpectedResponseFields, useNamespace); + public ResultBuilder(MethodInvocation method, String responseString, boolean allowUnexpectedResponseFields) { + this(method, responseString, null, null, null, allowUnexpectedResponseFields); } public ResultBuilder(MethodInvocation method, @@ -50,15 +48,13 @@ public ResultBuilder(MethodInvocation method, Integer statusCode, String statusMessage, Map> transportMeta, - boolean allowUnexpectedResponseFields, - boolean useNamespace) { + boolean allowUnexpectedResponseFields) { this.method = method; this.statusCode = statusCode; this.statusMessage = statusMessage; this.responseString = responseString; this.transportMeta = transportMeta; this.response = ResponseReader.parseGraphQLResponse(responseString, allowUnexpectedResponseFields); - this.useNamespace = useNamespace; } public Object read() { @@ -98,13 +94,8 @@ private JsonObject readData() { return null; JsonObject data = response.getJsonObject("data"); - - if (useNamespace) { - for (String namespace : method.getNamespaces()) { - data = data.getJsonObject(namespace); - } - } else if (method.getGroupName() != null) { - data = data.getJsonObject(method.getGroupName()); + for (String namespace : method.getNamespaces()) { + data = data.getJsonObject(namespace); } if (method.isSingle() && !data.containsKey(method.getName())) diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java index 4f9cbcbe6..5f44dc2a4 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/typesafe/reflection/MethodInvocation.java @@ -1,6 +1,5 @@ package io.smallrye.graphql.client.impl.typesafe.reflection; -import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import java.io.Closeable; @@ -11,7 +10,6 @@ import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -40,16 +38,16 @@ public static MethodInvocation of(Method method, Object... args) { private final TypeInfo type; private final Method method; private final Object[] parameterValues; - private final String groupName; - private List namespaces; - private String operationName; + private final List namespaces; + private final String operationName; private List parameters; private MethodInvocation(TypeInfo type, Method method, Object[] parameterValues) { this.type = type; this.method = method; this.parameterValues = parameterValues; - this.groupName = readGroupName(method); + this.namespaces = readNamespaces(method); + this.operationName = readOperationName(this.namespaces); } @Override @@ -268,47 +266,38 @@ public String getOperationTypeAsString() { } } - public String getGroupName() { - return groupName; + public List getNamespaces() { + return namespaces; } - private String readGroupName(Method method) { - Name annotation = method.getDeclaringClass().getAnnotation(Name.class); - if (annotation != null) { - String groupName = annotation.value().trim(); - if (!groupName.isEmpty()) { - return groupName; - } - } - return null; + public String getOperationName() { + return operationName; } - public List getNamespaces() { - if (namespaces == null) { - Namespace annotation = method.getDeclaringClass().getAnnotation(Namespace.class); - if (annotation != null) { - namespaces = Arrays.stream(annotation.value().split("/")) - .map(String::trim) - .collect(Collectors.toList()); - } else { - namespaces = List.of(); + private List readNamespaces(Method method) { + if (method.getDeclaringClass().isAnnotationPresent(Namespace.class)) { + String[] names = method.getDeclaringClass().getAnnotation(Namespace.class).value(); + if (names.length > 0) { + return List.of(names); + } + } else if (method.getDeclaringClass().isAnnotationPresent(Name.class)) { + String name = method.getDeclaringClass().getAnnotation(Name.class).value(); + if (!name.isBlank()) { + return List.of(name); } } - return namespaces; + return List.of(); } - public String getOperationName(boolean useNamespace) { - if (operationName == null) { - if (useNamespace) { - operationName = getNamespaces().stream().map(this::makeFirstLetterUppercase).collect(joining()) - + makeFirstLetterUppercase(getName()); - } else { - operationName = getGroupName() == null - ? getName() - : makeFirstLetterUppercase(getGroupName()) + makeFirstLetterUppercase(getName()); - } + private String readOperationName(List names) { + if (names.isEmpty()) { + return getName(); + } else { + String namespace = names.stream() + .map(this::makeFirstLetterUppercase) + .collect(Collectors.joining()); + return namespace + makeFirstLetterUppercase(getName()); } - return operationName; } private String makeFirstLetterUppercase(String value) { diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java index ebd48eab5..abaf682a0 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java @@ -64,10 +64,9 @@ private ClientModels generateClientModels() { graphQLApiAnnotations.forEach(graphQLApiAnnotation -> { ClientModel operationMap = new ClientModel(); ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); - boolean useNamespace = apiClass.hasDeclaredAnnotation(NAMESPACE); List methods = getAllMethodsIncludingFromSuperClasses(apiClass); methods.forEach(method -> { - String query = new QueryBuilder(method).build(useNamespace); + String query = new QueryBuilder(method).build(); LOG.debugf("[%s] – Query created: %s", apiClass.name().toString(), query); operationMap.getOperationMap() .putIfAbsent(OperationModel.of(method).getMethodKey(), query); diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java index 613946e55..9ed0f5d8b 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/QueryBuilder.java @@ -31,19 +31,15 @@ public QueryBuilder(MethodInfo method) { * * @return The constructed GraphQL query string. */ - public String build(boolean useNamespace) { + public String build() { StringBuilder request = new StringBuilder(method.getOperationTypeAsString()); request.append(" "); - request.append(method.getOperationName(useNamespace)); + request.append(method.getOperationName()); if (method.hasValueParameters()) { request.append(method.valueParameters().stream().map(method::declare).collect(joining(", ", "(", ")"))); } - if (useNamespace) { - method.getNamespaces().forEach(namespace -> request.append(" { ").append(namespace)); - } else if (method.getGroupName() != null) { - request.append(" { ").append(method.getGroupName()); - } + method.getNamespaces().forEach(namespace -> request.append(" { ").append(namespace)); if (method.isSingle()) { request.append(" { "); @@ -65,11 +61,7 @@ public String build(boolean useNamespace) { request.append(" }"); } - if (useNamespace) { - request.append(" }".repeat(method.getNamespaces().size())); - } else if (method.getGroupName() != null) { - request.append(" }"); - } + request.append(" }".repeat(method.getNamespaces().size())); return request.toString(); } diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java index b83592514..51b7fb848 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/helper/OperationModel.java @@ -10,7 +10,6 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -39,9 +38,8 @@ public class OperationModel implements NamedElement { private final Stack expressionStack = new Stack<>(); private Stack rawParametrizedTypes = new Stack<>(); private final List directives; - private final String groupName; - private String operationName; - private List namespaces; + private final String operationName; + private final List namespaces; /** * Creates a new {@code OperationModel} instance based on the provided Jandex {@link MethodInfo}. @@ -55,7 +53,8 @@ public class OperationModel implements NamedElement { getDirectiveLocation(), AnnotationTarget.Kind.METHOD) .map(DirectiveInstance::of) .collect(toList()); - this.groupName = readGroupName(method); + this.namespaces = readNamespaces(method); + this.operationName = readOperationName(this.namespaces); } /** @@ -403,51 +402,38 @@ private boolean isRawParametrizedType(TypeModel type) { return type.isCustomParametrizedType() && !type.getFirstRawType().isTypeVariable(); } - public String getGroupName() { - return groupName; + public List getNamespaces() { + return namespaces; } - private String readGroupName(MethodInfo method) { - List annotationInstances = method.declaringClass().annotations(NAME); - for (AnnotationInstance annotationInstance : annotationInstances) { - if (annotationInstance.target().kind() == AnnotationTarget.Kind.CLASS) { - if (annotationInstance.target().asClass().name().equals(method.declaringClass().name())) { - String groupName = annotationInstance.value().asString().trim(); - if (!groupName.isEmpty()) { - return groupName; - } - } - } - } - return null; + public String getOperationName() { + return operationName; } - public List getNamespaces() { - if (namespaces == null) { - AnnotationInstance annotationInstance = method.declaringClass().declaredAnnotation(NAMESPACE); - if (annotationInstance != null) { - namespaces = Arrays.stream(annotationInstance.value().asString().split("/")) - .map(String::trim) - .collect(Collectors.toList()); - } else { - namespaces = List.of(); + private List readNamespaces(MethodInfo method) { + if (method.declaringClass().hasDeclaredAnnotation(NAMESPACE)) { + String[] names = method.declaringClass().declaredAnnotation(NAMESPACE).value().asStringArray(); + if (names.length > 0) { + return List.of(names); + } + } else if (method.declaringClass().hasDeclaredAnnotation(NAME)) { + String value = method.declaringClass().declaredAnnotation(NAME).value().asString(); + if (!value.isEmpty()) { + return List.of(value); } } - return namespaces; + return List.of(); } - public String getOperationName(boolean useNamespace) { - if (operationName == null) { - if (useNamespace) { - operationName = getNamespaces().stream().map(this::makeFirstLetterUppercase).collect(joining()) - + makeFirstLetterUppercase(getName()); - } else { - operationName = getGroupName() == null - ? getName() - : makeFirstLetterUppercase(getGroupName()) + makeFirstLetterUppercase(getName()); - } + private String readOperationName(List names) { + if (names.isEmpty()) { + return getName(); + } else { + String namespace = names.stream() + .map(this::makeFirstLetterUppercase) + .collect(joining()); + return namespace + makeFirstLetterUppercase(getName()); } - return operationName; } private String makeFirstLetterUppercase(String value) { diff --git a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java index 8e2de88ef..649187fb7 100644 --- a/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java +++ b/client/model-builder/src/test/java/io/smallrye/graphql/client/model/ClientModelBuilderTest.java @@ -245,7 +245,7 @@ void namedClientModelTest() throws IOException { "mutation NamedUpdate($s: String) { named { update(s: $s) } }"); } - @Namespace("first/second") + @Namespace({ "first", "second" }) @GraphQLClientApi(configKey = "namespaced-string-api") interface NamespacedClientApi { @Query("findAll") diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java index be7792404..2de060fa9 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java @@ -44,13 +44,11 @@ import io.smallrye.graphql.schema.helper.BeanValidationDirectivesHelper; import io.smallrye.graphql.schema.helper.DescriptionHelper; import io.smallrye.graphql.schema.helper.Directives; -import io.smallrye.graphql.schema.helper.GroupHelper; import io.smallrye.graphql.schema.helper.NamespaceHelper; import io.smallrye.graphql.schema.helper.RolesAllowedDirectivesHelper; import io.smallrye.graphql.schema.helper.TypeAutoNameStrategy; import io.smallrye.graphql.schema.model.DirectiveType; import io.smallrye.graphql.schema.model.ErrorInfo; -import io.smallrye.graphql.schema.model.Group; import io.smallrye.graphql.schema.model.Namespace; import io.smallrye.graphql.schema.model.NamespaceContainer; import io.smallrye.graphql.schema.model.Operation; @@ -155,13 +153,9 @@ private Schema generateSchema() { for (AnnotationInstance graphQLApiAnnotation : graphQLApiAnnotations) { ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); List methods = getAllMethodsIncludingFromSuperClasses(apiClass); - if (apiClass.hasDeclaredAnnotation(NAMESPACE)) { - Optional namespace = NamespaceHelper.getNamespace(graphQLApiAnnotation); - addNamespacedOperations(namespace, schema, methods); - } else { - Optional group = GroupHelper.getGroup(graphQLApiAnnotation); - addOperations(group, schema, methods); - } + NamespaceHelper.getNamespace(graphQLApiAnnotation).ifPresentOrElse( + namespace -> addNamespacedOperations(namespace, schema, methods), + () -> addOperations(schema, methods)); } validateMethods(schema); @@ -192,24 +186,9 @@ private List findNamespacedMethodsErrors(Map .collect(Collectors.toList()); } - private List findGroupedMethodsErrors(Map> groups, Set operations) { - Set keys = groups.keySet().stream().map(Group::getName).collect(Collectors.toSet()); - - return operations.stream() - .filter(operation -> keys.contains(operation.getName())) - .map(operation -> "operation name: " + operation.getName() + ", class: " + operation.getClassName() - + ", method name: " + operation.getMethodName()) - .collect(Collectors.toList()); - } - private void validateMethods(Schema schema) { - List queryErrors = new ArrayList<>(findNamespacedMethodsErrors(schema.getNamespacedQueries(), - schema.getQueries())); - queryErrors.addAll(findGroupedMethodsErrors(schema.getGroupedQueries(), schema.getQueries())); - - List mutationErrors = new ArrayList<>(findNamespacedMethodsErrors(schema.getNamespacedMutations(), - schema.getMutations())); - mutationErrors.addAll(findGroupedMethodsErrors(schema.getGroupedMutations(), schema.getMutations())); + List queryErrors = findNamespacedMethodsErrors(schema.getNamespacedQueries(), schema.getQueries()); + List mutationErrors = findNamespacedMethodsErrors(schema.getNamespacedMutations(), schema.getMutations()); if (!queryErrors.isEmpty() || !mutationErrors.isEmpty()) { throw new RuntimeException("Inconsistent schema. Operation names overlap with namespaces." + @@ -237,7 +216,7 @@ private void validateSubscriptions(Collection graphQLApiAnno if (!errors.isEmpty()) { throw new RuntimeException("Subscriptions can't be nested. " + "Move your subscriptions to another @GraphQLApi class, not marked @Namespace or @Name. " + - "Check next places: " + String.join("; ", errors)); + "Check these places: " + String.join("; ", errors)); } } @@ -441,29 +420,15 @@ private boolean findOutstandingAndAddToSchema(ReferenceType referenceType, C return keepGoing; } - private void addNamespacedOperations(Optional namespace, Schema schema, - List methodInfoList) { + private void addNamespacedOperations(Namespace namespace, Schema schema, List methodInfoList) { for (MethodInfo methodInfo : methodInfoList) { Annotations annotationsForMethod = Annotations.getAnnotationsForMethod(methodInfo); if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.QUERY)) { Operation query = operationCreator.createOperation(methodInfo, OperationType.QUERY, null); - if (namespace.isPresent()) { - schema.addNamespacedQuery(namespace.get(), query); - } else { - schema.addQuery(query); - } + schema.addNamespacedQuery(namespace, query); } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.MUTATION)) { Operation mutation = operationCreator.createOperation(methodInfo, OperationType.MUTATION, null); - if (namespace.isPresent()) { - schema.addNamespacedMutation(namespace.get(), mutation); - } else { - schema.addMutation(mutation); - } - } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) { - if (namespace.isEmpty()) { - Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null); - schema.addSubscription(subscription); - } + schema.addNamespacedMutation(namespace, mutation); } } } @@ -475,30 +440,18 @@ private void addNamespacedOperations(Optional namespace, Schema schem * @param schema the schema to add the operation to. * @param methodInfoList the java methods. */ - private void addOperations(Optional group, Schema schema, List methodInfoList) { + private void addOperations(Schema schema, List methodInfoList) { for (MethodInfo methodInfo : methodInfoList) { Annotations annotationsForMethod = Annotations.getAnnotationsForMethod(methodInfo); if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.QUERY)) { Operation query = operationCreator.createOperation(methodInfo, OperationType.QUERY, null); - if (group.isPresent()) { - schema.addGroupedQuery(group.get(), query); - } else { - schema.addQuery(query); - } + schema.addQuery(query); } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.MUTATION)) { Operation mutation = operationCreator.createOperation(methodInfo, OperationType.MUTATION, null); - if (group.isPresent()) { - schema.addGroupedMutation(group.get(), mutation); - } else { - schema.addMutation(mutation); - } + schema.addMutation(mutation); } else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) { Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null); - if (group.isPresent()) { - schema.addGroupedSubscription(group.get(), subscription); - } else { - schema.addSubscription(subscription); - } + schema.addSubscription(subscription); } } } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java deleted file mode 100644 index 6235cdab3..000000000 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/GroupHelper.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.smallrye.graphql.schema.helper; - -import java.util.List; -import java.util.Optional; - -import org.jboss.jandex.AnnotationInstance; -import org.jboss.jandex.AnnotationValue; -import org.jboss.jandex.ClassInfo; - -import io.smallrye.graphql.schema.Annotations; -import io.smallrye.graphql.schema.model.Group; - -/** - * Helping with Group creation - * - * @author Phillip Kruger (phillip.kruger@redhat.com) - */ -public class GroupHelper { - - private GroupHelper() { - } - - public static Optional getGroup(AnnotationInstance graphQLApiAnnotation) { - Optional name = getName(graphQLApiAnnotation); - if (name.isPresent()) { - Optional description = getDescription(graphQLApiAnnotation); - Group group = new Group(); - group.setName(name.get()); - group.setDescription(description.orElse(null)); - return Optional.of(group); - } - return Optional.empty(); - } - - /** - * This gets the root name (by default 'root). - * This will allow grouping root queries under a logical name. - * - * @param graphQLApiAnnotation - * @return - */ - private static Optional getName(AnnotationInstance graphQLApiAnnotation) { - // Get the name - AnnotationValue value = graphQLApiAnnotation.value(); - if (value != null && value.asString() != null && !value.asString().isEmpty()) { - return Optional.of(value.asString()); - } else { - // Try the Name annotation - ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); - AnnotationInstance nameAnnotation = apiClass.classAnnotation(Annotations.NAME); - if (nameAnnotation != null && nameAnnotation.value() != null && nameAnnotation.value().asString() != null - && !nameAnnotation.value().asString().isEmpty()) { - return Optional.of(nameAnnotation.value().asString()); - } - } - return Optional.empty(); - } - - /** - * Get the description on a class type - * - * @param graphQLApiAnnotation annotation on the class - * @return the optional description - */ - private static Optional getDescription(AnnotationInstance graphQLApiAnnotation) { - ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); - if (apiClass.annotationsMap().containsKey(Annotations.DESCRIPTION)) { - List descriptionAnnotations = apiClass.annotationsMap().get(Annotations.DESCRIPTION); - if (descriptionAnnotations != null && !descriptionAnnotations.isEmpty()) { - for (AnnotationInstance descriptionAnnotation : descriptionAnnotations) { - if (descriptionAnnotation.target().equals(graphQLApiAnnotation.target())) { - AnnotationValue value = descriptionAnnotation.value(); - if (value != null && value.asString() != null && !value.asString().isEmpty()) { - return Optional.of(value.asString()); - } - } - } - } - } - return Optional.empty(); - } -} diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java index 8929cb5da..7e375bd72 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/NamespaceHelper.java @@ -4,7 +4,6 @@ import java.util.Optional; import org.jboss.jandex.AnnotationInstance; -import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; import io.smallrye.graphql.schema.Annotations; @@ -36,9 +35,16 @@ public static Optional getNamespace(AnnotationInstance graphQLApiAnno private static Optional> getNames(AnnotationInstance graphQLApiAnnotation) { ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); if (apiClass.hasDeclaredAnnotation(Annotations.NAMESPACE)) { - AnnotationValue value = apiClass.declaredAnnotation(Annotations.NAMESPACE).value(); - if (!value.asString().isEmpty()) { - return Optional.of(List.of(value.asString().split("/"))); + String[] namespaces = apiClass.declaredAnnotation(Annotations.NAMESPACE).value().asStringArray(); + if (namespaces.length > 0) { + return Optional.of(List.of(namespaces)); + } + } + + if (apiClass.hasDeclaredAnnotation(Annotations.NAME)) { + String value = apiClass.declaredAnnotation(Annotations.NAME).value().asString(); + if (!value.isEmpty()) { + return Optional.of(List.of(value)); } } return Optional.empty(); @@ -53,9 +59,9 @@ private static Optional> getNames(AnnotationInstance graphQLApiAnno private static Optional getDescription(AnnotationInstance graphQLApiAnnotation) { ClassInfo apiClass = graphQLApiAnnotation.target().asClass(); if (apiClass.hasDeclaredAnnotation(Annotations.DESCRIPTION)) { - AnnotationValue value = apiClass.declaredAnnotation(Annotations.DESCRIPTION).value(); - if (value != null && value.asString() != null && !value.asString().isEmpty()) { - return Optional.of(value.asString()); + String value = apiClass.declaredAnnotation(Annotations.DESCRIPTION).value().asString(); + if (!value.isEmpty()) { + return Optional.of(value); } } return Optional.empty(); diff --git a/common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java b/common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java index 7f53b8950..d7b8a370d 100644 --- a/common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java +++ b/common/schema-builder/src/test/java/io/smallrye/graphql/index/NamespaceTest.java @@ -24,7 +24,7 @@ public void apiWithNameTest() { Schema schema = SchemaBuilder.build(index); assertNotNull(schema); - assertEquals(schema.getGroupedQueries().values().size(), 1); + assertEquals(schema.getAllNamespacedQueryOperations().size(), 1); } @Test diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java deleted file mode 100644 index 992c8855a..000000000 --- a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Group.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.smallrye.graphql.schema.model; - -import java.io.Serializable; -import java.util.Objects; - -/** - * Allow grouping of queries and mutations. - * - * @author Phillip Kruger (phillip.kruger@redhat.com) - */ -public class Group implements Serializable { - private String name; - private String description; - - public Group() { - } - - public Group(String name, String description) { - this.name = name; - this.description = description; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 59 * hash + Objects.hashCode(this.name); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Group other = (Group) obj; - if (!Objects.equals(this.name, other.name)) { - return false; - } - return true; - } - - @Override - public String toString() { - return "Group{" + "name=" + name + ", description=" + description + '}'; - } - -} diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java index 21ec48fd1..714b8a7ae 100644 --- a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/Schema.java @@ -24,10 +24,6 @@ public final class Schema implements Serializable { private Set mutations = new HashSet<>(); private Set subscriptions = new HashSet<>(); - private Map> groupedQueries = new HashMap<>(); - private Map> groupedMutations = new HashMap<>(); - private Map> groupedSubscriptions = new HashMap<>(); - private Map namespacedQueries = new HashMap<>(); private Map namespacedMutations = new HashMap<>(); @@ -60,6 +56,16 @@ public Map getNamespacedMutations() { return namespacedMutations; } + public Set getAllOperations() { + Set operations = new HashSet<>(); + operations.addAll(queries); + operations.addAll(mutations); + operations.addAll(subscriptions); + operations.addAll(getAllNamespacedQueryOperations()); + operations.addAll(getAllNamespacedMutationOperations()); + return operations; + } + public Set getAllNamespacedQueryOperations() { return namespacedQueries.values().stream() .map(NamespaceContainer::getAllOperations) @@ -91,8 +97,9 @@ public void addQuery(Operation query) { } public boolean hasOperations() { - return hasQueries() || hasGroupedQueries() || hasNamespaceQueries() - || hasMutations() || hasGroupedMutations() || hasNamespaceMutations(); + return hasQueries() || hasNamespaceQueries() + || hasMutations() || hasNamespaceMutations() + || hasSubscriptions(); } public boolean hasQueries() { @@ -131,54 +138,6 @@ public boolean hasSubscriptions() { return !this.subscriptions.isEmpty(); } - public Map> getGroupedQueries() { - return groupedQueries; - } - - public void setGroupedQueries(Map> groupedQueries) { - this.groupedQueries = groupedQueries; - } - - public void addGroupedQuery(Group group, Operation query) { - addToOperationMap(this.groupedQueries, group, query); - } - - public boolean hasGroupedQueries() { - return !this.groupedQueries.isEmpty(); - } - - public Map> getGroupedMutations() { - return groupedMutations; - } - - public void setGroupedMutations(Map> groupedMutations) { - this.groupedMutations = groupedMutations; - } - - public void addGroupedMutation(Group group, Operation mutation) { - addToOperationMap(this.groupedMutations, group, mutation); - } - - public boolean hasGroupedMutations() { - return !this.groupedMutations.isEmpty(); - } - - public Map> getGroupedSubscriptions() { - return groupedSubscriptions; - } - - public void setGroupedSubscriptions(Map> groupedSubscriptions) { - this.groupedSubscriptions = groupedSubscriptions; - } - - public void addGroupedSubscription(Group group, Operation subscription) { - addToOperationMap(this.groupedSubscriptions, group, subscription); - } - - public boolean hasGroupedSubscriptions() { - return !this.groupedSubscriptions.isEmpty(); - } - public Map getInputs() { return inputs; } @@ -345,18 +304,6 @@ public List getBatchOperations() { return batchOperations; } - private void addToOperationMap(Map> map, Group group, Operation query) { - Set set; - - if (map.containsKey(group)) { - set = map.get(group); - } else { - set = new HashSet<>(); - } - set.add(query); - map.put(group, set); - } - public void addCustomScalarType(CustomScalarType customScalarType) { customScalarTypes.add(customScalarType); Scalars.registerCustomScalarInSchema( @@ -395,9 +342,8 @@ public String toString() { ", queries=" + queries + ", mutations=" + mutations + ", subscriptions=" + subscriptions + - ", groupedQueries=" + groupedQueries + - ", groupedMutations=" + groupedMutations + - ", groupedSubscriptions=" + groupedSubscriptions + + ", namespacedQueries=" + namespacedQueries + + ", namespacedMutations=" + namespacedMutations + ", directiveTypes=" + directiveTypes + ", customScalarTypes=" + customScalarTypes + ", inputs=" + inputs + diff --git a/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java b/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java index 5f045299a..4d8d3b784 100644 --- a/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java +++ b/server/api/src/main/java/io/smallrye/graphql/api/Namespace.java @@ -14,7 +14,7 @@ @Experimental("Grouping APIs by nested namespaces") public @interface Namespace { /** - * @return Namespaces separated by '/' (example - admin/users) + * @return Array of nested namespaces */ - String value(); + String[] value(); } diff --git a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java index 575148fd5..b72ffb1b0 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java @@ -20,7 +20,6 @@ import java.util.Set; import java.util.Stack; import java.util.stream.Collectors; -import java.util.stream.Stream; import jakarta.json.JsonReader; import jakarta.json.JsonReaderFactory; @@ -81,7 +80,6 @@ import io.smallrye.graphql.schema.model.EnumType; import io.smallrye.graphql.schema.model.EnumValue; import io.smallrye.graphql.schema.model.Field; -import io.smallrye.graphql.schema.model.Group; import io.smallrye.graphql.schema.model.InputType; import io.smallrye.graphql.schema.model.NamespaceContainer; import io.smallrye.graphql.schema.model.Operation; @@ -156,14 +154,8 @@ private void verifyInjectionIsAvailable() { LookupService lookupService = LookupService.get(); // This crazy stream operation basically collects all class names where we need to verify that // it belongs to an injectable bean - Stream.of( - schema.getQueries().stream().map(Operation::getClassName), - schema.getMutations().stream().map(Operation::getClassName), - schema.getGroupedQueries().values().stream().flatMap(Collection::stream).map(Operation::getClassName), - schema.getGroupedMutations().values().stream().flatMap(Collection::stream).map(Operation::getClassName), - schema.getAllNamespacedQueryOperations().stream().map(Operation::getClassName), - schema.getAllNamespacedMutationOperations().stream().map(Operation::getClassName)) - .flatMap(stream -> stream) + schema.getAllOperations().stream() + .map(Operation::getClassName) .distinct().forEach(beanClassName -> { // verify that the bean is injectable if (!lookupService.isResolvable(classloadingService.loadClass(beanClassName))) { @@ -337,9 +329,6 @@ private void addQueries(GraphQLSchema.Builder schemaBuilder) { if (schema.hasQueries()) { addRootObject(queryBuilder, schema.getQueries(), QUERY); } - if (schema.hasGroupedQueries()) { - addGroupedRootObject(queryBuilder, schema.getGroupedQueries(), QUERY); - } if (schema.hasNamespaceQueries()) { addNamespacedRootObject(queryBuilder, schema.getNamespacedQueries(), QUERY); } @@ -356,9 +345,6 @@ private void addMutations(GraphQLSchema.Builder schemaBuilder) { if (schema.hasMutations()) { addRootObject(mutationBuilder, schema.getMutations(), MUTATION); } - if (schema.hasGroupedMutations()) { - addGroupedRootObject(mutationBuilder, schema.getGroupedMutations(), MUTATION); - } if (schema.hasNamespaceMutations()) { addNamespacedRootObject(mutationBuilder, schema.getNamespacedMutations(), MUTATION); } @@ -377,9 +363,6 @@ private void addSubscriptions(GraphQLSchema.Builder schemaBuilder) { if (schema.hasSubscriptions()) { addRootObject(subscriptionBuilder, schema.getSubscriptions(), SUBSCRIPTION); } - if (schema.hasGroupedSubscriptions()) { - addGroupedRootObject(subscriptionBuilder, schema.getGroupedSubscriptions(), SUBSCRIPTION); - } GraphQLObjectType subscription = subscriptionBuilder.build(); if (subscription.getFieldDefinitions() != null && !subscription.getFieldDefinitions().isEmpty()) { @@ -481,51 +464,6 @@ private GraphQLObjectType createNamespaceType(String root, String suffix, Namesp return objectTypeBuilder.build(); } - private void addGroupedRootObject(GraphQLObjectType.Builder rootBuilder, - Map> operationMap, String rootName) { - Set>> operationsSet = operationMap.entrySet(); - - for (Entry> operationsEntry : operationsSet) { - Group group = operationsEntry.getKey(); - Set operations = operationsEntry.getValue(); - - GraphQLObjectType namedType = createNamedType(rootName, group, operations); - - GraphQLFieldDefinition.Builder graphQLFieldDefinitionBuilder = GraphQLFieldDefinition.newFieldDefinition() - .name(group.getName()).description(group.getDescription()); - - graphQLFieldDefinitionBuilder.type(namedType); - - DataFetcher dummyDataFetcher = dfe -> namedType.getName(); - - GraphQLFieldDefinition namedField = graphQLFieldDefinitionBuilder.build(); - - this.codeRegistryBuilder.dataFetcherIfAbsent( - FieldCoordinates.coordinates(rootName, namedField.getName()), - dummyDataFetcher); - - rootBuilder.field(namedField); - } - } - - private GraphQLObjectType createNamedType(String parent, Group group, Set operations) { - String namedTypeName = group.getName() + parent; - GraphQLObjectType.Builder objectTypeBuilder = GraphQLObjectType.newObject() - .name(namedTypeName) - .description(group.getDescription()); - - // Operations - for (Operation operation : operations) { - operation = eventEmitter.fireCreateOperation(operation); - - GraphQLFieldDefinition graphQLFieldDefinition = createGraphQLFieldDefinitionFromOperation(namedTypeName, - operation); - objectTypeBuilder = objectTypeBuilder.field(graphQLFieldDefinition); - } - - return objectTypeBuilder.build(); - } - // Create all enums and map them private void createGraphQLEnumTypes() { if (schema.hasEnums()) { @@ -1084,11 +1022,6 @@ private GraphQLOutputType referenceGraphQLOutputType(Field field) { } } - private GraphQLInputType referenceGraphQLInputType(Field field) { - Reference reference = getCorrectFieldReference(field); - return getGraphQLInputType(reference); - } - private GraphQLInputType getGraphQLInputType(Reference reference) { ReferenceType type = reference.getType(); String className = reference.getClassName(); diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java index 1a328ebfb..c385159c6 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceApi.java @@ -6,7 +6,7 @@ import io.smallrye.graphql.api.Namespace; @GraphQLApi -@Namespace("admin/users") +@Namespace({ "admin", "users" }) public class ExperimentalNamespaceApi { @Query public String find() { diff --git a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java index d40fcbd2d..425a6cbf2 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/test/namespace/ExperimentalNamespaceWithErrorApi.java @@ -8,7 +8,7 @@ @GraphQLApi @Name("users") -@Namespace("admin/users") +@Namespace({ "admin", "users" }) public class ExperimentalNamespaceWithErrorApi { @Query public String find() { From 1d7ad70f1986e4ce5a1ad414d36efe436c2913b9 Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Mon, 23 Sep 2024 02:03:20 +0300 Subject: [PATCH 5/7] simple code changes, update docs --- .../client/model/ClientModelBuilder.java | 4 +- .../graphql/schema/SchemaBuilder.java | 4 +- docs/namespaces-on-server-side.md | 201 ++++-------------- docs/typesafe-client-usage.md | 123 +---------- 4 files changed, 56 insertions(+), 276 deletions(-) diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java index abaf682a0..36f9b7d72 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java @@ -59,7 +59,7 @@ private ClientModels generateClientModels() { Collection graphQLApiAnnotations = getIndex() .getAnnotations(GRAPHQL_CLIENT_API); - validateAnnotations(graphQLApiAnnotations); + validateNamespaceAnnotations(graphQLApiAnnotations); graphQLApiAnnotations.forEach(graphQLApiAnnotation -> { ClientModel operationMap = new ClientModel(); @@ -80,7 +80,7 @@ private ClientModels generateClientModels() { return clientModels; } - private void validateAnnotations(Collection graphQLApiAnnotations) { + private void validateNamespaceAnnotations(Collection graphQLApiAnnotations) { List errorInterfaces = graphQLApiAnnotations.stream() .map(annotation -> annotation.target().asClass()) .filter(classInfo -> classInfo.hasDeclaredAnnotation(NAMESPACE) && classInfo.hasDeclaredAnnotation(NAME)) diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java index 2de060fa9..b588ee718 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java @@ -147,7 +147,7 @@ private Schema generateSchema() { addCustomScalarTypes(schema); - validateAnnotations(graphQLApiAnnotations); + validateNamespaceAnnotations(graphQLApiAnnotations); validateSubscriptions(graphQLApiAnnotations); for (AnnotationInstance graphQLApiAnnotation : graphQLApiAnnotations) { @@ -220,7 +220,7 @@ private void validateSubscriptions(Collection graphQLApiAnno } } - private void validateAnnotations(Collection graphQLApiAnnotations) { + private void validateNamespaceAnnotations(Collection graphQLApiAnnotations) { List errorClasses = graphQLApiAnnotations.stream() .map(annotation -> annotation.target().asClass()) .filter(classInfo -> classInfo.hasDeclaredAnnotation(NAMESPACE) && classInfo.hasDeclaredAnnotation(NAME)) diff --git a/docs/namespaces-on-server-side.md b/docs/namespaces-on-server-side.md index 2ba91eb4c..ba76a0bec 100644 --- a/docs/namespaces-on-server-side.md +++ b/docs/namespaces-on-server-side.md @@ -1,24 +1,22 @@ # Namespacing on the server side -## Before you continue reading > [NOTE] > Using approaches to form namespaces in the schema can be useful for large APIs. There are several ways to do this. > However, read the documentation carefully, especially the limitations and possible problems. -## How use namespaces -There are 4 options how to use the name space - use the @Name annotation, @Source, or combine them. +> [NOTE] You can only use one of the annotations - @Name or @Namespace over the GraphQLApi classes. -And modern @Namespace (new feature, read below). +## Using @Namespace annotation -> [NOTE] You can only use one of the annotations - @Name or @Namespace over the GraphQLApi classes. +The annotation accepts an array of strings containing the nesting of the namespace. +This method allows you to create any nesting of namespaces. +You can use any nesting and also combine different levels. -### Using @Name annotation -The easiest way is that you can separate your API into namespace areas using the annotation @Name with @GraphQLApi. ```java @GraphQLApi -@Name("users") -@Description("Users operations") -public class UserApi { +@Namespace({"admin", "users"}) +@Description("Admin users operations") +public class AdminUsersApi { @Query public List findAll() { // @@ -26,145 +24,11 @@ public class UserApi { } @GraphQLApi -@Name("roles") -@Description("Roles operations") -public class RoleApi { - @Query - public List findAll() { - // - } -} -``` -As a result, you can get methods with the same names. -``` -query { - users { - findAll { - .... - } - } - roles { - findAll { - .... - } - } -} -``` -When using annotation @Name, will be generated type - NameQuery, NameMutation and NameSubscription -(Subscriptions placed in this type will not work. More details below). - -### Using @Source annotation for deep nesting -You can use the @Source annotation to create deep nesting of namespaces. -```java -// create classes that represent namespaces -public class AdminQueryNamespace { -} - -public class AdminMutationNamespace { -} - -public class UserQueryNamespace { -} - -public class UserMutationNamespace { -} - -@GraphQLApi -public class UserApi { - @Query("admin") - public AdminQueryNamespace adminQueryNamespace() { - return new AdminQueryNamespace(); - } - - public UserQueryNamespace userQueryNamespace(@Source AdminQueryNamespace namespace) { - return new UserQueryNamespace(); - } - - public List findAll(@Source UserQueryNamespace namespace) { - // return users; - } - - @Mutation("admin") - public AdminMutationNamespace adminMutationNamespace() { - return new AdminMutationNamespace(); - } - - public UserMutationNamespace userMutationNamespace(@Source AdminMutationNamespace namespace) { - return new UserMutationNamespace(); - } - - public List save(@Source UserMutationNamespace namespace, User user) { - // save user - } -} -``` -As a result, you will be able to execute the following query. -``` -query { - admin { - users { - findAll { - .... - } - } - } -} - -mutation { - admin { - users { - save (user: ...) { - .... - } - } - } -} -``` -### Using @Source and @Name annotations together for deep nesting - -You can also simplify this example by using @Name. -```java -// create classes that represent namespaces -public class UserQueryNamespace { -} - -public class UserMutationNamespace { -} - -@GraphQLApi -@Name("admin") -@Description("Users operations") -public class UserApi { - @Query("users") - public UserQueryNamespace userQueryNamespace() { - return new UserQueryNamespace(); - } - - public List findAll(@Source UserQueryNamespace namespace) { - // return users; - } - - @Mutation("users") - public UserMutationNamespace userMutationNamespace() { - return new UserMutationNamespace(); - } - - public List save(@Source UserMutationNamespace namespace, User user) { - // save user - } -} -``` - -### Using @Namespace annotation - -The annotation accepts a string that contains namespaces separated by '/' - -```java -@GraphQLApi -@Namespace("admin/users") -public class ResourceApi { +@Namespace({"admin"}) +@Description("Admin operations") +public class AdminApi { @Query - public List findAll() { + public List findAll() { // } } @@ -177,12 +41,20 @@ type Query { admin: AdminQuery } +"Admin operations" type AdminQuery { users: AdminUsersQuery + findAll: [Admin] } +"Admin users operations" type AdminUsersQuery { - findAll: Info + findAll: [User] +} + +type Admin { + id: BigInteger + ... } type User { @@ -204,18 +76,29 @@ query { } ``` -You can use any nesting and also combine different levels +## Using @Name annotation (deprecated) +> [NOTE] This feature may be removed in the future. + +Does the same thing as @Namespace, the only difference is that there can only be one nesting level. ```java @GraphQLApi -@Namespace("admin/users") -public class ResourceApi { - // +@Name("users") +@Description("Users operations") +public class UserApi { + @Query + public List findAll() { + // + } } - -@GraphQLApi -@Namespace("admin") -public class ResourceApi { - // +``` +As a result, you can get methods with the same names. +``` +query { + users { + findAll { + .... + } + } } ``` @@ -239,7 +122,7 @@ As example, if you try to run such a subscription request, you will get an error ```java @GraphQLApi -@Name("resource") +@Namepace("resource") public class ResourceApi { @Subscription public Multi resourceChange() { diff --git a/docs/typesafe-client-usage.md b/docs/typesafe-client-usage.md index 199f6b1fd..8baacfb01 100644 --- a/docs/typesafe-client-usage.md +++ b/docs/typesafe-client-usage.md @@ -201,16 +201,18 @@ public interface ApiClient { ## Namespaces There are several ways to work with namespaces in a type-safe client -1. Using @Name, or wrapping -2. Using @Namespace (new feature) +1. Using @Namespace +2. Using @Name (deprecated) > [NOTE] You can only use one of the annotations - @Name or @Namespace over the GraphQLApi classes. ### Using @Namespace annotation -The annotation accepts a string that contains namespaces separated by '/' +The annotation accepts an array of strings containing the nesting of the namespace. +This method allows you to create any nesting of namespaces. +You can use any nesting and also combine different levels. -If remove graphql api has next schema +If remote graphql api has next schema ``` "Query root" type Query { @@ -233,7 +235,7 @@ type User { You can create next interface ```java -@Namespace("admin/users") +@Namespace({"admin", "users"}) @GraphQLClientApi public interface UsersClient { List findAll(); @@ -253,16 +255,10 @@ query AminUsersFindAll { } ``` -### Using @Name or type wrapping +### Using @Name (deprecated) +> [NOTE] This feature may be removed in the future. -> [NOTE] -> We strongly unrecommended the use namespaces with a type-safe client. -> It is possible to use the @Name annotation, with minimal changes to the code. -> However, for more complex cases it is better to use the dynamic client, since understanding the resulting code can be difficult. - -There are several ways to work with namespaces with the type-safe client. - -If only 1 level of nesting is used, then the interface can be marked with the @Name annotation. +Does the same thing as @Namespace, the only difference is that there can only be one nesting level. ``` query { @@ -281,102 +277,3 @@ public interface ApiClient { List findAll(); } ``` - -You also can use Wrapper class (but the code doesn't look great.). - -Modify server code from above. -```java -@Name("roles") // Add namespace -@GraphQLApi -public class RoleApi { - //// -} -``` - -Client code -```java -// Name field roles as method named -public record RolesWrapper(List findAllRolesByUserId) { -} - -@GraphQLClientApi -public interface ApiClient { - @Query("roles") // required naming as namespace - RolesWrapper getRoles( // extend nested params - @NestedParameter("findAllRolesByUserId") UUID userId, // here roles id name of field in wrapper class - @NestedParameter("findAllRolesByUserId.permission") @Name("limit") int permissionLimit, - @NestedParameter("findAllRolesByUserId.permission.permissionType") @Name("limit") int permissionTypeLimit - ); -} -``` - -If you have more than 1 level of nesting and want to use a type-safe client, the only way is with wrapper classes. -```java -@Name("admin") -@GraphQLApi -public class RoleApi { - public static class RoleQueryNamespace{ } - - @Query("roles") - public RoleQueryNamespace roleQueryNamespace(){ - return new RoleQueryNamespace(); - } - - public List findAll(@Source RoleQueryNamespace namespace, UUID userId) {} - public List permission(@Source Role role, @DefaultValue("5") int limit) {} - public List permissionType(@Source Permission permissions, @DefaultValue("5") int limit) {} -} -``` - -Query will be like -``` -query { - admin { - roles { - findAll(userId: ...) { - id - permission(limit: 1) { - id - permissionType(limit: 2) { - id - } - } - } - } - } -} -``` - -```java -// Without Name annotation it must have name as is in schema -public record AdminWrapper(RolesWrapper roles) { // namespace in schema - public record RolesWrapper(List findAllRolesByUserId){} // name method in schema -} - -@GraphQLClientApi(endpoint = "http://localhost:8081/graphql") -public interface ApiClient { - @Query("admin") - AdminWrapper findAllRolesByUserId( - // nested params must be such as field names in wrapper class - @NestedParameter("roles.findAllRolesByUserId") UUID userId, - @NestedParameter("roles.findAllRolesByUserId.permission") @Name("limit") int permissionLimit, - @NestedParameter("roles.findAllRolesByUserId.permission.permissionType") @Name("limit") int permissionTypeLimit - ); -} -/// or -public record AdminWrapper(@Name("roles") RolesWrapper rolesWrapper) { // @Name like namespace in schema - public record RolesWrapper(@Name("findAllRolesByUserId") List roles){} // @Name like method name in schema -} - -@GraphQLClientApi -public interface ApiClient { - @Query("admin") - AdminWrapper findAllRolesByUserId( - // nested params value must be such as field names in wrapper class - @NestedParameter("rolesWrapper.roles") UUID userId, - @NestedParameter("rolesWrapper.roles.permission") @Name("limit") int permissionLimit, - @NestedParameter("rolesWrapper.roles.permission.permissionType") @Name("limit") int permissionTypeLimit - ); -} -``` -As you can see, the code with wrapper classes is quite messy, so we don't recommend using this approach in a type-safe client. From 698fd8d681aa731b699f73b2daa7c41267f89cbc Mon Sep 17 00:00:00 2001 From: Roman Lovakov Date: Mon, 23 Sep 2024 02:07:05 +0300 Subject: [PATCH 6/7] fix exception messages --- .../vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java | 2 +- .../io/smallrye/graphql/client/model/ClientModelBuilder.java | 2 +- .../src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java index 404c5a1b4..4b74fc218 100644 --- a/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java +++ b/client/implementation-vertx/src/main/java/io/smallrye/graphql/client/vertx/typesafe/VertxTypesafeGraphQLClientBuilder.java @@ -152,7 +152,7 @@ public T build(Class apiClass) { if (nameAnnotation != null && namespaceAnnotation != null) { throw new RuntimeException("You can only use one of the annotations - @Name or @Namespace " + - "over the GraphQLClientApi interface. Please, fix the interface: " + apiClass.getName()); + "over the GraphQLClientApi interface. Please, fix the following interface: " + apiClass.getName()); } if (this.options == null) { diff --git a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java index 36f9b7d72..5e42f04b5 100644 --- a/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java +++ b/client/model-builder/src/main/java/io/smallrye/graphql/client/model/ClientModelBuilder.java @@ -88,7 +88,7 @@ private void validateNamespaceAnnotations(Collection graphQL .collect(Collectors.toList()); if (!errorInterfaces.isEmpty()) { throw new RuntimeException("You can only use one of the annotations - @Name or @Namespace " + - "over the GraphQLClientApi interface. Please, fix next interfaces: " + + "over the GraphQLClientApi interface. Please, fix the following interfaces: " + String.join(", ", errorInterfaces)); } } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java index b588ee718..e4e2ad13c 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java @@ -228,7 +228,7 @@ private void validateNamespaceAnnotations(Collection graphQL .collect(Collectors.toList()); if (!errorClasses.isEmpty()) { throw new RuntimeException("You can only use one of the annotations - @Name or @Namespace " + - "over the GraphQLClientApi interface. Please, fix next classes: " + + "over the GraphQLClientApi interface. Please, fix the following classes: " + String.join(", ", errorClasses)); } } From 80c949657e2d98b6a25579641d400b03db5391ec Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Mon, 23 Sep 2024 12:49:43 +0200 Subject: [PATCH 7/7] Switch CI to custom branch for 2.11 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d763d28b7..3f3433d46 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -96,8 +96,8 @@ jobs: - name: checkout Quarkus repository uses: actions/checkout@v2 with: - repository: quarkusio/quarkus - ref: main + repository: jmartisk/quarkus + ref: smallrye-graphql-2.11 path: quarkus - uses: actions/setup-java@v4