From 869008e196684d8a780ad293e749607b424ac6ca Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Wed, 7 Feb 2024 15:48:01 -0500 Subject: [PATCH 1/5] Implement new GraphQLDirectiveProvider interface; fix validation issues --- .../provider/dxm/DXGraphQLProvider.java | 10 +++- .../dxm/sdl/parsing/SDLSchemaService.java | 50 ++++++++++++------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/DXGraphQLProvider.java b/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/DXGraphQLProvider.java index c3dcf398a..65ce2dc65 100644 --- a/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/DXGraphQLProvider.java +++ b/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/DXGraphQLProvider.java @@ -50,7 +50,10 @@ import java.util.stream.Collectors; @Component(service = GraphQLProvider.class, immediate = true) -public class DXGraphQLProvider implements GraphQLTypesProvider, GraphQLQueryProvider, GraphQLMutationProvider, GraphQLSubscriptionProvider, GraphQLCodeRegistryProvider, DXGraphQLExtensionsProvider { +public class DXGraphQLProvider implements + GraphQLTypesProvider, GraphQLQueryProvider, GraphQLMutationProvider, GraphQLDirectiveProvider, + GraphQLSubscriptionProvider, GraphQLCodeRegistryProvider, DXGraphQLExtensionsProvider +{ private static Logger logger = LoggerFactory.getLogger(DXGraphQLProvider.class); private static DXGraphQLProvider instance; @@ -304,6 +307,11 @@ public Collection getTypes() { return types; } + @Override + public Collection getDirectives() { + return sdlSchemaService.getDirectives(); + } + @Override public Collection getQueries() { List defs = new ArrayList<>(queryType.getFieldDefinitions()); diff --git a/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java b/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java index 1039410ee..a989dd4a5 100644 --- a/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java +++ b/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java @@ -52,10 +52,12 @@ import java.net.URL; import java.text.MessageFormat; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import static graphql.Scalars.GraphQLBoolean; import static graphql.Scalars.GraphQLString; +import static org.jahia.modules.graphql.provider.dxm.sdl.SDLConstants.*; @Component(service = SDLSchemaService.class, immediate = true) public class SDLSchemaService { @@ -198,17 +200,16 @@ public List getSDLQueries() { List fieldDefinitions = graphQLSchema.getQueryType().getFieldDefinitions(); for (GraphQLFieldDefinition fieldDefinition : fieldDefinitions) { - GraphQLObjectType objectType = fieldDefinition.getType() instanceof GraphQLList ? - (GraphQLObjectType) ((GraphQLList) fieldDefinition.getType()).getWrappedType() : (GraphQLObjectType) fieldDefinition.getType(); - - GraphQLAppliedDirective directive = objectType.getAppliedDirective(SDLConstants.MAPPING_DIRECTIVE); + GraphQLDirectiveContainer directiveContainer = fieldDefinition.getType() instanceof GraphQLList ? + (GraphQLDirectiveContainer) ((GraphQLList) fieldDefinition.getType()).getWrappedType() : + (GraphQLDirectiveContainer) fieldDefinition.getType(); + GraphQLAppliedDirective directive = directiveContainer.getAppliedDirective(SDLConstants.MAPPING_DIRECTIVE); if (directive == null) { continue; } String nodeType = directive.getArgument(SDLConstants.MAPPING_DIRECTIVE_NODE).getValue().toString(); - //Handle connections if (fieldDefinition.getName().contains(SDLConstants.CONNECTION_QUERY_SUFFIX)) { String queryFieldName = fieldDefinition.getName().replace(SDLConstants.CONNECTION_QUERY_SUFFIX, ""); @@ -256,6 +257,17 @@ public List getSDLTypes() { return types; } + public Set getDirectives() { + if (graphQLSchema == null) { + generateSchema(); + } + + if (graphQLSchema != null) { + return new HashSet<>(graphQLSchema.getDirectives()); + } + return null; + } + public GraphQLSchema getGraphQLSchema() { return graphQLSchema; } @@ -334,27 +346,27 @@ private void applyDefaultFetcher(final List defs, final private TypeDefinitionRegistry prepareTypeRegistryDefinition() { TypeDefinitionRegistry typeDefinitionRegistry = new TypeDefinitionRegistry(); - typeDefinitionRegistry.add(new ObjectTypeDefinition("Query")); + Function newType = scalar -> new TypeName(scalar.getName()); + + typeDefinitionRegistry.add(ObjectTypeDefinition.newObjectTypeDefinition().name("Query") + .fieldDefinition(new FieldDefinition("_empty", newType.apply(GraphQLBoolean))) + .build()); typeDefinitionRegistry.add(new ScalarTypeDefinition("Date")); typeDefinitionRegistry.add(DirectiveDefinition.newDirectiveDefinition() .name(SDLConstants.MAPPING_DIRECTIVE) .directiveLocations(Arrays.asList( - DirectiveLocation.newDirectiveLocation().name("OBJECT").build(), - DirectiveLocation.newDirectiveLocation().name("FIELD_DEFINITION").build())) + new DirectiveLocation("OBJECT"), + new DirectiveLocation("FIELD_DEFINITION") )) .inputValueDefinitions(Arrays.asList( - InputValueDefinition.newInputValueDefinition().name(SDLConstants.MAPPING_DIRECTIVE_NODE).type(TypeName.newTypeName(GraphQLString.getName()).build()).build(), - InputValueDefinition.newInputValueDefinition().name(SDLConstants.MAPPING_DIRECTIVE_PROPERTY).type(TypeName.newTypeName(GraphQLString.getName()).build()).build(), - InputValueDefinition.newInputValueDefinition().name(SDLConstants.MAPPING_DIRECTIVE_IGNORE_DEFAULT_QUERIES).type(TypeName.newTypeName(GraphQLBoolean.getName()).build()).build())) + new InputValueDefinition(MAPPING_DIRECTIVE_NODE, newType.apply(GraphQLString)), + new InputValueDefinition(MAPPING_DIRECTIVE_PROPERTY, newType.apply(GraphQLString)), + new InputValueDefinition(MAPPING_DIRECTIVE_IGNORE_DEFAULT_QUERIES, newType.apply(GraphQLBoolean)) )) .build()); - typeDefinitionRegistry.add(DirectiveDefinition.newDirectiveDefinition() - .name(SDLConstants.FETCHER_DIRECTIVE) - .directiveLocations(Arrays.asList( - DirectiveLocation.newDirectiveLocation().name("FIELD_DEFINITION").build())) - .inputValueDefinitions(Arrays.asList( - InputValueDefinition.newInputValueDefinition().name(SDLConstants.FETCHER_DIRECTIVE_NAME).type(TypeName.newTypeName(GraphQLString.getName()).build()).build())) + .name(FETCHER_DIRECTIVE) + .directiveLocation(new DirectiveLocation("FIELD_DEFINITION")) + .inputValueDefinition(new InputValueDefinition(FETCHER_DIRECTIVE_NAME, newType.apply(GraphQLString))) .build()); - return typeDefinitionRegistry; } @@ -365,7 +377,7 @@ private void handleCustomConnectionTypes(TypeDefinitionRegistry typeDefinitionRe ObjectTypeExtensionDefinition query = typeDefinitionRegistry.objectTypeExtensions().get("Query").get(queryIndex); List fields = query.getFieldDefinitions(); - //Collect connection fields i. e. ones that map to Connection + //Collect connection fields i.e. ones that map to Connection for (FieldDefinition f : fields) { if (f.getName().endsWith(SDLConstants.CONNECTION_QUERY_SUFFIX) && f.getType() instanceof TypeName) { String connectionName = ((TypeName) f.getType()).getName(); From 0478f8844292f1534e16732e31b9c7ab4a8bd705 Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Wed, 7 Feb 2024 15:50:10 -0500 Subject: [PATCH 2/5] Add SDL extension tests --- tests/cypress/e2e/sdl/sdlExtensions.cy.js | 33 +++++++++++++++++++++ tests/cypress/fixtures/sdl/sdlExtensions.js | 26 ++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tests/cypress/e2e/sdl/sdlExtensions.cy.js create mode 100644 tests/cypress/fixtures/sdl/sdlExtensions.js diff --git a/tests/cypress/e2e/sdl/sdlExtensions.cy.js b/tests/cypress/e2e/sdl/sdlExtensions.cy.js new file mode 100644 index 000000000..88f9434ee --- /dev/null +++ b/tests/cypress/e2e/sdl/sdlExtensions.cy.js @@ -0,0 +1,33 @@ +import { + getCoreSdlExtensions, + getExampleSdlExtensions +} from '../../fixtures/sdl/sdlExtensions'; + +describe('SDL extensions', () => { + it('should have SDL extensions defined in dxm-provider module', () => { + cy.apollo({query: getCoreSdlExtensions}).then((response) => { + const {category, imageAsset} = response?.data || {}; + expect(category?.fields?.map(f => f.name)).to.deep.eq( + ['metadata', 'description', 'title'] + ); + expect(imageAsset?.fields?.map(f => f.name)).to.deep.eq( + ['metadata', 'type', 'size', 'height', 'width'] + ); + }); + }); + + it('should have SDL extensions defined in extension-examples module', () => { + cy.apollo({query: getExampleSdlExtensions}).then((response) => { + const {newsSdl, images, queries} = response?.data || {}; + expect(newsSdl?.fields?.map(f => f.name)).to.deep.eq( + ['metadata', 'description', 'title'] + ); + expect(images?.fields?.map(f => f.name)).to.deep.eq( + ['metadata', 'type', 'size', 'height', 'width'] + ); + ['newsByChecked', 'myNewsByDate', 'myImagesByHeight'].forEach(queryField => { + expect(queries?.fields?.find(f => f.name === queryField)).to.exist; + }); + }); + }); +}); diff --git a/tests/cypress/fixtures/sdl/sdlExtensions.js b/tests/cypress/fixtures/sdl/sdlExtensions.js new file mode 100644 index 000000000..b5ae1039a --- /dev/null +++ b/tests/cypress/fixtures/sdl/sdlExtensions.js @@ -0,0 +1,26 @@ +import gql from 'graphql-tag'; + +export const getCoreSdlExtensions = gql` + query coreSdlExtensions { + category: __type(name: "Category") { + fields {name} + }, + imageAsset: __type(name: "ImageAsset") { + fields {name} + } + } +`; + +export const getExampleSdlExtensions = gql` + query exampleSdlExtensions { + newsSdl: __type(name:"NewsSDL") { + fields {name} + } + images: __type(name:"Images") { + fields {name} + } + queries: __type(name: "Query") { + fields {name} + } + } +`; From d940827d8a61ce923252e81c49a000ba8cae8cdc Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Wed, 7 Feb 2024 15:50:31 -0500 Subject: [PATCH 3/5] Revert directive definition workaround --- .../src/main/resources/META-INF/graphql-extension.sdl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/graphql-extension-example/src/main/resources/META-INF/graphql-extension.sdl b/graphql-extension-example/src/main/resources/META-INF/graphql-extension.sdl index 2dfb31ead..51c90aa86 100644 --- a/graphql-extension-example/src/main/resources/META-INF/graphql-extension.sdl +++ b/graphql-extension-example/src/main/resources/META-INF/graphql-extension.sdl @@ -1,5 +1,3 @@ -directive @mapping(node : String, property: String, ignoreDefaultQueries: Boolean) on FIELD_DEFINITION - """This is news""" type NewsSDL @mapping(node:"jnt:news", ignoreDefaultQueries: true) { """This is title""" @@ -28,4 +26,4 @@ extend type Query { myNewsByDate: [NewsSDL] """This is myImagesByHeight""" myImagesByHeight: [Images] -} \ No newline at end of file +} From ae5b86f431f2063aeeda093d014c7781de45a0ce Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Fri, 9 Feb 2024 16:17:07 -0500 Subject: [PATCH 4/5] Fix test data --- tests/cypress/e2e/sdl/sdlExtensions.cy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cypress/e2e/sdl/sdlExtensions.cy.js b/tests/cypress/e2e/sdl/sdlExtensions.cy.js index 88f9434ee..10d085076 100644 --- a/tests/cypress/e2e/sdl/sdlExtensions.cy.js +++ b/tests/cypress/e2e/sdl/sdlExtensions.cy.js @@ -20,10 +20,10 @@ describe('SDL extensions', () => { cy.apollo({query: getExampleSdlExtensions}).then((response) => { const {newsSdl, images, queries} = response?.data || {}; expect(newsSdl?.fields?.map(f => f.name)).to.deep.eq( - ['metadata', 'description', 'title'] + ['title', 'description', 'checked', 'date'] ); expect(images?.fields?.map(f => f.name)).to.deep.eq( - ['metadata', 'type', 'size', 'height', 'width'] + ['height'] ); ['newsByChecked', 'myNewsByDate', 'myImagesByHeight'].forEach(queryField => { expect(queries?.fields?.find(f => f.name === queryField)).to.exist; From b282721a46b141c68b9473a0145114e72a3e643c Mon Sep 17 00:00:00 2001 From: Geofrey Flores Date: Sun, 11 Feb 2024 11:36:39 -0500 Subject: [PATCH 5/5] Handle null cases --- .../provider/dxm/sdl/parsing/SDLSchemaService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java b/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java index a989dd4a5..8e15d17e4 100644 --- a/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java +++ b/graphql-dxm-provider/src/main/java/org/jahia/modules/graphql/provider/dxm/sdl/parsing/SDLSchemaService.java @@ -258,14 +258,18 @@ public List getSDLTypes() { } public Set getDirectives() { + Set result = new HashSet<>(); if (graphQLSchema == null) { generateSchema(); } if (graphQLSchema != null) { - return new HashSet<>(graphQLSchema.getDirectives()); + List directives = graphQLSchema.getDirectives(); + if (directives != null) { + result.addAll(directives); + } } - return null; + return result; } public GraphQLSchema getGraphQLSchema() {