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 84510c8ec53c6153325422a39895be8bae5421bc Author: Serge Huber <[email protected]> AuthorDate: Thu Nov 7 16:38:21 2019 +0100 Remove SDL implementation since we will focus instead on GraphQL Java annotations-based implementation Signed-off-by: Serge Huber <[email protected]> --- graphql/README.md | 2 +- .../unomi/graphql/internal/CDPSDLServletImpl.java | 409 --------- .../src/main/resources/cdp-schema.graphqls | 974 --------------------- .../src/main/resources/unomi-schema.graphqls | 74 -- 4 files changed, 1 insertion(+), 1458 deletions(-) diff --git a/graphql/README.md b/graphql/README.md index d1755b2..5be691b 100644 --- a/graphql/README.md +++ b/graphql/README.md @@ -31,7 +31,7 @@ GraphQL Endpoint You can then access the GraphQL endpoint at the following URL: - http://localhost:8181/sdlgraphql + http://localhost:8181/graphql Query example ------------- 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 deleted file mode 100644 index 6a0e7ff..0000000 --- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.unomi.graphql.internal; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.google.common.base.Charsets; -import graphql.ExecutionInput; -import graphql.ExecutionResult; -import graphql.GraphQL; -import graphql.TypeResolutionEnvironment; -import graphql.execution.instrumentation.tracing.TracingInstrumentation; -import graphql.introspection.IntrospectionQuery; -import graphql.scalars.ExtendedScalars; -import graphql.schema.*; -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; -import org.osgi.service.component.annotations.Reference; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletResponse; -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( - service={javax.servlet.http.HttpServlet.class,javax.servlet.Servlet.class}, - property = {"alias=/sdlgraphql", "jmx.objectname=graphql.servlet:type=graphql"} -) -public class CDPSDLServletImpl extends HttpServlet { - - private BundleContext bundleContext; - private ObjectMapper objectMapper; - private GraphQL graphQL; - - private EventService eventService; - private DefinitionsService definitionsService; - private SegmentService segmentService; - - - @Activate - void activate(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - - @Reference - public void setEventService(EventService eventService) { - 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() - .name("EmptyTypeWorkAround") - .description("A marker type to get around the limitation of GraphQL that doesn't allow empty types. It should be always ignored.") - .coercing(new Coercing() { - @Override - public Object serialize(Object dataFetcherResult) throws CoercingSerializeException { - return null; - } - - @Override - public Object parseValue(Object input) throws CoercingParseValueException { - return input; - } - - @Override - public Object parseLiteral(Object input) throws CoercingParseLiteralException { - return input; - } - }) - .build(); - - GraphQLScalarType geopointScalarType = GraphQLScalarType.newScalar() - .name("GeoPoint") - .description("A type that represents a geographical location") - .coercing(new Coercing() { - @Override - public Object serialize(Object dataFetcherResult) throws CoercingSerializeException { - return null; - } - - @Override - public Object parseValue(Object input) throws CoercingParseValueException { - return input; - } - - @Override - public Object parseLiteral(Object input) throws CoercingParseLiteralException { - return input; - } - }) - .build(); - - return RuntimeWiring.newRuntimeWiring() - .scalar(ExtendedScalars.DateTime) - .scalar(ExtendedScalars.Date) - .scalar(ExtendedScalars.Json) - .scalar(ExtendedScalars.Time) - .scalar(emptyTypeWorkAroundScalarType) - .scalar(geopointScalarType) - .type("CDP_EventInterface", typeWiring -> typeWiring - .typeResolver(new TypeResolver() { - @Override - public GraphQLObjectType getType(TypeResolutionEnvironment env) { - Map<String,Object> object = env.getObject(); - String unomiEventType = (String) object.get("__unomiEventType"); - if ("view".equals(unomiEventType)) { - return env.getSchema().getObjectType("Unomi_PageViewEvent"); - } else if ("sessionCreated".equals(unomiEventType)) { - return env.getSchema().getObjectType("Unomi_SessionCreatedEvent"); - } else { - return env.getSchema().getObjectType("Unomi_UnknownEvent"); - } - } - })) - .type("CDP_ProfileInterface", typeWiring -> typeWiring - .typeResolver(new TypeResolver() { - @Override - public GraphQLObjectType getType(TypeResolutionEnvironment env) { - return null; - } - })) - .type("CDP_PropertyInterface", typeWiring -> typeWiring - .typeResolver(new TypeResolver() { - @Override - public GraphQLObjectType getType(TypeResolutionEnvironment env) { - 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; - })) - .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); - - SchemaParser schemaParser = new SchemaParser(); - SchemaGenerator schemaGenerator = new SchemaGenerator(); - - Reader cdpSchemaReader = getSchemaReader("cdp-schema.graphqls"); - Reader unomiSchemaReader = getSchemaReader("unomi-schema.graphqls"); - //File schemaFile2 = loadSchema("cdp-schema.graphqls"); - //File schemaFile3 = loadSchema("cdp-schema.graphqls"); - - TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry(); - - // each registry is merged into the main registry - typeRegistry.merge(schemaParser.parse(cdpSchemaReader)); - typeRegistry.merge(schemaParser.parse(unomiSchemaReader)); - //typeRegistry.merge(schemaParser.parse(schemaFile2)); - //typeRegistry.merge(schemaParser.parse(schemaFile3)); - - RuntimeWiring wiring = buildRuntimeWiring(); - GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring); - graphQL = GraphQL.newGraphQL(graphQLSchema) - .instrumentation(new TracingInstrumentation()) - .build(); - - objectMapper = new ObjectMapper(); - objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String query = req.getParameter("query"); - if ("/schema.json".equals(req.getPathInfo())) { - query = IntrospectionQuery.INTROSPECTION_QUERY; - } - String operationName = req.getParameter("operationName"); - String variableStr = req.getParameter("variables"); - Map<String, Object> variables = new HashMap<>(); - if ((variableStr != null) && (variableStr.trim().length() > 0)) { - TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() { - }; - variables = objectMapper.readValue(variableStr, typeRef); - } - - setupCORSHeaders(req, resp); - executeGraphQLRequest(resp, query, operationName, variables); - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - InputStream bodyStream = req.getInputStream(); - TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() { - }; - Map<String, Object> body = objectMapper.readValue(bodyStream, typeRef); - String query = (String) body.get("query"); - String operationName = (String) body.get("operationName"); - Map<String, Object> variables = (Map<String, Object>) body.get("variables"); - if (variables == null) { - variables = new HashMap<>(); - } - - setupCORSHeaders(req, resp); - executeGraphQLRequest(resp, query, operationName, variables); - } - - @Override - protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - setupCORSHeaders(req, resp); - resp.flushBuffer(); - } - - private void executeGraphQLRequest(HttpServletResponse resp, String query, String operationName, Map<String, Object> variables) throws IOException { - if (query == null || query.trim().length() == 0) { - throw new RuntimeException("Query cannot be empty or null"); - } - ExecutionInput executionInput = ExecutionInput.newExecutionInput() - .query(query) - .variables(variables) - .operationName(operationName) - .build(); - - ExecutionResult executionResult = graphQL.execute(executionInput); - - Map<String, Object> toSpecificationResult = executionResult.toSpecification(); - PrintWriter out = resp.getWriter(); - objectMapper.writeValue(out, toSpecificationResult); - } - - private Reader getSchemaReader(String resourceUrl) { - try { - return new InputStreamReader(bundleContext.getBundle().getResource(resourceUrl).openConnection().getInputStream(), Charsets.UTF_8.name()); - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - /** - * Setup CORS headers as soon as possible so that errors are not misconstrued on the client for CORS errors - * - * @param httpServletRequest - * @param response - * @throws IOException - */ - public void setupCORSHeaders(HttpServletRequest httpServletRequest, ServletResponse response) throws IOException { - if (response instanceof HttpServletResponse) { - // todo this should be configurable - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - if (httpServletRequest != null && httpServletRequest.getHeader("Origin") != null) { - httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin")); - } else { - httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); - } - httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Apollo-Tracing, test"); - httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); - httpServletResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS, POST, GET"); - // httpServletResponse.setHeader("Access-Control-Max-Age", "600"); - // httpServletResponse.setHeader("Access-Control-Expose-Headers","Access-Control-Allow-Origin"); - // httpServletResponse.flushBuffer(); - } - } - -} diff --git a/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls b/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls deleted file mode 100644 index bea3348..0000000 --- a/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls +++ /dev/null @@ -1,974 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -input CDP_AlgorithmInput { - name: String! - parameters: JSON -} - -type CDP_BooleanProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - defaultValue: Boolean -} - -input CDP_BooleanPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - defaultValue: Boolean -} - -type CDP_Client { - id: ID! - title: String -} - -input CDP_ClientInput { - id: ID! - title: String -} - -type CDP_Consent { - token: ID! - source: CDP_Source - client: CDP_Client - type: String! - status: CDP_ConsentStatus! - lastUpdate: DateTime - expiration: DateTime - profile: CDP_ProfileInterface - events: CDP_EventConnection -} - -enum CDP_ConsentStatus { - GRANTED - DENIED - REVOKED -} - -type CDP_ConsentUpdateEvent implements CDP_EventInterface { - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] - type: String! - status: String - lastUpdate: DateTime - expiration: DateTime -} - -"""Filter for consent update events""" -type CDP_ConsentUpdateEventFilter { - type_equals: String - status_equals: String - lastUpdate_equals: DateTime - lastUpdate_lt: DateTime - lastUpdate_lte: DateTime - lastUpdate_gt: DateTime - lastUpdate_gte: DateTime - expiration_equals: DateTime - expiration_lt: DateTime - expiration_lte: DateTime - expiration_gt: DateTime - expiration_gte: DateTime -} - -input CDP_ConsentUpdateEventFilterInput { - type_equals: String - status_equals: String - lastUpdate_equals: DateTime - lastUpdate_lt: DateTime - lastUpdate_lte: DateTime - lastUpdate_gt: DateTime - lastUpdate_gte: DateTime - expiration_equals: DateTime - expiration_lt: DateTime - expiration_lte: DateTime - expiration_gt: DateTime - expiration_gte: DateTime -} - -"""Standard EventType used to create or update a consent""" -input CDP_ConsentUpdateEventInput { - type: String! - status: String - lastUpdate: DateTime - expiration: DateTime -} - -type CDP_DateFilter { - after: DateTime - before: DateTime - includeAfter: Boolean - includeBefore: Boolean -} - -input CDP_DateFilterInput { - after: DateTime - before: DateTime - includeAfter: Boolean - includeBefore: Boolean -} - -"""Dates are in ISO-8601 format equivalent to Java 8 Instants.""" -type CDP_DateProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - defaultValue: String -} - -input CDP_DatePropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - defaultValue: String -} - -""" -The enumeration property type is a collection of unique strings that contain the -possible values for the enumeration property type -""" -type CDP_EnumProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - values: [String] -} - -input CDP_EnumPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - values: [String] -} - -type CDP_EventConnection { - edges: [CDP_EventEdge] - pageInfo: PageInfo -} - -type CDP_EventEdge { - node: CDP_EventInterface - cursor: String! -} - -type CDP_EventFilter { - and: [CDP_EventFilter] - or: [CDP_EventFilter] - id_equals: String - cdp_clientID_equals: String - cdp_sourceID_equals: String - cdp_profileID_equals: String - cdp_objectID_equals: String - cdp_location_distance: CDP_GeoDistanceFilter - cdp_timestamp_equals: DateTime - cdp_timestamp_lt: DateTime - cdp_timestamp_lte: DateTime - cdp_timestamp_gt: DateTime - cdp_timestamp_gte: DateTime - cdp_topics_equals: String - cdp_profileUpdateEvent: CDP_ProfileUpdateEventFilter - cdp_consentUpdateEvent: CDP_ConsentUpdateEventFilter - cdp_listsUpdateEvent: CDP_ListsUpdateEventFilter - cdp_sessionEvent: CDP_SessionEventFilter -} - -input CDP_EventFilterInput { - and: [CDP_EventFilterInput] - or: [CDP_EventFilterInput] - id_equals: String - cdp_clientID_equals: String - cdp_sourceID_equals: String - cdp_profileID_equals: String - cdp_objectID_equals: String - cdp_location_distance: CDP_GeoDistanceFilterInput - cdp_timestamp_equals: DateTime - cdp_timestamp_lt: DateTime - cdp_timestamp_lte: DateTime - cdp_timestamp_gt: DateTime - cdp_timestamp_gte: DateTime - cdp_profileUpdateEvent: CDP_ProfileUpdateEventFilterInput - cdp_consentUpdateEvent: CDP_ConsentUpdateEventFilterInput - cdp_listsUpdateEvent: CDP_ListsUpdateEventFilterInput - cdp_sessionEvent: CDP_SessionEventFilterInput -} - -""" -Event wrapper object to handle missing input inheritance in GraphQL -NB! For optimization reasons, a single EventInput may contain multiple events, -but only one of each type. ID is optional, with the exception of importing -""" -input CDP_EventInput { - id: ID - cdp_sourceID: String - cdp_profileID: CDP_ProfileIDInput! - cdp_objectID: ID! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [ID] - cdp_profileUpdateEvent: CDP_ProfileUpdateEventInput - cdp_consentUpdateEvent: CDP_ConsentUpdateEventInput - cdp_listsUpdateEvent: CDP_ListsUpdateEventInput - cdp_sessionEvent: CDP_SessionEventInput -} - -interface CDP_EventInterface { - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] -} - -input CDP_EventOccurenceBoostInput { - eventType: String - boost: Int - fromDate: DateTime - toDate: DateTime -} - -"""A result for a named filter match request.""" -type CDP_FilterMatch { - name: String - matched: Boolean - executionTimeMillis: Int -} - -type CDP_FloatProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - minValue: Float - maxValue: Float - defaultValue: Float -} - -input CDP_FloatPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - minValue: Float - maxValue: Float - defaultValue: Float -} - -type CDP_GeoDistanceFilter { - center: GeoPoint - unit: CDP_GeoDistanceFilterUnit - distance: Float -} - -input CDP_GeoDistanceFilterInput { - center: GeoPoint - unit: CDP_GeoDistanceFilterUnit - distance: Float -} - -enum CDP_GeoDistanceFilterUnit { - METERS - KILOMETERS - MILES -} - -"""Geopoints map to a String in lat,lon format""" -type CDP_GeoPointProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - defaultValue: String -} - -input CDP_GeoPointPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - defaultValue: String -} - -"""The identifier property type is a string that is used as an identifier""" -type CDP_IdentifierProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - regexp: String - defaultValue: String -} - -input CDP_IdentifierPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - regexp: String - defaultValue: String -} - -type CDP_Interest { - topic: CDP_Topic! - score: Float -} - -type CDP_InterestConnection { - totalCount: Int - edges: [CDP_InterestEdge] - pageInfo: PageInfo -} - -type CDP_InterestEdge { - node: CDP_Interest - cursor: String! -} - -type CDP_InterestFilter { - and: [CDP_InterestFilter] - or: [CDP_InterestFilter] - topic_equals: ID - score_equals: Float - score_lt: Float - score_lte: Float - score_gt: Float - score_gte: Float -} - -input CDP_InterestFilterInput { - and: [CDP_InterestFilterInput] - or: [CDP_InterestFilterInput] - topic_equals: ID - score_equals: Float - score_lt: Float - score_lte: Float - score_gt: Float - score_gte: Float -} - -input CDP_InterestInput { - topic: ID! - score: Float -} - -type CDP_IntProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - minValue: Int - maxValue: Int - defaultValue: Int -} - -input CDP_IntPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - minValue: Int - maxValue: Int - defaultValue: Int -} - -type CDP_List { - id: ID! - view: CDP_View! - name: String! - active(first: Int, after: String, last: Int, before: String): CDP_ProfileConnection - inactive(first: Int, after: String, last: Int, before: String): CDP_ProfileConnection -} - -type CDP_ListConnection { - totalCount: Int - edges: [CDP_ListEdge] - pageInfo: PageInfo -} - -type CDP_ListEdge { - node: CDP_List - cursor: String! -} - -input CDP_ListFilterInput { - and: [CDP_ListFilterInput] - or: [CDP_ListFilterInput] - view_equals: ID - name_equals: String -} - -""" -The id optional only when creating a list and can be server generated. For all other operations it is required -""" -input CDP_ListInput { - id: ID - view: ID! - name: String! -} - -type CDP_ListsUpdateEvent implements CDP_EventInterface { - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] - joinLists: [CDP_List] - leaveLists: [CDP_List] -} - -type CDP_ListsUpdateEventFilter { - joinLists_contains: [ID] - leaveLists_contains: [ID] -} - -input CDP_ListsUpdateEventFilterInput { - joinLists_contains: [ID] - leaveLists_contains: [ID] -} - -"""CDP standard eventType used to update profile list memberships""" -input CDP_ListsUpdateEventInput { - joinLists: [ID] - leaveLists: [ID] -} - -type CDP_Mutation { - """ - Please disregard the underscore field, it is only there because GraphQL schema doesn't allow empty types - """ - _: EmptyTypeWorkAround - processEvents(events: [CDP_EventInput]!): Int - createOrUpdateProfileProperties(properties: [CDP_PropertyInput]): Boolean - deleteProfileProperties(propertyNames: [ID]!): Boolean - deleteProfile(profileID: CDP_ProfileIDInput): CDP_Profile - deleteAllPersonalData(profileID: CDP_ProfileIDInput): Boolean - createOrUpdatePersona(persona: CDP_PersonaInput): CDP_Persona - deletePersona(personaID: String): CDP_Persona - createOrUpdateTopic(topic: CDP_TopicInput): CDP_Topic - deleteTopic(topicID: String): CDP_Topic - createOrUpdateSegment(segment: CDP_SegmentInput): CDP_Segment - deleteSegment(segmentID: String): CDP_Segment - createOrUpdateSource(source: CDP_SourceInput): CDP_Source - deleteSource(sourceID: ID!): Boolean - createOrUpdateList(list: CDP_ListInput): CDP_List - addProfileToList(listID: ID, profileID: CDP_ProfileIDInput, active: Boolean): CDP_List - removeProfileFromList(listID: ID, profileID: CDP_ProfileIDInput): CDP_List - deleteList(listID: ID): CDP_List - createOrUpdateView(view: CDP_ViewInput): CDP_View - deleteView(viewID: ID!): Boolean -} - -""" -Named filters are used to evaluate filters against a profile - useful for building personalized experiences. -""" -input CDP_NamedFilterInput { - name: String! - filter: CDP_ProfileFilterInput -} - -type CDP_Object { - uri: ID! - scheme: String - path: String - topics: [CDP_Topic] -} - -input CDP_ObjectInput { - uri: ID! -} - -input CDP_OptimizationInput { - name: String! - objects: [ID] - eventOccurenceBoosts: [CDP_EventOccurenceBoostInput] - strategy: String - size: Int -} - -type CDP_OptimizationResult { - name: String! - scoredObjects: [CDP_ScoredObject] -} - -input CDP_OrderByInput { - fieldName: String - order: CDP_SortOrder -} - -"""Emulate real profiles with personas""" -type CDP_Persona implements CDP_ProfileInterface { - id: ID! - cdp_name: String! - cdp_view: CDP_View! - cdp_profileIDs: [CDP_ProfileID] - cdp_segments(views: [ID]): [CDP_Segment] - cdp_interests(views: [ID]): [CDP_Interest] - cdp_consents: [CDP_Consent] - cdp_lists(views: [ID]): [CDP_List] -} - -"""Used to update personas""" -input CDP_PersonaConsentInput { - type: String! - status: String - lastUpdate: DateTime - expiration: DateTime -} - -input CDP_PersonaInput { - id: ID - cdp_name: String! - cdp_view: ID! - cdp_profileIDs: [CDP_ProfileIDInput] - cdp_segments: [ID] - cdp_interests: [CDP_InterestInput] - cdp_consents: [CDP_PersonaConsentInput] -} - -type CDP_Profile implements CDP_ProfileInterface { - cdp_profileIDs: [CDP_ProfileID] - cdp_events(filter: CDP_EventFilterInput, first: Int, last: Int, after: String, before: String): CDP_EventConnection - cdp_lastEvents(count: Int, profileID: CDP_ProfileIDInput): CDP_EventConnection - cdp_segments(views: [ID]): [CDP_Segment] - cdp_interests(views: [ID]): [CDP_Interest] - cdp_consents: [CDP_Consent] - cdp_lists(views: [ID]): [CDP_List] - cdp_matches(namedFilters: [CDP_NamedFilterInput]): [CDP_FilterMatch] - cdp_optimize(parameters: [CDP_OptimizationInput]): [CDP_OptimizationResult] - cdp_recommend(parameters: [CDP_RecommendationInput]): [CDP_RecommendationResult] -} - -type CDP_ProfileConnection { - totalCount: Int - edges: [CDP_ProfileEdge] - pageInfo: PageInfo -} - -type CDP_ProfileEdge { - node: CDP_ProfileInterface - cursor: String! -} - -type CDP_ProfileEventsFilter { - and: [CDP_ProfileEventsFilter] - or: [CDP_ProfileEventsFilter] - not: CDP_ProfileEventsFilter - minimalCount: Int - maximalCount: Int - eventFilter: CDP_EventFilter -} - -input CDP_ProfileEventsFilterInput { - and: [CDP_ProfileEventsFilterInput] - or: [CDP_ProfileEventsFilterInput] - not: CDP_ProfileEventsFilterInput - minimalCount: Int - maximalCount: Int - eventFilter: CDP_EventFilterInput -} - -type CDP_ProfileFilter { - profileIDs: [String] - properties: CDP_ProfilePropertiesFilter - segments_contains: [ID] - consents_contains: [ID] - lists_contains: [ID] - interests: CDP_InterestFilter - events: CDP_ProfileEventsFilter -} - -input CDP_ProfileFilterInput { - profileIDs_contains: [String] - properties: CDP_ProfilePropertiesFilterInput - segments_contains: [ID] - consents_contains: [ID] - lists_contains: [ID] - interests: CDP_InterestFilterInput - events: CDP_ProfileEventsFilterInput -} - -"""ProfileIDs uniquely identify a profile within a source""" -type CDP_ProfileID { - client: CDP_Client! - id: ID! - uri: ID -} - -input CDP_ProfileIDInput { - clientID: ID! - id: ID! -} - -"""Common interface for both profiles and personas""" -interface CDP_ProfileInterface { - cdp_profileIDs: [CDP_ProfileID] - cdp_segments(views: [ID]): [CDP_Segment] - cdp_interests(views: [ID]): [CDP_Interest] - cdp_consents: [CDP_Consent] - cdp_lists(views: [ID]): [CDP_List] -} - -"""Query profiles based on properties with this filter""" -type CDP_ProfilePropertiesFilter { - and: [CDP_ProfilePropertiesFilter] - or: [CDP_ProfilePropertiesFilter] -} - -input CDP_ProfilePropertiesFilterInput { - and: [CDP_ProfilePropertiesFilterInput] - or: CDP_ProfilePropertiesFilterInput -} - -type CDP_ProfileUpdateEvent implements CDP_EventInterface { - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] -} - -type CDP_ProfileUpdateEventFilter { - """ - Please disregard the underscore field, it is only there because GraphQL schema doesn't allow empty types - """ - _: EmptyTypeWorkAround -} - -input CDP_ProfileUpdateEventFilterInput { - """ - Please disregard the underscore field, it is only there because GraphQL schema doesn't allow empty types - """ - _: EmptyTypeWorkAround -} - -"""CDP standard eventType used to update profile properties""" -input CDP_ProfileUpdateEventInput { - """ - Please disregard the underscore field, it is only there because GraphQL schema doesn't allow empty types - """ - _: EmptyTypeWorkAround -} - -type CDP_PropertyConnection { - edges: [CDP_PropertyEdge] - pageInfo: PageInfo -} - -type CDP_PropertyEdge { - node: CDP_PropertyInterface - cursor: String! -} - -""" -Workaround for missing GraphQL inheritance, only one field allowed at a time, all others should be null. -""" -input CDP_PropertyInput { - identifier: CDP_IdentifierPropertyInput - string: CDP_StringPropertyInput - int: CDP_IntPropertyInput - float: CDP_FloatPropertyInput - date: CDP_DatePropertyInput - boolean: CDP_BooleanPropertyInput - geopoint: CDP_GeoPointPropertyInput - enum: CDP_EnumPropertyInput - set: CDP_SetPropertyInput -} - -"""This interface regroups all the common fields between properties.""" -interface CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] -} - -"""Namespaced queries""" -type CDP_Query { - """ - Please disregard the underscore field, it is only there because GraphQL schema doesn't allow empty types - """ - _: EmptyTypeWorkAround - getEvent(id: String!): CDP_EventInterface - findEvents(filter: CDP_EventFilterInput, orderBy: [CDP_OrderByInput], first: Int, after: String, last: Int, before: String): CDP_EventConnection - getProfile(profileID: CDP_ProfileIDInput, createIfMissing: Boolean): CDP_Profile - findProfiles(filter: CDP_ProfileFilterInput, orderBy: [CDP_OrderByInput], first: Int, after: String, last: Int, before: String): CDP_ProfileConnection - getProfileProperties: CDP_PropertyConnection - getPersona(personaID: String): CDP_Persona - findPersonas(filter: CDP_ProfileFilterInput, orderBy: [CDP_OrderByInput], first: Int, after: String, last: Int, before: String): CDP_ProfileConnection - getTopic(topicID: ID): CDP_Topic - findTopics(filter: CDP_TopicFilterInput, orderBy: [CDP_OrderByInput], first: Int, after: String, last: Int, before: String): CDP_TopicConnection - getSegment(segmentID: ID): CDP_Segment - findSegments(filter: CDP_SegmentFilterInput, orderBy: [CDP_OrderByInput], first: Int, after: String, last: Int, before: String): CDP_SegmentConnection - getSources: [CDP_Source] - getList(listID: ID): CDP_List - findLists(filter: CDP_ListFilterInput, orderBy: [CDP_OrderByInput], first: Int, after: String, last: Int, before: String): CDP_ListConnection - getViews: [CDP_View] -} - -input CDP_RecommendationInput { - name: String! - objectUri: ID - topics: [ID] - size: Int - algorithm: CDP_AlgorithmInput -} - -type CDP_RecommendationResult { - name: String! - scoredObjects: [CDP_ScoredObject] -} - -type CDP_ScoredObject { - object: CDP_Object - score: Float -} - -type CDP_Segment { - id: ID! - view: CDP_View! - name: String! - profiles: CDP_ProfileFilter -} - -type CDP_SegmentConnection { - totalCount: Int - edges: [CDP_SegmentEdge] - pageInfo: PageInfo -} - -type CDP_SegmentEdge { - node: CDP_Segment - cursor: String! -} - -input CDP_SegmentFilterInput { - and: [CDP_SegmentFilterInput] - or: [CDP_SegmentFilterInput] - view_equals: ID - name_equals: String -} - -input CDP_SegmentInput { - id: ID - view: ID! - name: String - profiles: CDP_ProfileFilterInput -} - -type CDP_SessionEvent implements CDP_EventInterface { - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] - state: CDP_SessionState -} - -type CDP_SessionEventFilter { - state_equals: CDP_SessionState -} - -input CDP_SessionEventFilterInput { - state_equals: CDP_SessionState -} - -input CDP_SessionEventInput { - state: CDP_SessionState -} - -enum CDP_SessionState { - START - STOP - PAUSE - RESUME -} - -"""Enables creation of nested property types.""" -type CDP_SetProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - properties: [CDP_PropertyInterface] -} - -input CDP_SetPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - properties: [CDP_PropertyInput] -} - -enum CDP_SortOrder { - ASC - DESC - UNSPECIFIED -} - -type CDP_Source { - id: ID! - thirdParty: Boolean -} - -input CDP_SourceInput { - id: ID! - thirdParty: Boolean -} - -type CDP_StringProperty implements CDP_PropertyInterface { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - regexp: String - defaultValue: String -} - -input CDP_StringPropertyInput { - name: ID! - minOccurrences: Int - maxOccurrences: Int - tags: [String] - regexp: String - defaultValue: String -} - -type CDP_Subscription { - """ - Please disregard the underscore field, it is only there because GraphQL schema doesn't allow empty types - """ - _: EmptyTypeWorkAround - eventListener(filter: CDP_EventFilterInput): CDP_EventInterface! - profileListener(filter: CDP_ProfileFilterInput): CDP_Profile -} - -type CDP_Topic { - id: ID! - view: CDP_View! - name: String! -} - -type CDP_TopicConnection { - totalCount: Int - edges: [CDP_TopicEdge] - pageInfo: PageInfo -} - -type CDP_TopicEdge { - node: CDP_Topic - cursor: String! -} - -input CDP_TopicFilterInput { - and: [CDP_TopicFilterInput] - or: [CDP_TopicFilterInput] - view_equals: ID - id_equals: String - name_equals: String -} - -input CDP_TopicInput { - id: ID - view: ID! - name: String! -} - -type CDP_View { - name: ID! -} - -input CDP_ViewInput { - name: ID! -} - -""" -Uses RFC-3339 representation, for example 1996-12-19, see -https://github.com/graphql-java/graphql-java-extended-scalars for example -implementation -""" -scalar Date - -""" -Uses RFC-3339 representation, for example 1996-12-19T16:39:57-08:00, see -https://github.com/graphql-java/graphql-java-extended-scalars for example -implementation -""" -scalar DateTime - -""" -This scalar is simply used to mark types as empty, since GraphQL doesn't allow -that by default. Please ignore any fields using this scalar as they are not -intended to be exposed -""" -scalar EmptyTypeWorkAround - -"""Uses a string representation of lat,lon""" -scalar GeoPoint - -"""For values and arguments that cannot be defined structurally""" -scalar JSON - -type Mutation { - cdp: CDP_Mutation -} - -type PageInfo { - hasPreviousPage: Boolean! - hasNextPage: Boolean! -} - -type Query { - cdp: CDP_Query -} - -type Subscription { - cdp: CDP_Subscription -} - -""" -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 diff --git a/graphql/cxs-impl/src/main/resources/unomi-schema.graphqls b/graphql/cxs-impl/src/main/resources/unomi-schema.graphqls deleted file mode 100644 index 73a87ec..0000000 --- a/graphql/cxs-impl/src/main/resources/unomi-schema.graphqls +++ /dev/null @@ -1,74 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# This file contains extensions to the CDP specification that are specific to Apache Unomi - -type Unomi_PageView { - url : String - path : String - referrer : String -} - -type Unomi_PageViewEvent implements CDP_EventInterface { - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] - - pageView : Unomi_PageView -} - -type Unomi_SessionCreated { - creationTime : DateTime - duration : Int -} - -type Unomi_SessionCreatedEvent implements CDP_EventInterface { - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] - - sessionCreated : Unomi_SessionCreated -} - -type Unomi_PropertyPair { - name : String - value : JSON -} - -type Unomi_UnknownEvent implements CDP_EventInterface { - - id: ID! - cdp_source: CDP_Source - cdp_client: CDP_Client - cdp_profileID: CDP_ProfileID! - cdp_profile: CDP_Profile! - cdp_object: CDP_Object! - cdp_location: GeoPoint - cdp_timestamp: DateTime - cdp_topics: [CDP_Topic] - - unknownProperties : [Unomi_PropertyPair] -} \ No newline at end of file
