You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2019/05/28 18:09:12 UTC

[unomi] 01/02: findSegments and findEvents fields now work partially, retrieving partially built results. Filters are not yet doing anything.

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 e420ae329a0d3eec511630de472667eb0bdb1788
Author: Serge Huber <sh...@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