This is an automated email from the ASF dual-hosted git repository. shuber pushed a commit to branch UNOMI-180-CXS-GRAPHQLAPI in repository https://gitbox.apache.org/repos/asf/unomi.git
commit 54ca4398e6460f516739f9d840c9fb2ba3cc5afd Author: Serge Huber <shu...@jahia.com> AuthorDate: Tue May 28 15:36:29 2019 +0200 findSegments and findEvents fields now work partially, retrieving partially built results. Filters are not yet doing anything. --- graphql/README.md | 77 ++++++++++ .../unomi/graphql/internal/CDPSDLServletImpl.java | 156 +++++++++++++++++---- .../src/main/resources/cdp-schema.graphqls | 8 +- 3 files changed, 213 insertions(+), 28 deletions(-) diff --git a/graphql/README.md b/graphql/README.md new file mode 100644 index 0000000..94e8714 --- /dev/null +++ b/graphql/README.md @@ -0,0 +1,77 @@ +Apache Unomi GraphQL API +======================== + +Install +------- + +Installing GraphQL feature: + + feature:repo-add mvn:org.apache.unomi/cdp-graphql-feature/1.4.0-SNAPSHOT/xml/features + feature:install cdp-graphql-feature + +GraphQL Endpoint +---------------- + +You can then access the GraphQL endpoint at the following URL: + + http://localhost:8181/sdlgraphql + +Query example +------------- + +operation:: + + query findEvents($filter: CDP_EventFilterInput) { + cdp { + findEvents(filter: $filter) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + cursor + node { + id + cdp_profileID { + client { + id + title + } + id + uri + } + __typename + } + } + } + } + } + +variables:: + + { + "filter": { + "cdp_profileID_equals": "" + } + } + +Segment query operation: + + query findSegments($segmentFilter: CDP_SegmentFilterInput) { + cdp { + findSegments(filter: $segmentFilter) { + edges { + node { + id + name + view { + name + } + profiles { + profileIDs + } + } + } + } + } + } diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java index 68be5b9..2deae05 100644 --- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java +++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java @@ -32,7 +32,15 @@ import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; +import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.PartialList; +import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.query.Query; +import org.apache.unomi.api.segments.Segment; +import org.apache.unomi.api.services.DefinitionsService; import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.SegmentService; import org.osgi.framework.BundleContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -45,7 +53,9 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; @Component( @@ -59,6 +69,9 @@ public class CDPSDLServletImpl extends HttpServlet { private GraphQL graphQL; private EventService eventService; + private DefinitionsService definitionsService; + private SegmentService segmentService; + @Activate void activate(BundleContext bundleContext) { @@ -70,6 +83,16 @@ public class CDPSDLServletImpl extends HttpServlet { this.eventService = eventService; } + @Reference + public void setDefinitionService(DefinitionsService definitionService) { + this.definitionsService = definitionService; + } + + @Reference + public void setSegmentService(SegmentService segmentService) { + this.segmentService = segmentService; + } + RuntimeWiring buildRuntimeWiring() { GraphQLScalarType emptyTypeWorkAroundScalarType = GraphQLScalarType.newScalar() @@ -125,7 +148,7 @@ public class CDPSDLServletImpl extends HttpServlet { .typeResolver(new TypeResolver() { @Override public GraphQLObjectType getType(TypeResolutionEnvironment env) { - return null; + return env.getSchema().getObjectType("CDP_ProfileUpdateEvent"); } })) .type("CDP_ProfileInterface", typeWiring -> typeWiring @@ -142,37 +165,116 @@ public class CDPSDLServletImpl extends HttpServlet { return null; } })) - .type("CDP_Query", typeWiring -> typeWiring.dataFetcher("findEvents", new DataFetcher() { - @Override - public Object get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception { - // PartialList<Event> events = eventService.searchEvents(condition, offset, size); - return null; + .type("Query", typeWiring -> typeWiring.dataFetcher("cdp", dataFetchingEnvironment -> "CDP")) + .type("CDP_Query", typeWiring -> typeWiring + .dataFetcher("findEvents", dataFetchingEnvironment -> { + Map<String,Object> arguments = dataFetchingEnvironment.getArguments(); + Integer size = (Integer) arguments.get("first"); + if (size == null) { + size = 10; + } + String after = (String) arguments.get("after"); + if (after == null) { + after = "0"; + } + int offset = Integer.parseInt(after); + Object filter = arguments.get("filter"); + Condition condition = eventFilter2Condition(filter); + PartialList<Event> events = eventService.searchEvents(condition, offset, size); + Map<String,Object> eventConnection = new HashMap<>(); + List<Map<String,Object>> eventEdges = new ArrayList<>(); + for (Event event : events.getList()) { + Map<String,Object> eventEdge = new HashMap<>(); + Map<String,Object> eventNode = new HashMap<>(); + eventNode.put("id", event.getItemId()); + eventNode.put("__unomiEventType", event.getEventType()); + eventNode.put("cdp_profileID", getCDPProfileID(event.getProfileId())); + eventEdge.put("node", eventNode); + eventEdge.put("cursor", event.getItemId()); + eventEdges.add(eventEdge); } + eventConnection.put("edges", eventEdges); + Map<String,Object> pageInfo = new HashMap<>(); + pageInfo.put("hasPreviousPage", false); + pageInfo.put("hasNextPage", events.getTotalSize() > events.getList().size()); + eventConnection.put("pageInfo", pageInfo); + return eventConnection; + }) + .dataFetcher("findSegments", dataFetchingEnvironment -> { + Map<String,Object> arguments = dataFetchingEnvironment.getArguments(); + Integer size = (Integer) arguments.get("first"); + if (size == null) { + size = 10; + } + String after = (String) arguments.get("after"); + if (after == null) { + after = "0"; + } + int offset = Integer.parseInt(after); + Object filter = arguments.get("filter"); + Condition condition = eventFilter2Condition(filter); + + Map<String,Object> segmentConnection = new HashMap<>(); + Query query = new Query(); + query.setCondition(condition); + query.setLimit(size); + query.setOffset(offset); + // query.setSortby(sortBy); + PartialList<Metadata> segmentMetadatas = segmentService.getSegmentMetadatas(query); + List<Map<String,Object>> segmentEdges = new ArrayList<>(); + for (Metadata segmentMetadata : segmentMetadatas.getList()) { + Map<String,Object> segment = new HashMap<>(); + segment.put("id", segmentMetadata.getId()); + segment.put("name", segmentMetadata.getName()); + Map<String,Object> segmentView = new HashMap<>(); + segmentView.put("name", segmentMetadata.getScope()); + segment.put("view", segmentView); + Segment unomiSegment = segmentService.getSegmentDefinition(segmentMetadata.getId()); + Condition segmentCondition = unomiSegment.getCondition(); + segment.put("profiles", segmentConditionToProfileFilter(segmentCondition)); + Map<String,Object> segmentEdge = new HashMap<>(); + segmentEdge.put("node", segment); + segmentEdge.put("cursor", segmentMetadata.getId()); + segmentEdges.add(segmentEdge); + } + segmentConnection.put("edges", segmentEdges); + Map<String,Object> pageInfo = new HashMap<>(); + pageInfo.put("hasPreviousPage", false); + pageInfo.put("hasNextPage", segmentMetadatas.getTotalSize() > segmentMetadatas.getList().size()); + segmentConnection.put("pageInfo", pageInfo); + return segmentConnection; })) - // this uses builder function lambda syntax - /* - .type("QueryType", typeWiring -> typeWiring - .dataFetcher("hero", new StaticDataFetcher(StarWarsData.getArtoo())) - .dataFetcher("human", StarWarsData.getHumanDataFetcher()) - .dataFetcher("droid", StarWarsData.getDroidDataFetcher()) - ) - .type("Human", typeWiring -> typeWiring - .dataFetcher("friends", StarWarsData.getFriendsDataFetcher()) - ) - // you can use builder syntax if you don't like the lambda syntax - .type("Droid", typeWiring -> typeWiring - .dataFetcher("friends", StarWarsData.getFriendsDataFetcher()) - ) - // or full builder syntax if that takes your fancy - .type( - newTypeWiring("Character") - .typeResolver(StarWarsData.getCharacterTypeResolver()) - .build() - ) - */ .build(); } + private Map<String, Object> segmentConditionToProfileFilter(Condition segmentCondition) { + Map<String,Object> profileFilter = new HashMap<>(); + // profileFilter.put("profileIDs", new ArrayList<String>()); + return profileFilter; + } + + private Map<String,Object> getCDPProfileID(String profileId) { + Map<String,Object> cdpProfileID = new HashMap<>(); + Map<String,Object> client = getCDPClient(profileId); + cdpProfileID.put("client", client); + cdpProfileID.put("id", profileId); + cdpProfileID.put("uri", "cdp_profile:" + client.get("id") + "/" + profileId); + return cdpProfileID; + } + + private Map<String,Object> getCDPClient(String profileId) { + Map<String,Object> cdpClient = new HashMap<>(); + cdpClient.put("id", "unomi"); + cdpClient.put("title", "Default Unomi client"); + return cdpClient; + } + + private Condition eventFilter2Condition(Object filter) { + // todo implement transformation to proper event conditions + Condition matchAllCondition = new Condition(definitionsService.getConditionType("matchAllCondition")); + return matchAllCondition; + } + @Override public void init(ServletConfig config) throws ServletException { super.init(config); diff --git a/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls b/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls index 6e178a6..1e71cbe 100644 --- a/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls +++ b/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls @@ -971,4 +971,10 @@ Uses RFC-3339 representation, for example 16:39:57-08:00, see https://github.com/graphql-java/graphql-java-extended-scalars for example implementation """ -scalar Time \ No newline at end of file +scalar Time + +schema { + query : Query + mutation : Mutation + subscription : Subscription +} \ No newline at end of file