diff --git a/README.md b/README.md index 1ac38d5..2807ad2 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,14 @@ curl -v -i -s -k -X POST https://api.paion-data.dev:8444/services \ curl -i -k -X POST https://api.paion-data.dev:8444/services/wilhelm-ws-expand/routes \ --data "paths[]=/wilhelm/expand" \ --data name=wilhelm-ws-expand + +# search +curl -v -i -s -k -X POST https://api.paion-data.dev:8444/services \ + --data name=wilhelm-ws-search \ + --data url="http://${GATEWAY_PUBLIC_IP}:8080/v1/neo4j/search" +curl -i -k -X POST https://api.paion-data.dev:8444/services/wilhelm-ws-search/routes \ + --data "paths[]=/wilhelm/search" \ + --data name=wilhelm-ws-search ``` We should see `HTTP/1.1 201 Created` as signs of success. diff --git a/src/main/java/org/qubitpi/wilhelm/web/endpoints/Neo4JServlet.java b/src/main/java/org/qubitpi/wilhelm/web/endpoints/Neo4JServlet.java index c0c6c31..cb7a7f4 100644 --- a/src/main/java/org/qubitpi/wilhelm/web/endpoints/Neo4JServlet.java +++ b/src/main/java/org/qubitpi/wilhelm/web/endpoints/Neo4JServlet.java @@ -137,6 +137,93 @@ public Response getVocabularyByLanguagePaged( .build(); } + /** + * Search all nodes whose label contains a specified keyword. + * + * @param keyword The provided keyword + * + * @return all nodes whose "name" attribute contains the search keyword + */ + @GET + @Path("/search/{keyword}") + @Produces(MediaType.APPLICATION_JSON) + @SuppressWarnings("MultipleStringLiterals") + public Response search(@NotNull @PathParam("keyword") final String keyword) { + final String query = String.format("MATCH (node) WHERE node.name =~ '.*%s.*' RETURN node", keyword); + + return Response + .status(Response.Status.OK) + .entity(executeNonPathQuery(query)) + .build(); + } + + /** + * Runs a cypher query against Neo4J database and return result as a JSON-serializable. + *
+ * Use this method only if the {@code query} does not involve path, because this method cannot handle query result + * that has path object nested in it + * + * @param query A standard cypher query string + * + * @return query's native result + */ + private Object executeNonPathQuery(@NotNull final String query) { + return executeNativeQuery(query).records() + .stream() + .map( + record -> record.keys() + .stream() + .map(key -> new AbstractMap.SimpleImmutableEntry<>(key, expand(record.get(key)))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) + ) + .collect(Collectors.toList()); + } + + /** + * Transforms a Neo4J {@link Value} object into a Jackson-serializable Java object. + * + * See https://neo4j.com/docs/java-manual/current/data-types/ for more details + * + * @param value An object graph. Cannot be {@code null} + * + * @return a {@link Map} representation of the object graph and can be Jackson-serialized + */ + private static Object expand(@NotNull final Value value) { + if (isTerminalValue(value)) { + if (value.type().equals(InternalTypeSystem.TYPE_SYSTEM.INTEGER())) { + return value.asInt(); + } else if (value.type().equals(InternalTypeSystem.TYPE_SYSTEM.BOOLEAN())) { + return value.asBoolean(); + } else { + return value.asString(); + } + } + + return StreamSupport.stream(value.keys().spliterator(), false) + .map(key -> new AbstractMap.SimpleImmutableEntry<>(key, expand(value.get(key)))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + /** + * Returns whether or not a {@link Value} object is the "leaf" node in Jackson serialization. + *
+ * A "leaf" node is defined to be one of + *
- * Use this method only if the {@code query} does not involve path, because this method cannot handle query result - * that has path object nested in it - * - * @param query A standard cypher query string - * - * @return query's native result - */ - private Object executeNonPathQuery(@NotNull final String query) { - return executeNativeQuery(query).records() - .stream() - .map( - record -> record.keys() - .stream() - .map(key -> new AbstractMap.SimpleImmutableEntry<>(key, expand(record.get(key)))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) - ) - .collect(Collectors.toList()); - } /** * Runs a cypher query against Neo4J database and return the query result unmodified. @@ -294,49 +360,4 @@ private EagerResult executeNativeQuery(@NotNull final String query) { .execute(); } } - - /** - * Transforms a Neo4J {@link Value} object into a Jackson-serializable Java object. - * - * See https://neo4j.com/docs/java-manual/current/data-types/ for more details - * - * @param value An object graph. Cannot be {@code null} - * - * @return a {@link Map} representation of the object graph and can be Jackson-serialized - */ - private static Object expand(@NotNull final Value value) { - if (isTerminalValue(value)) { - if (value.type().equals(InternalTypeSystem.TYPE_SYSTEM.INTEGER())) { - return value.asInt(); - } else if (value.type().equals(InternalTypeSystem.TYPE_SYSTEM.BOOLEAN())) { - return value.asBoolean(); - } else { - return value.asString(); - } - } - - return StreamSupport.stream(value.keys().spliterator(), false) - .map(key -> new AbstractMap.SimpleImmutableEntry<>(key, expand(value.get(key)))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - /** - * Returns whether or not a {@link Value} object is the "leaf" node in Jackson serialization. - *
- * A "leaf" node is defined to be one of - *