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 a26ec842c0f42b5a7d2ce731869c250dc6d84c6f Author: danhaywood <[email protected]> AuthorDate: Thu Jan 18 23:33:38 2024 +0000 CAUSEWAY-3676 : tests failing, abandon --- .../object/entity/_EntityFacetForTesting.java | 5 + .../graphql/viewer/source/GqlvObjectSpec.java | 124 ++++++++ .../viewer/source/GraphQlSourceForCauseway.java | 78 ++--- .../graphql/viewer/source/ObjectTypeFactory.java | 315 +++++++++------------ .../graphql/viewer/source/QueryFieldFactory.java | 2 +- .../viewer/graphql/viewer/source/TypeMapper.java | 4 +- .../{_Utils.java => _GraphQLObjectType.java} | 27 +- .../source/{_Utils.java => _LogicalTypeName.java} | 20 +- 8 files changed, 318 insertions(+), 257 deletions(-) diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/entity/_EntityFacetForTesting.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/entity/_EntityFacetForTesting.java index b94dc4026a..38ba7c8848 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/entity/_EntityFacetForTesting.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/entity/_EntityFacetForTesting.java @@ -96,6 +96,11 @@ class _EntityFacetForTesting implements EntityFacet { throw _Exceptions.unsupportedOperation(); } + @Override + public Object versionOf(Object pojo) { + return _Exceptions.unsupportedOperation(); + } + @Override public boolean isProxyEnhancement(final Method method) { throw _Exceptions.unsupportedOperation(); diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/GqlvObjectSpec.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/GqlvObjectSpec.java new file mode 100644 index 0000000000..1f77da06ec --- /dev/null +++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/GqlvObjectSpec.java @@ -0,0 +1,124 @@ +package org.apache.causeway.viewer.graphql.viewer.source; + +import graphql.Scalars; +import graphql.schema.GraphQLFieldDefinition; +import graphql.schema.GraphQLList; +import graphql.schema.GraphQLObjectType; + +import graphql.schema.GraphQLTypeReference; + +import lombok.Getter; +import lombok.val; + +import org.apache.causeway.applib.services.metamodel.BeanSort; +import org.apache.causeway.core.metamodel.spec.ObjectSpecification; +import org.apache.causeway.core.metamodel.spec.feature.MixedIn; +import org.apache.causeway.core.metamodel.spec.feature.OneToManyAssociation; +import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation; + +import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; +import static graphql.schema.GraphQLNonNull.nonNull; +import static graphql.schema.GraphQLObjectType.newObject; + +/** + * A wrapper around {@link ObjectSpecification} + */ +public class GqlvObjectSpec { + + private final ObjectSpecification objectSpec; + + public String getLogicalTypeNameSanitized() { + val logicalTypeName = objectSpec.getLogicalTypeName(); + return _LogicalTypeName.sanitized(logicalTypeName); + } + + public BeanSort getBeanSort() { + return objectSpec.getBeanSort(); + } + + @Getter private final GraphQLObjectType.Builder objectTypeBuilder; + + @Getter private final GraphQLObjectType metaType; + + static GqlvObjectSpec gqlv(final ObjectSpecification objectSpec) { + return new GqlvObjectSpec(objectSpec); + } + + GqlvObjectSpec(final ObjectSpecification objectSpec) { + this.objectSpec = objectSpec; + this.objectTypeBuilder = newObject().name(getLogicalTypeNameSanitized()); + this.metaType = _GraphQLObjectType.create(getLogicalTypeNameSanitized(), getBeanSort()); + } + + + void addFields() { + objectSpec.streamProperties(MixedIn.INCLUDED) + .forEach(this::addField); + } + + private void addField(OneToOneAssociation otoa) { + ObjectSpecification fieldObjectSpecification = otoa.getElementType(); + BeanSort beanSort = fieldObjectSpecification.getBeanSort(); + switch (beanSort) { + + case VIEW_MODEL: + case ENTITY: + + String logicalTypeNameOfField = fieldObjectSpecification.getLogicalTypeName(); + + GraphQLFieldDefinition.Builder fieldBuilder = newFieldDefinition() + .name(otoa.getId()) + .type(otoa.isOptional() + ? GraphQLTypeReference.typeRef( + _LogicalTypeName.sanitized(logicalTypeNameOfField)) + : nonNull(GraphQLTypeReference.typeRef( + _LogicalTypeName.sanitized(logicalTypeNameOfField)))); + getObjectTypeBuilder().field(fieldBuilder); + + break; + + case VALUE: + + // todo: map ... + + GraphQLFieldDefinition.Builder valueBuilder = newFieldDefinition() + .name(otoa.getId()) + .type(otoa.isOptional() + ? Scalars.GraphQLString + : nonNull(Scalars.GraphQLString)); + getObjectTypeBuilder().field(valueBuilder); + + break; + + } + } + + void addCollections() { + objectSpec.streamCollections(MixedIn.INCLUDED).forEach(this::addCollection); + } + + private void addCollection(OneToManyAssociation otom) { + + ObjectSpecification elementType = otom.getElementType(); + BeanSort beanSort = elementType.getBeanSort(); + switch (beanSort) { + + case VIEW_MODEL: + case ENTITY: + String logicalTypeNameOfField = elementType.getLogicalTypeName(); + GraphQLFieldDefinition.Builder fieldBuilder = newFieldDefinition() + .name(otom.getId()) + .type(GraphQLList.list(GraphQLTypeReference.typeRef( + _LogicalTypeName.sanitized(logicalTypeNameOfField)))); + objectTypeBuilder.field(fieldBuilder); + break; + + case VALUE: + GraphQLFieldDefinition.Builder valueBuilder = newFieldDefinition() + .name(otom.getId()) + .type(GraphQLList.list(TypeMapper.typeFor(elementType.getCorrespondingClass()))); + objectTypeBuilder.field(valueBuilder); + break; + } + } +} diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/GraphQlSourceForCauseway.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/GraphQlSourceForCauseway.java index 47a717d99a..3dc550fa9c 100644 --- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/GraphQlSourceForCauseway.java +++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/GraphQlSourceForCauseway.java @@ -30,6 +30,7 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; import org.apache.causeway.applib.id.HasLogicalType; + import org.apache.causeway.core.metamodel.spec.ObjectSpecification; import org.springframework.graphql.execution.GraphQlSource; @@ -43,6 +44,7 @@ import org.apache.causeway.core.metamodel.specloader.SpecificationLoader; import graphql.GraphQL; import graphql.Scalars; +import graphql.execution.instrumentation.tracing.TracingInstrumentation; import graphql.schema.DataFetcher; import graphql.schema.GraphQLCodeRegistry; import graphql.schema.GraphQLObjectType; @@ -87,46 +89,15 @@ public class GraphQlSourceForCauseway implements GraphQlSource { throw new IllegalStateException("Metamodel is not fully introspected"); } - val queryBuilder = newObject().name("Query"); - GraphQLCodeRegistry.Builder codeRegistryBuilder = GraphQLCodeRegistry.newCodeRegistry(); + final GraphQLObjectType.Builder queryBuilder = newObject().name("Query"); + final GraphQLCodeRegistry.Builder codeRegistryBuilder = GraphQLCodeRegistry.newCodeRegistry(); Set<GraphQLType> graphQLObjectTypes = new HashSet<>(); specificationLoader.snapshotSpecifications() - .distinct((a, b) -> a.getLogicalTypeName().equals(b.getLogicalTypeName())) - .sorted(Comparator.comparing(HasLogicalType::getLogicalTypeName)) - .forEach(objectSpecification -> { - - val logicalTypeName = objectSpecification.getLogicalTypeName(); - String logicalTypeNameSanitized = _Utils.logicalTypeNameSanitized(logicalTypeName); - - switch (objectSpecification.getBeanSort()) { - - case ABSTRACT: - case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL) - case ENTITY: // @DomainObject(nature=ENTITY) - - // TODO: App interface should mapp to gql interfaces? - objectTypeFactory - .objectTypeFromObjectSpecification(objectSpecification, graphQLObjectTypes, codeRegistryBuilder); - - break; - - case MANAGED_BEAN_CONTRIBUTING: //@DomainService - - queryFieldFactory - .queryFieldFromObjectSpecification(queryBuilder, codeRegistryBuilder, objectSpecification); - break; - - case MANAGED_BEAN_NOT_CONTRIBUTING: // a @Service or @Component ... ignore - case MIXIN: - case VALUE: - case COLLECTION: - case VETOED: - case UNKNOWN: - break; - } - }); + .distinct((a, b) -> a.getLogicalTypeName().equals(b.getLogicalTypeName())) + .sorted(Comparator.comparing(HasLogicalType::getLogicalTypeName)) + .forEach(objectSpec -> handleObjectSpec(objectSpec, graphQLObjectTypes, queryBuilder, codeRegistryBuilder)); val query_numServices = newFieldDefinition() .name("numServices") @@ -137,13 +108,12 @@ public class GraphQlSourceForCauseway implements GraphQlSource { .field(query_numServices) .build(); - val codeRegistry = codeRegistryBuilder - .dataFetcher(coordinates(query.getName(), query_numServices.getName()), + .dataFetcher( + coordinates(query.getName(), query_numServices.getName()), (DataFetcher<Object>) environment -> this.serviceRegistry.streamRegisteredBeans().count()) .build(); - return GraphQLSchema.newSchema() .query(query) .additionalTypes(graphQLObjectTypes) @@ -151,4 +121,34 @@ public class GraphQlSourceForCauseway implements GraphQlSource { .build(); } + private void handleObjectSpec( + final ObjectSpecification objectSpec, + final Set<GraphQLType> graphQLObjectTypes, + final GraphQLObjectType.Builder queryBuilder, final GraphQLCodeRegistry.Builder codeRegistryBuilder) { + switch (objectSpec.getBeanSort()) { + + case ABSTRACT: + case VIEW_MODEL: // @DomainObject(nature=VIEW_MODEL) + case ENTITY: // @DomainObject(nature=ENTITY) + + // TODO: App interface should map to gql interfaces? + objectTypeFactory.objectTypeFromObjectSpecification(objectSpec, graphQLObjectTypes, codeRegistryBuilder); + + break; + + case MANAGED_BEAN_CONTRIBUTING: //@DomainService + + queryFieldFactory + .queryFieldFromObjectSpecification(queryBuilder, codeRegistryBuilder, objectSpec); + break; + + case MANAGED_BEAN_NOT_CONTRIBUTING: // a @Service or @Component ... ignore + case MIXIN: + case VALUE: + case COLLECTION: + case VETOED: + case UNKNOWN: + break; + } + } } diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/ObjectTypeFactory.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/ObjectTypeFactory.java index b1f6983e2e..919fc90df4 100644 --- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/ObjectTypeFactory.java +++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/ObjectTypeFactory.java @@ -32,6 +32,8 @@ import javax.inject.Inject; import org.apache.causeway.core.metamodel.objectmanager.ObjectManager; +import org.apache.causeway.core.metamodel.spec.feature.ObjectAction; + import org.springframework.stereotype.Component; import org.apache.causeway.applib.services.bookmark.BookmarkService; @@ -43,9 +45,6 @@ import org.apache.causeway.core.metamodel.spec.feature.MixedIn; import org.apache.causeway.core.metamodel.spec.feature.ObjectAssociation; import org.apache.causeway.core.metamodel.specloader.SpecificationLoader; -import static org.apache.causeway.viewer.graphql.viewer.source._Utils.metaTypeName; -import static org.apache.causeway.viewer.graphql.viewer.source._Utils.mutatorsTypeName; - import graphql.Scalars; import graphql.schema.DataFetcher; import graphql.schema.FieldCoordinates; @@ -55,54 +54,73 @@ import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLInputObjectType; import graphql.schema.GraphQLInputType; -import graphql.schema.GraphQLList; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; import graphql.schema.GraphQLType; -import graphql.schema.GraphQLTypeReference; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.RequiredArgsConstructor; +import lombok.experimental.UtilityClass; import lombok.val; @Component @RequiredArgsConstructor(onConstructor_ = {@Inject}) public class ObjectTypeFactory { + final static String GQL_INPUTTYPE_PREFIX = "_gql_input__"; + final static String GQL_MUTATTIONS_FIELDNAME = "_gql_mutations"; private final BookmarkService bookmarkService; private final SpecificationLoader specificationLoader; private final ObjectManager objectManager; - private static GraphQLFieldDefinition idField = newFieldDefinition() - .name("id").type(nonNull(Scalars.GraphQLString)).build(); + static String mutatorsTypeName(final String logicalTypeNameSanitized){ + return logicalTypeNameSanitized + "__DomainObject_mutators"; + } - private static GraphQLFieldDefinition logicalTypeNameField = newFieldDefinition() - .name("logicalTypeName").type(nonNull(Scalars.GraphQLString)).build(); + static String metaTypeName(final String logicalTypeNameSanitized){ + return logicalTypeNameSanitized + "__DomainObject_meta"; + } - private static GraphQLFieldDefinition versionField = newFieldDefinition() - .name("version").type(Scalars.GraphQLString).build(); + @UtilityClass + static class Fields { + static GraphQLFieldDefinition id = + newFieldDefinition() + .name("id") + .type(nonNull(Scalars.GraphQLString)) + .build(); + static GraphQLFieldDefinition logicalTypeName = + newFieldDefinition() + .name("logicalTypeName") + .type(nonNull(Scalars.GraphQLString)) + .build(); + static GraphQLFieldDefinition version = + newFieldDefinition() + .name("version") + .type(Scalars.GraphQLString).build(); + } public void objectTypeFromObjectSpecification( - final ObjectSpecification objectSpecification, + final ObjectSpecification objectSpec, final Set<GraphQLType> graphQLObjectTypes, final GraphQLCodeRegistry.Builder codeRegistryBuilder) { - val logicalTypeName = objectSpecification.getLogicalTypeName(); - String logicalTypeNameSanitized = _Utils.logicalTypeNameSanitized(logicalTypeName); - - GraphQLObjectType.Builder objectTypeBuilder = newObject().name(logicalTypeNameSanitized); + val gqlvObjectSpec = GqlvObjectSpec.gqlv(objectSpec); // create meta field type - BeanSort objectSpecificationBeanSort = objectSpecification.getBeanSort(); - GraphQLObjectType metaType = - createAndRegisterMetaType(logicalTypeNameSanitized, objectSpecificationBeanSort, graphQLObjectTypes); + BeanSort objectSpecificationBeanSort = objectSpec.getBeanSort(); + final String logicalTypeNameSanitized = gqlvObjectSpec.getLogicalTypeNameSanitized(); + + GraphQLObjectType metaType = _GraphQLObjectType.create(logicalTypeNameSanitized, objectSpecificationBeanSort); + + addTypeIfNotAlreadyPresent(graphQLObjectTypes, metaType, logicalTypeNameSanitized); // add meta field - GraphQLFieldDefinition gql_meta = newFieldDefinition().name("_gql_meta").type(metaType).build(); - objectTypeBuilder.field(gql_meta); + val _gql_meta_Field = newFieldDefinition().name("_gql_meta").type(metaType).build(); + gqlvObjectSpec.getObjectTypeBuilder().field(_gql_meta_Field); // create input type - String inputTypeName = _Utils.GQL_INPUTTYPE_PREFIX + logicalTypeNameSanitized; + String inputTypeName = GQL_INPUTTYPE_PREFIX + gqlvObjectSpec.getLogicalTypeNameSanitized(); GraphQLInputObjectType.Builder inputTypeBuilder = newInputObject().name(inputTypeName); inputTypeBuilder .field(GraphQLInputObjectField.newInputObjectField() @@ -113,28 +131,28 @@ public class ObjectTypeFactory { addTypeIfNotAlreadyPresent(graphQLObjectTypes, inputType, inputTypeName); // add fields - addFields(objectSpecification, objectTypeBuilder); + gqlvObjectSpec.addFields(); // add collections - addCollections(objectSpecification, objectTypeBuilder); + gqlvObjectSpec.addCollections(); // add actions MutatorsDataForEntity mutatorsDataForEntity = - addActions(logicalTypeNameSanitized, objectSpecification, objectTypeBuilder, graphQLObjectTypes); + addActions(gqlvObjectSpec.getLogicalTypeNameSanitized(), objectSpec, gqlvObjectSpec.getObjectTypeBuilder(), graphQLObjectTypes); // build and register object type - GraphQLObjectType graphQLObjectType = objectTypeBuilder.build(); - addTypeIfNotAlreadyPresent(graphQLObjectTypes, graphQLObjectType, logicalTypeNameSanitized); + GraphQLObjectType graphQLObjectType = gqlvObjectSpec.getObjectTypeBuilder().build(); + addTypeIfNotAlreadyPresent(graphQLObjectTypes, graphQLObjectType, gqlvObjectSpec.getLogicalTypeNameSanitized()); // create and register data fetchers createAndRegisterDataFetchersForMetaData( - codeRegistryBuilder, objectSpecificationBeanSort, metaType, gql_meta, graphQLObjectType); - if (mutatorsDataForEntity!=null) createAndRegisterDataFetchersForMutators( - codeRegistryBuilder, objectSpecificationBeanSort, mutatorsDataForEntity, graphQLObjectType); - createAndRegisterDataFetchersForField(objectSpecification, codeRegistryBuilder, graphQLObjectType); - createAndRegisterDataFetchersForCollection(objectSpecification, codeRegistryBuilder, graphQLObjectType); - - return; + codeRegistryBuilder, objectSpecificationBeanSort, metaType, _gql_meta_Field, graphQLObjectType); + if (mutatorsDataForEntity!=null) { + createAndRegisterDataFetchersForMutators( + codeRegistryBuilder, objectSpecificationBeanSort, mutatorsDataForEntity, graphQLObjectType); + } + createAndRegisterDataFetchersForField(objectSpec, codeRegistryBuilder, graphQLObjectType); + createAndRegisterDataFetchersForCollection(objectSpec, codeRegistryBuilder, graphQLObjectType); } private void createAndRegisterDataFetchersForMutators( @@ -177,50 +195,6 @@ public class ObjectTypeFactory { } } - void addFields( - final ObjectSpecification objectSpecification, - final GraphQLObjectType.Builder objectTypeBuilder) { - - objectSpecification.streamProperties(MixedIn.INCLUDED) - .forEach(otoa -> { - - ObjectSpecification fieldObjectSpecification = otoa.getElementType(); - BeanSort beanSort = fieldObjectSpecification.getBeanSort(); - switch (beanSort) { - - case VIEW_MODEL: - case ENTITY: - - String logicalTypeNameOfField = fieldObjectSpecification.getLogicalTypeName(); - - GraphQLFieldDefinition.Builder fieldBuilder = newFieldDefinition() - .name(otoa.getId()) - .type(otoa.isOptional() - ? GraphQLTypeReference.typeRef( - _Utils.logicalTypeNameSanitized(logicalTypeNameOfField)) - : nonNull(GraphQLTypeReference.typeRef( - _Utils.logicalTypeNameSanitized(logicalTypeNameOfField)))); - objectTypeBuilder.field(fieldBuilder); - - break; - - case VALUE: - - // todo: map ... - - GraphQLFieldDefinition.Builder valueBuilder = newFieldDefinition() - .name(otoa.getId()) - .type(otoa.isOptional() - ? Scalars.GraphQLString - : nonNull(Scalars.GraphQLString)); - objectTypeBuilder.field(valueBuilder); - - break; - - } - }); - } - void createAndRegisterDataFetchersForField( final ObjectSpecification objectSpecification, final GraphQLCodeRegistry.Builder codeRegistryBuilder, @@ -233,43 +207,6 @@ public class ObjectTypeFactory { }); } - void addCollections( - final ObjectSpecification objectSpecification, - final GraphQLObjectType.Builder objectTypeBuilder) { - - objectSpecification.streamCollections(MixedIn.INCLUDED).forEach(otom -> { - - ObjectSpecification elementType = otom.getElementType(); - BeanSort beanSort = elementType.getBeanSort(); - switch (beanSort) { - - case VIEW_MODEL: - case ENTITY: - - String logicalTypeNameOfField = elementType.getLogicalTypeName(); - GraphQLFieldDefinition.Builder fieldBuilder = newFieldDefinition() - .name(otom.getId()) - .type(GraphQLList.list(GraphQLTypeReference.typeRef( - _Utils.logicalTypeNameSanitized(logicalTypeNameOfField)))); - objectTypeBuilder.field(fieldBuilder); - - break; - - case VALUE: - - GraphQLFieldDefinition.Builder valueBuilder = newFieldDefinition() - .name(otom.getId()) - .type(GraphQLList.list(TypeMapper.typeFor(elementType.getCorrespondingClass()))); - objectTypeBuilder.field(valueBuilder); - - break; - - } - - }); - - } - void createAndRegisterDataFetchersForCollection( final ObjectSpecification objectSpecification, final GraphQLCodeRegistry.Builder codeRegistryBuilder, @@ -287,67 +224,23 @@ public class ObjectTypeFactory { final GraphQLObjectType.Builder objectTypeBuilder, final Set<GraphQLType> graphQLObjectTypes) { - String mutatorsTypeName = mutatorsTypeName(logicalTypeNameSanitized); - GraphQLObjectType.Builder mutatorsTypeBuilder = newObject().name(mutatorsTypeName); - final List<GraphQLFieldDefinition> mutatorsTypeFields = new ArrayList<>(); + MutatorManager result = mutatorManager(logicalTypeNameSanitized); objectSpecification.streamActions(ActionScope.PRODUCTION, MixedIn.INCLUDED) - .forEach(objectAction -> { - - if (objectAction.getSemantics().isSafeInNature()) { - - String fieldName = objectAction.getId(); - GraphQLFieldDefinition.Builder builder = newFieldDefinition() - .name(fieldName) - .type((GraphQLOutputType) TypeMapper.typeForObjectAction(objectAction)); - if (objectAction.getParameters().isNotEmpty()) { - builder.arguments(objectAction.getParameters().stream() - .map(objectActionParameter -> GraphQLArgument.newArgument() - .name(objectActionParameter.getId()) - .type(objectActionParameter.isOptional() - ? TypeMapper.inputTypeFor(objectActionParameter) - : nonNull(TypeMapper.inputTypeFor(objectActionParameter))) - .build()) - .collect(Collectors.toList())); - } - objectTypeBuilder.field(builder); - - } else { - - String fieldName = objectAction.getId(); - GraphQLFieldDefinition.Builder builder = newFieldDefinition() - .name(fieldName) - .type((GraphQLOutputType) TypeMapper.typeForObjectAction(objectAction)); - if (objectAction.getParameters().isNotEmpty()) { - builder.arguments(objectAction.getParameters().stream() - .map(objectActionParameter -> GraphQLArgument.newArgument() - .name(objectActionParameter.getId()) - .type(objectActionParameter.isOptional() - ? TypeMapper.inputTypeFor(objectActionParameter) - : nonNull(TypeMapper.inputTypeFor(objectActionParameter))) - .build()) - .collect(Collectors.toList())); - } - - GraphQLFieldDefinition fieldDefinition = builder.build(); - mutatorsTypeBuilder.field(fieldDefinition); - mutatorsTypeFields.add(fieldDefinition); - - } + .forEach(objectAction -> + addAction(objectAction, objectTypeBuilder, result.mutatorsTypeBuilder, result.mutatorsTypeFields) + ); - - }); - - if (!mutatorsTypeFields.isEmpty()){ - GraphQLObjectType mutatorsType = mutatorsTypeBuilder.build(); - addTypeIfNotAlreadyPresent(graphQLObjectTypes, mutatorsType, mutatorsTypeName); + if (!result.mutatorsTypeFields.isEmpty()){ + GraphQLObjectType mutatorsType = result.mutatorsTypeBuilder.build(); + addTypeIfNotAlreadyPresent(graphQLObjectTypes, mutatorsType, result.mutatorsTypeName); GraphQLFieldDefinition gql_mutations = newFieldDefinition() - .name(_Utils.GQL_MUTATTIONS_FIELDNAME) + .name(GQL_MUTATTIONS_FIELDNAME) .type(mutatorsType) .build(); objectTypeBuilder.field(gql_mutations); - return new MutatorsDataForEntity(mutatorsType, mutatorsTypeFields); + return new MutatorsDataForEntity(mutatorsType, result.mutatorsTypeFields); // // I think we have to create and register data fetcher for mutations here, but we can't since we have no objectTypeYet // codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(graphQLTypeReference, gql_mutations), new DataFetcher<Object>() { @@ -376,6 +269,69 @@ public class ObjectTypeFactory { } + private static MutatorManager mutatorManager(String logicalTypeNameSanitized) { + val mutatorsTypeName = mutatorsTypeName(logicalTypeNameSanitized); + GraphQLObjectType.Builder mutatorsTypeBuilder = newObject().name(mutatorsTypeName); + final List<GraphQLFieldDefinition> mutatorsTypeFields = new ArrayList<>(); + MutatorManager result = new MutatorManager(mutatorsTypeName, mutatorsTypeBuilder, mutatorsTypeFields); + return result; + } + + private static class MutatorManager { + public final String mutatorsTypeName; + public final GraphQLObjectType.Builder mutatorsTypeBuilder; + public final List<GraphQLFieldDefinition> mutatorsTypeFields; + + public MutatorManager(String mutatorsTypeName, GraphQLObjectType.Builder mutatorsTypeBuilder, List<GraphQLFieldDefinition> mutatorsTypeFields) { + this.mutatorsTypeName = mutatorsTypeName; + this.mutatorsTypeBuilder = mutatorsTypeBuilder; + this.mutatorsTypeFields = mutatorsTypeFields; + } + } + + private static void addAction(ObjectAction objectAction, GraphQLObjectType.Builder objectTypeBuilder, GraphQLObjectType.Builder mutatorsTypeBuilder, List<GraphQLFieldDefinition> mutatorsTypeFields) { + if (objectAction.getSemantics().isSafeInNature()) { + + String fieldName = objectAction.getId(); + GraphQLFieldDefinition.Builder builder = newFieldDefinition() + .name(fieldName) + .type((GraphQLOutputType) TypeMapper.typeForObjectAction(objectAction)); + if (objectAction.getParameters().isNotEmpty()) { + builder.arguments(objectAction.getParameters().stream() + .map(objectActionParameter -> GraphQLArgument.newArgument() + .name(objectActionParameter.getId()) + .type(objectActionParameter.isOptional() + ? TypeMapper.inputTypeFor(objectActionParameter) + : nonNull(TypeMapper.inputTypeFor(objectActionParameter))) + .build()) + .collect(Collectors.toList())); + } + objectTypeBuilder.field(builder); + + } else { + + String fieldName = objectAction.getId(); + GraphQLFieldDefinition.Builder builder = newFieldDefinition() + .name(fieldName) + .type((GraphQLOutputType) TypeMapper.typeForObjectAction(objectAction)); + if (objectAction.getParameters().isNotEmpty()) { + builder.arguments(objectAction.getParameters().stream() + .map(objectActionParameter -> GraphQLArgument.newArgument() + .name(objectActionParameter.getId()) + .type(objectActionParameter.isOptional() + ? TypeMapper.inputTypeFor(objectActionParameter) + : nonNull(TypeMapper.inputTypeFor(objectActionParameter))) + .build()) + .collect(Collectors.toList())); + } + + GraphQLFieldDefinition fieldDefinition = builder.build(); + mutatorsTypeBuilder.field(fieldDefinition); + mutatorsTypeFields.add(fieldDefinition); + + } + } + @Data @AllArgsConstructor class MutatorsDataForEntity { @@ -426,23 +382,6 @@ public class ObjectTypeFactory { } - GraphQLObjectType createAndRegisterMetaType( - final String logicalTypeNameSanitized, - final BeanSort objectSpecificationBeanSort, - final Set<GraphQLType> graphQLObjectTypes) { - - String metaTypeName = metaTypeName(logicalTypeNameSanitized); - GraphQLObjectType.Builder metaTypeBuilder = newObject().name(metaTypeName); - metaTypeBuilder.field(idField); - metaTypeBuilder.field(logicalTypeNameField); - if (objectSpecificationBeanSort == BeanSort.ENTITY) { - metaTypeBuilder.field(versionField); - } - GraphQLObjectType metaType = metaTypeBuilder.build(); - addTypeIfNotAlreadyPresent(graphQLObjectTypes, metaType, logicalTypeNameSanitized); - return metaType; - } - GraphQLObjectType createAndRegisterMutatorsType( final String logicalTypeNameSanitized, final BeanSort objectSpecificationBeanSort, @@ -469,18 +408,18 @@ public class ObjectTypeFactory { .orElse(null); //TODO: is this correct ? }); - codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(metaType, idField), (DataFetcher<Object>) environment -> { + codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(metaType, Fields.id), (DataFetcher<Object>) environment -> { GqlMeta gqlMeta = environment.getSource(); return gqlMeta.id(); }); - codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(metaType, logicalTypeNameField), (DataFetcher<Object>) environment -> { + codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(metaType, Fields.logicalTypeName), (DataFetcher<Object>) environment -> { GqlMeta gqlMeta = environment.getSource(); return gqlMeta.logicalTypeName(); }); if (objectSpecificationBeanSort == BeanSort.ENTITY) { - codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(metaType, versionField), (DataFetcher<Object>) environment -> { + codeRegistryBuilder.dataFetcher(FieldCoordinates.coordinates(metaType, Fields.version), (DataFetcher<Object>) environment -> { GqlMeta gqlMeta = environment.getSource(); return gqlMeta.version(); }); diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/QueryFieldFactory.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/QueryFieldFactory.java index 6488f09124..a49452f383 100644 --- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/QueryFieldFactory.java +++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/QueryFieldFactory.java @@ -65,7 +65,7 @@ public class QueryFieldFactory { final ObjectSpecification objectSpecification) { val logicalTypeName = objectSpecification.getLogicalTypeName(); - String logicalTypeNameSanitized = _Utils.logicalTypeNameSanitized(logicalTypeName); + String logicalTypeNameSanitized = _LogicalTypeName.sanitized(logicalTypeName); serviceRegistry.lookupBeanById(logicalTypeName) .ifPresent(service -> { diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/TypeMapper.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/TypeMapper.java index 210b334fc1..cdf79bc6d5 100644 --- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/TypeMapper.java +++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/TypeMapper.java @@ -61,7 +61,7 @@ public class TypeMapper { case ENTITY: case VIEW_MODEL: - return GraphQLTypeReference.typeRef(_Utils.GQL_INPUTTYPE_PREFIX + _Utils.logicalTypeNameSanitized(elementType.getLogicalTypeName())); + return GraphQLTypeReference.typeRef(ObjectTypeFactory.GQL_INPUTTYPE_PREFIX + _LogicalTypeName.sanitized(elementType.getLogicalTypeName())); case VALUE: return (GraphQLInputType) typeFor(elementType.getCorrespondingClass()); @@ -101,7 +101,7 @@ public class TypeMapper { case ABSTRACT: case ENTITY: case VIEW_MODEL: - return GraphQLTypeReference.typeRef(_Utils.logicalTypeNameSanitized(objectSpecification.getLogicalTypeName())); + return GraphQLTypeReference.typeRef(_LogicalTypeName.sanitized(objectSpecification.getLogicalTypeName())); case VALUE: return typeFor(objectSpecification.getCorrespondingClass()); diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_Utils.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_GraphQLObjectType.java similarity index 51% copy from incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_Utils.java copy to incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_GraphQLObjectType.java index a54c58336b..2d85503012 100644 --- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_Utils.java +++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_GraphQLObjectType.java @@ -18,21 +18,24 @@ */ package org.apache.causeway.viewer.graphql.viewer.source; -final class _Utils { +import graphql.schema.GraphQLObjectType; - final static String GQL_INPUTTYPE_PREFIX = "_gql_input__"; - final static String GQL_MUTATTIONS_FIELDNAME = "_gql_mutations"; +import lombok.experimental.UtilityClass; - static String metaTypeName(final String logicalTypeNameSanitized){ - return logicalTypeNameSanitized + "__DomainObject_meta"; - } +import org.apache.causeway.applib.services.metamodel.BeanSort; - static String mutatorsTypeName(final String logicalTypeNameSanitized){ - return logicalTypeNameSanitized + "__DomainObject_mutators"; - } +import static graphql.schema.GraphQLObjectType.newObject; - static String logicalTypeNameSanitized(final String logicalTypeName) { - return logicalTypeName.replace('.', '_'); +@UtilityClass +final class _GraphQLObjectType { + static GraphQLObjectType create(String logicalTypeNameSanitized, BeanSort objectSpecificationBeanSort) { + String metaTypeName = ObjectTypeFactory.metaTypeName(logicalTypeNameSanitized); + GraphQLObjectType.Builder metaTypeBuilder = newObject().name(metaTypeName); + metaTypeBuilder.field(ObjectTypeFactory.Fields.id); + metaTypeBuilder.field(ObjectTypeFactory.Fields.logicalTypeName); + if (objectSpecificationBeanSort == BeanSort.ENTITY) { + metaTypeBuilder.field(ObjectTypeFactory.Fields.version); + } + return metaTypeBuilder.build(); } - } diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_Utils.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_LogicalTypeName.java similarity index 60% rename from incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_Utils.java rename to incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_LogicalTypeName.java index a54c58336b..fee3851003 100644 --- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_Utils.java +++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/source/_LogicalTypeName.java @@ -18,21 +18,11 @@ */ package org.apache.causeway.viewer.graphql.viewer.source; -final class _Utils { +import lombok.experimental.UtilityClass; - final static String GQL_INPUTTYPE_PREFIX = "_gql_input__"; - final static String GQL_MUTATTIONS_FIELDNAME = "_gql_mutations"; - - static String metaTypeName(final String logicalTypeNameSanitized){ - return logicalTypeNameSanitized + "__DomainObject_meta"; - } - - static String mutatorsTypeName(final String logicalTypeNameSanitized){ - return logicalTypeNameSanitized + "__DomainObject_mutators"; +@UtilityClass +final class _LogicalTypeName { + static String sanitized(final String name) { + return name.replace('.', '_'); } - - static String logicalTypeNameSanitized(final String logicalTypeName) { - return logicalTypeName.replace('.', '_'); - } - }
