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 d325a70f63ca15ab1a4747245491a0a1c50d570c Author: danhaywood <[email protected]> AuthorDate: Fri Jan 26 09:31:21 2024 +0000 CAUSEWAY-3676: wip on property choices --- .../graphql/model/domain/GqlvActionParam.java | 9 ++++ .../model/domain/GqlvActionParamAutoComplete.java | 2 +- .../model/domain/GqlvActionParamChoices.java | 2 +- .../model/domain/GqlvActionParamDefault.java | 2 +- .../viewer/graphql/model/domain/GqlvProperty.java | 14 ++++-- ...pertyValidate.java => GqlvPropertyChoices.java} | 56 +++++++++------------- .../graphql/model/domain/GqlvPropertyValidate.java | 45 +++++------------ .../viewer/graphql/model/types/TypeMapper.java | 3 ++ .../graphql/viewer/test/domain/Department.java | 17 ++++++- .../graphql/viewer/test/domain/DeptHead.java | 7 ++- .../graphql/test/src/test/resources/schema.gql | 4 ++ 11 files changed, 87 insertions(+), 74 deletions(-) diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java index d59feaa758..da00e37958 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParam.java @@ -57,8 +57,17 @@ public class GqlvActionParam private final GqlvActionParamHidden hidden; private final GqlvActionParamDisabled validate; + /** + * Populated iff there are choices for this param + */ private final GqlvActionParamChoices choices; + /** + * Populated iff there is an autocomplete for this param + */ private final GqlvActionParamAutoComplete autoComplete; + /** + * Populated iff there is a default for this param + */ private final GqlvActionParamDefault default_; private final GqlvActionParamValidate disabled; diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java index c975d2fcb5..cd5927147c 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamAutoComplete.java @@ -72,7 +72,7 @@ package org.apache.causeway.viewer.graphql.model.domain; val fieldBuilder = newFieldDefinition() .name("autoComplete") .type(GraphQLList.list(TypeMapper.outputTypeFor(elementType))); - addGqlArguments(holder.getObjectAction(), fieldBuilder, TypeMapper.InputContext.DISABLE, holder.getParamNum()); + addGqlArguments(holder.getObjectAction(), fieldBuilder, TypeMapper.InputContext.AUTOCOMPLETE, holder.getParamNum()); fieldBuilder.argument(GraphQLArgument.newArgument() .name(SEARCH_PARAM_NAME) .type(TypeMapper.scalarTypeFor(String.class))) diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java index dfa51597a2..0d8d528843 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamChoices.java @@ -70,7 +70,7 @@ import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; val fieldBuilder = newFieldDefinition() .name("choices") .type(GraphQLList.list(TypeMapper.outputTypeFor(elementType))); - addGqlArguments(holder.getObjectAction(), fieldBuilder, TypeMapper.InputContext.DISABLE, holder.getParamNum()); + addGqlArguments(holder.getObjectAction(), fieldBuilder, TypeMapper.InputContext.CHOICES, holder.getParamNum()); this.field = holder.addField(fieldBuilder.build()); } else { this.field = null; diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java index 3cd04d25c7..7373ba5eeb 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvActionParamDefault.java @@ -65,7 +65,7 @@ package org.apache.causeway.viewer.graphql.model.domain; val fieldBuilder = newFieldDefinition() .name("default") .type(TypeMapper.outputTypeFor(elementType)); - addGqlArguments(holder.getObjectAction(), fieldBuilder, TypeMapper.InputContext.DISABLE, holder.getParamNum()); + addGqlArguments(holder.getObjectAction(), fieldBuilder, TypeMapper.InputContext.DEFAULT, holder.getParamNum()); this.field = holder.addField(fieldBuilder.build()); } else { this.field = null; diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java index bba16febc6..6312606612 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvProperty.java @@ -34,16 +34,21 @@ public class GqlvProperty implements GqlvMemberHidden.Holder<OneToOneAssociation>, GqlvMemberDisabled.Holder<OneToOneAssociation>, GqlvPropertyGet.Holder, - GqlvPropertySet.Holder, - GqlvPropertyValidate.Holder { + GqlvPropertyChoices.Holder, + GqlvPropertyValidate.Holder, + GqlvPropertySet.Holder { private final GraphQLObjectType.Builder gqlObjectTypeBuilder; private final GraphQLObjectType gqlObjectType; private final GqlvMemberHidden<OneToOneAssociation> hidden; private final GqlvMemberDisabled<OneToOneAssociation> disabled; private final GqlvPropertyGet get; - private final GqlvPropertySet set; + /** + * Populated iff there are choices + */ + private final GqlvPropertyChoices choices; private final GqlvPropertyValidate validate; + private final GqlvPropertySet set; public GqlvProperty( final Holder holder, @@ -56,8 +61,9 @@ public class GqlvProperty this.hidden = new GqlvMemberHidden<>(this, context); this.disabled = new GqlvMemberDisabled<>(this, context); this.get = new GqlvPropertyGet(this, context); - this.set = new GqlvPropertySet(this, context); this.validate = new GqlvPropertyValidate(this, context); + this.choices = new GqlvPropertyChoices(this, context); + this.set = new GqlvPropertySet(this, context); this.gqlObjectType = gqlObjectTypeBuilder.build(); diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyChoices.java similarity index 67% copy from incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java copy to incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyChoices.java index 69a560e1eb..8ac620eccc 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyChoices.java @@ -18,11 +18,15 @@ */ package org.apache.causeway.viewer.graphql.model.domain; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.causeway.commons.collections.Can; import org.apache.causeway.core.metamodel.consent.Consent; import org.apache.causeway.core.metamodel.consent.InteractionInitiatedBy; import org.apache.causeway.core.metamodel.object.ManagedObject; +import org.apache.causeway.core.metamodel.spec.ObjectSpecification; import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation; import org.apache.causeway.viewer.graphql.model.context.Context; import org.apache.causeway.viewer.graphql.model.fetcher.BookmarkedPojo; @@ -30,6 +34,8 @@ import org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationP import org.apache.causeway.viewer.graphql.model.mmproviders.OneToOneAssociationProvider; import org.apache.causeway.viewer.graphql.model.types.TypeMapper; +import graphql.schema.GraphQLList; + import lombok.val; import graphql.schema.DataFetchingEnvironment; @@ -37,41 +43,31 @@ import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLOutputType; import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; +import static org.apache.causeway.viewer.graphql.model.domain.GqlvProperty.addGqlArgument; -public class GqlvPropertyValidate { +public class GqlvPropertyChoices { final Holder holder; private final Context context; final GraphQLFieldDefinition field; - public GqlvPropertyValidate( + public GqlvPropertyChoices( final Holder holder, final Context context) { this.holder = holder; this.context = context; - this.field = fieldDefinition(holder); - } - GraphQLFieldDefinition fieldDefinition(final Holder holder) { - - GraphQLFieldDefinition fieldDefinition = null; - GraphQLOutputType type = outputTypeFor(); - if (type != null) { + val otoa = holder.getOneToOneAssociation(); + if (otoa.hasChoices()) { + val elementType = otoa.getElementType(); val fieldBuilder = newFieldDefinition() - .name("validate") - .type(type); - final OneToOneAssociation oneToOneAssociation = holder.getOneToOneAssociation(); - - GqlvProperty.addGqlArgument(oneToOneAssociation, fieldBuilder, TypeMapper.InputContext.VALIDATE); - fieldDefinition = fieldBuilder.build(); - - holder.addField(fieldDefinition); + .name("choices") + .type(TypeMapper.outputTypeFor(elementType)); + addGqlArgument(otoa, fieldBuilder, TypeMapper.InputContext.CHOICES); + this.field = holder.addField(fieldBuilder.build()); + } else { + this.field = null; } - return fieldDefinition; - } - - GraphQLOutputType outputTypeFor() { - return TypeMapper.scalarTypeFor(String.class); } void addDataFetcher() { @@ -86,32 +82,26 @@ public class GqlvPropertyValidate { case ENTITY: context.codeRegistryBuilder.dataFetcher( holder.coordinatesFor(field), - this::validate); + this::choices); break; } } - Object validate(final DataFetchingEnvironment dataFetchingEnvironment) { - + List<Object> choices(final DataFetchingEnvironment dataFetchingEnvironment) { val sourcePojo = BookmarkedPojo.sourceFrom(dataFetchingEnvironment); - val sourcePojoClass = sourcePojo.getClass(); - val objectSpecification = context.specificationLoader.loadSpecification(sourcePojoClass); + val objectSpecification = context.specificationLoader.loadSpecification(sourcePojo.getClass()); if (objectSpecification == null) { - // not expected return null; } val association = holder.getOneToOneAssociation(); val managedObject = ManagedObject.adaptSingular(objectSpecification, sourcePojo); - Map<String, Object> arguments = dataFetchingEnvironment.getArguments(); - Object argumentValue = arguments.get(association.getId()); - ManagedObject argumentManagedObject = ManagedObject.adaptProperty(association, argumentValue); - Consent consent = association.isAssociationValid(managedObject, argumentManagedObject, InteractionInitiatedBy.USER); - return consent.isVetoed() ? consent.getReasonAsString().orElse("invalid") : null; + val choicesManagedObject = association.getChoices(managedObject, InteractionInitiatedBy.USER); + return choicesManagedObject.stream().map(ManagedObject::getPojo).collect(Collectors.toList()); } public interface Holder diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java index 69a560e1eb..161a9cb22a 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/GqlvPropertyValidate.java @@ -23,7 +23,6 @@ import java.util.Map; import org.apache.causeway.core.metamodel.consent.Consent; import org.apache.causeway.core.metamodel.consent.InteractionInitiatedBy; import org.apache.causeway.core.metamodel.object.ManagedObject; -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.fetcher.BookmarkedPojo; import org.apache.causeway.viewer.graphql.model.mmproviders.ObjectSpecificationProvider; @@ -34,9 +33,9 @@ import lombok.val; import graphql.schema.DataFetchingEnvironment; import graphql.schema.GraphQLFieldDefinition; -import graphql.schema.GraphQLOutputType; import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; +import static org.apache.causeway.viewer.graphql.model.domain.GqlvProperty.addGqlArgument; public class GqlvPropertyValidate { @@ -49,29 +48,13 @@ public class GqlvPropertyValidate { final Context context) { this.holder = holder; this.context = context; - this.field = fieldDefinition(holder); - } - - GraphQLFieldDefinition fieldDefinition(final Holder holder) { - - GraphQLFieldDefinition fieldDefinition = null; - GraphQLOutputType type = outputTypeFor(); - if (type != null) { - val fieldBuilder = newFieldDefinition() - .name("validate") - .type(type); - final OneToOneAssociation oneToOneAssociation = holder.getOneToOneAssociation(); - - GqlvProperty.addGqlArgument(oneToOneAssociation, fieldBuilder, TypeMapper.InputContext.VALIDATE); - fieldDefinition = fieldBuilder.build(); - holder.addField(fieldDefinition); - } - return fieldDefinition; - } + val fieldBuilder = newFieldDefinition() + .name("validate") + .type(TypeMapper.scalarTypeFor(String.class)); + addGqlArgument(holder.getOneToOneAssociation(), fieldBuilder, TypeMapper.InputContext.VALIDATE); - GraphQLOutputType outputTypeFor() { - return TypeMapper.scalarTypeFor(String.class); + this.field = holder.addField(fieldBuilder.build()); } void addDataFetcher() { @@ -94,24 +77,22 @@ public class GqlvPropertyValidate { Object validate(final DataFetchingEnvironment dataFetchingEnvironment) { - val sourcePojo = BookmarkedPojo.sourceFrom(dataFetchingEnvironment); - val sourcePojoClass = sourcePojo.getClass(); - val objectSpecification = context.specificationLoader.loadSpecification(sourcePojoClass); + val objectSpecification = context.specificationLoader.loadSpecification(sourcePojo.getClass()); if (objectSpecification == null) { - // not expected return null; } val association = holder.getOneToOneAssociation(); val managedObject = ManagedObject.adaptSingular(objectSpecification, sourcePojo); - Map<String, Object> arguments = dataFetchingEnvironment.getArguments(); - Object argumentValue = arguments.get(association.getId()); - ManagedObject argumentManagedObject = ManagedObject.adaptProperty(association, argumentValue); - Consent consent = association.isAssociationValid(managedObject, argumentManagedObject, InteractionInitiatedBy.USER); - return consent.isVetoed() ? consent.getReasonAsString().orElse("invalid") : null; + val arguments = dataFetchingEnvironment.getArguments(); + val argumentValue = arguments.get(association.getId()); + val argumentManagedObject = ManagedObject.adaptProperty(association, argumentValue); + + val valid = association.isAssociationValid(managedObject, argumentManagedObject, InteractionInitiatedBy.USER); + return valid.isVetoed() ? valid.getReasonAsString().orElse("invalid") : null; } public interface Holder diff --git a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapper.java b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapper.java index 3dd16d5220..f445f93776 100644 --- a/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapper.java +++ b/incubator/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/types/TypeMapper.java @@ -160,6 +160,9 @@ public class TypeMapper { HIDE, DISABLE, VALIDATE, + CHOICES, + AUTOCOMPLETE, + DEFAULT, INVOKE, SET, ; diff --git a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/Department.java b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/Department.java index 2c0f2e3394..ec886325fd 100644 --- a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/Department.java +++ b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/Department.java @@ -18,6 +18,7 @@ */ package org.apache.causeway.viewer.graphql.viewer.test.domain; +import javax.inject.Inject; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @@ -25,12 +26,14 @@ 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.Editing; import org.apache.causeway.applib.annotation.Nature; import org.apache.causeway.applib.annotation.Property; import org.apache.causeway.applib.annotation.SemanticsOf; @@ -59,6 +62,7 @@ import java.util.stream.Collectors; @DomainObject(nature = Nature.ENTITY, bounding = Bounding.BOUNDED) public class Department implements Comparable<Department> { + public Department(String name, DeptHead deptHead) { this.name = name; this.deptHead = deptHead; @@ -93,11 +97,19 @@ public class Department implements Comparable<Department> { @Getter @Setter - @Property + @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") @@ -165,4 +177,7 @@ public class Department implements Comparable<Department> { public int compareTo(final Department o) { return Comparator.comparing(Department::getName).compare(this, o); } + + @Inject @Transient private DeptHeadRepository deptHeadRepository; + } diff --git a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java index ad3d4f1074..59d11361fd 100644 --- a/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java +++ b/incubator/viewers/graphql/test/src/test/java/org/apache/causeway/viewer/graphql/viewer/test/domain/DeptHead.java @@ -75,11 +75,16 @@ public class DeptHead implements Comparable<DeptHead> { private String name; @Getter @Setter - @Property + @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 { diff --git a/incubator/viewers/graphql/test/src/test/resources/schema.gql b/incubator/viewers/graphql/test/src/test/resources/schema.gql index fea9e4f6c6..56be60a742 100644 --- a/incubator/viewers/graphql/test/src/test/resources/schema.gql +++ b/incubator/viewers/graphql/test/src/test/resources/schema.gql @@ -291,6 +291,7 @@ type causeway_applib_UserMemento__authenticationCode__gqlv_property { } type causeway_applib_UserMemento__authenticationSource__gqlv_property { + choices(authenticationSource: String): String disabled: String get: String! hidden: Boolean @@ -742,6 +743,7 @@ type causeway_feat_ApplicationTypeAction { } type causeway_feat_ApplicationTypeAction__actionSemantics__gqlv_property { + choices(actionSemantics: String): String disabled: String get: String! hidden: Boolean @@ -2443,6 +2445,7 @@ type university_dept_DeptHead__changeName__newName__gqlv_action_parameter { } type university_dept_DeptHead__department__gqlv_property { + choices(department: university_dept_Department__gqlv_input): university_dept_Department disabled: String get: university_dept_Department hidden: Boolean @@ -2507,6 +2510,7 @@ type university_dept_StaffMember { } type university_dept_StaffMember__department__gqlv_property { + choices(department: university_dept_Department__gqlv_input): university_dept_Department disabled: String get: university_dept_Department hidden: Boolean
