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 1281d96aaaa56d07c319b6cbd83ebea4b1541e12 Author: danhaywood <[email protected]> AuthorDate: Sun Feb 11 16:05:27 2024 +0000 CAUSEWAY-3676: further refactorings --- .../graphql/model/domain/GqlvDomainObject.java | 59 ++++++++++++++-------- .../integration/GraphQlSourceForCauseway.java | 45 ++++------------- .../viewer/toplevel/GqlvTopLevelMutation.java | 38 ++------------ .../graphql/viewer/toplevel/GqlvTopLevelQuery.java | 57 +++++++++------------ 4 files changed, 77 insertions(+), 122 deletions(-) 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 997f780cd8..7595c0fefb 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 @@ -23,6 +23,7 @@ import java.util.SortedMap; import java.util.TreeMap; import graphql.Scalars; +import graphql.schema.DataFetcher; import graphql.schema.FieldCoordinates; import graphql.schema.GraphQLArgument; import graphql.schema.GraphQLFieldDefinition; @@ -44,19 +45,22 @@ 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.registry.GraphQLTypeRegistry; -import static org.apache.causeway.core.config.CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_WITH_MUTATIONS_NON_SPEC_COMPLIANT; - import lombok.Getter; import lombok.val; /** * Exposes a domain object (view model or entity) via the GQL viewer. */ -public class GqlvDomainObject implements GqlvAction.Holder, GqlvProperty.Holder, GqlvCollection.Holder, GqlvMeta.Holder { +public class GqlvDomainObject + implements GqlvAction.Holder, GqlvProperty.Holder, GqlvCollection.Holder, GqlvMeta.Holder { + private final Holder holder; @Getter private final ObjectSpecification objectSpecification; private final Context context; + @Getter + private final GraphQLFieldDefinition lookupField; + private final GqlvMeta meta; private final GraphQLObjectType.Builder gqlObjectTypeBuilder; @@ -70,10 +74,12 @@ public class GqlvDomainObject implements GqlvAction.Holder, GqlvProperty.Holder, @Getter private final GraphQLInputObjectType gqlInputObjectType; public GqlvDomainObject( + final GqlvDomainObject.Holder holder, final ObjectSpecification objectSpecification, final Context context, final ObjectManager objectManager, final GraphQLTypeRegistry graphQLTypeRegistry) { + this.holder = holder; this.objectSpecification = objectSpecification; this.context = context; @@ -90,32 +96,35 @@ public class GqlvDomainObject implements GqlvAction.Holder, GqlvProperty.Holder, .build()); gqlInputObjectType = inputTypeBuilder.build(); + this.lookupField = buildFieldDefinition(gqlInputObjectType); + addMembers(); + + gqlObjectType = gqlObjectTypeBuilder.build(); + graphQLTypeRegistry.addTypeIfNotAlreadyPresent(gqlObjectType); + meta.registerTypesInto(graphQLTypeRegistry); + graphQLTypeRegistry.addTypeIfNotAlreadyPresent(gqlInputObjectType); + } - public GraphQLFieldDefinition getField() { + private GraphQLFieldDefinition buildFieldDefinition(GraphQLInputObjectType gqlInputObjectType) { val lookupConfig = this.context.causewayConfiguration.getViewer().getGraphql().getLookup(); - ObjectSpecification objectSpec = getObjectSpecification(); + val objectSpec = getObjectSpecification(); + val fieldName = String.format("%s%s%s", + lookupConfig.getFieldNamePrefix(), // eg "_gqlv_lookup__" + TypeNames.objectTypeNameFor(objectSpec), + lookupConfig.getFieldNameSuffix()); + return newFieldDefinition() - .name(String.format("%s%s%s", - lookupConfig.getFieldNamePrefix(), // eg "_gqlv_lookup__" - TypeNames.objectTypeNameFor(objectSpec), - lookupConfig.getFieldNameSuffix()) // eg "" - ) + .name(fieldName) .type(this.context.typeMapper.outputTypeFor(objectSpec)) .argument(GraphQLArgument.newArgument() .name(lookupConfig.getArgument()) // eg "object" - .type(getGqlInputObjectType()) + .type(gqlInputObjectType) .build()) .build(); } - public void addTypesInto(GraphQLTypeRegistry graphQLTypeRegistry) { - gqlObjectType = gqlObjectTypeBuilder.build(); - graphQLTypeRegistry.addTypeIfNotAlreadyPresent(gqlObjectType); - meta.registerTypesInto(graphQLTypeRegistry); - graphQLTypeRegistry.addTypeIfNotAlreadyPresent(gqlInputObjectType); - } private void addMembers() { @@ -156,6 +165,15 @@ public class GqlvDomainObject implements GqlvAction.Holder, GqlvProperty.Holder, public void addDataFetchers() { + + this.context.codeRegistryBuilder.dataFetcher( + holder.coordinatesFor(getLookupField()), + (DataFetcher<Object>) environment -> { + Object target = environment.getArgument("object"); + return GqlvAction.asPojo(getObjectSpecification(), target, this.context.bookmarkService) + .orElse(null); + }); + meta.addDataFetchers(); properties.forEach((id, property) -> property.addDataFetcher()); collections.forEach((id, collection) -> collection.addDataFetcher()); @@ -165,10 +183,6 @@ public class GqlvDomainObject implements GqlvAction.Holder, GqlvProperty.Holder, @Override public FieldCoordinates coordinatesFor(final GraphQLFieldDefinition fieldDefinition) { - if (gqlObjectType == null) { - throw new IllegalStateException(String.format( - "GraphQLObjectType has not yet been built for %s", objectSpecification.getLogicalTypeName())); - } return FieldCoordinates.coordinates(gqlObjectType, fieldDefinition); } @@ -178,4 +192,7 @@ public class GqlvDomainObject implements GqlvAction.Holder, GqlvProperty.Holder, return objectSpecification.getLogicalTypeName(); } + public interface Holder extends GqlvHolder { + } + } diff --git a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java index 86a1b923e8..0c0c4c0420 100644 --- a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java +++ b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/integration/GraphQlSourceForCauseway.java @@ -19,12 +19,10 @@ package org.apache.causeway.viewer.graphql.viewer.integration; import java.util.ArrayList; -import java.util.LinkedHashMap; import javax.annotation.PostConstruct; import javax.inject.Inject; -import org.apache.causeway.core.metamodel.spec.ObjectSpecification; import org.apache.causeway.viewer.graphql.viewer.toplevel.GqlvTopLevelMutation; import org.springframework.graphql.execution.GraphQlSource; @@ -105,49 +103,28 @@ public class GraphQlSourceForCauseway implements GraphQlSource { val codeRegistryBuilder = GraphQLCodeRegistry.newCodeRegistry(); val context = new Context(codeRegistryBuilder, bookmarkService, specificationLoader, typeMapper, serviceRegistry, causewayConfiguration, causewaySystemEnvironment); - // domain objects - val domainObjects = new LinkedHashMap<ObjectSpecification, GqlvDomainObject>(); - val domainObjectList = new ArrayList<GqlvDomainObject>(); - context.objectSpecifications().forEach(objectSpec -> { - switch (objectSpec.getBeanSort()) { - - case ABSTRACT: - case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL) - case ENTITY: // @DomainObject(nature=ENTITY) - - val domainObject = new GqlvDomainObject(objectSpec, context, objectManager, graphQLTypeRegistry); - domainObject.addTypesInto(graphQLTypeRegistry); - domainObject.addDataFetchers(); - - domainObjectList.add(domainObject); - domainObjects.put(objectSpec, domainObject); - - break; - } - }); - - // top-level query type and (dependent on configuration) the top-level mutation type - val topLevelQuery = new GqlvTopLevelQuery(context, domainObjectList); - - + // top-level query and mutation type + val topLevelQuery = new GqlvTopLevelQuery(context, objectManager, graphQLTypeRegistry); val topLevelMutation = causewayConfiguration.getViewer().getGraphql().getApiVariant() == CausewayConfiguration.Viewer.Graphql.ApiVariant.QUERY_AND_MUTATIONS ? new GqlvTopLevelMutation(context) : null; + // add the data fetchers + topLevelQuery.addDataFetchers(); + if (topLevelMutation != null) { + topLevelMutation.addDataFetchers(); + } - // finalize the fetcher/mutator code that's been registered + // finalize the fetcher/mutator code that's been added val codeRegistry = codeRegistryBuilder.build(); // build the schema - val schemaBuilder = GraphQLSchema.newSchema() + return GraphQLSchema.newSchema() .query(topLevelQuery.getObjectType()) .additionalTypes(graphQLTypeRegistry.getGraphQLTypes()) - .codeRegistry(codeRegistry); - if (topLevelMutation != null) { - schemaBuilder.mutation(topLevelMutation.getGqlObjectType()); - } - return schemaBuilder + .codeRegistry(codeRegistry) + .mutation(topLevelMutation != null ? topLevelMutation.getObjectType() : null) .build(); } diff --git a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelMutation.java b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelMutation.java index 8b19244dc1..4bce77cc6c 100644 --- a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelMutation.java +++ b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelMutation.java @@ -1,7 +1,6 @@ package org.apache.causeway.viewer.graphql.viewer.toplevel; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import graphql.schema.FieldCoordinates; @@ -10,8 +9,6 @@ import graphql.schema.GraphQLObjectType; import static graphql.schema.GraphQLObjectType.newObject; -import org.apache.causeway.applib.id.HasLogicalType; -import org.apache.causeway.commons.functional.Either; import org.apache.causeway.core.metamodel.facets.properties.update.modify.PropertySetterFacet; import org.apache.causeway.core.metamodel.spec.ObjectSpecification; import org.apache.causeway.core.metamodel.spec.feature.MixedIn; @@ -29,13 +26,10 @@ public class GqlvTopLevelMutation private final Context context; - @Getter final GraphQLObjectType.Builder gqlObjectTypeBuilder; + private final GraphQLObjectType.Builder gqlObjectTypeBuilder; - - /** - * Built using {@link #buildMutationType()} - */ - private GraphQLObjectType gqlObjectType; + @Getter + private final GraphQLObjectType objectType; private final List<GqlvMutationForAction> actions = new ArrayList<>(); private final List<GqlvMutationForProperty> properties = new ArrayList<>(); @@ -57,29 +51,7 @@ public class GqlvTopLevelMutation }); - buildMutationType(); - - addDataFetchers(); - } - - - - public GraphQLObjectType buildMutationType() { - if (gqlObjectType != null) { - throw new IllegalStateException("Mutation type has already been built"); - } - return gqlObjectType = gqlObjectTypeBuilder.build(); - } - - /** - * - * @see #buildMutationType() - */ - public GraphQLObjectType getGqlObjectType() { - if (gqlObjectType == null) { - throw new IllegalStateException("Mutation type has not yet been built"); - } - return gqlObjectType; + objectType = gqlObjectTypeBuilder.build(); } @@ -99,7 +71,7 @@ public class GqlvTopLevelMutation @Override public FieldCoordinates coordinatesFor(GraphQLFieldDefinition fieldDefinition) { - return FieldCoordinates.coordinates(gqlObjectType, fieldDefinition); + return FieldCoordinates.coordinates(objectType, fieldDefinition); } public void addDataFetchers() { diff --git a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelQuery.java b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelQuery.java index f8dd4cbd35..53f87e4887 100644 --- a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelQuery.java +++ b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/toplevel/GqlvTopLevelQuery.java @@ -3,52 +3,50 @@ package org.apache.causeway.viewer.graphql.viewer.toplevel; import java.util.ArrayList; import java.util.List; -import graphql.schema.DataFetcher; import graphql.schema.FieldCoordinates; -import graphql.schema.GraphQLArgument; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLObjectType; -import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; import static graphql.schema.GraphQLObjectType.newObject; +import org.apache.causeway.core.metamodel.objectmanager.ObjectManager; import org.apache.causeway.core.metamodel.spec.ObjectSpecification; import org.apache.causeway.viewer.graphql.model.context.Context; -import org.apache.causeway.viewer.graphql.model.domain.GqlvAction; import org.apache.causeway.viewer.graphql.model.domain.GqlvDomainObject; import org.apache.causeway.viewer.graphql.model.domain.GqlvDomainService; -import org.apache.causeway.viewer.graphql.model.domain.TypeNames; +import org.apache.causeway.viewer.graphql.model.registry.GraphQLTypeRegistry; import lombok.Getter; import lombok.val; -public class GqlvTopLevelQuery implements GqlvDomainService.Holder { +public class GqlvTopLevelQuery implements GqlvDomainService.Holder, GqlvDomainObject.Holder { + + private static final String OBJECT_TYPE_NAME = "Query"; final GraphQLObjectType.Builder objectTypeBuilder; + @Getter private final GraphQLObjectType objectType; private final List<GqlvDomainService> domainServices = new ArrayList<>(); + private final List<GqlvDomainObject> domainObjects = new ArrayList<>(); private final Context context; - private final List<GqlvDomainObject> domainObjects; - - - @Getter private final GraphQLObjectType objectType; - public GqlvTopLevelQuery( final Context context, - final List<GqlvDomainObject> domainObjects) { + final ObjectManager objectManager, + final GraphQLTypeRegistry graphQLTypeRegistry) { + this.context = context; - this.domainObjects = domainObjects; - this.objectTypeBuilder = newObject().name("Query"); + this.objectTypeBuilder = newObject().name(OBJECT_TYPE_NAME); - // add services to top-level query context.objectSpecifications().forEach(objectSpec -> { switch (objectSpec.getBeanSort()) { - case MANAGED_BEAN_CONTRIBUTING: // @DomainService - context.serviceRegistry.lookupBeanById(objectSpec.getLogicalTypeName()) - .ifPresent(servicePojo -> { - addDomainService(objectSpec, servicePojo, context); - }); + + case ABSTRACT: + case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL) + case ENTITY: // @DomainObject(nature=ENTITY) + + domainObjects.add(new GqlvDomainObject(this, objectSpec, context, objectManager, graphQLTypeRegistry)); + break; } }); @@ -59,7 +57,7 @@ public class GqlvTopLevelQuery implements GqlvDomainService.Holder { case MANAGED_BEAN_CONTRIBUTING: // @DomainService context.serviceRegistry.lookupBeanById(objectSpec.getLogicalTypeName()) .ifPresent(servicePojo -> { - addDataFetchers(); + addDomainService(objectSpec, servicePojo, context); }); break; } @@ -67,10 +65,9 @@ public class GqlvTopLevelQuery implements GqlvDomainService.Holder { // add lookup to top-level query for (GqlvDomainObject domainObject : this.domainObjects) { - addField(domainObject.getField()); + addField(domainObject.getLookupField()); } - objectType = objectTypeBuilder.build(); } @@ -82,7 +79,7 @@ public class GqlvTopLevelQuery implements GqlvDomainService.Holder { @Override public FieldCoordinates coordinatesFor(GraphQLFieldDefinition fieldDefinition) { - return FieldCoordinates.coordinates("Query", fieldDefinition.getName()); + return FieldCoordinates.coordinates(OBJECT_TYPE_NAME, fieldDefinition.getName()); } @Override @@ -99,16 +96,8 @@ public class GqlvTopLevelQuery implements GqlvDomainService.Holder { } }); - domainObjects.forEach(domainObject -> { - ObjectSpecification objectSpec = domainObject.getObjectSpecification(); - this.context.codeRegistryBuilder.dataFetcher( - coordinatesFor(domainObject.getField()), - (DataFetcher<Object>) environment -> { - Object target = environment.getArgument("object"); - return GqlvAction.asPojo(objectSpec, target, this.context.bookmarkService) - .orElse(null); - }); - }); + + domainObjects.forEach(GqlvDomainObject::addDataFetchers); }
