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
The following commit(s) were added to refs/heads/CAUSEWAY-3676 by this push:
new 2fb16249da CAUSEWAY-3676: improves handling of abstract input types
2fb16249da is described below
commit 2fb16249da3e11596ca51eb050caa4fbfaf807e4
Author: danhaywood <[email protected]>
AuthorDate: Tue Feb 20 07:16:08 2024 +0000
CAUSEWAY-3676: improves handling of abstract input types
... can now specify concrete type when needed using 'logicalTypeName'
---
.../DomainObjectAnnotationFacetFactory.java | 2 +-
.../viewer/graphql/model/domain/GqlvAction.java | 72 ++++--
.../model/domain/GqlvActionInvokeArgsArg.java | 6 -
.../graphql/model/domain/GqlvDomainObject.java | 40 ++-
.../model/domain/GqlvMutationForAction.java | 33 ++-
.../model/domain/GqlvMutationForProperty.java | 32 ++-
.../graphql/model/domain/GqlvScenarioStep.java | 14 +-
.../graphql/model/toplevel/GqlvTopLevelQuery.java | 16 +-
.../graphql/viewer/test/domain/dept/DeptHead.java | 2 +-
.../graphql/viewer/test/domain/dept/People.java | 36 +++
.../graphql/viewer/test/domain/dept/Person.java | 17 ++
.../viewer/test/domain/dept/StaffMember.java | 2 +-
...alculator_IntegTest.each.add_big_decimals._.gql | 9 +
.../e2e/People_IntegTest.each.find_person._.gql | 31 +++
...People_IntegTest.each.find_person.approved.json | 33 +++
.../graphql/viewer/test/e2e/People_IntegTest.java | 72 ++++++
...Test.each.name_of_when_dept_head_using_id._.gql | 14 +
...h.name_of_when_dept_head_using_id.approved.json | 27 ++
...est.each.name_of_when_dept_head_using_ref._.gql | 33 +++
....name_of_when_dept_head_using_ref.approved.json | 35 +++
...ame_of_when_staff_member_using_invalid_id._.gql | 14 +
...hen_staff_member_using_invalid_id.approved.json | 27 ++
....each.name_of_when_staff_member_using_ref._.gql | 33 +++
...me_of_when_staff_member_using_ref.approved.json | 35 +++
.../graphql/viewer/test/e2e/Person_IntegTest.java | 72 ++++++
.../e2e/special/DeptHeadMutating_IntegTest.java | 1 -
...ting_IntegTest.java => Person_2_IntegTest.java} | 31 ++-
...me_of_person_using_id_and_logicalTypeName._.gql | 7 +
...rson_using_id_and_logicalTypeName.approved.json | 9 +
...rson_using_id_but_invalid_logicalTypeName._.gql | 7 +
...ng_id_but_invalid_logicalTypeName.approved.json | 16 ++
viewers/graphql/test/src/test/resources/schema.gql | 282 +++++++++++++++++++++
32 files changed, 1004 insertions(+), 56 deletions(-)
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index 612a61c28e..3fbe85e74a 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -118,7 +118,7 @@ implements
final Optional<DomainObject> domainObjectIfAny,
final ProcessObjectTypeContext processClassContext) {
- if(!domainObjectIfAny.isPresent()) {
+ if(domainObjectIfAny.isEmpty()) {
return;
}
diff --git
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
index f03611501a..73d84df5ce 100644
---
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
+++
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvAction.java
@@ -130,6 +130,8 @@ public class GqlvAction
.map(oap -> {
final ObjectSpecification elementType =
oap.getElementType();
Object argumentValue = argumentPojos.get(oap.getId());
+ Object pojoOrPojoList;
+
switch (elementType.getBeanSort()) {
case VALUE:
@@ -140,20 +142,23 @@ public class GqlvAction
if (argumentValue == null) {
return ManagedObject.empty(elementType);
}
- Object pojoOrPojoList;
+ // fall through
+
+ case ABSTRACT:
+ // if the parameter is abstract, we still attempt
to figure out the arguments.
+ // the arguments will need to either use 'ref' or
else both 'id' AND 'logicalTypeName'
if (argumentValue instanceof List) {
val argumentValueList = (List<Object>)
argumentValue;
pojoOrPojoList = argumentValueList.stream()
- .map(value ->
asPojo(oap.getElementType(), value, context.bookmarkService, environment))
+ .map(value ->
asPojo(oap.getElementType(), value, environment, context))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
} else {
- pojoOrPojoList = asPojo(oap.getElementType(),
argumentValue, context.bookmarkService, environment).orElse(null);
+ pojoOrPojoList = asPojo(oap.getElementType(),
argumentValue, environment, context).orElse(null);
}
return ManagedObject.adaptParameter(oap,
pojoOrPojoList);
- case ABSTRACT:
case COLLECTION:
case MANAGED_BEAN_CONTRIBUTING:
case VETOED:
@@ -185,27 +190,64 @@ public class GqlvAction
public static Optional<Object> asPojo(
final ObjectSpecification elementType,
final Object argumentValueObj,
- final BookmarkService bookmarkService,
- final Environment environment) {
+ final Environment environment,
+ final Context context
+ ) {
val argumentValue = (Map<String, String>) argumentValueObj;
- String idValue = argumentValue.get("id");
+
+ val refValue = argumentValue.get("ref");
+ if (refValue != null) {
+ String key = GqlvMetaSaveAs.keyFor(refValue);
+ BookmarkedPojo bookmarkedPojo =
environment.getGraphQlContext().get(key);
+ if (bookmarkedPojo == null) {
+ throw new IllegalArgumentException(String.format(
+ "Could not find object referenced '%s' in the execution
context; was it saved previously using \"saveAs\" ?", refValue));
+ }
+ val targetPojoClass = bookmarkedPojo.getTargetPojo().getClass();
+ val targetPojoSpec =
context.specificationLoader.loadSpecification(targetPojoClass);
+ if (targetPojoSpec == null) {
+ throw new IllegalArgumentException(String.format(
+ "The object referenced '%s' is not part of the metamodel
(has class '%s')",
+ refValue, targetPojoClass.getCanonicalName()));
+ }
+ if (!elementType.isPojoCompatible(bookmarkedPojo.getTargetPojo()))
{
+ throw new IllegalArgumentException(String.format(
+ "The object referenced '%s' has a type '%s' that is not
assignable to the required type '%s'",
+ refValue, targetPojoSpec.getLogicalTypeName(),
elementType.getLogicalTypeName()));
+ }
+ return
Optional.of(bookmarkedPojo).map(BookmarkedPojo::getTargetPojo);
+ }
+
+ val idValue = argumentValue.get("id");
if (idValue != null) {
Class<?> paramClass = elementType.getCorrespondingClass();
- Optional<Bookmark> bookmarkIfAny =
bookmarkService.bookmarkFor(paramClass, idValue);
+ Optional<Bookmark> bookmarkIfAny;
+ if(elementType.isAbstract()) {
+ val logicalTypeName = argumentValue.get("logicalTypeName");
+ if (logicalTypeName == null) {
+ throw new IllegalArgumentException(String.format(
+ "The 'logicalTypeName' is required along with the
'id', because the input type '%s' is abstract",
+ elementType.getLogicalTypeName()));
+ }
+
if(context.specificationLoader.specForLogicalTypeName(logicalTypeName).isEmpty())
{
+ throw new IllegalArgumentException(String.format(
+ "The 'logicalTypeName' of '%s' is unknown in the
metamodel",
+ logicalTypeName));
+ }
+
+ bookmarkIfAny =
Optional.of(Bookmark.forLogicalTypeNameAndIdentifier(logicalTypeName, idValue));
+ } else {
+ bookmarkIfAny =
context.bookmarkService.bookmarkFor(paramClass, idValue);
+ }
return bookmarkIfAny
- .map(bookmarkService::lookup)
+ .map(context.bookmarkService::lookup)
.filter(Optional::isPresent)
.map(Optional::get);
}
- String refValue = argumentValue.get("ref");
- if (refValue != null) {
- String key = GqlvMetaSaveAs.keyFor(refValue);
- BookmarkedPojo value = environment.getGraphQlContext().get(key);
- return Optional.of(value).map(BookmarkedPojo::getTargetPojo);
- }
throw new IllegalArgumentException("Either 'id' or 'ref' must be
specified for a DomainObject input type");
}
+
public void addGqlArguments(
final ObjectAction objectAction,
final GraphQLFieldDefinition.Builder builder,
diff --git
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvokeArgsArg.java
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvokeArgsArg.java
index f46436a4d1..f5627da21e 100644
---
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvokeArgsArg.java
+++
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionInvokeArgsArg.java
@@ -26,8 +26,6 @@ import
org.apache.causeway.core.metamodel.object.ManagedObject;
import org.apache.causeway.core.metamodel.spec.feature.ObjectAction;
import org.apache.causeway.core.metamodel.spec.feature.ObjectActionParameter;
import org.apache.causeway.viewer.graphql.model.context.Context;
-import org.apache.causeway.viewer.graphql.model.domain.GqlvAbstract;
-import org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo;
import
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectActionProvider;
import
org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider;
@@ -37,12 +35,8 @@ import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import lombok.val;
-import java.util.Map;
-
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
-import static
org.apache.causeway.viewer.graphql.model.domain.GqlvAction.asPojo;
-
@Log4j2
public class GqlvActionInvokeArgsArg
extends GqlvAbstract {
diff --git
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
index 64f200eb2a..cc4849cca0 100644
---
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
+++
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvDomainObject.java
@@ -60,7 +60,35 @@ public class GqlvDomainObject
public static GqlvDomainObject of(
final ObjectSpecification objectSpecification,
final Context context) {
- return context.domainObjectBySpec.computeIfAbsent(objectSpecification,
spec -> new GqlvDomainObject(spec, context));
+
+ mapSuperclassesIfNecessary(objectSpecification, context);
+
+ return computeIfAbsentGqlvDomainObject(context, objectSpecification);
+ }
+
+ private static void mapSuperclassesIfNecessary(
+ final ObjectSpecification objectSpecification,
+ final Context context) {
+ // no need to map if the target subclass has already been built
+ if(context.domainObjectBySpec.containsKey(objectSpecification)) {
+ return;
+ }
+ val superclasses = superclassesOf(objectSpecification);
+ superclasses.forEach(objectSpec ->
computeIfAbsentGqlvDomainObject(context, objectSpec));
+ }
+
+ private static GqlvDomainObject computeIfAbsentGqlvDomainObject(Context
context, ObjectSpecification objectSpec) {
+ return context.domainObjectBySpec.computeIfAbsent(objectSpec, spec ->
new GqlvDomainObject(spec, context));
+ }
+
+ private static List<ObjectSpecification> superclassesOf(final
ObjectSpecification objectSpecification) {
+ val superclasses = new ArrayList<ObjectSpecification>();
+ ObjectSpecification superclass = objectSpecification.superclass();
+ while (superclass != null && superclass.getCorrespondingClass() !=
Object.class) {
+ superclasses.add(0, superclass);
+ superclass = superclass.superclass();
+ }
+ return superclasses;
}
private GqlvDomainObject(
@@ -83,11 +111,19 @@ public class GqlvDomainObject
inputObjectTypeBuilder
.field(newInputObjectField()
.name("id")
+ .description("Use either 'id' or 'ref'; looks up an
entity from the persistent data store, or if a view model, then recreates using
the id as a memento of the object's state")
.type(Scalars.GraphQLID)
.build()
)
+ .field(newInputObjectField()
+ .name("logicalTypeName")
+ .description("If object identified by 'id', then
optionally specifies concrete type. This is only required if the parameter
type defines a super class")
+ .type(Scalars.GraphQLString)
+ .build()
+ )
.field(newInputObjectField()
.name("ref")
+ .description("Use either 'ref' or 'id'; looks up an
object previously saved to the execution context using 'saveAs(ref: ...)'")
.type(Scalars.GraphQLString)
.build()
)
@@ -156,7 +192,7 @@ public class GqlvDomainObject
@Override
protected Object fetchData(DataFetchingEnvironment
dataFetchingEnvironment) {
Object target = dataFetchingEnvironment.getArgument("object");
- return GqlvAction.asPojo(getObjectSpecification(), target,
this.context.bookmarkService, new Environment.For(dataFetchingEnvironment))
+ return GqlvAction.asPojo(getObjectSpecification(), target, new
Environment.For(dataFetchingEnvironment), context)
.orElse(null);
}
diff --git
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
index 3a92c863b1..3f89482512 100644
---
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
+++
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForAction.java
@@ -19,6 +19,8 @@
package org.apache.causeway.viewer.graphql.model.domain;
import java.util.ArrayList;
+import java.util.Map;
+import java.util.Optional;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.GraphQLArgument;
@@ -29,6 +31,9 @@ import graphql.schema.GraphQLType;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
+import org.apache.causeway.applib.services.bookmark.Bookmark;
+import org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo;
+
import org.springframework.lang.Nullable;
import org.apache.causeway.applib.annotation.Where;
@@ -126,7 +131,33 @@ public class GqlvMutationForAction extends GqlvAbstract {
sourcePojo =
context.serviceRegistry.lookupServiceElseFail(objectSpec.getCorrespondingClass());
} else {
Object target = dataFetchingEnvironment.getArgument(argumentName);
- sourcePojo = GqlvAction.asPojo(objectSpec, target,
context.bookmarkService, environment)
+ Optional<Object> result;
+ val argumentValue = (Map<String, String>) target;
+ String idValue = argumentValue.get("id");
+ if (idValue != null) {
+ String logicalTypeName = argumentValue.get("logicalTypeName");
+ Optional<Bookmark> bookmarkIfAny;
+ if (logicalTypeName != null) {
+ bookmarkIfAny =
Optional.of(Bookmark.forLogicalTypeNameAndIdentifier(logicalTypeName, idValue));
+ } else {
+ Class<?> paramClass = objectSpec.getCorrespondingClass();
+ bookmarkIfAny =
context.bookmarkService.bookmarkFor(paramClass, idValue);
+ }
+ result = bookmarkIfAny
+ .map(context.bookmarkService::lookup)
+ .filter(Optional::isPresent)
+ .map(Optional::get);
+ } else {
+ String refValue = argumentValue.get("ref");
+ if (refValue != null) {
+ String key = GqlvMetaSaveAs.keyFor(refValue);
+ BookmarkedPojo value = ((Environment)
environment).getGraphQlContext().get(key);
+ result =
Optional.of(value).map(BookmarkedPojo::getTargetPojo);
+ } else {
+ throw new IllegalArgumentException("Either 'id' or 'ref'
must be specified for a DomainObject input type");
+ }
+ }
+ sourcePojo = result
.orElseThrow(); // TODO: better error handling if no such
object found.
}
diff --git
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
index 5320b48702..e4c6502436 100644
---
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
+++
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvMutationForProperty.java
@@ -19,6 +19,7 @@
package org.apache.causeway.viewer.graphql.model.domain;
import java.util.Map;
+import java.util.Optional;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.GraphQLArgument;
@@ -28,6 +29,7 @@ import graphql.schema.GraphQLOutputType;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
import org.apache.causeway.applib.annotation.Where;
+import org.apache.causeway.applib.services.bookmark.Bookmark;
import org.apache.causeway.core.metamodel.consent.InteractionInitiatedBy;
import org.apache.causeway.core.metamodel.object.ManagedObject;
import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
@@ -36,6 +38,7 @@ import
org.apache.causeway.viewer.graphql.model.context.Context;
import org.apache.causeway.viewer.graphql.model.exceptions.DisabledException;
import org.apache.causeway.viewer.graphql.model.exceptions.HiddenException;
import org.apache.causeway.viewer.graphql.model.exceptions.InvalidException;
+import org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo;
import org.apache.causeway.viewer.graphql.model.types.TypeMapper;
import lombok.val;
@@ -80,7 +83,34 @@ public class GqlvMutationForProperty extends GqlvAbstract {
Object target = dataFetchingEnvironment.getArgument(argumentName);
- Object sourcePojo = GqlvAction.asPojo(objectSpec, target,
context.bookmarkService, new Environment.For(dataFetchingEnvironment))
+ Optional<Object> result;
+ final Environment environment = new
Environment.For(dataFetchingEnvironment);
+ val argumentValue1 = (Map<String, String>) target;
+ String idValue = argumentValue1.get("id");
+ if (idValue != null) {
+ String logicalTypeName = argumentValue1.get("logicalTypeName");
+ Optional<Bookmark> bookmarkIfAny;
+ if (logicalTypeName != null) {
+ bookmarkIfAny =
Optional.of(Bookmark.forLogicalTypeNameAndIdentifier(logicalTypeName, idValue));
+ } else {
+ Class<?> paramClass = objectSpec.getCorrespondingClass();
+ bookmarkIfAny =
context.bookmarkService.bookmarkFor(paramClass, idValue);
+ }
+ result = bookmarkIfAny
+ .map(context.bookmarkService::lookup)
+ .filter(Optional::isPresent)
+ .map(Optional::get);
+ } else {
+ String refValue = argumentValue1.get("ref");
+ if (refValue != null) {
+ String key = GqlvMetaSaveAs.keyFor(refValue);
+ BookmarkedPojo value =
environment.getGraphQlContext().get(key);
+ result = Optional.of(value).map(BookmarkedPojo::getTargetPojo);
+ } else {
+ throw new IllegalArgumentException("Either 'id' or 'ref' must
be specified for a DomainObject input type");
+ }
+ }
+ Object sourcePojo = result
.orElseThrow(); // TODO: better error handling if no such
object found.
val managedObject = ManagedObject.adaptSingular(objectSpec,
sourcePojo);
diff --git
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioStep.java
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioStep.java
index 7b9718e774..d0826236bd 100644
---
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioStep.java
+++
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvScenarioStep.java
@@ -25,6 +25,7 @@ public class GqlvScenarioStep
return;
}
+ // add domain object lookup to top-level query
context.objectSpecifications().forEach(objectSpec -> {
switch (objectSpec.getBeanSort()) {
@@ -32,7 +33,7 @@ public class GqlvScenarioStep
case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL)
case ENTITY: // @DomainObject(nature=ENTITY)
- domainObjects.add(GqlvDomainObject.of(objectSpec,
context));
+
domainObjects.add(addChildFieldFor(GqlvDomainObject.of(objectSpec, context)));
break;
}
@@ -41,19 +42,10 @@ public class GqlvScenarioStep
context.objectSpecifications().forEach(objectSpec -> {
if (Objects.requireNonNull(objectSpec.getBeanSort()) ==
BeanSort.MANAGED_BEAN_CONTRIBUTING) { // @DomainService
context.serviceRegistry.lookupBeanById(objectSpec.getLogicalTypeName())
- .ifPresent(servicePojo -> {
- val gqlvDomainService =
GqlvDomainService.of(objectSpec, servicePojo, context);
- addChildFieldFor(gqlvDomainService);
- domainServices.add(gqlvDomainService);
- });
+ .ifPresent(servicePojo ->
domainServices.add(addChildFieldFor(GqlvDomainService.of(objectSpec,
servicePojo, context))));
}
});
- // add domain object lookup to top-level query
- for (val gqlvDomainObject : this.domainObjects) {
- addChildFieldFor(gqlvDomainObject);
- }
-
buildObjectType();
}
diff --git
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
index 0dee8a582a..ad1308039f 100644
---
a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
+++
b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/toplevel/GqlvTopLevelQuery.java
@@ -27,6 +27,7 @@ public class GqlvTopLevelQuery
public GqlvTopLevelQuery(final Context context) {
super("Query", context);
+ // add domain object lookup to top-level query
context.objectSpecifications().forEach(objectSpec -> {
switch (objectSpec.getBeanSort()) {
@@ -34,7 +35,7 @@ public class GqlvTopLevelQuery
case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL)
case ENTITY: // @DomainObject(nature=ENTITY)
- domainObjects.add(GqlvDomainObject.of(objectSpec,
context));
+
domainObjects.add(addChildFieldFor(GqlvDomainObject.of(objectSpec, context)));
break;
}
@@ -45,20 +46,13 @@ public class GqlvTopLevelQuery
switch (objectSpec.getBeanSort()) {
case MANAGED_BEAN_CONTRIBUTING: // @DomainService
context.serviceRegistry.lookupBeanById(objectSpec.getLogicalTypeName())
- .ifPresent(servicePojo -> {
- val gqlvDomainService =
GqlvDomainService.of(objectSpec, servicePojo, context);
- addChildFieldFor(gqlvDomainService);
- domainServices.add(gqlvDomainService);
- });
+ .ifPresent(servicePojo ->
+ domainServices.add(
+
addChildFieldFor(GqlvDomainService.of(objectSpec, servicePojo, context))));
break;
}
});
- // add domain object lookup to top-level query
- for (val gqlvDomainObject : this.domainObjects) {
- addChildFieldFor(gqlvDomainObject);
- }
-
addChildFieldFor(scenario = new GqlvScenario(context));
buildObjectType();
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/DeptHead.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/DeptHead.java
index 12ed53631a..00694e37e8 100644
---
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/DeptHead.java
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/DeptHead.java
@@ -58,7 +58,7 @@ import lombok.Setter;
)
@DomainObjectLayout(describedAs = "Departmental head, responsible for
curriculum, research, funding and staff")
@NoArgsConstructor
-public class DeptHead implements Comparable<DeptHead> {
+public class DeptHead extends Person implements Comparable<DeptHead> {
public DeptHead(String name) {
this.name = name;
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/People.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/People.java
new file mode 100644
index 0000000000..197815aa63
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/People.java
@@ -0,0 +1,36 @@
+package org.apache.causeway.viewer.graphql.viewer.test.domain.dept;
+
+import lombok.RequiredArgsConstructor;
+
+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;
+
+@Named("university.dept.People")
+@DomainService(
+ nature= NatureOfService.VIEW)
[email protected](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/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/Person.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/Person.java
new file mode 100644
index 0000000000..612d71ab71
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/Person.java
@@ -0,0 +1,17 @@
+package org.apache.causeway.viewer.graphql.viewer.test.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/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/StaffMember.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/StaffMember.java
index a8e471699c..1813f9fd8e 100644
---
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/StaffMember.java
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/dept/StaffMember.java
@@ -54,7 +54,7 @@ import lombok.Setter;
@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 implements Comparable<StaffMember> {
+public class StaffMember extends Person implements Comparable<StaffMember> {
public StaffMember(
final String name,
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Calculator_IntegTest.each.add_big_decimals._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Calculator_IntegTest.each.add_big_decimals._.gql
index 5bb92ef25d..3b022461fb 100644
---
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Calculator_IntegTest.each.add_big_decimals._.gql
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Calculator_IntegTest.each.add_big_decimals._.gql
@@ -9,5 +9,14 @@
results
}
}
+ addBigDecimals {
+ invoke(x: "1.1", y: "2.2") {
+ args {
+ x
+ y
+ }
+ results
+ }
+ }
}
}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.each.find_person._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.each.find_person._.gql
new file mode 100644
index 0000000000..4effad8393
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.each.find_person._.gql
@@ -0,0 +1,31 @@
+{
+ Scenario(name: "DeptHead is also a Person") {
+ Name
+ Given {
+ university_dept_People {
+ findNamed {
+ invoke(name: "Dr. Helen Johansen") {
+ args {
+ name
+ }
+ results {
+ name {
+ get
+ }
+ _meta {
+ saveAs(ref: "dept-head")
+ }
+ }
+ }
+ }
+ }
+ }
+ When {
+ university_dept_Person(object: {ref: "dept-head"}) {
+ name {
+ get
+ }
+ }
+ }
+ }
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.each.find_person.approved.json
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.each.find_person.approved.json
new file mode 100644
index 0000000000..1079e5c78d
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.each.find_person.approved.json
@@ -0,0 +1,33 @@
+{
+ "data" : {
+ "Scenario" : {
+ "Name" : "DeptHead is also a Person",
+ "Given" : {
+ "university_dept_People" : {
+ "findNamed" : {
+ "invoke" : {
+ "args" : {
+ "name" : "Dr. Helen Johansen"
+ },
+ "results" : {
+ "name" : {
+ "get" : "Dr. Helen Johansen"
+ },
+ "_meta" : {
+ "saveAs" : "dept-head"
+ }
+ }
+ }
+ }
+ }
+ },
+ "When" : {
+ "university_dept_Person" : {
+ "name" : {
+ "get" : "Dr. Helen Johansen"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.java
new file mode 100644
index 0000000000..f5b031bc83
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/People_IntegTest.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.test.e2e;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+
+import org.approvaltests.Approvals;
+import org.approvaltests.integrations.junit5.JupiterApprovals;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.TestFactory;
+
+import org.springframework.test.context.ActiveProfiles;
+
+import lombok.val;
+
+
+//NOT USING @Transactional since we are running server within same transaction
otherwise
+@Order(50)
+@ActiveProfiles("test")
+public class People_IntegTest extends Abstract_IntegTest {
+
+ @TestFactory
+ Iterable<DynamicTest> each() throws IOException, URISyntaxException {
+
+ val integClassName = getClass().getSimpleName();
+ val classUrl = getClass().getResource(integClassName + ".class");
+ Path classPath = Paths.get(classUrl.toURI());
+ Path directoryPath = classPath.getParent();
+
+ return Files.walk(directoryPath)
+ .filter(Files::isRegularFile)
+ .filter(file -> {
+ String fileName = file.getFileName().toString();
+ return fileName.startsWith(integClassName) &&
fileName.endsWith("._.gql");
+ })
+ .map(file -> {
+ String fileName = file.getFileName().toString();
+ String testName =
fileName.substring(integClassName.length() +
".each.".length()).replace("._.gql", "");
+ return JupiterApprovals.dynamicTest(
+ testName,
+ options -> {
+ Approvals.verify(submitFileNamed(fileName),
jsonOptions(options));
+ afterEach();
+ beforeEach();
+ });
+ })
+ .collect(Collectors.toList());
+ }
+
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_id._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_id._.gql
new file mode 100644
index 0000000000..507b900e46
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_id._.gql
@@ -0,0 +1,14 @@
+{
+ Scenario(name: "Obtain name of person but forget to specify the
logicalTypeName") {
+ Name
+ When {
+ university_dept_People {
+ nameOf {
+ invoke(person: {id: "123"}) {
+ results
+ }
+ }
+ }
+ }
+ }
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_id.approved.json
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_id.approved.json
new file mode 100644
index 0000000000..7bb8f1b44e
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_id.approved.json
@@ -0,0 +1,27 @@
+{
+ "errors" : [ {
+ "message" : "Exception while fetching data
(/Scenario/When/university_dept_People/nameOf/invoke/results) : The
'logicalTypeName' is required along with the 'id', because the input type
'university.dept.Person' is abstract",
+ "locations" : [ {
+ "line" : 8,
+ "column" : 13
+ } ],
+ "path" : [ "Scenario", "When", "university_dept_People", "nameOf",
"invoke", "results" ],
+ "extensions" : {
+ "classification" : "DataFetchingException"
+ }
+ } ],
+ "data" : {
+ "Scenario" : {
+ "Name" : "Obtain name of person but forget to specify the
logicalTypeName",
+ "When" : {
+ "university_dept_People" : {
+ "nameOf" : {
+ "invoke" : {
+ "results" : null
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_ref._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_ref._.gql
new file mode 100644
index 0000000000..2fb8d4beee
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_ref._.gql
@@ -0,0 +1,33 @@
+{
+ Scenario(name: "Obtain name of person that's a DeptHead") {
+ Name
+ Given {
+ university_dept_DeptHeads {
+ findHeadByName {
+ invoke(name: "Dr. Helen Johansen") {
+ args {
+ name
+ }
+ results {
+ name {
+ get
+ }
+ _meta {
+ saveAs(ref: "dept-head")
+ }
+ }
+ }
+ }
+ }
+ }
+ When {
+ university_dept_People {
+ nameOf {
+ invoke(person: {ref: "dept-head"}) {
+ results
+ }
+ }
+ }
+ }
+ }
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_ref.approved.json
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_ref.approved.json
new file mode 100644
index 0000000000..2ac1a93c81
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_dept_head_using_ref.approved.json
@@ -0,0 +1,35 @@
+{
+ "data" : {
+ "Scenario" : {
+ "Name" : "Obtain name of person that's a DeptHead",
+ "Given" : {
+ "university_dept_DeptHeads" : {
+ "findHeadByName" : {
+ "invoke" : {
+ "args" : {
+ "name" : "Dr. Helen Johansen"
+ },
+ "results" : {
+ "name" : {
+ "get" : "Dr. Helen Johansen"
+ },
+ "_meta" : {
+ "saveAs" : "dept-head"
+ }
+ }
+ }
+ }
+ }
+ },
+ "When" : {
+ "university_dept_People" : {
+ "nameOf" : {
+ "invoke" : {
+ "results" : "Dr. Helen Johansen"
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_invalid_id._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_invalid_id._.gql
new file mode 100644
index 0000000000..eae4185397
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_invalid_id._.gql
@@ -0,0 +1,14 @@
+{
+ Scenario(name: "Obtain name of person that's a non-existent StaffMember") {
+ Name
+ When {
+ university_dept_People {
+ nameOf {
+ invoke(person: {id: "123456", logicalTypeName:
"university.dept.StaffMember"}) {
+ results
+ }
+ }
+ }
+ }
+ }
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_invalid_id.approved.json
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_invalid_id.approved.json
new file mode 100644
index 0000000000..b8b5fe2be9
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_invalid_id.approved.json
@@ -0,0 +1,27 @@
+{
+ "errors" : [ {
+ "message" : "Exception while fetching data
(/Scenario/When/university_dept_People/nameOf/invoke/results) : 'Person' is
mandatory",
+ "locations" : [ {
+ "line" : 8,
+ "column" : 13
+ } ],
+ "path" : [ "Scenario", "When", "university_dept_People", "nameOf",
"invoke", "results" ],
+ "extensions" : {
+ "classification" : "DataFetchingException"
+ }
+ } ],
+ "data" : {
+ "Scenario" : {
+ "Name" : "Obtain name of person that's a non-existent StaffMember",
+ "When" : {
+ "university_dept_People" : {
+ "nameOf" : {
+ "invoke" : {
+ "results" : null
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_ref._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_ref._.gql
new file mode 100644
index 0000000000..a993291aef
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_ref._.gql
@@ -0,0 +1,33 @@
+{
+ Scenario(name: "Obtain name of person that's a StaffMember") {
+ Name
+ Given {
+ university_dept_Staff {
+ findStaffMemberByName {
+ invoke(name: "Letitia Leadbetter") {
+ args {
+ name
+ }
+ results {
+ name {
+ get
+ }
+ _meta {
+ saveAs(ref: "staff-member")
+ }
+ }
+ }
+ }
+ }
+ }
+ When {
+ university_dept_People {
+ nameOf {
+ invoke(person: {ref: "staff-member"}) {
+ results
+ }
+ }
+ }
+ }
+ }
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_ref.approved.json
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_ref.approved.json
new file mode 100644
index 0000000000..d189aa83bb
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.each.name_of_when_staff_member_using_ref.approved.json
@@ -0,0 +1,35 @@
+{
+ "data" : {
+ "Scenario" : {
+ "Name" : "Obtain name of person that's a StaffMember",
+ "Given" : {
+ "university_dept_Staff" : {
+ "findStaffMemberByName" : {
+ "invoke" : {
+ "args" : {
+ "name" : "Letitia Leadbetter"
+ },
+ "results" : {
+ "name" : {
+ "get" : "Letitia Leadbetter"
+ },
+ "_meta" : {
+ "saveAs" : "staff-member"
+ }
+ }
+ }
+ }
+ }
+ },
+ "When" : {
+ "university_dept_People" : {
+ "nameOf" : {
+ "invoke" : {
+ "results" : "Letitia Leadbetter"
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.java
new file mode 100644
index 0000000000..403a9e0087
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/Person_IntegTest.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.test.e2e;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+
+import org.approvaltests.Approvals;
+import org.approvaltests.integrations.junit5.JupiterApprovals;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.TestFactory;
+
+import org.springframework.test.context.ActiveProfiles;
+
+import lombok.val;
+
+
+//NOT USING @Transactional since we are running server within same transaction
otherwise
+@Order(50)
+@ActiveProfiles("test")
+public class Person_IntegTest extends Abstract_IntegTest {
+
+ @TestFactory
+ Iterable<DynamicTest> each() throws IOException, URISyntaxException {
+
+ val integClassName = getClass().getSimpleName();
+ val classUrl = getClass().getResource(integClassName + ".class");
+ Path classPath = Paths.get(classUrl.toURI());
+ Path directoryPath = classPath.getParent();
+
+ return Files.walk(directoryPath)
+ .filter(Files::isRegularFile)
+ .filter(file -> {
+ String fileName = file.getFileName().toString();
+ return fileName.startsWith(integClassName) &&
fileName.endsWith("._.gql");
+ })
+ .map(file -> {
+ String fileName = file.getFileName().toString();
+ String testName =
fileName.substring(integClassName.length() +
".each.".length()).replace("._.gql", "");
+ return JupiterApprovals.dynamicTest(
+ testName,
+ options -> {
+ Approvals.verify(submitFileNamed(fileName),
jsonOptions(options));
+ afterEach();
+ beforeEach();
+ });
+ })
+ .collect(Collectors.toList());
+ }
+
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/DeptHeadMutating_IntegTest.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/DeptHeadMutating_IntegTest.java
index abd2185aa5..f60514e5bc 100644
---
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/DeptHeadMutating_IntegTest.java
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/DeptHeadMutating_IntegTest.java
@@ -60,6 +60,5 @@ public class DeptHeadMutating_IntegTest extends
Abstract_IntegTest {
// then payload
Approvals.verify(response, jsonOptions());
-
}
}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/DeptHeadMutating_IntegTest.java
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.java
similarity index 63%
copy from
viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/DeptHeadMutating_IntegTest.java
copy to
viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.java
index abd2185aa5..5752a5d6af 100644
---
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/DeptHeadMutating_IntegTest.java
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.java
@@ -20,6 +20,8 @@ package
org.apache.causeway.viewer.graphql.viewer.test.e2e.special;
import java.util.Optional;
+import org.apache.causeway.viewer.graphql.viewer.test.domain.dept.StaffMember;
+
import org.approvaltests.Approvals;
import org.approvaltests.reporters.DiffReporter;
import org.approvaltests.reporters.UseReporter;
@@ -40,26 +42,45 @@ import lombok.val;
//NOT USING @Transactional since we are running server within same transaction
otherwise
@Order(120)
@ActiveProfiles("test")
-public class DeptHeadMutating_IntegTest extends Abstract_IntegTest {
+public class Person_2_IntegTest extends Abstract_IntegTest {
@Test
@UseReporter(DiffReporter.class)
- void change_department_name() throws Exception {
+ void name_of_person_using_id_and_logicalTypeName() throws Exception {
final Bookmark bookmark =
transactionService.callTransactional(
Propagation.REQUIRED,
() -> {
- Department department =
departmentRepository.findByName("Classics");
- Optional<Bookmark> bookmark1 =
bookmarkService.bookmarkFor(department);
+ StaffMember staffMember =
staffMemberRepository.findByName("Letitia Leadbetter");
+ Optional<Bookmark> bookmark1 =
bookmarkService.bookmarkFor(staffMember);
return bookmark1.orElseThrow();
}
).valueAsNonNullElseFail();
- val response = submit(_Maps.unmodifiable("$departmentId",
bookmark.getIdentifier()));
+ val response = submit(_Maps.unmodifiable("$staffMemberId",
bookmark.getIdentifier()));
// then payload
Approvals.verify(response, jsonOptions());
+ }
+
+ @Test
+ @UseReporter(DiffReporter.class)
+ void name_of_person_using_id_but_invalid_logicalTypeName() throws
Exception {
+
+ final Bookmark bookmark =
+ transactionService.callTransactional(
+ Propagation.REQUIRED,
+ () -> {
+ StaffMember staffMember =
staffMemberRepository.findByName("Letitia Leadbetter");
+ Optional<Bookmark> bookmark1 =
bookmarkService.bookmarkFor(staffMember);
+ return bookmark1.orElseThrow();
+ }
+ ).valueAsNonNullElseFail();
+
+ val response = submit(_Maps.unmodifiable("$staffMemberId",
bookmark.getIdentifier()));
+ // then payload
+ Approvals.verify(response, jsonOptions());
}
}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_and_logicalTypeName._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_and_logicalTypeName._.gql
new file mode 100644
index 0000000000..d390911377
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_and_logicalTypeName._.gql
@@ -0,0 +1,7 @@
+{
+ university_dept_Person(object: {id: "$staffMemberId", logicalTypeName:
"university.dept.StaffMember"}) {
+ name {
+ get
+ }
+ }
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_and_logicalTypeName.approved.json
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_and_logicalTypeName.approved.json
new file mode 100644
index 0000000000..74cfd1d566
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_and_logicalTypeName.approved.json
@@ -0,0 +1,9 @@
+{
+ "data" : {
+ "university_dept_Person" : {
+ "name" : {
+ "get" : "Letitia Leadbetter"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_but_invalid_logicalTypeName._.gql
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_but_invalid_logicalTypeName._.gql
new file mode 100644
index 0000000000..7d26fdc242
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_but_invalid_logicalTypeName._.gql
@@ -0,0 +1,7 @@
+{
+ university_dept_Person(object: {id: "$staffMemberId", logicalTypeName:
"university.dept.XXX"}) {
+ name {
+ get
+ }
+ }
+}
diff --git
a/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_but_invalid_logicalTypeName.approved.json
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_but_invalid_logicalTypeName.approved.json
new file mode 100644
index 0000000000..66c31d82e8
--- /dev/null
+++
b/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/e2e/special/Person_2_IntegTest.name_of_person_using_id_but_invalid_logicalTypeName.approved.json
@@ -0,0 +1,16 @@
+{
+ "errors" : [ {
+ "message" : "Exception while fetching data (/university_dept_Person) : The
'logicalTypeName' of 'university.dept.XXX' is unknown in the metamodel",
+ "locations" : [ {
+ "line" : 2,
+ "column" : 3
+ } ],
+ "path" : [ "university_dept_Person" ],
+ "extensions" : {
+ "classification" : "DataFetchingException"
+ }
+ } ],
+ "data" : {
+ "university_dept_Person" : null
+ }
+}
\ No newline at end of file
diff --git a/viewers/graphql/test/src/test/resources/schema.gql
b/viewers/graphql/test/src/test/resources/schema.gql
index ece5374fe6..d8c8312fca 100644
--- a/viewers/graphql/test/src/test/resources/schema.gql
+++ b/viewers/graphql/test/src/test/resources/schema.gql
@@ -111,6 +111,8 @@ type Query {
university_dept_Departments: university_dept_Departments
university_dept_DeptHead(object: university_dept_DeptHead__gqlv_input):
university_dept_DeptHead
university_dept_DeptHeads: university_dept_DeptHeads
+ university_dept_People: university_dept_People
+ university_dept_Person(object: university_dept_Person__gqlv_input):
university_dept_Person
university_dept_Staff: university_dept_Staff
university_dept_StaffMember(object:
university_dept_StaffMember__gqlv_input): university_dept_StaffMember
}
@@ -169,6 +171,8 @@ type ScenarioStep {
university_dept_Departments: university_dept_Departments
university_dept_DeptHead(object: university_dept_DeptHead__gqlv_input):
university_dept_DeptHead
university_dept_DeptHeads: university_dept_DeptHeads
+ university_dept_People: university_dept_People
+ university_dept_Person(object: university_dept_Person__gqlv_input):
university_dept_Person
university_dept_Staff: university_dept_Staff
university_dept_StaffMember(object:
university_dept_StaffMember__gqlv_input): university_dept_StaffMember
}
@@ -1601,6 +1605,22 @@ type
causeway_schema_metamodel_v2_DomainClassDto__service__gqlv_property {
validate(service: Boolean): String
}
+type causeway_schema_metamodel_v2_FacetHolder {
+ "Object metadata"
+ _meta: causeway_schema_metamodel_v2_FacetHolder__gqlv_meta
+}
+
+type causeway_schema_metamodel_v2_FacetHolder__gqlv_meta {
+ cssClass: String
+ grid: String
+ icon: String
+ id: String!
+ layout: String
+ logicalTypeName: String!
+ saveAs(ref: String): String
+ title: String!
+}
+
type causeway_security_LoginRedirect {
"Object metadata"
_meta: causeway_security_LoginRedirect__gqlv_meta
@@ -3738,6 +3758,102 @@ type
university_dept_DeptHeads__findHeadByName__name__gqlv_action_parameter {
validity: String
}
+type university_dept_People {
+ "Find Named"
+ findNamed: university_dept_People__findNamed__gqlv_action
+ "Name Of"
+ nameOf: university_dept_People__nameOf__gqlv_action
+}
+
+type university_dept_People__findNamed__gqlv_action {
+ disabled: String
+ hidden: Boolean
+ invoke(name: String!): university_dept_People__findNamed__gqlv_action_invoke
+ "Parameters of this action"
+ params: university_dept_People__findNamed__gqlv_action_params
+ validate(name: String): String
+}
+
+type university_dept_People__findNamed__gqlv_action_args {
+ name: String
+}
+
+type university_dept_People__findNamed__gqlv_action_invoke {
+ "Arguments used to invoke this action"
+ args: university_dept_People__findNamed__gqlv_action_args
+ results: university_dept_Person
+}
+
+type university_dept_People__findNamed__gqlv_action_params {
+ "Name"
+ name: university_dept_People__findNamed__name__gqlv_action_parameter
+}
+
+type university_dept_People__findNamed__name__gqlv_action_parameter {
+ datatype: String
+ disabled(name: String): String
+ hidden: Boolean
+ validity: String
+}
+
+type university_dept_People__nameOf__gqlv_action {
+ disabled: String
+ hidden: Boolean
+ invoke(person: university_dept_Person__gqlv_input!):
university_dept_People__nameOf__gqlv_action_invoke
+ "Parameters of this action"
+ params: university_dept_People__nameOf__gqlv_action_params
+ validate(person: university_dept_Person__gqlv_input): String
+}
+
+type university_dept_People__nameOf__gqlv_action_args {
+ person: university_dept_Person
+}
+
+type university_dept_People__nameOf__gqlv_action_invoke {
+ "Arguments used to invoke this action"
+ args: university_dept_People__nameOf__gqlv_action_args
+ results: String
+}
+
+type university_dept_People__nameOf__gqlv_action_params {
+ "Person"
+ person: university_dept_People__nameOf__person__gqlv_action_parameter
+}
+
+type university_dept_People__nameOf__person__gqlv_action_parameter {
+ datatype: String
+ disabled(person: university_dept_Person__gqlv_input): String
+ hidden: Boolean
+ validity: String
+}
+
+type university_dept_Person {
+ "Object metadata"
+ _meta: university_dept_Person__gqlv_meta
+ "Name"
+ name: university_dept_Person__name__gqlv_property
+}
+
+type university_dept_Person__gqlv_meta {
+ cssClass: String
+ grid: String
+ icon: String
+ id: String!
+ layout: String
+ logicalTypeName: String!
+ saveAs(ref: String): String
+ title: String!
+}
+
+type university_dept_Person__name__gqlv_property {
+ datatype: String
+ disabled: String
+ get: String!
+ hidden: Boolean
+ set(name: String!): university_dept_Person
+ validate(name: String): String
+}
+
type university_dept_Staff {
"Staff member of a university department, responsible for delivering
lectures, tutorials, exam invigilation and candidate interviews"
createStaffMember: university_dept_Staff__createStaffMember__gqlv_action
@@ -3959,186 +4075,352 @@ scalar Time
scalar UUID
input causeway_applib_DomainObjectList__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_FacetGroupNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_ParameterNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_PropertyNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_RoleMemento__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_TypeNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_UserMemento__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_node_ActionNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_node_CollectionNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_node_FacetAttrNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_applib_node_FacetNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_conf_ConfigurationProperty__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_conf_ConfigurationViewmodel__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_feat_ApplicationFeatureViewModel__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_feat_ApplicationNamespace__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_feat_ApplicationTypeAction__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_feat_ApplicationTypeCollection__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_feat_ApplicationTypeMember__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_feat_ApplicationTypeProperty__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_feat_ApplicationType__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_schema_metamodel_v2_DomainClassDto__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
+ id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
+ ref: String
+}
+
+input causeway_schema_metamodel_v2_FacetHolder__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_security_LoginRedirect__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input causeway_testing_fixtures_FixtureResult__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_lang_Runnable__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_util_Map__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_util_SortedMap__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_util_concurrent_Callable__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_util_function_BiFunction__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_util_function_Consumer__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_util_function_Function__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input java_util_stream_Stream__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input org_apache_causeway_core_metamodel_inspect_model_MMNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input org_apache_causeway_core_metamodel_inspect_model_MemberNode__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input
org_apache_causeway_testing_fixtures_applib_fixturescripts_FixtureScript__gqlv_input
{
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input university_dept_Department__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input university_dept_DeptHead__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
+ id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
+ ref: String
+}
+
+input university_dept_Person__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}
input university_dept_StaffMember__gqlv_input {
+ "Use either 'id' or 'ref'; looks up an entity from the persistent data
store, or if a view model, then recreates using the id as a memento of the
object's state"
id: ID
+ "If object identified by 'id', then optionally specifies concrete type.
This is only required if the parameter type defines a super class"
+ logicalTypeName: String
+ "Use either 'ref' or 'id'; looks up an object previously saved to the
execution context using 'saveAs(ref: ...)'"
ref: String
}