This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3676
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit 5fd8a280e17a125071b639a60755ff5956456e00
Author: danhaywood <[email protected]>
AuthorDate: Sun Jan 28 15:46:49 2024 +0000

    CAUSEWAY-3676: introduces ApiVariant config property
---
 .../ROOT/pages/2024/2.0.0-RC5/mignotes.adoc        | 21 +++++++++++
 .../ROOT/pages/2024/2.0.0-RC5/relnotes.adoc        | 12 ++++++
 .../core/config/CausewayConfiguration.java         | 43 ++++++++++++++++++++++
 .../graphql/model/domain/GqlvDomainObject.java     | 11 ++++--
 .../graphql/model/domain/GqlvDomainService.java    | 11 +++++-
 .../viewer/graphql/model/domain/GqlvProperty.java  | 17 ++++++++-
 6 files changed, 107 insertions(+), 8 deletions(-)

diff --git 
a/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/mignotes.adoc 
b/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/mignotes.adoc
index ad2e59b983..9d6f857f6b 100644
--- a/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/mignotes.adoc
+++ b/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/mignotes.adoc
@@ -52,3 +52,24 @@ Changes:
 
 For more details, see 
link:https://issues.apache.org/jira/browse/CAUSEWAY-3675[CAUSEWAY-3675].
 
+
+== Mavendeps webapp module and the GraphQL viewer (CAUSEWAY-3676)
+
+The GraphQL viewer is a brand new viewer, automatically exposing your domain 
object model as a GraphQL API.
+For more on this new feature, see the corresponding 
xref:relnotes::2024/2.0.0-RC5/relnotes.adoc#the-graphql-viewer-causeway-3676[release
 notes].
+
+As part of this work, the 
`org.apache.causeway.mavendeps:causeway-mavendeps-webapp` convenience module 
has been updated.
+It now references all 3 viewers (Wicket, Restful and GraphQL) as a one-stop 
shop for bringing in viewers.
+
+[source,xml]
+.pom.xml
+----
+<dependency>
+    <groupId>org.apache.causeway.mavendeps</groupId>
+       <artifactId>causeway-mavendeps-webapp</artifactId>
+</dependency>
+----
+
+It is still necessary to add in the persistence and security modules.
+
+For more details, see 
link:https://issues.apache.org/jira/browse/CAUSEWAY-3676[CAUSEWAY-3676].
diff --git 
a/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/relnotes.adoc 
b/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/relnotes.adoc
index 4e6c4ebb22..1e78ff4b37 100644
--- a/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/relnotes.adoc
+++ b/antora/components/relnotes/modules/ROOT/pages/2024/2.0.0-RC5/relnotes.adoc
@@ -6,3 +6,15 @@
 
 
 NOTE: Not yet released.
+
+[#the-graphql-viewer-causeway-3676]
+== The GraphQL viewer (CAUSEWAY-3676)
+
+The GraphQL viewer is a brand new viewer which automatically exposes your 
domain object model as a GraphQL API.
+
+Built using link:https://spring.io/projects/spring-graphql[Spring for 
GraphQL], it provides a GraphQL API
+
+It is important to know that the generated API (in this first release) 
deliberately -conformant to one of the rueles
+
+The documentation can be found xref:gqlv:ROOT:about.adoc[here].
+See also 
link:https://issues.apache.org/jira/browse/CAUSEWAY-3676[CAUSEWAY-3676].
diff --git 
a/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java
 
b/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java
index 76c7dd4845..ed0964ce86 100644
--- 
a/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java
+++ 
b/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java
@@ -2346,6 +2346,49 @@ public class CausewayConfiguration {
         @Data
         public static class Graphql {
 
+            public enum ApiVariant {
+                /**
+                 * Exposes only a Query API, of properties, collections and 
safe (query-onl) actions.
+                 * Any actions that mutate the state of the system (in other 
words are idempotent or non-idempotent)
+                 * are excluded from the API, as is the ability to set 
properties.
+                 */
+                QUERY_ONLY,
+                /**
+                 * Exposes only a Query API, but relaxes the rule that system 
state may not be changed by also including
+                 * idempotent and non-idempotent actions as part of the 
&quot;query&quot; API.  Modifiable properties
+                 * can also be set.
+                 *
+                 * <p>
+                 *     <b>IMPORTANT</b>: be aware that the resultant API is 
not compliant with the rules of the
+                 *     GraphQL spec; in particular, it violates <a 
href="https://spec.graphql.org/June2018/#sec-Language.Operations";>2.3 
Operations</a> which states:
+                 *     &quot;query – [is] a read‐only fetch.&quot;
+                 * </p>
+                 */
+                QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT,
+                /**
+                 * Exposes an API with Query for query/safe separate queries 
and field access, with mutating (idempotent
+                 * and non-idempotent) actions instead surfaced as Mutations, 
as per the
+                 * <a 
href="https://spec.graphql.org/June2018/#sec-Language.Operations";>GraphQL 
spec</a>.
+                 *
+                 * <p>
+                 * <b>NOTE</b>: this is not currently implemented.
+                 * </p>
+                 */
+                QUERY_AND_MUTATIONS,
+                ;
+            }
+
+            /**
+             * Which variant of API to expose: {@link ApiVariant#QUERY_ONLY} 
(which suppresses any actions that mutate the state of the
+             * system), or alternatively as {@link 
ApiVariant#QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT} (which does expose actions 
that mutate the system but within a query, and so is not spec-compliant), or
+             * as {@link ApiVariant#QUERY_AND_MUTATIONS} (which also exposes 
actions that mutate the system but as mutations, and so <i>is</i> 
spec-compliant.
+             *
+             * <p>
+             *     <b>NOTE:</b> {@link ApiVariant#QUERY_AND_MUTATIONS} is not 
currently implemented.
+             * </p>
+             */
+            private ApiVariant apiVariant = 
ApiVariant.QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT;
+
             private final MetaData metaData = new MetaData();
             @Data
             public static class MetaData {
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
index 1498b8a62e..23b6018187 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
@@ -37,10 +37,13 @@ import graphql.schema.GraphQLFieldDefinition;
 import graphql.schema.GraphQLInputObjectType;
 import graphql.schema.GraphQLObjectType;
 
+import lombok.val;
+
 import static graphql.schema.GraphQLInputObjectField.newInputObjectField;
 import static graphql.schema.GraphQLInputObjectType.newInputObject;
 import static graphql.schema.GraphQLNonNull.nonNull;
 import static graphql.schema.GraphQLObjectType.newObject;
+import static 
org.apache.causeway.core.config.CausewayConfiguration.Viewer.Graphql.ApiVariant.*;
 
 /**
  * Exposes a domain object (view model or entity) via the GQL viewer.
@@ -100,11 +103,11 @@ public class GqlvDomainObject implements 
GqlvAction.Holder, GqlvProperty.Holder,
         
objectSpecification.streamProperties(MixedIn.INCLUDED).forEach(this::addProperty);
         
objectSpecification.streamCollections(MixedIn.INCLUDED).forEach(this::addCollection);
 
-        // TODO: pay attention to deploymentType
+        val variant = 
context.causewayConfiguration.getViewer().getGraphql().getApiVariant();
+
         objectSpecification.streamActions(context.getActionScope(), 
MixedIn.INCLUDED)
-                // TODO: for now, we ignore any actions that have any 
collection parameters
-                //  however, this is supportable in GraphQL, 
https://chat.openai.com/c/7ca721d5-865a-4765-9f90-5c28046516cd
-                // .filter(objectAction -> 
objectAction.getParameters().stream().noneMatch(ObjectActionParameter::isPlural))
+                .filter(x -> x.getSemantics().isSafeInNature() ||
+                             variant == 
QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT)
                 .forEach(objectAction -> {
                     actions.put(objectAction.getId(), new GqlvAction(this, 
objectAction, context));
                 });
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
index fe81854d56..a5d2d1e64e 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainService.java
@@ -21,11 +21,9 @@ package org.apache.causeway.viewer.graphql.model.domain;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import org.apache.causeway.core.metamodel.spec.ActionScope;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.spec.feature.MixedIn;
 import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
-import org.apache.causeway.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 
 import lombok.Getter;
@@ -34,10 +32,14 @@ import graphql.schema.FieldCoordinates;
 import graphql.schema.GraphQLFieldDefinition;
 import graphql.schema.GraphQLObjectType;
 
+import lombok.val;
+
 import static graphql.schema.FieldCoordinates.coordinates;
 import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 import static graphql.schema.GraphQLObjectType.newObject;
 
+import static 
org.apache.causeway.core.config.CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT;
+
 /**
  * Exposes a domain service (view model or entity) via the GQL viewer.
  */
@@ -83,7 +85,12 @@ public class GqlvDomainService implements GqlvAction.Holder {
     }
 
     private void addActions() {
+
+        val variant = 
context.causewayConfiguration.getViewer().getGraphql().getApiVariant();
+
         objectSpecification.streamActions(context.getActionScope(), 
MixedIn.INCLUDED)
+                .filter(x -> x.getSemantics().isSafeInNature() ||
+                             variant == 
QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT)
                 .forEach(this::addAction);
     }
 
diff --git 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
index 0960db17f7..e36d3c826f 100644
--- 
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
+++ 
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java
@@ -18,6 +18,7 @@
  */
 package org.apache.causeway.viewer.graphql.model.domain;
 
+import org.apache.causeway.core.config.CausewayConfiguration;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.causeway.viewer.graphql.model.context.Context;
@@ -55,6 +56,9 @@ public class GqlvProperty
      */
     private final GqlvPropertyAutoComplete autoComplete;
     private final GqlvPropertyValidate validate;
+    /**
+     * Populated iff the API variant allows for it.
+     */
     private final GqlvPropertySet set;
 
     public GqlvProperty(
@@ -73,7 +77,14 @@ public class GqlvProperty
         this.choices = choices.hasChoices() ? choices : null;
         val autoComplete = new GqlvPropertyAutoComplete(this, context);
         this.autoComplete = autoComplete.hasAutoComplete() ? autoComplete : 
null;
-        this.set = new GqlvPropertySet(this, context);
+
+        val variant = 
context.causewayConfiguration.getViewer().getGraphql().getApiVariant();
+        if (variant == 
CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT)
 {
+            this.set = new GqlvPropertySet(this, context);
+        } else {
+            this.set = null;
+        }
+
 
         this.gqlObjectType = gqlObjectTypeBuilder.build();
 
@@ -134,7 +145,9 @@ public class GqlvProperty
             autoComplete.addDataFetcher();
         }
         validate.addDataFetcher();
-        set.addDataFetcher();
+        if (set != null) {
+            set.addDataFetcher();
+        }
     }
 
 

Reply via email to