You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2024/03/14 11:49:48 UTC

(causeway) branch CAUSEWAY-3676 updated (2f816efb5f -> 75c7b80b37)

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

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


    from 2f816efb5f CAUSEWAY-3676: reworks to use an SPI instead of annotation
     add 950e538cc2 Merge pull request #2275 from apache/CAUSEWAY-3676
     add 237f92da30 Bump com.google.errorprone:error_prone_annotations from 2.26.0 to 2.26.1
     add 29b89f7c5d Merge pull request #2278 from apache/dependabot/maven/master/com.google.errorprone-error_prone_annotations-2.26.1
     add a488b0107d Bump org.apache.cxf:cxf-rt-rs-client from 3.6.2 to 3.6.3
     add 8af2651255 Merge pull request #2277 from apache/dependabot/maven/master/org.apache.cxf-cxf-rt-rs-client-3.6.3
     add a311294f24 CAUSEWAY-2445: remove unused imports
     add f1d39033f1 CAUSEWAY-3650: adds javadoc, removes unused methods and reduces visibility of some helper methods in FixtureScripts.
     add 96be4d9afc CAUSEWAY-3650: regens docs
     add 67f4ebf5a1 CAUSEWAY-3489: wkt vwr: templates for temporal editing with zone and offset (yet just mockups)
     add f7b0a55837 CAUSEWAY-3489: let TemporalValueSemantics provide choices for zones and offsets
     add 7429d88952 CAUSEWAY-3489: populate dropdows from underlying providers
     add cc84f51394 CAUSEWAY-3489: introduces TemporalDecomposition
     add e151bb2512 CAUSEWAY-3489: remove debug lines
     add 58ee4b7473 Merge pull request #2279 from apache/3489-temporal.editing.w.tz
     add bf82e2168b CAUSEWAY-3697: renames NatureOfService enum constants
     add 020a713d92 CAUSEWAY-3697: regens docs
     add d5e1169cc9 CAUSEWAY-3697: fixes compile issues in regression tests, incubator
     add 34c17811a3 Merge pull request #2281 from apache/CAUSEWAY-3697
     add 8e773c7773 CAUSEWAY-2297: fixes _OsUtil#terminateProcessByPid
     add f6140228c0 Bump com.google.guava:guava from 33.0.0-jre to 33.1.0-jre
     add 25bf5c06dd Merge pull request #2283 from apache/dependabot/maven/master/com.google.guava-guava-33.1.0-jre
     add dba64e531f CAUSEWAY-3697: reinstate old enum values - mark deprecated
     add 5c9221d00c CAUSEWAY-3697: deprecates DomainService(nature=NatureOfService..)
     add b9dcd781b6 CAUSEWAY-3697: optimizations and cleanups
     new 28ec90f8e1 CAUSEWAY-3676 : adds ability to filter GraphQL by view model
     new 6b99d52c70 CAUSEWAY-3676: adds tests for graphql with different scope
     new 75c7b80b37 CAUSEWAY-3676: updates docs

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../applib/pages/index/annotation/Action.adoc      |  13 --
 .../applib/pages/index/annotation/Collection.adoc  |  13 --
 .../pages/index/annotation/DomainService.adoc      |   2 +-
 .../pages/index/annotation/NatureOfService.adoc    |  66 +++++--
 .../applib/pages/index/annotation/Parameter.adoc   |  13 --
 .../applib/pages/index/annotation/Property.adoc    |  13 --
 .../DomainObject_028-autoCompleteRepository.adoc   |   4 +-
 .../annotation/hooks/DomainService_022-nature.adoc |   2 +-
 .../services/ascii/AsciiIdentifierService.adoc     |  17 ++
 .../services/iactnlayer/InteractionService.adoc    |  12 +-
 .../pages/index/services/swagger/Visibility.adoc   |   4 +-
 ...sewayConfiguration_Viewer_Graphql_ApiScope.adoc |  42 +++++
 ...ayConfiguration_Viewer_Graphql_SchemaStyle.adoc |  72 +++++++
 .../applib/fixturescripts/FixtureScripts.adoc      |  77 +++++---
 .../ROOT/partials/domain-services/progmodel.adoc   |   4 +-
 .../globally-defined-dropdowns.adoc                |   2 +-
 .../ui-layout-and-hints/menubars-layout.adoc       |   4 +-
 api/applib/src/main/java/module-info.java          |   1 +
 .../causeway/applib/annotation/DomainService.java  |   2 +
 .../applib/annotation/NatureOfService.java         |  40 +---
 .../services/appfeatui/ApplicationFeatureMenu.java |   5 +-
 .../services/confview/ConfigurationMenu.java       |   5 +-
 .../services/iactnlayer/InteractionService.java    |  27 ++-
 .../applib/services/metamodel/BeanSort.java        |   3 +-
 .../services/metamodel/MetaModelServiceMenu.java   |   5 +-
 .../scope/ActionContributionFilterService.java     |  36 ++--
 .../applib/services/swagger/Visibility.java        |   6 +-
 .../applib/services/user/ImpersonateMenu.java      |   5 +-
 .../applib/services/user/ImpersonateStopMenu.java  |   5 +-
 .../causeway/applib/services/userui/UserMenu.java  |   5 +-
 .../value/semantics/TemporalValueSemantics.java    |  29 +++
 bom/pom.xml                                        |  11 +-
 .../causeway/commons/internal/os/_OsUtil.java      |   6 +-
 core/adoc/modules/_overview/pages/about.adoc       |  48 ++++-
 .../adoc/modules/config/pages/sections/Other.adoc  |   2 +-
 .../config/pages/sections/causeway.applib.adoc     | 136 +++++++++++---
 .../pages/sections/causeway.core.meta-model.adoc   |   2 +-
 .../causeway.core.meta-model.introspector.adoc     |   4 +-
 .../causeway.core.meta-model.validator.adoc        |  18 +-
 .../sections/causeway.core.runtime-services.adoc   |  10 +-
 .../config/pages/sections/causeway.extensions.adoc |  24 +--
 .../sections/causeway.persistence.commons.adoc     |   2 +-
 .../sections/causeway.persistence.schema.adoc      |   2 +-
 .../pages/sections/causeway.security.keycloak.adoc |   6 +-
 .../pages/sections/causeway.value-types.adoc       |   4 +-
 .../pages/sections/causeway.viewer.common.adoc     |   4 +-
 .../pages/sections/causeway.viewer.graphql.adoc    |  26 ++-
 .../sections/causeway.viewer.restfulobjects.adoc   |   5 +-
 .../pages/sections/causeway.viewer.wicket.adoc     |  58 +++---
 .../modules/config/pages/sections/datanucleus.adoc |   8 +-
 .../modules/config/pages/sections/eclipselink.adoc |  50 ++---
 .../modules/config/pages/sections/resteasy.adoc    |   2 +-
 .../core/config/CausewayConfiguration.java         |  64 ++++++-
 .../config/beans/CausewayBeanTypeClassifier.java   |  26 +++
 .../beans/CausewayBeanTypeClassifierDefault.java   |   5 +-
 core/metamodel/src/main/java/module-info.java      |   1 -
 .../metamodel/context/HasMetaModelContext.java     |  14 +-
 .../core/metamodel/context/MetaModelContext.java   |   2 -
 .../NotInServiceMenuFacetAbstract.java             |  39 ----
 ...otInServiceMenuFacetFromDomainServiceFacet.java |  55 ------
 ...viceMenuFacetFromDomainServiceFacetFactory.java |  65 -------
 .../object/domainservice/DomainServiceFacet.java   |  62 ++----
 .../domainservice/DomainServiceFacetAbstract.java  |  26 +--
 .../DomainServiceFacetAnnotationFactory.java       |   3 +-
 .../DomainServiceFacetForAnnotation.java           |  28 ++-
 .../RemoveAnnotatedMethodsFacetFactory.java        |  18 +-
 .../LogicalTypeFacetFromClassNameFactory.java      |   7 +-
 .../dflt/ProgrammingModelFacetsJava11.java         |   3 -
 .../services/metamodel/MetaModelExporter.java      |  35 +---
 .../core/metamodel/spec/ObjectSpecification.java   |  28 +++
 .../specimpl/dflt/ObjectSpecificationDefault.java  |  13 ++
 .../causeway/core/metamodel/util/Facets.java       | 207 +++++++++++----------
 ...MenuFacetFromDomainServiceFacetFactoryTest.java | 129 -------------
 .../DomainServiceFacetAnnotationFactoryTest.java   |   3 +-
 .../facets/param/name/ParameterNameFacetTest.java  |   2 +-
 .../bootstrap/MenuBarsServiceBootstrap.java        |  26 +--
 .../runtimeservices/menubars/bootstrap/Bar.java    |   5 +-
 .../security/authentication/logout/LogoutMenu.java |   5 +-
 .../commandlog/applib/app/CommandLogMenu.java      |   3 +-
 .../docgen/help/menu/DocumentationMenu.java        |   3 +-
 .../bulkupdate/BulkUpdateMenuForDemoToDoItem.java  |   5 +-
 .../ExcelPivotByCategoryAndSubcategoryMenu.java    |   5 +-
 .../ExcelUploadServiceForDemoToDoItem.java         |   5 +-
 .../todomodule/dom/ExcelDemoToDoItemMenu.java      |   5 +-
 .../executionlog/applib/app/ExecutionLogMenu.java  |   3 +-
 .../applib/app/ExecutionOutboxMenu.java            |   5 +-
 .../applib/restapi/OutboxRestApi.java              |   3 +-
 .../github/menu/LayoutLoadersGitHubMenu.java       |   3 +-
 .../audittrail/applib/app/AuditTrailMenu.java      |   3 +-
 .../permission/menu/ApplicationPermissionMenu.java |   5 +-
 .../applib/role/menu/ApplicationRoleMenu.java      |   5 +-
 .../tenancy/menu/ApplicationTenancyMenu.java       |   5 +-
 .../applib/user/menu/ApplicationUserMenu.java      |   5 +-
 .../secman/applib/user/menu/MeService.java         |   5 +-
 .../sessionlog/applib/app/SessionLogMenu.java      |   3 +-
 .../dom/PdfJsDemoObjectWithBlobMenu.java           |   8 +-
 .../demoapp/web/replay/DemoReplayController.java   |   4 +-
 .../restapi/CommandRetrievalOnPrimaryService.java  |   5 +-
 .../primary/ui/CommandReplayOnPrimaryService.java  |   5 +-
 .../ui/CommandReplayOnSecondaryService.java        |   5 +-
 .../testdomain/jdo/JdoInventoryResource.java       |   2 -
 .../testdomain/jpa/JpaInventoryResource.java       |   3 +-
 .../model/actnsemantics/BlobDemoMenu.java          |   3 +-
 .../model/bad/InvalidServiceWithAlias.java         |   3 +-
 .../model/good/ProperServiceWithAlias.java         |   3 +-
 .../model/good/ProperServiceWithMixin.java         |   3 +-
 .../causeway/testdomain/rospec/RoSpecSampler.java  |   5 +-
 .../dom/FakeDataDemoObjectWithAllMenu.java         |   5 +-
 .../applib/fixturescripts/FixtureScripts.java      | 153 +++++++++++----
 .../h2console/ui/services/H2ManagerMenu.java       |   5 +-
 .../hsqldbmgr/dom/services/HsqlDbManagerMenu.java  |   5 +-
 .../services/menu/MenuUiServiceDefault.java        |   2 +-
 viewers/graphql/adoc/modules/ROOT/pages/i18n.adoc  |   2 +-
 .../ROOT/pages/setup-and-configuration.adoc        |   5 +
 .../adoc/modules/ROOT/pages/testsupport.adoc       |   2 +-
 .../viewer/graphql/model/context/Context.java      |   9 +-
 .../viewer/graphql/model/domain/ElementCustom.java |  22 +++
 .../domain/common/query/CommonDomainObject.java    |   7 +-
 .../domain/common/query/CommonDomainService.java   |   2 +
 .../common/query/CommonTopLevelQueryAbstract.java  |   7 +-
 .../domain/common/query/ObjectFeatureUtils.java    |   2 +-
 .../domain/rich/mutation/RichTopLevelMutation.java |   1 +
 .../simple/mutation/SimpleTopLevelMutation.java    |   6 +-
 .../graphql/model/types/TypeMapperDefault.java     |  40 ++--
 viewers/graphql/pom.xml                            |   1 +
 .../viewer/test/domain/admin/AdminMenu.java        |   9 +-
 .../viewer/test/domain/calc/Calculator.java        |  53 +++---
 .../viewer/test/domain/dept/Departments.java       |   4 +-
 .../graphql/viewer/test/domain/dept/DeptHeads.java |   3 +-
 .../graphql/viewer/test/domain/dept/People.java    |   8 +-
 .../graphql/viewer/test/domain/dept/Staff.java     |   4 +-
 .../viewer/test/domain/i18n/I18nCalculator.java    |   8 +-
 viewers/graphql/test2/pom.xml                      | 101 ++++++++++
 .../viewer/graphql/viewer/test2}/.gitignore        |   0
 .../viewer/test2/domain/UniversityModule.java      |  24 +--
 .../viewer/test2}/domain/calc/Calculator.java      |   4 +-
 .../graphql/viewer/test2/domain/calc/Month.java    |  27 +++
 .../viewer/test2/domain/calc/Month_Test.java       |  14 ++
 .../viewer/test2/domain/dept/Department.java       | 207 +++++++++++++++++++++
 .../test2/domain/dept/DepartmentRepository.java    |  60 ++++++
 .../viewer/test2/domain/dept}/Departments.java     |   4 +-
 .../graphql/viewer/test2/domain/dept/DeptHead.java | 137 ++++++++++++++
 .../test2/domain/dept/DeptHeadRepository.java      |  71 +++++++
 .../viewer/test2/domain/dept}/DeptHeads.java       |   4 +-
 .../graphql/viewer/test2/domain/dept/Grade.java    |  26 +--
 .../graphql/viewer/test2}/domain/dept/People.java  |   4 +-
 .../graphql/viewer/test2/domain/dept/Person.java   |  17 ++
 .../graphql/viewer/test2/domain/dept}/Staff.java   |   4 +-
 .../viewer/test2/domain/dept/StaffMember.java      | 119 ++++++++++++
 .../test2/domain/dept/StaffMemberRepository.java   |  72 +++++++
 .../viewer/test2/e2e/Abstract_IntegTest.java       |  61 ++++++
 ...alculator_IntegTest.each.add_big_decimals._.gql |   0
 ...r_IntegTest.each.add_big_decimals.approved.json |   0
 ...alculator_IntegTest.each.add_big_integers._.gql |   0
 ...r_IntegTest.each.add_big_integers.approved.json |   0
 ...ulator_IntegTest.each.add_double_wrappers._.gql |   0
 ...ntegTest.each.add_double_wrappers.approved.json |   0
 .../Calculator_IntegTest.each.add_doubles._.gql    |   0
 ...ulator_IntegTest.each.add_doubles.approved.json |   0
 ...culator_IntegTest.each.add_float_wrappers._.gql |   0
 ...IntegTest.each.add_float_wrappers.approved.json |   0
 .../Calculator_IntegTest.each.add_floats._.gql     |   0
 ...culator_IntegTest.each.add_floats.approved.json |   0
 ...lator_IntegTest.each.add_integer_wrappers._.gql |   0
 ...tegTest.each.add_integer_wrappers.approved.json |   0
 .../Calculator_IntegTest.each.add_integers._.gql   |   0
 ...lator_IntegTest.each.add_integers.approved.json |   0
 .../Calculator_IntegTest.each.boolean_and_1._.gql  |   0
 ...ator_IntegTest.each.boolean_and_1.approved.json |   0
 .../Calculator_IntegTest.each.boolean_and_2._.gql  |   0
 ...ator_IntegTest.each.boolean_and_2.approved.json |   0
 .../Calculator_IntegTest.each.boolean_not._.gql    |   0
 ...ulator_IntegTest.each.boolean_not.approved.json |   0
 .../Calculator_IntegTest.each.boolean_or_1._.gql   |   0
 ...lator_IntegTest.each.boolean_or_1.approved.json |   0
 .../Calculator_IntegTest.each.boolean_or_2._.gql   |   0
 ...lator_IntegTest.each.boolean_or_2.approved.json |   0
 .../calc/Calculator_IntegTest.each.concat._.gql    |   0
 .../Calculator_IntegTest.each.concat.approved.json |   0
 ...lator_IntegTest.each.jdk8_local_plus_days._.gql |   0
 ...tegTest.each.jdk8_local_plus_days.approved.json |   0
 ...st.each.jdk8_local_plus_hours_and_minutes._.gql |   0
 ...jdk8_local_plus_hours_and_minutes.approved.json |   0
 ...k8_offset_plus_days_and_hours_and_minutes._.gql |   0
 ...t_plus_days_and_hours_and_minutes.approved.json |   0
 ...t.each.jdk8_offset_plus_hours_and_minutes._.gql |   0
 ...dk8_offset_plus_hours_and_minutes.approved.json |   0
 ...dk8_zoned_plus_days_and_hours_and_minutes._.gql |   0
 ...d_plus_days_and_hours_and_minutes.approved.json |   0
 ...lator_IntegTest.each.joda_local_plus_days._.gql |   0
 ...tegTest.each.joda_local_plus_days.approved.json |   0
 ...st.each.joda_local_plus_hours_and_minutes._.gql |   0
 ...joda_local_plus_hours_and_minutes.approved.json |   0
 .../Calculator_IntegTest.each.joda_plus_days._.gql |   0
 ...tor_IntegTest.each.joda_plus_days.approved.json |   0
 .../Calculator_IntegTest.each.next_month._.gql     |   0
 ...culator_IntegTest.each.next_month.approved.json |   0
 ...Calculator_IntegTest.each.scenario_concat._.gql |   0
 ...or_IntegTest.each.scenario_concat.approved.json |   0
 .../Calculator_IntegTest.each.some_locale._.gql    |   0
 ...ulator_IntegTest.each.some_locale.approved.json |   0
 .../calc/Calculator_IntegTest.each.some_url._.gql  |   0
 ...alculator_IntegTest.each.some_url.approved.json |   0
 .../calc/Calculator_IntegTest.each.some_uuid._.gql |   0
 ...lculator_IntegTest.each.some_uuid.approved.json |   0
 .../test2/e2e/calc/Calculator_IntegTest.java       |  29 ++-
 .../viewer/test2/schema/PrintSchemaIntegTest.java  |  66 +++++++
 .../viewer/test2/schema/VerifySchemaIntegTest.java |  76 ++++++++
 .../src/test/resources/application-test.properties |   0
 .../src/test/resources/junit-platform.properties   |   0
 .../integration/GraphQlSourceForCauseway.java      |   1 -
 .../hints-and-tips/view-model-as-parameter.adoc    |   2 +-
 .../rendering/ReprRendererAbstract.java            |   6 -
 .../swagger/internal/_OpenApiModelFactory.java     |   2 +-
 ...sewayViewerRestfulObjectsIntegTestAbstract.java |   9 +-
 .../test/domain/dom/Departments.java               |   4 +-
 .../restfulobjects/test/domain/dom/DeptHeads.java  |   3 +-
 .../restfulobjects/test/domain/dom/People.java     |   8 +-
 .../restfulobjects/test/domain/dom/Staff.java      |   4 +-
 .../test/scenarios/dept/Department_IntegTest.java  |  15 +-
 .../viewer/context/ResourceContext.java            |   7 +
 .../resources/DomainServiceResourceServerside.java |  14 +-
 .../resources/DomainServicesListReprRenderer.java  |  14 +-
 .../viewer/resources/HomePageReprRenderer.java     |   2 +-
 .../viewer/resources/ResourceAbstract.java         |   9 +-
 .../components/scalars/ScalarFragmentFactory.java  |   4 +-
 .../scalars/ScalarPanelFormFieldAbstract.html      |  22 ++-
 .../scalars/ScalarPanelTextFieldAbstract.java      |   8 +-
 .../ScalarPanelTextFieldWithTemporalPicker.java    | 111 +++++++++--
 .../scalars/datepicker/TemporalDecomposition.java  | 154 +++++++++++++++
 .../datepicker/TextFieldWithDateTimePicker.java    |  22 +--
 .../wicket/ui/pages/login/SignInPanelAbstract.java |  23 +--
 .../apache/causeway/viewer/wicket/ui/util/Wkt.java |  29 ++-
 .../viewer/wicket/ui/util/WktComponents.java       |  63 +++++--
 .../ComponentFactoryRegistrarDefault.java          |   7 +-
 235 files changed, 2729 insertions(+), 1259 deletions(-)
 create mode 100644 antora/components/refguide-index/modules/applib/pages/index/services/ascii/AsciiIdentifierService.adoc
 create mode 100644 antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_ApiScope.adoc
 create mode 100644 antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_SchemaStyle.adoc
 copy regressiontests/base/src/main/java/org/apache/causeway/testdomain/model/bad/InvalidServiceWithAlias.java => api/applib/src/main/java/org/apache/causeway/applib/services/scope/ActionContributionFilterService.java (54%)
 delete mode 100644 core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/notinservicemenu/NotInServiceMenuFacetAbstract.java
 delete mode 100644 core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/notinservicemenu/derived/NotInServiceMenuFacetFromDomainServiceFacet.java
 delete mode 100644 core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/notinservicemenu/derived/NotInServiceMenuFacetFromDomainServiceFacetFactory.java
 delete mode 100644 core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/actions/notinservicemenu/derived/NotInServiceMenuFacetFromDomainServiceFacetFactoryTest.java
 create mode 100644 viewers/graphql/test2/pom.xml
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/.gitignore (100%)
 rename core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/notinservicemenu/NotInServiceMenuFacet.java => viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/UniversityModule.java (60%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/domain/calc/Calculator.java (98%)
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month.java
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month_Test.java
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Department.java
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DepartmentRepository.java
 copy viewers/{restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/domain/dom => graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept}/Departments.java (95%)
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHead.java
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHeadRepository.java
 copy viewers/{restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/domain/dom => graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept}/DeptHeads.java (93%)
 copy core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/Bar.java => viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Grade.java (63%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/domain/dept/People.java (91%)
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Person.java
 copy viewers/{restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/domain/dom => graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept}/Staff.java (95%)
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMember.java
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMemberRepository.java
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/Abstract_IntegTest.java
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_big_decimals._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_big_decimals.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_big_integers._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_big_integers.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_double_wrappers._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_double_wrappers.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_doubles._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_doubles.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_float_wrappers._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_float_wrappers.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_floats._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_floats.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_integers._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.add_integers.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_and_1._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_and_1.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_and_2._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_and_2.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_not._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_not.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_or_1._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_or_1.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_or_2._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.boolean_or_2.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.concat._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.concat.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.joda_plus_days._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.joda_plus_days.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.next_month._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.next_month.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.scenario_concat._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.scenario_concat.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.some_locale._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.some_locale.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.some_url._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.some_url.approved.json (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.some_uuid._.gql (100%)
 copy viewers/graphql/{test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test => test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2}/e2e/calc/Calculator_IntegTest.each.some_uuid.approved.json (100%)
 copy regressiontests/base/src/main/java/org/apache/causeway/testdomain/model/good/ProperServiceWithMixin.java => viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.java (57%)
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/PrintSchemaIntegTest.java
 create mode 100644 viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/VerifySchemaIntegTest.java
 copy viewers/graphql/{test => test2}/src/test/resources/application-test.properties (100%)
 copy viewers/graphql/{test => test2}/src/test/resources/junit-platform.properties (100%)
 create mode 100644 viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/scalars/datepicker/TemporalDecomposition.java


(causeway) 02/03: CAUSEWAY-3676: adds tests for graphql with different scope

Posted by da...@apache.org.
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 6b99d52c70fb2ffafdf89dbf6983925b6331b897
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Mar 14 10:55:51 2024 +0000

    CAUSEWAY-3676: adds tests for graphql with different scope
---
 bom/pom.xml                                        |   5 +
 .../pages/sections/causeway.viewer.graphql.adoc    |   8 +
 .../viewer/graphql/model/context/Context.java      |   7 +-
 .../viewer/graphql/model/domain/ElementCustom.java |  22 +++
 .../domain/common/query/CommonDomainObject.java    |  17 --
 .../domain/common/query/CommonDomainService.java   |   2 +
 .../common/query/CommonTopLevelQueryAbstract.java  |  20 +-
 .../domain/common/query/ObjectFeatureUtils.java    |   2 +-
 .../domain/rich/mutation/RichTopLevelMutation.java |   1 +
 .../simple/mutation/SimpleTopLevelMutation.java    |   6 +-
 .../graphql/model/types/TypeMapperDefault.java     |  40 ++--
 viewers/graphql/pom.xml                            |   1 +
 viewers/graphql/test2/pom.xml                      | 101 ++++++++++
 .../viewer/graphql/viewer/test2/.gitignore         |   2 +
 .../viewer/test2/domain/UniversityModule.java      |  32 ++++
 .../viewer/test2/domain/calc/Calculator.java       | 178 ++++++++++++++++++
 .../graphql/viewer/test2/domain/calc/Month.java    |  27 +++
 .../viewer/test2/domain/calc/Month_Test.java       |  14 ++
 .../viewer/test2/domain/dept/Department.java       | 207 +++++++++++++++++++++
 .../test2/domain/dept/DepartmentRepository.java    |  60 ++++++
 .../viewer/test2/domain/dept/Departments.java      |  63 +++++++
 .../graphql/viewer/test2/domain/dept/DeptHead.java | 137 ++++++++++++++
 .../test2/domain/dept/DeptHeadRepository.java      |  71 +++++++
 .../viewer/test2/domain/dept/DeptHeads.java        |  53 ++++++
 .../graphql/viewer/test2/domain/dept/Grade.java    |  30 +++
 .../graphql/viewer/test2/domain/dept/People.java   |  36 ++++
 .../graphql/viewer/test2/domain/dept/Person.java   |  17 ++
 .../graphql/viewer/test2/domain/dept/Staff.java    |  61 ++++++
 .../viewer/test2/domain/dept/StaffMember.java      | 119 ++++++++++++
 .../test2/domain/dept/StaffMemberRepository.java   |  72 +++++++
 .../viewer/test2/e2e/Abstract_IntegTest.java       |  61 ++++++
 ...alculator_IntegTest.each.add_big_decimals._.gql |  24 +++
 ...r_IntegTest.each.add_big_decimals.approved.json |  17 ++
 ...alculator_IntegTest.each.add_big_integers._.gql |  11 ++
 ...r_IntegTest.each.add_big_integers.approved.json |  13 ++
 ...ulator_IntegTest.each.add_double_wrappers._.gql |  11 ++
 ...ntegTest.each.add_double_wrappers.approved.json |  13 ++
 .../Calculator_IntegTest.each.add_doubles._.gql    |  11 ++
 ...ulator_IntegTest.each.add_doubles.approved.json |  13 ++
 ...culator_IntegTest.each.add_float_wrappers._.gql |  11 ++
 ...IntegTest.each.add_float_wrappers.approved.json |  13 ++
 .../Calculator_IntegTest.each.add_floats._.gql     |  11 ++
 ...culator_IntegTest.each.add_floats.approved.json |  13 ++
 ...lator_IntegTest.each.add_integer_wrappers._.gql |  11 ++
 ...tegTest.each.add_integer_wrappers.approved.json |  13 ++
 .../Calculator_IntegTest.each.add_integers._.gql   |  11 ++
 ...lator_IntegTest.each.add_integers.approved.json |  13 ++
 .../Calculator_IntegTest.each.boolean_and_1._.gql  |  11 ++
 ...ator_IntegTest.each.boolean_and_1.approved.json |  13 ++
 .../Calculator_IntegTest.each.boolean_and_2._.gql  |  11 ++
 ...ator_IntegTest.each.boolean_and_2.approved.json |  13 ++
 .../Calculator_IntegTest.each.boolean_not._.gql    |  11 ++
 ...ulator_IntegTest.each.boolean_not.approved.json |  13 ++
 .../Calculator_IntegTest.each.boolean_or_1._.gql   |  11 ++
 ...lator_IntegTest.each.boolean_or_1.approved.json |  13 ++
 .../Calculator_IntegTest.each.boolean_or_2._.gql   |  11 ++
 ...lator_IntegTest.each.boolean_or_2.approved.json |  13 ++
 .../calc/Calculator_IntegTest.each.concat._.gql    |  11 ++
 .../Calculator_IntegTest.each.concat.approved.json |  13 ++
 ...lator_IntegTest.each.jdk8_local_plus_days._.gql |  11 ++
 ...tegTest.each.jdk8_local_plus_days.approved.json |  13 ++
 ...st.each.jdk8_local_plus_hours_and_minutes._.gql |  11 ++
 ...jdk8_local_plus_hours_and_minutes.approved.json |  13 ++
 ...k8_offset_plus_days_and_hours_and_minutes._.gql |  11 ++
 ...t_plus_days_and_hours_and_minutes.approved.json |  13 ++
 ...t.each.jdk8_offset_plus_hours_and_minutes._.gql |  11 ++
 ...dk8_offset_plus_hours_and_minutes.approved.json |  13 ++
 ...dk8_zoned_plus_days_and_hours_and_minutes._.gql |  11 ++
 ...d_plus_days_and_hours_and_minutes.approved.json |  13 ++
 ...lator_IntegTest.each.joda_local_plus_days._.gql |  11 ++
 ...tegTest.each.joda_local_plus_days.approved.json |  13 ++
 ...st.each.joda_local_plus_hours_and_minutes._.gql |  11 ++
 ...joda_local_plus_hours_and_minutes.approved.json |  13 ++
 .../Calculator_IntegTest.each.joda_plus_days._.gql |  11 ++
 ...tor_IntegTest.each.joda_plus_days.approved.json |  13 ++
 .../Calculator_IntegTest.each.next_month._.gql     |  11 ++
 ...culator_IntegTest.each.next_month.approved.json |  13 ++
 ...Calculator_IntegTest.each.scenario_concat._.gql |  20 ++
 ...or_IntegTest.each.scenario_concat.approved.json |  22 +++
 .../Calculator_IntegTest.each.some_locale._.gql    |  11 ++
 ...ulator_IntegTest.each.some_locale.approved.json |  13 ++
 .../calc/Calculator_IntegTest.each.some_url._.gql  |  11 ++
 ...alculator_IntegTest.each.some_url.approved.json |  13 ++
 .../calc/Calculator_IntegTest.each.some_uuid._.gql |  11 ++
 ...lculator_IntegTest.each.some_uuid.approved.json |  13 ++
 .../test2/e2e/calc/Calculator_IntegTest.java       |  41 ++++
 .../viewer/test2/schema/PrintSchemaIntegTest.java  |  66 +++++++
 .../viewer/test2/schema/VerifySchemaIntegTest.java |  76 ++++++++
 .../src/test/resources/application-test.properties |  30 +++
 .../src/test/resources/junit-platform.properties   |   2 +
 90 files changed, 2319 insertions(+), 51 deletions(-)

diff --git a/bom/pom.xml b/bom/pom.xml
index dce9bcbfb3..deef864a80 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -527,6 +527,11 @@ It is therefore a copy of org.apache:apache, with customisations clearly identif
                 <artifactId>causeway-viewer-graphql-test</artifactId>
                 <version>2.0.0-SNAPSHOT</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.causeway.viewer</groupId>
+                <artifactId>causeway-viewer-graphql-test2</artifactId>
+                <version>2.0.0-SNAPSHOT</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.causeway.viewer</groupId>
                 <artifactId>causeway-viewer-graphql-viewer</artifactId>
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc b/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc
index 8be5edaac9..0c57594ecc 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc
@@ -11,6 +11,14 @@ include::../section-hooks/causeway.viewer.graphql~pre.adoc[]
 |Property
 |Default
 |Description
+|
+[[causeway.viewer.graphql.api-scope]]
+causeway.viewer.graphql.api-scope
+
+| 
+| Which domain objects to include the GraphQL schema.
+
+
 |
 [[causeway.viewer.graphql.api-variant]]
 causeway.viewer.graphql. +
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java
index a76300f777..0ae9fa904d 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/context/Context.java
@@ -90,10 +90,15 @@ public class Context {
     }
 
     public List<ObjectSpecification> objectSpecifications(final Predicate<ObjectSpecification> predicate) {
+        val includeEntities = causewayConfiguration.getViewer().getGraphql().getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL;
         return specificationLoader.snapshotSpecifications()
                 .filter(x -> x.getCorrespondingClass().getPackage() != Either.class.getPackage())   // exclude the org.apache_causeway.commons.functional
                 .distinct((a, b) -> a.getLogicalTypeName().equals(b.getLogicalTypeName()))
-                .filter(x -> x.isEntityOrViewModelOrAbstract() || x.getBeanSort().isManagedBeanContributing())
+                .filter(x ->
+                           x.isViewModel()
+                        || x.isEntity() && includeEntities
+                        || x.getBeanSort().isManagedBeanContributing()
+                )
                 .filter(predicate)
                 .sorted(Comparator.comparing(HasLogicalType::getLogicalTypeName))
                 .toList();
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/ElementCustom.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/ElementCustom.java
index fb5c815bb5..5711455595 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/ElementCustom.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/ElementCustom.java
@@ -25,6 +25,11 @@ import graphql.schema.GraphQLObjectType;
 import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 import static graphql.schema.GraphQLObjectType.newObject;
 
+import org.apache.causeway.core.config.CausewayConfiguration;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
+import org.apache.causeway.core.metamodel.spec.feature.ObjectAssociation;
+
 import org.springframework.lang.Nullable;
 
 import org.apache.causeway.viewer.graphql.model.context.Context;
@@ -152,4 +157,21 @@ public abstract class ElementCustom
         return FieldCoordinates.coordinates(gqlObjectType, fieldName);
     }
 
+    protected boolean inApiScope(ObjectAction act) {
+        if (graphqlConfiguration.getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL) {
+            return true;
+        }
+        val returnType = act.getElementType();
+        return returnType.isViewModelOrValueOrVoid() &&
+                act.getParameterTypes().stream().allMatch(ObjectSpecification::isViewModelOrValue);
+    }
+
+    protected boolean inApiScope(final ObjectAssociation objAssoc) {
+        if (graphqlConfiguration.getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL) {
+            return true;
+        }
+        return objAssoc.getElementType().isViewModelOrValue();
+    }
+
+
 }
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java
index 52c7a8d15f..807f96a8f5 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java
@@ -37,7 +37,6 @@ 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.ObjectAssociation;
-import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import org.apache.causeway.viewer.graphql.model.domain.Environment;
 import org.apache.causeway.viewer.graphql.model.domain.Element;
@@ -174,22 +173,6 @@ public class CommonDomainObject
                 .forEach(act -> actions.add(addChildFieldFor(schemaStrategy.newAction(this, act, context))));
     }
 
-    private boolean inApiScope(ObjectAction act) {
-        if (graphqlConfiguration.getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL) {
-            return true;
-        }
-        val returnType = act.getElementType();
-        return returnType.isViewModelOrValueOrVoid() &&
-               act.getParameterTypes().stream().allMatch(ObjectSpecification::isViewModelOrValue);
-    }
-
-    private boolean inApiScope(final ObjectAssociation objAssoc) {
-        if (graphqlConfiguration.getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL) {
-            return true;
-        }
-        return objAssoc.getElementType().isViewModelOrValue();
-    }
-
     @SuppressWarnings("unused")
     private ActionScope determineActionScope() {
         return context.causewaySystemEnvironment.getDeploymentType().isProduction()
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainService.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainService.java
index be21351628..362b91eaf8 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainService.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainService.java
@@ -89,7 +89,9 @@ public class CommonDomainService
     private void addActions() {
 
         val apiVariant = context.causewayConfiguration.getViewer().getGraphql().getApiVariant();
+        val apiScope = context.causewayConfiguration.getViewer().getGraphql().getApiVariant();
         objectSpecification.streamActions(context.getActionScope(), MixedIn.INCLUDED)
+                .filter(this::inApiScope)
                 .filter(objectAction -> objectAction.getSemantics().isSafeInNature() ||
                         apiVariant != CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_ONLY    // the other variants have an entry for all actions.
                 )
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java
index f2b6454043..d37fdaace0 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java
@@ -23,7 +23,6 @@ import java.util.List;
 
 import graphql.schema.DataFetchingEnvironment;
 
-import org.apache.causeway.core.config.CausewayConfiguration;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import org.apache.causeway.viewer.graphql.model.domain.Element;
@@ -49,18 +48,16 @@ public abstract class CommonTopLevelQueryAbstract
         super(schemaStrategy.getSchemaType().name() + "Schema", context);
         this.schemaStrategy = schemaStrategy;
 
-        boolean includeEntities = context.causewayConfiguration.getViewer().getGraphql().getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL;
         context.objectSpecifications().forEach(objectSpec -> {
             switch (objectSpec.getBeanSort()) {
 
                 case ABSTRACT:
                 case VIEW_MODEL:
-                    addDomainObject(objectSpec, schemaStrategy, context);
-                    break;
                 case ENTITY:
-                    if (includeEntities) {
-                        addDomainObject(objectSpec, schemaStrategy, context);
-                    }
+                    val gqlvDomainObject = schemaStrategy.domainObjectFor(objectSpec, context);
+                    addChildField(gqlvDomainObject.newField());
+                    domainObjects.add(gqlvDomainObject);
+                    break;
 
             }
         });
@@ -78,15 +75,6 @@ public abstract class CommonTopLevelQueryAbstract
         });
     }
 
-    private void addDomainObject(
-            final ObjectSpecification objectSpec,
-            final SchemaStrategy schemaStrategy,
-            final Context context) {
-        val gqlvDomainObject = schemaStrategy.domainObjectFor(objectSpec, context);
-        addChildField(gqlvDomainObject.newField());
-        domainObjects.add(gqlvDomainObject);
-    }
-
     public static List<ObjectSpecification> superclassesOf(final ObjectSpecification objectSpecification) {
         val superclasses = new ArrayList<ObjectSpecification>();
         ObjectSpecification superclass = objectSpecification.superclass();
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java
index fecaae4647..2a6d1814ce 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/ObjectFeatureUtils.java
@@ -39,7 +39,7 @@ import lombok.val;
 @UtilityClass
 public class ObjectFeatureUtils {
 
-    public static Optional<Object> asPojo(
+    static Optional<Object> asPojo(
             final ObjectSpecification elementType,
             final Object argumentValueObj,
             final Environment environment,
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/rich/mutation/RichTopLevelMutation.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/rich/mutation/RichTopLevelMutation.java
index 6676ef098f..f9649b8664 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/rich/mutation/RichTopLevelMutation.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/rich/mutation/RichTopLevelMutation.java
@@ -53,6 +53,7 @@ public class RichTopLevelMutation
 
         objectSpecifications.forEach(objectSpec -> {
             objectSpec.streamActions(context.getActionScope(), MixedIn.INCLUDED)
+                    .filter(this::inApiScope)
                     .filter(x -> ! x.getSemantics().isSafeInNature())
                     .forEach(objectAction -> addAction(objectSpec, objectAction));
             objectSpec.streamProperties(MixedIn.INCLUDED)
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/mutation/SimpleTopLevelMutation.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/mutation/SimpleTopLevelMutation.java
index e5671a732e..372263c0be 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/mutation/SimpleTopLevelMutation.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/simple/mutation/SimpleTopLevelMutation.java
@@ -51,15 +51,17 @@ public class SimpleTopLevelMutation
         }
         val objectSpecifications = context.objectSpecifications();
 
-        objectSpecifications.forEach(objectSpec -> {
+        objectSpecifications
+                .forEach(objectSpec -> {
             objectSpec.streamActions(context.getActionScope(), MixedIn.INCLUDED)
+                    .filter(this::inApiScope)
                     .filter(x -> ! x.getSemantics().isSafeInNature())
                     .forEach(objectAction -> addAction(objectSpec, objectAction));
             objectSpec.streamProperties(MixedIn.INCLUDED)
                     .filter(property -> ! property.isAlwaysHidden())
+                    .filter(this::inApiScope)
                     .filter(property -> property.containsFacet(PropertySetterFacet.class))
                     .forEach(property -> addProperty(objectSpec, property));
-
         });
 
         buildObjectType();
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapperDefault.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapperDefault.java
index 7e315870f1..622dd65fba 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapperDefault.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapperDefault.java
@@ -95,27 +95,36 @@ public class TypeMapperDefault implements TypeMapper {
             final OneToOneFeature oneToOneFeature,
             final SchemaType schemaType) {
         ObjectSpecification otoaObjectSpec = oneToOneFeature.getElementType();
+
         switch (otoaObjectSpec.getBeanSort()) {
 
             case VIEW_MODEL:
-            case ENTITY:
+                return typeRefPossiblyOptional(oneToOneFeature, schemaType, otoaObjectSpec);
 
-                GraphQLTypeReference fieldTypeRef = typeRef(TypeNames.objectTypeNameFor(otoaObjectSpec, schemaType));
-                return oneToOneFeature.isOptional()
-                        ? fieldTypeRef
-                        : nonNull(fieldTypeRef);
+            case ENTITY:
+                return typeRefPossiblyOptional(oneToOneFeature, schemaType, otoaObjectSpec);
 
             case VALUE:
-
-                GraphQLOutputType scalarType = outputTypeFor(otoaObjectSpec.getCorrespondingClass());
-
-                return oneToOneFeature.isOptional()
-                        ? scalarType
-                        : nonNull(scalarType);
+                return scalarTypePossiblyOptional(oneToOneFeature, otoaObjectSpec);
         }
         return null;
     }
 
+    private static GraphQLOutputType typeRefPossiblyOptional(OneToOneFeature oneToOneFeature, SchemaType schemaType, ObjectSpecification otoaObjectSpec) {
+        GraphQLTypeReference fieldTypeRef = typeRef(TypeNames.objectTypeNameFor(otoaObjectSpec, schemaType));
+        return oneToOneFeature.isOptional()
+                ? fieldTypeRef
+                : nonNull(fieldTypeRef);
+    }
+
+    private GraphQLOutputType scalarTypePossiblyOptional(OneToOneFeature oneToOneFeature, ObjectSpecification otoaObjectSpec) {
+        GraphQLOutputType scalarType = outputTypeFor(otoaObjectSpec.getCorrespondingClass());
+        return oneToOneFeature.isOptional()
+                ? scalarType
+                : nonNull(scalarType);
+    }
+
+
     @Override
     @Nullable
     public GraphQLOutputType outputTypeFor(
@@ -124,9 +133,10 @@ public class TypeMapperDefault implements TypeMapper {
 
         switch (objectSpecification.getBeanSort()){
             case ABSTRACT:
-            case ENTITY:
             case VIEW_MODEL:
                 return typeRef(TypeNames.objectTypeNameFor(objectSpecification, schemaType));
+            case ENTITY:
+                return typeRef(TypeNames.objectTypeNameFor(objectSpecification, schemaType));
 
             case VALUE:
                 return outputTypeFor(objectSpecification.getCorrespondingClass());
@@ -179,9 +189,10 @@ public class TypeMapperDefault implements TypeMapper {
         val elementObjectSpec = oneToOneFeature.getElementType();
         switch (elementObjectSpec.getBeanSort()) {
             case ABSTRACT:
-            case ENTITY:
             case VIEW_MODEL:
                 return typeRef(TypeNames.inputTypeNameFor(elementObjectSpec, schemaType));
+            case ENTITY:
+                return typeRef(TypeNames.inputTypeNameFor(elementObjectSpec, schemaType));
 
             case VALUE:
                 return inputTypeFor(elementObjectSpec.getCorrespondingClass());
@@ -208,9 +219,10 @@ public class TypeMapperDefault implements TypeMapper {
             final SchemaType schemaType){
         switch (elementType.getBeanSort()) {
             case ABSTRACT:
-            case ENTITY:
             case VIEW_MODEL:
                 return typeRef(TypeNames.inputTypeNameFor(elementType, schemaType));
+            case ENTITY:
+                return typeRef(TypeNames.inputTypeNameFor(elementType, schemaType));
 
             case VALUE:
                 return inputTypeFor(elementType.getCorrespondingClass());
diff --git a/viewers/graphql/pom.xml b/viewers/graphql/pom.xml
index 726c6b7ae0..cd12a944cb 100644
--- a/viewers/graphql/pom.xml
+++ b/viewers/graphql/pom.xml
@@ -52,6 +52,7 @@
 		<module>model</module>
 		<module>testsupport</module>
 		<module>test</module>
+		<module>test2</module>
 		<module>viewer</module>
 	</modules>
 
diff --git a/viewers/graphql/test2/pom.xml b/viewers/graphql/test2/pom.xml
new file mode 100644
index 0000000000..9492ba36f1
--- /dev/null
+++ b/viewers/graphql/test2/pom.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.causeway.viewer</groupId>
+		<artifactId>causeway-viewer-graphql</artifactId>
+		<version>2.0.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>causeway-viewer-graphql-test2</artifactId>
+	<name>Apache Causeway Viewer - GraphQL (Test 2)</name>
+
+	<properties>
+		<jar-plugin.automaticModuleName>org.apache.causeway.viewer.graphql.test2</jar-plugin.automaticModuleName>
+		<git-plugin.propertiesDir>org/apache/causeway/viewer/graphql/test2</git-plugin.propertiesDir>
+        <maven.install.skip>true</maven.install.skip>
+        <maven.deploy.skip>true</maven.deploy.skip>
+
+		<!-- as a minimum requirement of
+		    org.springframework.graphql:spring-graphql-test:1.2.4 -->
+        <maven.compiler.release>17</maven.compiler.release>
+
+
+    </properties>
+
+    <build>
+		<testResources>
+			<testResource>
+				<directory>src/test/resources</directory>
+				<filtering>true</filtering>
+			</testResource>
+			<testResource>
+				<directory>src/test/java</directory>
+				<filtering>false</filtering>
+			</testResource>
+		</testResources>
+	</build>
+	<dependencies>
+
+		<!-- TESTING -->
+
+        <dependency>
+            <groupId>org.apache.causeway.viewer</groupId>
+            <artifactId>causeway-viewer-graphql-testsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.causeway.persistence</groupId>
+            <artifactId>causeway-persistence-jpa-eclipselink</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test-autoconfigure</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.gavlyukovskiy</groupId>
+            <artifactId>datasource-proxy-spring-boot-starter</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.vertical-blank</groupId>
+            <artifactId>sql-formatter</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+
+</project>
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/.gitignore b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/.gitignore
new file mode 100644
index 0000000000..837d57bea7
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/.gitignore
@@ -0,0 +1,2 @@
+*.received.gql
+*.received.json
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/UniversityModule.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/UniversityModule.java
new file mode 100644
index 0000000000..777e6b93a0
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/UniversityModule.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain;
+
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+
+@Configuration
+@ComponentScan
+@EnableJpaRepositories
+@EntityScan(basePackageClasses = {UniversityModule.class})
+public class UniversityModule  {
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Calculator.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Calculator.java
new file mode 100644
index 0000000000..55777d325b
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Calculator.java
@@ -0,0 +1,178 @@
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.calc;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URL;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.ZonedDateTime;
+import java.util.Locale;
+import java.util.UUID;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.DomainService;
+import org.apache.causeway.applib.annotation.NatureOfService;
+import org.apache.causeway.applib.annotation.Optionality;
+import org.apache.causeway.applib.annotation.Parameter;
+import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+
+@Named("university.calc.Calculator")
+@DomainService(nature= NatureOfService.BOTH)
+@Priority(PriorityPrecedence.EARLY)
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class Calculator {
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public byte addBytes(byte x, byte y) {
+        return (byte)(x+y);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public int addByteWrappers(Byte x, @Parameter(optionality = Optionality.OPTIONAL) Byte y) {
+        return y != null ? x+y : x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public short addShorts(short x, short y) {
+        return (short)(x+y);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public Short addShortWrappers(Short x, @Parameter(optionality = Optionality.OPTIONAL) Short y) {
+        return y != null ? (short)(x+y) : x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public int addIntegers(int x, int y) {
+        return x+y;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public int addIntegerWrappers(Integer x, @Parameter(optionality = Optionality.OPTIONAL) Integer y) {
+        return y != null ? x+y : x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public double addDoubles(double x, double y) {
+        return x+y;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public Double addDoubleWrappers(Double x, @Parameter(optionality = Optionality.OPTIONAL) Double y) {
+        return y != null ? x+y : x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public float addFloats(float x, float y) {
+        return x+y;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public Float addFloatWrappers(Float x, @Parameter(optionality = Optionality.OPTIONAL) Float y) {
+        return y != null ? (float)(x+y) : x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public BigInteger addBigIntegers(BigInteger x, @Parameter(optionality = Optionality.OPTIONAL) BigInteger y) {
+        return y != null ? x.add(y) : x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public BigDecimal addBigDecimals(BigDecimal x, @Parameter(optionality = Optionality.OPTIONAL) BigDecimal y) {
+        return y != null ? x.add(y) : x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public LocalDate jdk8LocalPlusDays(LocalDate date, int numDays) {
+        return date.plusDays(numDays);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public OffsetDateTime jdk8OffsetPlusDaysAndHoursAndMinutes(OffsetDateTime dateTime, int numDays, int numHours, int numMinutes) {
+        return dateTime.plusDays(numDays).plusHours(numHours).plusMinutes(numMinutes);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public ZonedDateTime jdk8ZonedPlusDaysAndHoursAndMinutes(ZonedDateTime dateTime, int numDays, int numHours, int numMinutes) {
+        return dateTime.plusDays(numDays).plusHours(numHours).plusMinutes(numMinutes);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public OffsetTime jdk8OffsetPlusHoursAndMinutes(OffsetTime time, int numHours, int numMinutes) {
+        return time.plusHours(numHours).plusMinutes(numMinutes);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public LocalTime jdk8LocalPlusHoursAndMinutes(LocalTime time, int numHours, int numMinutes) {
+        return time.plusHours(numHours).plusMinutes(numMinutes);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public org.joda.time.LocalDate jodaLocalPlusDays(org.joda.time.LocalDate date, int numDays) {
+        return date.plusDays(numDays);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public org.joda.time.DateTime jodaPlusDaysAndHoursAndMinutes(org.joda.time.DateTime dateTime, int numDays, int numHours, int numMinutes) {
+        return dateTime.plusDays(numDays).plusHours(numHours).plusMinutes(numMinutes);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public org.joda.time.LocalTime jodaLocalPlusHoursAndMinutes(org.joda.time.LocalTime time, int numHours, int numMinutes) {
+        return time.plusHours(numHours).plusMinutes(numMinutes);
+    }
+
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public boolean and(boolean x, boolean y) {
+        return x & y;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public boolean or(boolean x, boolean y) {
+        return x | y;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public boolean not(boolean x) {
+        return !x;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public Month nextMonth(Month month) {
+        return month.nextMonth();
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public String concat(String prefix, @Parameter(optionality = Optionality.OPTIONAL) String suffix) {
+        return prefix + suffix;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public UUID someUuid() {
+        return UUID.fromString("91be0d2d-1752-4962-ad2c-89a7ef73a656");
+    }
+
+    @SneakyThrows
+    @Action(semantics = SemanticsOf.SAFE)
+    public URL someUrl() {
+        return new URL("https://causeway.apache.org");
+    }
+
+    @SneakyThrows
+    @Action(semantics = SemanticsOf.SAFE)
+    public Locale someLocale() {
+        return Locale.UK;
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month.java
new file mode 100644
index 0000000000..223aa75595
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month.java
@@ -0,0 +1,27 @@
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.calc;
+
+public enum Month {
+    JANUARY,
+    FEBRUARY,
+    MARCH,
+    APRIL,
+    MAY,
+    JUNE,
+    JULY,
+    AUGUST,
+    SEPTEMBER,
+    OCTOBER,
+    NOVEMBER,
+    DECEMBER,
+    ;
+
+    public Month nextMonth() {
+        int currentMonthOrdinal = this.ordinal();
+        int nextMonthOrdinal = (currentMonthOrdinal + 1) % Month.values().length;
+        return Month.values()[nextMonthOrdinal];
+    }
+
+    public String toString() {
+        return "Month of " + ("" + name().charAt(0)).toUpperCase() + (name().substring(1).toLowerCase());
+    }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month_Test.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month_Test.java
new file mode 100644
index 0000000000..4bb21cbceb
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/calc/Month_Test.java
@@ -0,0 +1,14 @@
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.calc;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class Month_Test {
+
+    @Test
+    public void testNextMonth() {
+        assertThat(Month.JANUARY.nextMonth()).isEqualTo(Month.FEBRUARY);
+        assertThat(Month.DECEMBER.nextMonth()).isEqualTo(Month.JANUARY);
+    }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Department.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Department.java
new file mode 100644
index 0000000000..a99ae0c2af
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Department.java
@@ -0,0 +1,207 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.ActionLayout;
+import org.apache.causeway.applib.annotation.Bounding;
+import org.apache.causeway.applib.annotation.Collection;
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.DomainObjectLayout;
+import org.apache.causeway.applib.annotation.Editing;
+import org.apache.causeway.applib.annotation.Nature;
+import org.apache.causeway.applib.annotation.Property;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.val;
+
+@Entity
+@Table(
+        schema = "public",
+        name = "Department"
+)
+@javax.inject.Named("university.dept.Department")
+@NoArgsConstructor
+@DomainObject(nature = Nature.ENTITY, bounding = Bounding.BOUNDED)
+@DomainObjectLayout(describedAs = "University department specializing in a field of study")
+public class Department implements Comparable<Department> {
+
+
+    public Department(String name, DeptHead deptHead) {
+        this.name = name;
+        this.deptHead = deptHead;
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @Getter @Setter
+    private String name;
+    @Action(semantics = SemanticsOf.IDEMPOTENT)
+    public class changeName {
+
+        public Department act(final String newName){
+            setName(newName);
+            return Department.this;
+        }
+
+        public String default0Act(){
+            return getName();
+        }
+
+        public String validate0Act(String name) {
+            if (name.contains("!")) {
+                return "Name cannot contain '!' character";
+            }
+            return null;
+        }
+    }
+
+
+
+    @Getter @Setter
+    @Property(editing = Editing.ENABLED) // yes, I know: this duplicates the functionality of changeDeptHead action
+    @OneToOne(optional = true)
+    @JoinColumn(name = "deptHead_id")
+    private DeptHead deptHead;
+
+    // overriding the default via @DomainObject to filter out the current dept head.
+    public List<DeptHead> autoCompleteDeptHead(String search) {
+        return deptHeadRepository.findByNameContaining(search)
+                .stream()
+                .filter(x -> x != getDeptHead())
+                .collect(Collectors.toList());
+    }
+
+
+    @Action(semantics = SemanticsOf.IDEMPOTENT)
+    @ActionLayout(associateWith = "deptHead")
+    public class changeDeptHead {
+        public Department act(DeptHead newDeptHead) {
+            setDeptHead(newDeptHead);
+            return Department.this;
+        }
+        public DeptHead default0Act() {
+            return getDeptHead();
+        }
+        public String validate0Act(DeptHead newDeptHead) {
+            if (newDeptHead == getDeptHead()) {
+                return "Same as current";
+            }
+            return null;
+        }
+    }
+
+
+    @OneToMany(mappedBy = "department")
+    private Set<StaffMember> staffMembers = new TreeSet<>();
+
+    // because the ordering seems not to be deterministic?
+    @Collection
+    public List<StaffMember> getStaffMembers() {
+        return staffMembers.stream().sorted().collect(Collectors.toList());
+    }
+
+    @Action(semantics = SemanticsOf.IDEMPOTENT)
+    @ActionLayout(associateWith = "staffMembers")
+    public class addStaffMember {
+
+        public Department act(StaffMember staffMember) {
+            val department = Department.this;
+
+            department.staffMembers.add(staffMember);
+            staffMember.setDepartment(department);
+            return department;
+        }
+    }
+
+    @Action(semantics = SemanticsOf.IDEMPOTENT)
+    @ActionLayout(associateWith = "staffMembers")
+    public class addStaffMembers {
+
+        public Department act(List<StaffMember> staffMembers) {
+            val department = Department.this;
+
+            staffMembers.forEach(sm -> sm.setDepartment(department));
+            department.staffMembers.addAll(staffMembers);
+
+            return department;
+        }
+        public List<StaffMember> choices0Act() {
+            val choices = new ArrayList<>(staffMemberRepository.findAll());
+            choices.removeAll(getStaffMembers());
+            return choices;
+        }
+
+        @Inject
+        StaffMemberRepository staffMemberRepository;
+    }
+
+
+    @Action(semantics = SemanticsOf.IDEMPOTENT)
+    @ActionLayout(associateWith = "staffMembers")
+    @RequiredArgsConstructor
+    public class removeStaffMember {
+
+        public Department act(StaffMember staffMember) {
+            val department = Department.this;
+
+            department.getStaffMembers().add(staffMember);
+            staffMember.setDepartment(department);
+            return department;
+        }
+        public List<StaffMember> choices0Act() {
+            val department = Department.this;
+            return department.getStaffMembers()
+                        .stream()
+                        .sorted(Comparator.comparing(StaffMember::getName))
+                        .collect(Collectors.toList());
+        }
+    }
+
+    @Override
+    public int compareTo(final Department o) {
+        return Comparator.comparing(Department::getName).compare(this, o);
+    }
+
+    @Inject @Transient private DeptHeadRepository deptHeadRepository;
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DepartmentRepository.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DepartmentRepository.java
new file mode 100644
index 0000000000..d2cae7b405
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DepartmentRepository.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+
+import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Repository;
+
+import org.apache.causeway.applib.services.repository.RepositoryService;
+
+@Repository
+public class DepartmentRepository {
+
+    @Inject private RepositoryService repositoryService;
+
+    public Department create(final String name, @Nullable final DeptHead deptHead) {
+        Department department = new Department(name, deptHead);
+        repositoryService.persistAndFlush(department);
+        return department;
+    }
+
+    public List<Department> findAll() {
+        return repositoryService.allInstances(Department.class).stream()
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+    public void removeAll(){
+        repositoryService.removeAll(Department.class);
+    }
+
+    public Department findByName(final String name){
+        return findAll().stream()
+                .filter(dept -> dept.getName().equals(name))
+                .sorted()
+                .findFirst()
+                .orElse(null);
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Departments.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Departments.java
new file mode 100644
index 0000000000..d1e05b87a1
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Departments.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.springframework.lang.Nullable;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.DomainService;
+import org.apache.causeway.applib.annotation.NatureOfService;
+import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+
+import lombok.RequiredArgsConstructor;
+
+@Named("university.dept.Departments")
+@DomainService(
+        nature=NatureOfService.BOTH)
+@javax.annotation.Priority(PriorityPrecedence.EARLY)
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class Departments {
+
+    final DepartmentRepository departmentRepository;
+
+    @Action(semantics = SemanticsOf.NON_IDEMPOTENT)
+    public Department createDepartment(
+            final String name,
+            @Nullable final DeptHead deptHead
+    ){
+        return departmentRepository.create(name, deptHead);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public List<Department> findAllDepartments(){
+        return departmentRepository.findAll();
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public Department findDepartmentByName(final String name){
+        return departmentRepository.findByName(name);
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHead.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHead.java
new file mode 100644
index 0000000000..1c79cb31d0
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHead.java
@@ -0,0 +1,137 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.DomainObjectLayout;
+import org.apache.causeway.applib.annotation.Nature;
+import org.apache.causeway.applib.annotation.Property;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+
+import static org.apache.causeway.applib.annotation.Editing.ENABLED;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity
+@Table(
+        schema = "public",
+        name = "DeptHead"
+)
+@javax.inject.Named("university.dept.DeptHead")
+@DomainObject(
+        nature = Nature.ENTITY,
+        autoCompleteRepository = DeptHeadRepository.class,
+        autoCompleteMethod = "findByNameContaining"
+)
+@DomainObjectLayout(describedAs = "Departmental head, responsible for curriculum, research, funding and staff")
+@NoArgsConstructor
+public class DeptHead extends Person implements Comparable<DeptHead>  {
+
+    public DeptHead(String name) {
+        this.name = name;
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @Getter @Setter
+    @Column(unique=true)
+    private String name;
+
+    @Getter @Setter
+    @Property(editing = ENABLED)
+    @OneToOne(optional = true)
+    @JoinColumn(name = "department_id")
+    private Department department;
+
+    public List<Department> choicesDepartment() {
+        return departmentRepository.findAll();
+    }
+
+
+
+    @Action(semantics = SemanticsOf.IDEMPOTENT)
+    public class changeName {
+
+        public DeptHead act(final String newName){
+            setName(newName);
+            return DeptHead.this;
+        }
+
+        public String default0Act(){
+            return getName();
+        }
+
+        public String validateAct(String name) {
+            if (name.contains("!")) {
+                return "Name cannot contain '!' character";
+            }
+            return null;
+        }
+    }
+
+
+
+    @Action(semantics = SemanticsOf.IDEMPOTENT)
+    public class changeDepartment {
+
+        public DeptHead act(final Department department){
+            setDepartment(department);
+            return DeptHead.this;
+        }
+
+        public List<Department> choices0Act(){
+            return departmentRepository.findAll().stream().
+                    filter(d -> d != getDepartment()).
+                    collect(Collectors.toList());
+        }
+
+        public String validateAct(final Department department){
+            if (getDepartment() == department) return "Already there";
+            return null;
+        }
+    }
+
+    @Override
+    public int compareTo(final DeptHead o) {
+        return Comparator.comparing(DeptHead::getName).compare(this, o);
+    }
+
+    @Inject @Transient DepartmentRepository departmentRepository;
+
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHeadRepository.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHeadRepository.java
new file mode 100644
index 0000000000..e9fa922342
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHeadRepository.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+
+import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Repository;
+
+import org.apache.causeway.applib.services.repository.RepositoryService;
+
+@Repository
+public class DeptHeadRepository {
+
+    @Inject private RepositoryService repositoryService;
+
+    public DeptHead create(final String name, @Nullable final Department department) {
+        DeptHead deptHead = new DeptHead(name);
+        if (department != null) {
+            deptHead.setDepartment(department);
+            department.setDeptHead(deptHead);
+        }
+        repositoryService.persistAndFlush(deptHead);
+        return deptHead;
+    }
+
+    public List<DeptHead> findAll() {
+        return repositoryService.allInstances(DeptHead.class).stream()
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+    public void removeAll(){
+        repositoryService.removeAll(DeptHead.class);
+    }
+
+    public DeptHead findByName(final String name){
+        return findAll().stream()
+                .filter(deptHead -> deptHead.getName().equals(name))
+                .sorted()
+                .findFirst()
+                .orElse(null);
+    }
+
+    public List<DeptHead> findByNameContaining(final String name){
+        return findAll().stream()
+                .filter(deptHead -> deptHead.getName().contains(name))
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHeads.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHeads.java
new file mode 100644
index 0000000000..0eea767761
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/DeptHeads.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.DomainService;
+import org.apache.causeway.applib.annotation.NatureOfService;
+import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+
+import lombok.RequiredArgsConstructor;
+
+@Named("university.dept.DeptHeads")
+@DomainService(nature=NatureOfService.BOTH)
+@javax.annotation.Priority(PriorityPrecedence.EARLY)
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class DeptHeads {
+
+    final DeptHeadRepository deptHeadRepository;
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public List<DeptHead> findAllHeads(){
+        return deptHeadRepository.findAll();
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public DeptHead findHeadByName(final String name){
+        return deptHeadRepository.findByName(name);
+    }
+
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Grade.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Grade.java
new file mode 100644
index 0000000000..356ae5e605
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Grade.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+public enum Grade  {
+
+    PROFESSOR,
+    READER,
+    SENIOR_LECTURER,
+    LECTURER,
+    RESEARCH_ASSISTANT,
+    ;
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/People.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/People.java
new file mode 100644
index 0000000000..ded65ad6f1
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/People.java
@@ -0,0 +1,36 @@
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.DomainService;
+import org.apache.causeway.applib.annotation.NatureOfService;
+import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+
+import lombok.RequiredArgsConstructor;
+
+@Named("university.dept.People")
+@DomainService(
+        nature= NatureOfService.BOTH)
+@javax.annotation.Priority(PriorityPrecedence.EARLY)
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class People {
+
+    private final StaffMemberRepository staffMemberRepository;
+    private final DeptHeadRepository deptHeadRepository;
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public Person findNamed(String name) {
+        return Optional.ofNullable((Person)staffMemberRepository.findByName(name))
+                .orElse(deptHeadRepository.findByName(name));
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public String nameOf(Person person) {
+        return person.getName();
+    }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Person.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Person.java
new file mode 100644
index 0000000000..9a0b96d847
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Person.java
@@ -0,0 +1,17 @@
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import javax.inject.Named;
+import javax.persistence.MappedSuperclass;
+
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.Nature;
+import org.apache.causeway.applib.annotation.Property;
+
+@MappedSuperclass
+@Named("university.dept.Person")
+@DomainObject(nature = Nature.NOT_SPECIFIED)
+public abstract class Person {
+
+    @Property
+    public abstract String getName();
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Staff.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Staff.java
new file mode 100644
index 0000000000..14d8dea9c6
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/Staff.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.DomainService;
+import org.apache.causeway.applib.annotation.NatureOfService;
+import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+
+import lombok.RequiredArgsConstructor;
+
+@Named("university.dept.Staff")
+@DomainService(
+        nature=NatureOfService.BOTH)
+@javax.annotation.Priority(PriorityPrecedence.EARLY)
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class Staff {
+
+    final StaffMemberRepository staffMemberRepository;
+
+    @Action(semantics = SemanticsOf.NON_IDEMPOTENT)
+    public StaffMember createStaffMember(
+            final String name,
+            final Department department
+    ){
+        return staffMemberRepository.create(name, department);
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public List<StaffMember> findAllStaffMembers(){
+        return staffMemberRepository.findAll();
+    }
+
+    @Action(semantics = SemanticsOf.SAFE)
+    public StaffMember findStaffMemberByName(final String name){
+        return staffMemberRepository.findByName(name);
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMember.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMember.java
new file mode 100644
index 0000000000..be226367e2
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMember.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.Comparator;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.DomainObjectLayout;
+import org.apache.causeway.applib.annotation.Editing;
+import org.apache.causeway.applib.annotation.Nature;
+import org.apache.causeway.applib.annotation.Optionality;
+import org.apache.causeway.applib.annotation.Property;
+import org.apache.causeway.applib.annotation.PropertyLayout;
+import org.apache.causeway.applib.value.Blob;
+import org.apache.causeway.persistence.jpa.applib.types.BlobJpaEmbeddable;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity
+@Table(
+        schema = "public",
+        name = "StaffMember"
+)
+@javax.inject.Named("university.dept.StaffMember")
+@DomainObject(nature = Nature.ENTITY, autoCompleteRepository = StaffMemberRepository.class, autoCompleteMethod = "findByNameMatching")
+@DomainObjectLayout(describedAs = "Staff member of a university department, responsible for delivering lectures, tutorials, exam invigilation and candidate interviews")
+@NoArgsConstructor
+public class StaffMember extends Person implements Comparable<StaffMember> {
+
+    public StaffMember(
+            final String name,
+            final Department department,
+            final Grade grade) {
+        this.name = name;
+        this.department = department;
+        this.grade = grade;
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @Getter @Setter
+    @Property(editing = Editing.ENABLED)
+    private String name;
+    public String validateName(String proposedName) {
+        if(proposedName.contains("!")) {
+            return "Name cannot contain '!' character";
+        }
+        return null;
+    }
+
+    @Getter @Setter
+    @Property
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "department_id")
+    private Department department;
+
+
+    @Getter @Setter
+    @Property(editing = Editing.ENABLED)
+    private Grade grade;
+
+
+    @AttributeOverrides({
+            @AttributeOverride(name="name",    column=@Column(name="photo_name")),
+            @AttributeOverride(name="mimeType",column=@Column(name="photo_mimeType")),
+            @AttributeOverride(name="bytes",   column=@Column(name="photo_bytes"))
+    })
+    @Embedded
+    private BlobJpaEmbeddable photo;
+
+    @Property(optionality = Optionality.OPTIONAL)
+    @PropertyLayout(fieldSetId = "content", sequence = "1")
+    public Blob getPhoto() {
+        return BlobJpaEmbeddable.toBlob(photo);
+    }
+    public void setPhoto(final Blob photo) {
+        this.photo = BlobJpaEmbeddable.fromBlob(photo);
+    }
+
+
+
+
+
+    @Override
+    public int compareTo(final StaffMember o) {
+        return Comparator.comparing(StaffMember::getName).compare(this, o);
+    }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMemberRepository.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMemberRepository.java
new file mode 100644
index 0000000000..09b1687cd8
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/domain/dept/StaffMemberRepository.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.domain.dept;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Repository;
+
+import org.apache.causeway.applib.services.repository.RepositoryService;
+import org.apache.causeway.applib.value.Blob;
+
+@Repository
+public class StaffMemberRepository {
+
+    @Inject private RepositoryService repositoryService;
+
+    public StaffMember create(final String name, final Department department) {
+        return create(name, department, null);
+    }
+    public StaffMember create(final String name, final Department department, final Blob photo) {
+        StaffMember staffMember = new StaffMember(name, department, Grade.LECTURER);
+        staffMember.setPhoto(photo);
+        department.new addStaffMember().act(staffMember);
+        repositoryService.persistAndFlush(staffMember);
+        return staffMember;
+    }
+
+    public List<StaffMember> findAll() {
+        return repositoryService.allInstances(StaffMember.class).stream()
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+    public void removeAll(){
+        repositoryService.removeAll(StaffMember.class);
+    }
+
+    public StaffMember findByName(final String name){
+        return findAll().stream()
+                .filter(dept -> dept.getName().equals(name))
+                .sorted()
+                .findFirst()
+                .orElse(null);
+    }
+
+    public List<StaffMember> findByNameMatching(final String name){
+        return findAll().stream()
+                .filter(dept -> dept.getName().contains(name))
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/Abstract_IntegTest.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/Abstract_IntegTest.java
new file mode 100644
index 0000000000..2d80b3dc94
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/Abstract_IntegTest.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.e2e;
+
+import javax.inject.Inject;
+
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+
+import org.apache.causeway.applib.services.bookmark.BookmarkService;
+import org.apache.causeway.core.config.CausewayConfiguration;
+import org.apache.causeway.persistence.jpa.eclipselink.CausewayModulePersistenceJpaEclipselink;
+import org.apache.causeway.viewer.graphql.viewer.test2.domain.UniversityModule;
+import org.apache.causeway.viewer.graphql.viewer.test2.domain.dept.DepartmentRepository;
+import org.apache.causeway.viewer.graphql.viewer.test2.domain.dept.DeptHeadRepository;
+import org.apache.causeway.viewer.graphql.viewer.test2.domain.dept.StaffMemberRepository;
+import org.apache.causeway.viewer.graphql.viewer.testsupport.CausewayViewerGraphqlIntegTestAbstract;
+
+
+@Import({
+        UniversityModule.class,
+        CausewayModulePersistenceJpaEclipselink.class,
+})
+public abstract class Abstract_IntegTest extends CausewayViewerGraphqlIntegTestAbstract {
+
+    protected Abstract_IntegTest() {
+        super(Abstract_IntegTest.class);
+    }
+
+    @DynamicPropertySource
+    static void apiVariant(final DynamicPropertyRegistry registry) {
+        registry.add("causeway.viewer.graphql.api-scope", CausewayConfiguration.Viewer.Graphql.ApiScope.VIEW_MODELS::name);
+        registry.add("causeway.viewer.graphql.api-variant", CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT::name);
+        registry.add("causeway.viewer.graphql.schema.rich.enable-scenario-testing", () -> Boolean.TRUE);
+        registry.add("causeway.viewer.graphql.resources.response-type", CausewayConfiguration.Viewer.Graphql.ResponseType.ATTACHMENT::name);
+    }
+
+    @Inject protected DepartmentRepository departmentRepository;
+    @Inject protected DeptHeadRepository deptHeadRepository;
+    @Inject protected StaffMemberRepository staffMemberRepository;
+    @Inject protected BookmarkService bookmarkService;
+
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_decimals._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_decimals._.gql
new file mode 100644
index 0000000000..d85e0e7e3e
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_decimals._.gql
@@ -0,0 +1,24 @@
+{
+  rich {
+    university_calc_Calculator {
+      addBigDecimals {
+        invoke(x: "1.1", y: "2.2") {
+          args {
+            x
+            y
+          }
+          results
+        }
+      }
+      addBigDecimals {
+        invoke(x: "1.1", y: "2.2") {
+          args {
+            x
+            y
+          }
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_decimals.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_decimals.approved.json
new file mode 100644
index 0000000000..4741f93156
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_decimals.approved.json
@@ -0,0 +1,17 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addBigDecimals" : {
+          "invoke" : {
+            "args" : {
+              "x" : "1.1",
+              "y" : "2.2"
+            },
+            "results" : "3.3"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_integers._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_integers._.gql
new file mode 100644
index 0000000000..cd3d224da6
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_integers._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      addBigIntegers {
+        invoke(x: "1", y: "2") {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_integers.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_integers.approved.json
new file mode 100644
index 0000000000..315e98b2f9
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_big_integers.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addBigIntegers" : {
+          "invoke" : {
+            "results" : "3"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_double_wrappers._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_double_wrappers._.gql
new file mode 100644
index 0000000000..73536f7453
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_double_wrappers._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      addDoubleWrappers {
+        invoke(x: 1.1, y: 2.2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_double_wrappers.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_double_wrappers.approved.json
new file mode 100644
index 0000000000..4c39ad89af
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_double_wrappers.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addDoubleWrappers" : {
+          "invoke" : {
+            "results" : 3.3000000000000003
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_doubles._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_doubles._.gql
new file mode 100644
index 0000000000..05a63e0f72
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_doubles._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      addDoubles {
+        invoke(x: 1.1, y: 2.2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_doubles.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_doubles.approved.json
new file mode 100644
index 0000000000..55aa93ad16
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_doubles.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addDoubles" : {
+          "invoke" : {
+            "results" : 3.3000000000000003
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_float_wrappers._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_float_wrappers._.gql
new file mode 100644
index 0000000000..5d283c9f22
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_float_wrappers._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      addFloatWrappers {
+        invoke(x: 1.1, y: 2.2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_float_wrappers.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_float_wrappers.approved.json
new file mode 100644
index 0000000000..e4deb9f92d
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_float_wrappers.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addFloatWrappers" : {
+          "invoke" : {
+            "results" : 3.3000002
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_floats._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_floats._.gql
new file mode 100644
index 0000000000..c74ea6f73b
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_floats._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      addFloats {
+        invoke(x: 1.1, y: 2.2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_floats.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_floats.approved.json
new file mode 100644
index 0000000000..4debea3886
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_floats.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addFloats" : {
+          "invoke" : {
+            "results" : 3.3000002
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers._.gql
new file mode 100644
index 0000000000..23df33558a
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      addIntegerWrappers {
+        invoke(x: 1, y: 2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers.approved.json
new file mode 100644
index 0000000000..3ef588b36c
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integer_wrappers.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addIntegerWrappers" : {
+          "invoke" : {
+            "results" : 3
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integers._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integers._.gql
new file mode 100644
index 0000000000..f2fc6bc58f
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integers._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      addIntegers {
+        invoke(x: 1, y: 2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integers.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integers.approved.json
new file mode 100644
index 0000000000..c1d6527036
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.add_integers.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "addIntegers" : {
+          "invoke" : {
+            "results" : 3
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_1._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_1._.gql
new file mode 100644
index 0000000000..972bcb320f
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_1._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      and {
+        invoke(x: true, y: true) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_1.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_1.approved.json
new file mode 100644
index 0000000000..97194ca052
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_1.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "and" : {
+          "invoke" : {
+            "results" : true
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_2._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_2._.gql
new file mode 100644
index 0000000000..5ec20044c5
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_2._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      and {
+        invoke(x: true, y: false) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_2.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_2.approved.json
new file mode 100644
index 0000000000..559f39b3fb
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_and_2.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "and" : {
+          "invoke" : {
+            "results" : false
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_not._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_not._.gql
new file mode 100644
index 0000000000..70987f2d6b
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_not._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      not {
+        invoke(x: true) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_not.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_not.approved.json
new file mode 100644
index 0000000000..cd5d8e76f1
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_not.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "not" : {
+          "invoke" : {
+            "results" : false
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_1._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_1._.gql
new file mode 100644
index 0000000000..751d934a89
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_1._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      or {
+        invoke(x: true, y: true) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_1.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_1.approved.json
new file mode 100644
index 0000000000..b005b549cd
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_1.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "or" : {
+          "invoke" : {
+            "results" : true
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_2._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_2._.gql
new file mode 100644
index 0000000000..e78bb39775
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_2._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      or {
+        invoke(x: true, y: false) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_2.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_2.approved.json
new file mode 100644
index 0000000000..b005b549cd
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.boolean_or_2.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "or" : {
+          "invoke" : {
+            "results" : true
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.concat._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.concat._.gql
new file mode 100644
index 0000000000..32bd0f108e
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.concat._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      concat {
+        invoke(prefix: "Fizz", suffix: "Buzz") {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.concat.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.concat.approved.json
new file mode 100644
index 0000000000..2ed5392de6
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.concat.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "concat" : {
+          "invoke" : {
+            "results" : "FizzBuzz"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days._.gql
new file mode 100644
index 0000000000..fea5812c49
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jdk8LocalPlusDays {
+        invoke(date: "2024-01-26", numDays: 2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days.approved.json
new file mode 100644
index 0000000000..e9ec810876
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_days.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jdk8LocalPlusDays" : {
+          "invoke" : {
+            "results" : "2024-01-28"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes._.gql
new file mode 100644
index 0000000000..e00ee784c3
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jdk8LocalPlusHoursAndMinutes {
+        invoke(time: "13:35:05", numHours: 2, numMinutes: 20) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes.approved.json
new file mode 100644
index 0000000000..2a9317e49f
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_local_plus_hours_and_minutes.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jdk8LocalPlusHoursAndMinutes" : {
+          "invoke" : {
+            "results" : "15:55:05"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes._.gql
new file mode 100644
index 0000000000..87c33879b7
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jdk8OffsetPlusDaysAndHoursAndMinutes {
+        invoke(dateTime: "2024-08-12T04:05:20-01:00", numDays: 3, numHours: 2, numMinutes: 15) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes.approved.json
new file mode 100644
index 0000000000..83d75bae6e
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_days_and_hours_and_minutes.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jdk8OffsetPlusDaysAndHoursAndMinutes" : {
+          "invoke" : {
+            "results" : "2024-08-15T06:20:20.000-01:00"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes._.gql
new file mode 100644
index 0000000000..aa88011f7d
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jdk8OffsetPlusHoursAndMinutes {
+        invoke(time: "04:05:20-01:00", numHours: 2, numMinutes: 15) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes.approved.json
new file mode 100644
index 0000000000..f4b24d3e77
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_offset_plus_hours_and_minutes.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jdk8OffsetPlusHoursAndMinutes" : {
+          "invoke" : {
+            "results" : "06:20:20-01:00"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes._.gql
new file mode 100644
index 0000000000..2875862b5a
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jdk8ZonedPlusDaysAndHoursAndMinutes {
+        invoke(dateTime: "2022-04-15T08:20:10+02:00", numDays: 3, numHours: 2, numMinutes: 15) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes.approved.json
new file mode 100644
index 0000000000..a02148b7f9
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.jdk8_zoned_plus_days_and_hours_and_minutes.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jdk8ZonedPlusDaysAndHoursAndMinutes" : {
+          "invoke" : {
+            "results" : "2022-04-18T10:35:10+02:00"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days._.gql
new file mode 100644
index 0000000000..c2cae30c6f
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jodaLocalPlusDays {
+        invoke(date: "2024-01-26", numDays: 2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days.approved.json
new file mode 100644
index 0000000000..2ae1808714
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_days.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jodaLocalPlusDays" : {
+          "invoke" : {
+            "results" : "2024-01-28"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes._.gql
new file mode 100644
index 0000000000..87d3ae34cc
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jodaLocalPlusHoursAndMinutes {
+        invoke(time: "13:35:05", numHours: 2, numMinutes: 20) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes.approved.json
new file mode 100644
index 0000000000..f0d6f31b8c
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_local_plus_hours_and_minutes.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jodaLocalPlusHoursAndMinutes" : {
+          "invoke" : {
+            "results" : "15:55:05.000"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_plus_days._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_plus_days._.gql
new file mode 100644
index 0000000000..c2cae30c6f
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_plus_days._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      jodaLocalPlusDays {
+        invoke(date: "2024-01-26", numDays: 2) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_plus_days.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_plus_days.approved.json
new file mode 100644
index 0000000000..2ae1808714
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.joda_plus_days.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "jodaLocalPlusDays" : {
+          "invoke" : {
+            "results" : "2024-01-28"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.next_month._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.next_month._.gql
new file mode 100644
index 0000000000..4d5b085bd2
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.next_month._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      nextMonth {
+        invoke(month: JUNE) {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.next_month.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.next_month.approved.json
new file mode 100644
index 0000000000..c921223fab
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.next_month.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "nextMonth" : {
+          "invoke" : {
+            "results" : "JULY"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.scenario_concat._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.scenario_concat._.gql
new file mode 100644
index 0000000000..e87c92d590
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.scenario_concat._.gql
@@ -0,0 +1,20 @@
+{
+  rich {
+    Scenario(name: "Fizz and buzz are concatenated together"){
+      Name
+      When {
+        university_calc_Calculator {
+          concat {
+            invoke(prefix: "Fizz", suffix: "Buzz") {
+              args {
+                prefix
+                suffix
+              }
+              results
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.scenario_concat.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.scenario_concat.approved.json
new file mode 100644
index 0000000000..f881e49802
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.scenario_concat.approved.json
@@ -0,0 +1,22 @@
+{
+  "data" : {
+    "rich" : {
+      "Scenario" : {
+        "Name" : "Fizz and buzz are concatenated together",
+        "When" : {
+          "university_calc_Calculator" : {
+            "concat" : {
+              "invoke" : {
+                "args" : {
+                  "prefix" : "Fizz",
+                  "suffix" : "Buzz"
+                },
+                "results" : "FizzBuzz"
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_locale._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_locale._.gql
new file mode 100644
index 0000000000..60f83ecb00
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_locale._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      someLocale {
+        invoke {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_locale.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_locale.approved.json
new file mode 100644
index 0000000000..7ff2e97cc7
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_locale.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "someLocale" : {
+          "invoke" : {
+            "results" : "en_GB"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_url._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_url._.gql
new file mode 100644
index 0000000000..e25df11d43
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_url._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      someUrl {
+        invoke {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_url.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_url.approved.json
new file mode 100644
index 0000000000..894d36e3d2
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_url.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "someUrl" : {
+          "invoke" : {
+            "results" : "https://causeway.apache.org"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_uuid._.gql b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_uuid._.gql
new file mode 100644
index 0000000000..26a82eb19a
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_uuid._.gql
@@ -0,0 +1,11 @@
+{
+  rich {
+    university_calc_Calculator {
+      someUuid {
+        invoke {
+          results
+        }
+      }
+    }
+  }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_uuid.approved.json b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_uuid.approved.json
new file mode 100644
index 0000000000..272ac56ae5
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.each.some_uuid.approved.json
@@ -0,0 +1,13 @@
+{
+  "data" : {
+    "rich" : {
+      "university_calc_Calculator" : {
+        "someUuid" : {
+          "invoke" : {
+            "results" : "91be0d2d-1752-4962-ad2c-89a7ef73a656"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.java
new file mode 100644
index 0000000000..cf30d1f5f1
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/e2e/calc/Calculator_IntegTest.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.e2e.calc;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.apache.causeway.viewer.graphql.viewer.test2.e2e.Abstract_IntegTest;
+
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.TestFactory;
+
+
+//NOT USING @Transactional since we are running server within same transaction otherwise
+@Order(30)
+public class Calculator_IntegTest extends Abstract_IntegTest {
+
+    @Override
+    @TestFactory
+    public Iterable<DynamicTest> each() throws IOException, URISyntaxException {
+        return super.each();
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/PrintSchemaIntegTest.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/PrintSchemaIntegTest.java
new file mode 100644
index 0000000000..f58d891fc2
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/PrintSchemaIntegTest.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.schema;
+
+import graphql.schema.idl.SchemaPrinter;
+
+import lombok.val;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.apache.causeway.persistence.jpa.eclipselink.CausewayModulePersistenceJpaEclipselink;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import org.springframework.context.annotation.Import;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+
+import org.apache.causeway.core.config.CausewayConfiguration;
+import org.apache.causeway.viewer.graphql.viewer.test2.domain.UniversityModule;
+import org.apache.causeway.viewer.graphql.viewer.testsupport.schema.PrintSchemaIntegTestAbstract;
+
+import static org.apache.causeway.commons.internal.assertions._Assert.assertNotNull;
+
+@Import({
+        UniversityModule.class,
+        CausewayModulePersistenceJpaEclipselink.class,
+})
+@EnableJpaRepositories
+public class PrintSchemaIntegTest extends PrintSchemaIntegTestAbstract {
+
+    @DynamicPropertySource
+    static void apiVariant(final DynamicPropertyRegistry registry) {
+        registry.add("causeway.viewer.graphql.api-scope", CausewayConfiguration.Viewer.Graphql.ApiScope.VIEW_MODELS::name);
+        registry.add("causeway.viewer.graphql.api-variant", CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT::name);
+        registry.add("causeway.viewer.graphql.schema.rich.enable-scenario-testing", () -> Boolean.TRUE);
+        registry.add("causeway.viewer.graphql.resources.response-type", CausewayConfiguration.Viewer.Graphql.ResponseType.ATTACHMENT::name);
+    }
+
+    @Disabled
+    @Override
+    protected void schema() throws Exception {
+        super.schema();
+    }
+}
diff --git a/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/VerifySchemaIntegTest.java b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/VerifySchemaIntegTest.java
new file mode 100644
index 0000000000..4f5e619e1b
--- /dev/null
+++ b/viewers/graphql/test2/src/test/java/org/apache/causeway/viewer/graphql/viewer/test2/schema/VerifySchemaIntegTest.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.causeway.viewer.graphql.viewer.test2.schema;
+
+import graphql.schema.idl.SchemaPrinter;
+
+import lombok.val;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.apache.causeway.viewer.graphql.viewer.test2.e2e.Abstract_IntegTest;
+
+import org.approvaltests.Approvals;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import org.springframework.context.annotation.Import;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+
+import org.apache.causeway.core.config.CausewayConfiguration;
+import org.apache.causeway.persistence.jpa.eclipselink.CausewayModulePersistenceJpaEclipselink;
+import org.apache.causeway.viewer.graphql.viewer.test2.domain.UniversityModule;
+import org.apache.causeway.viewer.graphql.viewer.testsupport.schema.PrintSchemaIntegTestAbstract;
+
+import static org.apache.causeway.commons.internal.assertions._Assert.assertNotNull;
+
+@Import({
+        UniversityModule.class,
+        CausewayModulePersistenceJpaEclipselink.class,
+})
+@EnableJpaRepositories
+public class VerifySchemaIntegTest extends Abstract_IntegTest {
+
+    @DynamicPropertySource
+    static void apiVariant(final DynamicPropertyRegistry registry) {
+        registry.add("causeway.viewer.graphql.api-scope", CausewayConfiguration.Viewer.Graphql.ApiScope.VIEW_MODELS::name);
+        registry.add("causeway.viewer.graphql.api-variant", CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT::name);
+        registry.add("causeway.viewer.graphql.schema.rich.enable-scenario-testing", () -> Boolean.TRUE);
+        registry.add("causeway.viewer.graphql.resources.response-type", CausewayConfiguration.Viewer.Graphql.ResponseType.ATTACHMENT::name);
+    }
+
+    @Disabled
+    @Test
+    protected void schema() throws Exception {
+
+        val graphQL = graphQlSourceForCauseway.graphQl();
+        val graphQLSchema = graphQL.getGraphQLSchema();
+
+        val printer = new SchemaPrinter();
+        val submit = printer.print(graphQLSchema);
+
+        Approvals.verify(submit);
+    }
+
+}
diff --git a/viewers/graphql/test2/src/test/resources/application-test.properties b/viewers/graphql/test2/src/test/resources/application-test.properties
new file mode 100644
index 0000000000..a86c70af91
--- /dev/null
+++ b/viewers/graphql/test2/src/test/resources/application-test.properties
@@ -0,0 +1,30 @@
+#logging.level.org.springframework=DEBUG
+#logging.level.graphql=DEBUG
+
+
+
+
+# One of logging libraries (slf4j, jul, common, sysout)
+decorator.datasource.datasource-proxy.logging=slf4j
+
+decorator.datasource.datasource-proxy.query.enable-logging=true
+decorator.datasource.datasource-proxy.query.log-level=debug
+# Logger name to log all queries, default depends on chosen logging, e.g. net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener
+decorator.datasource.datasource-proxy.query.logger-name=
+
+decorator.datasource.datasource-proxy.slow-query.enable-logging=true
+decorator.datasource.datasource-proxy.slow-query.log-level=warn
+decorator.datasource.datasource-proxy.slow-query.logger-name=
+# Number of seconds to consider query as slow and log it
+decorator.datasource.datasource-proxy.slow-query.threshold=300
+
+decorator.datasource.datasource-proxy.multiline=true
+
+# Formats the SQL for better readability. Uses Hibernate's formatter if present on the class path. If you opted in for a different JPA provider you need to add https://github.com/vertical-blank/sql-formatter as a runtime dependency to your app  to enable this.
+# Mutually exclusive with json-format=true
+decorator.datasource.datasource-proxy.format-sql=false
+decorator.datasource.datasource-proxy.json-format=false
+
+# Enable Query Metrics
+decorator.datasource.datasource-proxy.count-query=false
+
diff --git a/viewers/graphql/test2/src/test/resources/junit-platform.properties b/viewers/graphql/test2/src/test/resources/junit-platform.properties
new file mode 100644
index 0000000000..f61913bd47
--- /dev/null
+++ b/viewers/graphql/test2/src/test/resources/junit-platform.properties
@@ -0,0 +1,2 @@
+# ClassOrderer$OrderAnnotation sorts classes based on their @Order annotation
+junit.jupiter.testclass.order.default=org.junit.jupiter.api.ClassOrderer$OrderAnnotation
\ No newline at end of file


(causeway) 01/03: CAUSEWAY-3676 : adds ability to filter GraphQL by view model

Posted by da...@apache.org.
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 28ec90f8e16c377ea55e7d36c60e7687aa31ae66
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Mar 14 08:49:08 2024 +0000

    CAUSEWAY-3676 : adds ability to filter GraphQL by view model
---
 .../applib/services/metamodel/BeanSort.java        |  3 +-
 .../applib/services/swagger/Visibility.java        |  4 +-
 .../core/config/CausewayConfiguration.java         | 52 +++++++++++++++++++---
 .../core/metamodel/spec/ObjectSpecification.java   | 23 ++++++++++
 .../domain/common/query/CommonDomainObject.java    | 24 +++++++++-
 .../common/query/CommonTopLevelQueryAbstract.java  | 23 +++++++---
 .../integration/GraphQlSourceForCauseway.java      |  1 -
 7 files changed, 114 insertions(+), 16 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/metamodel/BeanSort.java b/api/applib/src/main/java/org/apache/causeway/applib/services/metamodel/BeanSort.java
index 5490a6e4bc..c87a758b41 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/services/metamodel/BeanSort.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/services/metamodel/BeanSort.java
@@ -129,7 +129,7 @@ public enum BeanSort {
         return this == UNKNOWN;
     }
 
-    // -- HIGER LEVEL PREDICATES
+    // -- HIGHER LEVEL PREDICATES
 
     public boolean isToBeIntrospected() {
 
@@ -150,5 +150,6 @@ public enum BeanSort {
     }
 
 
+
     // ...
 }
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/swagger/Visibility.java b/api/applib/src/main/java/org/apache/causeway/applib/services/swagger/Visibility.java
index 918ccd3051..dc4d78175a 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/services/swagger/Visibility.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/services/swagger/Visibility.java
@@ -46,7 +46,7 @@ public enum Visibility {
      * The generated swagger spec is therefore restricted only to include only
      * view models ({@link DomainObject#nature()} of
      * {@link org.apache.causeway.applib.annotation.Nature#VIEW_MODEL})
-     * and to REST domain services ({@link DomainService#nature()} of
+     * and to Web API domain services ({@link DomainService#nature()} of
      * {@link NatureOfService#WEB_API}). Exposing entities also would couple the
      * REST client too deeply to the backend implementation.
      * </p>
@@ -60,7 +60,7 @@ public enum Visibility {
      * This visibility level removes all constraints and so includes the
      * specifications of domain entities as well as view models. This is
      * perfectly acceptable where the team developing the REST client is the
-     * same as the team developing the backend service ... the use of the REST
+     * same as the team developing the backend service ... the use of the Web
      * API between the client and server is a private implementation detail of
      * the application.
      * </p>
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 b2dea70284..629157f69f 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
@@ -57,6 +57,8 @@ import javax.validation.constraints.Min;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
+import org.apache.causeway.applib.annotation.NatureOfService;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
@@ -2364,7 +2366,7 @@ public class CausewayConfiguration {
                  *
                  * <p>
                  *     Optionally, fields for Scenario (given/when/then) testing may also be added if the
-                 *     {@link #isEnableScenarioTestingForRich()} config property is set.
+                 *     {@link Schema.Rich#isEnableScenarioTesting()} config property is set.
                  * </p>
                  * <p>
                  *     Suitable for clients where the application logic and state remains in the backend, within the
@@ -2374,8 +2376,8 @@ public class CausewayConfiguration {
                 RICH_ONLY,
                 /**
                  * Exposes both the simple and rich schemas, for the query have each under a field as defined by
-                 * {@link #getTopLevelFieldNameForSimple()} (by default &quot;simple&quot;) and
-                 * {@link #getTopLevelFieldNameForRich()} (by default &quot;rich&quot;).
+                 * {@link Schema.Simple#getTopLevelFieldName()} (by default &quot;simple&quot;) and
+                 * {@link Schema.Rich#getTopLevelFieldName()} (by default &quot;rich&quot;).
                  *
                  * <p>
                  *     For mutations, use the <i>simple</i> schema types.
@@ -2384,8 +2386,8 @@ public class CausewayConfiguration {
                 SIMPLE_AND_RICH,
                 /**
                  * Exposes both the simple and rich schemas, for the query have each under a field as defined by
-                 * {@link #getTopLevelFieldNameForSimple()} (by default &quot;simple&quot;) and
-                 * {@link #getTopLevelFieldNameForRich()} (by default &quot;rich&quot;).
+                 * {@link Schema.Simple#getTopLevelFieldName()} (by default &quot;simple&quot;) and
+                 * {@link Schema.Rich#getTopLevelFieldName()} (by default &quot;rich&quot;).
                  *
                  * <p>
                  *     For mutations, use the <i>rich</i> schema types.
@@ -2490,6 +2492,46 @@ public class CausewayConfiguration {
              */
             private ApiVariant apiVariant = ApiVariant.QUERY_AND_MUTATIONS;
 
+            /**
+             * Specifies which elements of the metamodel are included within the generated
+             * GraphQL spec.
+             *
+             * @since 1.x {@index}
+             */
+            public enum ApiScope {
+
+                /**
+                 * The generated GraphQL spec is restricted only to include only
+                 * {@link org.apache.causeway.applib.annotation.Nature#VIEW_MODEL view model}s.
+                 *
+                 * <p>
+                 * Applicable when the GraphQL API is in use by third-party clients, ie public use and not
+                 * under the control of the authors of the backend Apache Causeway application.
+                 * Exposing entities also would couple the GraphQL client too deeply to the backend implementation.
+                 * </p>
+                 */
+                VIEW_MODELS,
+                /**
+                 * The generated GraphQL spec is not restricted, includes both
+                 * {@link org.apache.causeway.applib.annotation.Nature#ENTITY domain entities} as well as
+                 * {@link org.apache.causeway.applib.annotation.Nature#VIEW_MODEL view model}s.
+                 *
+                 * <p>
+                 * This is perfectly acceptable where the team developing the GraphQL client is the
+                 * same as the team developing the backend service ... the use of the Web
+                 * API between the client and server is a private implementation detail of
+                 * the application.
+                 * </p>
+                 */
+                ALL,
+                ;
+            }
+
+            /**
+             * Which domain objects to include the GraphQL schema.
+             */
+            private ApiScope apiScope = ApiScope.ALL;
+
             private final MetaData metaData = new MetaData();
             @Data
             public static class MetaData {
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/ObjectSpecification.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/ObjectSpecification.java
index 8680f5e289..01acac6fa5 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/ObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/ObjectSpecification.java
@@ -479,11 +479,34 @@ extends
     /**
      * Includes abstract types that have
      * {@link ViewModelFacet} or {@link EntityFacet}.
+     *
+     * @see #isViewModel()
+     * @see #isEntity()
      */
     default boolean isEntityOrViewModel() {
         return isViewModel() || isEntity();
     }
 
+    /**
+     * @see #isViewModel()
+     * @see #isValue()
+     */
+    default boolean isViewModelOrValue() {
+        return isViewModel() || isValue();
+    }
+
+    /**
+     * @see #isViewModel()
+     * @see #isValue()
+     * @see #isVoid()
+     */
+    default boolean isViewModelOrValueOrVoid() {
+        return isViewModel() || isValue() || isVoid();
+    }
+
+    /**
+     * @see #getBeanSort()
+     */
     default boolean isEntityOrViewModelOrAbstract() {
         // optimized, no need to check facets
         return getBeanSort().isViewModel()
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java
index bb06f934fe..52c7a8d15f 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonDomainObject.java
@@ -31,9 +31,13 @@ import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
 import static graphql.schema.GraphQLInputObjectField.newInputObjectField;
 import static graphql.schema.GraphQLInputObjectType.newInputObject;
 
+import org.apache.causeway.core.config.CausewayConfiguration;
 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.ObjectAssociation;
+import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import org.apache.causeway.viewer.graphql.model.domain.Environment;
 import org.apache.causeway.viewer.graphql.model.domain.Element;
@@ -158,16 +162,34 @@ public class CommonDomainObject
 
 
     private void addMembers() {
-
         objectSpecification.streamProperties(MixedIn.INCLUDED)
+                .filter(this::inApiScope)
                 .forEach(prop -> properties.add(addChildFieldFor(schemaStrategy.newProperty(this, prop, context))));
         objectSpecification.streamCollections(MixedIn.INCLUDED)
+                .filter(this::inApiScope)
                 .forEach(coll -> collections.add(addChildFieldFor(schemaStrategy.newCollection(this, coll, context))));
         objectSpecification.streamActions(context.getActionScope(), MixedIn.INCLUDED)
+                .filter((this::inApiScope))
                 .filter(act -> schemaStrategy.shouldInclude(graphqlConfiguration.getApiVariant(), act))
                 .forEach(act -> actions.add(addChildFieldFor(schemaStrategy.newAction(this, act, context))));
     }
 
+    private boolean inApiScope(ObjectAction act) {
+        if (graphqlConfiguration.getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL) {
+            return true;
+        }
+        val returnType = act.getElementType();
+        return returnType.isViewModelOrValueOrVoid() &&
+               act.getParameterTypes().stream().allMatch(ObjectSpecification::isViewModelOrValue);
+    }
+
+    private boolean inApiScope(final ObjectAssociation objAssoc) {
+        if (graphqlConfiguration.getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL) {
+            return true;
+        }
+        return objAssoc.getElementType().isViewModelOrValue();
+    }
+
     @SuppressWarnings("unused")
     private ActionScope determineActionScope() {
         return context.causewaySystemEnvironment.getDeploymentType().isProduction()
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java
index 632ca78074..f2b6454043 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/CommonTopLevelQueryAbstract.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import graphql.schema.DataFetchingEnvironment;
 
+import org.apache.causeway.core.config.CausewayConfiguration;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.viewer.graphql.model.context.Context;
 import org.apache.causeway.viewer.graphql.model.domain.Element;
@@ -48,17 +49,19 @@ public abstract class CommonTopLevelQueryAbstract
         super(schemaStrategy.getSchemaType().name() + "Schema", context);
         this.schemaStrategy = schemaStrategy;
 
+        boolean includeEntities = context.causewayConfiguration.getViewer().getGraphql().getApiScope() == CausewayConfiguration.Viewer.Graphql.ApiScope.ALL;
         context.objectSpecifications().forEach(objectSpec -> {
             switch (objectSpec.getBeanSort()) {
 
                 case ABSTRACT:
-                case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL)
-                case ENTITY:     // @DomainObject(nature=ENTITY)
-
-                    val gqlvDomainObject = schemaStrategy.domainObjectFor(objectSpec, context);
-                    addChildField(gqlvDomainObject.newField());
-                    domainObjects.add(gqlvDomainObject);
+                case VIEW_MODEL:
+                    addDomainObject(objectSpec, schemaStrategy, context);
                     break;
+                case ENTITY:
+                    if (includeEntities) {
+                        addDomainObject(objectSpec, schemaStrategy, context);
+                    }
+
             }
         });
 
@@ -73,7 +76,15 @@ public abstract class CommonTopLevelQueryAbstract
                     break;
             }
         });
+    }
 
+    private void addDomainObject(
+            final ObjectSpecification objectSpec,
+            final SchemaStrategy schemaStrategy,
+            final Context context) {
+        val gqlvDomainObject = schemaStrategy.domainObjectFor(objectSpec, context);
+        addChildField(gqlvDomainObject.newField());
+        domainObjects.add(gqlvDomainObject);
     }
 
     public static List<ObjectSpecification> superclassesOf(final ObjectSpecification objectSpecification) {
diff --git a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java
index 4b6d7922b1..ab7d670128 100644
--- a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java
+++ b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java
@@ -43,7 +43,6 @@ import org.apache.causeway.viewer.graphql.model.toplevel.BothTopLevelQuery;
 import lombok.val;
 
 @Service()
-//@RequiredArgsConstructor(onConstructor_ = {@Inject})
 public class GraphQlSourceForCauseway implements GraphQlSource {
 
     private final CausewayConfiguration causewayConfiguration;


(causeway) 03/03: CAUSEWAY-3676: updates docs

Posted by da...@apache.org.
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 75c7b80b37916326ce39b890dbf3975e64d21755
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Mar 14 11:47:36 2024 +0000

    CAUSEWAY-3676: updates docs
---
 .../pages/index/annotation/NatureOfService.adoc    | 86 ++++++++++++----------
 .../pages/index/services/swagger/Visibility.adoc   |  4 +-
 ...sewayConfiguration_Viewer_Graphql_ApiScope.adoc | 42 +++++++++++
 ...ayConfiguration_Viewer_Graphql_SchemaStyle.adoc | 72 ++++++++++++++++++
 core/adoc/modules/_overview/pages/about.adoc       | 46 +++++++++++-
 .../pages/sections/causeway.viewer.graphql.adoc    |  4 +-
 .../core/config/CausewayConfiguration.java         | 16 +++-
 .../ROOT/pages/setup-and-configuration.adoc        |  5 ++
 8 files changed, 229 insertions(+), 46 deletions(-)

diff --git a/antora/components/refguide-index/modules/applib/pages/index/annotation/NatureOfService.adoc b/antora/components/refguide-index/modules/applib/pages/index/annotation/NatureOfService.adoc
index 8b7ce76a5a..1603af19a9 100644
--- a/antora/components/refguide-index/modules/applib/pages/index/annotation/NatureOfService.adoc
+++ b/antora/components/refguide-index/modules/applib/pages/index/annotation/NatureOfService.adoc
@@ -9,41 +9,48 @@ The different sorts of domain services recognized by Causeway, as specified in _
 .NatureOfService.java
 ----
 enum NatureOfService {
-  WEB_UI     // <.>
-  WEB_API     // <.>
-  BOTH     // <.>
-  boolean isBoth()     // <.>
-  boolean isWebUi()     // <.>
-  boolean isWebApi()     // <.>
+  WEB_UI
+  WEB_API
+  BOTH
+  VIEW     // <.>
+  REST     // <.>
+  boolean isEnabledEverywhere()     // <.>
+  boolean isEnabledForUi()     // <.>
+  boolean isEnabledForWebApi()     // <.>
 }
 ----
 
-<.> xref:#WEB_UI[WEB_UI]
+<.> xref:#VIEW[VIEW]
 +
 --
-The service's actions appear only in the menu bar human-usable Web UIs (such as Wicket viewer). They do _not_ appear in any REST or GraphQL APIs.
---
-<.> xref:#WEB_API[WEB_API]
-+
---
-The service's actions should only be visible in the Web API exposed by the Restful Objects viewer and the GraphQL viewer. They do _not_ appear in any human-usable Web UIs (such as Wicket viewer)
+[WARNING]
+====
+[red]#_deprecated:_#
+
+use _#BOTH_ instead
+====
 --
-<.> xref:#BOTH[BOTH]
+<.> xref:#REST[REST]
 +
 --
-The service's actions appear in the menu bar of Web UIs (such as Wicket viewer), and also appear in the Web APIs (Restful Objects viewer and GraphQL viewer).
+[WARNING]
+====
+[red]#_deprecated:_#
+
+use _#WEB_API_ instead
+====
 --
-<.> xref:#isBoth_[isBoth()]
+<.> xref:#isEnabledEverywhere_[isEnabledEverywhere()]
 +
 --
-Whether a service contributes its actions to both human-usable Web UIs and the Web APIs.
+Whether a service contributes its actions to both human-usable UIs and the Web APIs.
 --
-<.> xref:#isWebUi_[isWebUi()]
+<.> xref:#isEnabledForUi_[isEnabledForUi()]
 +
 --
-Whether a service contributes its actions exclusively to human-usable Web UIs.
+Whether a service contributes its actions to human-usable UIs.
 --
-<.> xref:#isWebApi_[isWebApi()]
+<.> xref:#isEnabledForWebApi_[isEnabledForWebApi()]
 +
 --
 Whether a service contributes its actions to Web APIs (REST and GraphQL)
@@ -51,32 +58,37 @@ Whether a service contributes its actions to Web APIs (REST and GraphQL)
 
 == Members
 
-[#WEB_UI]
-=== WEB_UI
+[#VIEW]
+=== VIEW
 
-The service's actions appear only in the menu bar human-usable Web UIs (such as Wicket viewer). They do _not_ appear in any REST or GraphQL APIs.
+[WARNING]
+====
+[red]#_deprecated:_#
 
-[#WEB_API]
-=== WEB_API
+use _#BOTH_ instead
+====
 
-The service's actions should only be visible in the Web API exposed by the Restful Objects viewer and the GraphQL viewer. They do _not_ appear in any human-usable Web UIs (such as Wicket viewer)
+[#REST]
+=== REST
 
-[#BOTH]
-=== BOTH
+[WARNING]
+====
+[red]#_deprecated:_#
 
-The service's actions appear in the menu bar of Web UIs (such as Wicket viewer), and also appear in the Web APIs (Restful Objects viewer and GraphQL viewer).
+use _#WEB_API_ instead
+====
 
-[#isBoth_]
-=== isBoth()
+[#isEnabledEverywhere_]
+=== isEnabledEverywhere()
 
-Whether a service contributes its actions to both human-usable Web UIs and the Web APIs.
+Whether a service contributes its actions to both human-usable UIs and the Web APIs.
 
-[#isWebUi_]
-=== isWebUi()
+[#isEnabledForUi_]
+=== isEnabledForUi()
 
-Whether a service contributes its actions exclusively to human-usable Web UIs.
+Whether a service contributes its actions to human-usable UIs.
 
-[#isWebApi_]
-=== isWebApi()
+[#isEnabledForWebApi_]
+=== isEnabledForWebApi()
 
 Whether a service contributes its actions to Web APIs (REST and GraphQL)
diff --git a/antora/components/refguide-index/modules/applib/pages/index/services/swagger/Visibility.adoc b/antora/components/refguide-index/modules/applib/pages/index/services/swagger/Visibility.adoc
index 95803de4f0..6934194482 100644
--- a/antora/components/refguide-index/modules/applib/pages/index/services/swagger/Visibility.adoc
+++ b/antora/components/refguide-index/modules/applib/pages/index/services/swagger/Visibility.adoc
@@ -41,14 +41,14 @@ As _#PRIVATE_ , also including any prototype actions (where _Action#restrictTo()
 
 Specification for use by third-party clients, ie public use and not under the control of the authors of the backend Apache Causeway application.
 
-The generated swagger spec is therefore restricted only to include only view models ( _DomainObject#nature()_ of _org.apache.causeway.applib.annotation.Nature#VIEW_MODEL_ ) and to REST domain services ( _DomainService#nature()_ of _NatureOfService#WEB_API_ ). Exposing entities also would couple the REST client too deeply to the backend implementation.
+The generated swagger spec is therefore restricted only to include only view models ( _DomainObject#nature()_ of _org.apache.causeway.applib.annotation.Nature#VIEW_MODEL_ ) and to Web API domain services ( _DomainService#nature()_ of _NatureOfService#WEB_API_ ). Exposing entities also would couple the REST client too deeply to the backend implementation.
 
 [#PRIVATE]
 === PRIVATE
 
 Specification for use only by internally-managed clients, ie private internal use.
 
-This visibility level removes all constraints and so includes the specifications of domain entities as well as view models. This is perfectly acceptable where the team developing the REST client is the same as the team developing the backend service ... the use of the REST API between the client and server is a private implementation detail of the application.
+This visibility level removes all constraints and so includes the specifications of domain entities as well as view models. This is perfectly acceptable where the team developing the REST client is the same as the team developing the backend service ... the use of the Web API between the client and server is a private implementation detail of the application.
 
 [#PRIVATE_WITH_PROTOTYPING]
 === PRIVATE_WITH_PROTOTYPING
diff --git a/antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_ApiScope.adoc b/antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_ApiScope.adoc
new file mode 100644
index 0000000000..ff5daec1a5
--- /dev/null
+++ b/antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_ApiScope.adoc
@@ -0,0 +1,42 @@
+= CausewayConfiguration.Viewer.Graphql.ApiScope _(enum)_
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
+
+Specifies which elements of the metamodel are included within the generated GraphQL spec.
+
+== API
+
+[source,java]
+.CausewayConfiguration_Viewer_Graphql_ApiScope.java
+----
+enum ApiScope {
+  VIEW_MODELS     // <.>
+  ALL     // <.>
+}
+----
+
+<.> xref:#VIEW_MODELS[VIEW_MODELS]
++
+--
+The generated GraphQL spec is restricted only to include only _org.apache.causeway.applib.annotation.Nature#VIEW_MODEL view model_ s.
+--
+<.> xref:#ALL[ALL]
++
+--
+The generated GraphQL spec is not restricted, includes both _org.apache.causeway.applib.annotation.Nature#ENTITY domain entities_ as well as _org.apache.causeway.applib.annotation.Nature#VIEW_MODEL view model_ s.
+--
+
+== Members
+
+[#VIEW_MODELS]
+=== VIEW_MODELS
+
+The generated GraphQL spec is restricted only to include only _org.apache.causeway.applib.annotation.Nature#VIEW_MODEL view model_ s.
+
+Applicable when the GraphQL API is in use by third-party clients, ie public use and not under the control of the authors of the backend Apache Causeway application. Exposing entities also would couple the GraphQL client too deeply to the backend implementation.
+
+[#ALL]
+=== ALL
+
+The generated GraphQL spec is not restricted, includes both _org.apache.causeway.applib.annotation.Nature#ENTITY domain entities_ as well as _org.apache.causeway.applib.annotation.Nature#VIEW_MODEL view model_ s.
+
+This is perfectly acceptable where the team developing the GraphQL client is the same as the team developing the backend service ... the use of the Web API between the client and server is a private implementation detail of the application.
diff --git a/antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_SchemaStyle.adoc b/antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_SchemaStyle.adoc
new file mode 100644
index 0000000000..d02bfa50c6
--- /dev/null
+++ b/antora/components/refguide-index/modules/core/pages/index/config/CausewayConfiguration_Viewer_Graphql_SchemaStyle.adoc
@@ -0,0 +1,72 @@
+= CausewayConfiguration.Viewer.Graphql.SchemaStyle _(enum)_
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
+
+Which style of schema to expose: "simple", "rich" or some combination of both.
+
+== API
+
+[source,java]
+.CausewayConfiguration_Viewer_Graphql_SchemaStyle.java
+----
+enum SchemaStyle {
+  SIMPLE_ONLY     // <.>
+  RICH_ONLY     // <.>
+  SIMPLE_AND_RICH     // <.>
+  RICH_AND_SIMPLE     // <.>
+  boolean isRich()
+  boolean isSimple()
+}
+----
+
+<.> xref:#SIMPLE_ONLY[SIMPLE_ONLY]
++
+--
+Expose only the "simple" schema, defining only fields that return the state of the domain objects but with no fields to represent additional facets of state (such as whether an action is hidden or disabled).
+--
+<.> xref:#RICH_ONLY[RICH_ONLY]
++
+--
+Expose only the "rich" schema, exposing not only fields that return the state of the domain objects but _also_ with fields to represent additional facets of state (such as whether an action is hidden or disabled).
+--
+<.> xref:#SIMPLE_AND_RICH[SIMPLE_AND_RICH]
++
+--
+Exposes both the simple and rich schemas, for the query have each under a field as defined by _Schema.Simple#getTopLevelFieldName()_ (by default "simple") and _Schema.Rich#getTopLevelFieldName()_ (by default "rich").
+--
+<.> xref:#RICH_AND_SIMPLE[RICH_AND_SIMPLE]
++
+--
+Exposes both the simple and rich schemas, for the query have each under a field as defined by _Schema.Simple#getTopLevelFieldName()_ (by default "simple") and _Schema.Rich#getTopLevelFieldName()_ (by default "rich").
+--
+
+== Members
+
+[#SIMPLE_ONLY]
+=== SIMPLE_ONLY
+
+Expose only the "simple" schema, defining only fields that return the state of the domain objects but with no fields to represent additional facets of state (such as whether an action is hidden or disabled).
+
+Suitable for clients where the application logic and state is the responsibility of the client.
+
+[#RICH_ONLY]
+=== RICH_ONLY
+
+Expose only the "rich" schema, exposing not only fields that return the state of the domain objects but _also_ with fields to represent additional facets of state (such as whether an action is hidden or disabled).
+
+Optionally, fields for Scenario (given/when/then) testing may also be added if the _Schema.Rich#isEnableScenarioTesting()_ config property is set.
+
+Suitable for clients where the application logic and state remains in the backend, within the domain model hosted by Causeway.
+
+[#SIMPLE_AND_RICH]
+=== SIMPLE_AND_RICH
+
+Exposes both the simple and rich schemas, for the query have each under a field as defined by _Schema.Simple#getTopLevelFieldName()_ (by default "simple") and _Schema.Rich#getTopLevelFieldName()_ (by default "rich").
+
+For mutations, use the _simple_ schema types.
+
+[#RICH_AND_SIMPLE]
+=== RICH_AND_SIMPLE
+
+Exposes both the simple and rich schemas, for the query have each under a field as defined by _Schema.Simple#getTopLevelFieldName()_ (by default "simple") and _Schema.Rich#getTopLevelFieldName()_ (by default "rich").
+
+For mutations, use the _rich_ schema types.
diff --git a/core/adoc/modules/_overview/pages/about.adoc b/core/adoc/modules/_overview/pages/about.adoc
index 4413114ad4..aa8ff9ccbe 100644
--- a/core/adoc/modules/_overview/pages/about.adoc
+++ b/core/adoc/modules/_overview/pages/about.adoc
@@ -1132,7 +1132,7 @@ org.springframework.boot:spring-boot-configuration-processor:jar:<managed> +
 
 .Document Index Entries
 ****
-xref:refguide:core:index/config/datasources/DataSourceIntrospectionService.adoc[DataSourceIntrospectionService]
+xref:refguide:core:index/config/CausewayConfiguration_Viewer_Graphql_ApiScope.adoc[CausewayConfiguration.Viewer.Graphql.ApiScope], xref:refguide:core:index/config/CausewayConfiguration_Viewer_Graphql_SchemaStyle.adoc[CausewayConfiguration.Viewer.Graphql.SchemaStyle], xref:refguide:core:index/config/datasources/DataSourceIntrospectionService.adoc[DataSourceIntrospectionService]
 ****
 
 |Apache Causeway Core - Interaction
@@ -2518,6 +2518,12 @@ skinparam rectangle<<GraphQL.ApacheCausewayViewerGraphQLModel>> {
   BorderColor #2e6295
   shadowing false
 }
+skinparam rectangle<<GraphQL.ApacheCausewayViewerGraphQLTest2>> {
+  BackgroundColor #438dd5
+  FontColor #fffffe
+  BorderColor #2e6295
+  shadowing false
+}
 skinparam rectangle<<GraphQL.ApacheCausewayViewerGraphQLTestSupport>> {
   BackgroundColor #438dd5
   FontColor #fffffe
@@ -2547,15 +2553,17 @@ rectangle "GraphQL\n<size:10>[Software System]</size>" <<GraphQL>> {
   rectangle "==Apache Causeway Viewer - GraphQL (Applib)\n<size:10>[Container: packaging: jar]</size>" <<GraphQL.ApacheCausewayViewerGraphQLApplib>> as GraphQL.ApacheCausewayViewerGraphQLApplib
   rectangle "==Apache Causeway Viewer - GraphQL (Model)\n<size:10>[Container: packaging: jar]</size>" <<GraphQL.ApacheCausewayViewerGraphQLModel>> as GraphQL.ApacheCausewayViewerGraphQLModel
   rectangle "==Apache Causeway Viewer - GraphQL (Test)\n<size:10>[Container: packaging: jar]</size>" <<GraphQL.ApacheCausewayViewerGraphQLTest>> as GraphQL.ApacheCausewayViewerGraphQLTest
+  rectangle "==Apache Causeway Viewer - GraphQL (Test 2)\n<size:10>[Container: packaging: jar]</size>" <<GraphQL.ApacheCausewayViewerGraphQLTest2>> as GraphQL.ApacheCausewayViewerGraphQLTest2
   rectangle "==Apache Causeway Viewer - GraphQL (Test Support)\n<size:10>[Container: packaging: jar]</size>" <<GraphQL.ApacheCausewayViewerGraphQLTestSupport>> as GraphQL.ApacheCausewayViewerGraphQLTestSupport
   rectangle "==Apache Causeway Viewer - GraphQL (Viewer)\n<size:10>[Container: packaging: jar]</size>" <<GraphQL.ApacheCausewayViewerGraphQLViewer>> as GraphQL.ApacheCausewayViewerGraphQLViewer
 }
 
+GraphQL.ApacheCausewayViewerGraphQL .[#707070,thickness=2].> GraphQL.ApacheCausewayViewerGraphQLModel : "<color:#707070>"
 GraphQL.ApacheCausewayViewerGraphQL .[#707070,thickness=2].> GraphQL.ApacheCausewayViewerGraphQLTest : "<color:#707070>"
+GraphQL.ApacheCausewayViewerGraphQL .[#707070,thickness=2].> GraphQL.ApacheCausewayViewerGraphQLTest2 : "<color:#707070>"
 GraphQL.ApacheCausewayViewerGraphQL .[#707070,thickness=2].> GraphQL.ApacheCausewayViewerGraphQLTestSupport : "<color:#707070>"
 GraphQL.ApacheCausewayViewerGraphQL .[#707070,thickness=2].> GraphQL.ApacheCausewayViewerGraphQLViewer : "<color:#707070>"
 GraphQL.ApacheCausewayViewerGraphQL .[#707070,thickness=2].> GraphQL.ApacheCausewayViewerGraphQLApplib : "<color:#707070>"
-GraphQL.ApacheCausewayViewerGraphQL .[#707070,thickness=2].> GraphQL.ApacheCausewayViewerGraphQLModel : "<color:#707070>"
 @enduml
 ----
 
@@ -2671,6 +2679,24 @@ org.apache.causeway.viewer:causeway-viewer-graphql-testsupport:jar:<managed> +
 org.springframework.boot:spring-boot-test-autoconfigure:jar:<managed> +
 ****
 
+|Apache Causeway Viewer - GraphQL (Test 2)
+[source,yaml]
+----
+Group: org.apache.causeway.viewer
+Artifact: causeway-viewer-graphql-test2
+Type: jar
+Directory: /viewers/graphql/test2
+----
+|.Dependencies
+****
+com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:jar:<managed> +
+com.github.vertical-blank:sql-formatter:jar:<managed> +
+com.h2database:h2:jar:<managed> +
+org.apache.causeway.persistence:causeway-persistence-jpa-eclipselink:jar:<managed> +
+org.apache.causeway.viewer:causeway-viewer-graphql-testsupport:jar:<managed> +
+org.springframework.boot:spring-boot-test-autoconfigure:jar:<managed> +
+****
+
 |Apache Causeway Viewer - GraphQL (Test Support)
 [source,yaml]
 ----
@@ -7323,6 +7349,12 @@ Directory: /incubator/extensions/core/commandreplay/primary
 ----
 |A module for obtaining commands from a primary
 
+.Components
+****
+o.a.i.extensions.commandreplay.primary.config.PrimaryConfig +
+o.a.i.extensions.commandreplay.primary.spiimpl.CaptureResultOfCommand +
+****
+
 .Dependencies
 ****
 org.apache.causeway.core:causeway-core-config:jar:<managed> +
@@ -7348,6 +7380,16 @@ Directory: /incubator/extensions/core/commandreplay/secondary
 |A module providing a Quartz Job to run on a secondary system,
 for obtaining commands from a primary and saving them so that they are replayed.
 
+.Components
+****
+o.a.i.extensions.commandreplay.secondary.analyser.CommandReplayAnalyserException +
+o.a.i.extensions.commandreplay.secondary.analyser.CommandReplayAnalyserResult +
+o.a.i.extensions.commandreplay.secondary.analysis.CommandReplayAnalysisService +
+o.a.i.extensions.commandreplay.secondary.config.SecondaryConfig +
+o.a.i.extensions.commandreplay.secondary.fetch.CommandFetcher +
+o.a.i.extensions.commandreplay.secondary.job.ReplicateAndReplayJob +
+****
+
 .Dependencies
 ****
 org.apache.causeway.core:causeway-core-config:jar:<managed> +
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc b/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc
index 0c57594ecc..5708adc19e 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/causeway.viewer.graphql.adoc
@@ -16,7 +16,7 @@ include::../section-hooks/causeway.viewer.graphql~pre.adoc[]
 causeway.viewer.graphql.api-scope
 
 | 
-| Which domain objects to include the GraphQL schema.
+| Which domain objects to include the GraphQL schema. By default, all domain objects are exposed (entities and view models).
 
 
 |
@@ -138,7 +138,7 @@ causeway.viewer.graphql. +
 schema-style
 
 | 
-| Which ``SchemaStyle`` to expose.
+| Which ``SchemaStyle`` to expose, "simple" or "rich". By default both are exposed under top-level field names. @see Schema.Rich#getTopLevelFieldName() @see Schema.Simple#getTopLevelFieldName()
 
 
 |
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 629157f69f..1c18236d7e 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
@@ -2348,6 +2348,11 @@ public class CausewayConfiguration {
         @Data
         public static class Graphql {
 
+            /**
+             * Which style of schema to expose: &quot;simple&quot;, &quot;rich&quot; or some combination of both.
+             *
+             * @since 2.0 {@index}
+             */
             public enum SchemaStyle {
                 /**
                  * Expose only the &quot;simple&quot; schema, defining only fields that return the state of the domain
@@ -2405,7 +2410,11 @@ public class CausewayConfiguration {
             }
 
             /**
-             * Which {@link SchemaStyle} to expose.
+             * Which {@link SchemaStyle} to expose, &quot;simple&quot; or &quot;rich&quot;.  By default both are
+             * exposed under top-level field names.
+             *
+             * @see Schema.Rich#getTopLevelFieldName()
+             * @see Schema.Simple#getTopLevelFieldName()
              */
             private SchemaStyle schemaStyle = SchemaStyle.RICH_AND_SIMPLE;
 
@@ -2496,7 +2505,7 @@ public class CausewayConfiguration {
              * Specifies which elements of the metamodel are included within the generated
              * GraphQL spec.
              *
-             * @since 1.x {@index}
+             * @since 2.x {@index}
              */
             public enum ApiScope {
 
@@ -2528,7 +2537,8 @@ public class CausewayConfiguration {
             }
 
             /**
-             * Which domain objects to include the GraphQL schema.
+             * Which domain objects to include the GraphQL schema.  By default, all domain objects are exposed
+             * (entities and view models).
              */
             private ApiScope apiScope = ApiScope.ALL;
 
diff --git a/viewers/graphql/adoc/modules/ROOT/pages/setup-and-configuration.adoc b/viewers/graphql/adoc/modules/ROOT/pages/setup-and-configuration.adoc
index 67ec965f0d..cdadfeeca4 100644
--- a/viewers/graphql/adoc/modules/ROOT/pages/setup-and-configuration.adoc
+++ b/viewers/graphql/adoc/modules/ROOT/pages/setup-and-configuration.adoc
@@ -41,6 +41,11 @@ The most important configuration properties are:
 +
 Whether to support relaxed (but non-spec compliant) queries with mutations, or instead to expose an API that is query only.
 
+* xref:refguide:config:sections/causeway.viewer.graphql.adoc#causeway.viewer.graphql.api-scope[api-scope]
++
+Whether to include all domain classes in the GraphQL schema (entities and view models), or whether only to include view models.
+Which to use depends upon whether the GraphQL client is owned by the same team the owns the backend application.
+
 * xref:refguide:config:sections/causeway.viewer.graphql.adoc#causeway.viewer.graphql.schema-style[schema-style]
 +
 Whether to use the "simple" schema style (data only, client-driven), the "rich" schema style (includes supporting facets, server-driven) or both schema styles.