From 852eaa0764cd3f5182ac0d754feff041df4ebe4f Mon Sep 17 00:00:00 2001 From: jadepeng Date: Mon, 9 May 2022 17:16:54 +0800 Subject: [PATCH 1/5] feat: support query data by use cypher language(#1748) --- hugegraph-api/pom.xml | 6 ++ .../hugegraph/api/gremlin/CypherAPI.java | 89 ++++++++++++++++++ .../hugegraph/api/gremlin/GremlinAPI.java | 71 +-------------- .../api/gremlin/GremlinQueryAPI.java | 90 +++++++++++++++++++ .../baidu/hugegraph/api/CypherApiTest.java | 57 ++++++++++++ 5 files changed, 243 insertions(+), 70 deletions(-) create mode 100644 hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java create mode 100644 hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinQueryAPI.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java diff --git a/hugegraph-api/pom.xml b/hugegraph-api/pom.xml index 0bc3a36bb7..4bd6ecc1a5 100644 --- a/hugegraph-api/pom.xml +++ b/hugegraph-api/pom.xml @@ -115,6 +115,12 @@ io.dropwizard.metrics metrics-jersey3 + + + org.opencypher.gremlin + translation + 1.0.4 + diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java new file mode 100644 index 0000000000..02bd53f7de --- /dev/null +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java @@ -0,0 +1,89 @@ +package com.baidu.hugegraph.api.gremlin; + +import java.util.Collections; + +import org.opencypher.gremlin.translation.TranslationFacade; +import org.slf4j.Logger; + +import com.baidu.hugegraph.api.filter.CompressInterceptor; +import com.baidu.hugegraph.util.E; +import com.baidu.hugegraph.util.Log; +import com.codahale.metrics.annotation.Timed; + +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response; + +@Path("graphs/{graph}/cypher") +@Singleton +public class CypherAPI extends GremlinQueryAPI { + + private static final Logger LOG = Log.logger(CypherAPI.class); + + + @GET + @Timed + @CompressInterceptor.Compress(buffer = (1024 * 40)) + @Produces(APPLICATION_JSON_WITH_CHARSET) + public Response query(@PathParam("graph") String graph, + @Context HttpHeaders headers, + @QueryParam("cypher") String cypher) { + LOG.debug("Graph [{}] query by cypher: {}", graph, cypher); + + return this.queryByCypher(graph, headers, cypher); + } + + @POST + @Timed + @CompressInterceptor.Compress + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON_WITH_CHARSET) + public Response post(@PathParam("graph") String graph, + @Context HttpHeaders headers, + String cypher) { + LOG.debug("Graph [{}] query by cypher: {}", graph, cypher); + return this.queryByCypher(graph, headers, cypher); + } + + private Response queryByCypher(String graph, + HttpHeaders headers, + String cypher) { + E.checkArgument(cypher != null && !cypher.isEmpty(), + "The cypher parameter can't be null or empty"); + + String gremlin = this.translateCpyher2Gremlin(graph, cypher); + LOG.debug("translated gremlin is {}", gremlin); + + String auth = headers.getHeaderString(HttpHeaders.AUTHORIZATION); + MultivaluedMap params = new MultivaluedHashMap<>(); + params.put("gremlin", Collections.singletonList(gremlin)); + Response response = this.client().doGetRequest(auth, params); + return transformResponseIfNeeded(response); + } + + private String translateCpyher2Gremlin(String graph, String cypher) { + TranslationFacade translator = new TranslationFacade(); + String gremlin = translator.toGremlinGroovy(cypher); + gremlin = this.buildQueryableGremlin(graph, gremlin); + return gremlin; + } + + private String buildQueryableGremlin(String graph, String gremlin) { + gremlin = "g = " + graph + ".traversal()\n" + gremlin; + + // hg not support single + gremlin = gremlin.replace(".property(single,", ".property("); + + return gremlin; + } +} diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinAPI.java index 60fc5c9b19..78ce651138 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinAPI.java @@ -49,40 +49,13 @@ @Path("gremlin") @Singleton -public class GremlinAPI extends API { +public class GremlinAPI extends GremlinQueryAPI { private static final Histogram GREMLIN_INPUT_HISTOGRAM = MetricsUtil.registerHistogram(GremlinAPI.class, "gremlin-input"); private static final Histogram GREMLIN_OUTPUT_HISTOGRAM = MetricsUtil.registerHistogram(GremlinAPI.class, "gremlin-output"); - private static final Set FORBIDDEN_REQUEST_EXCEPTIONS = - ImmutableSet.of("java.lang.SecurityException", - "jakarta.ws.rs.ForbiddenException"); - private static final Set BAD_REQUEST_EXCEPTIONS = ImmutableSet.of( - "java.lang.IllegalArgumentException", - "java.util.concurrent.TimeoutException", - "groovy.lang.", - "org.codehaus.", - "com.baidu.hugegraph." - ); - - @Context - private Provider configProvider; - - private GremlinClient client; - - public GremlinClient client() { - if (this.client != null) { - return this.client; - } - HugeConfig config = this.configProvider.get(); - String url = config.get(ServerOptions.GREMLIN_SERVER_URL); - int timeout = config.get(ServerOptions.GREMLIN_SERVER_TIMEOUT) * 1000; - int maxRoutes = config.get(ServerOptions.GREMLIN_SERVER_MAX_ROUTE); - this.client = new GremlinClient(url, timeout, maxRoutes, maxRoutes); - return this.client; - } @POST @Timed @@ -120,46 +93,4 @@ public Response get(@Context HugeConfig conf, GREMLIN_OUTPUT_HISTOGRAM.update(response.getLength()); return transformResponseIfNeeded(response); } - - private static Response transformResponseIfNeeded(Response response) { - MediaType mediaType = response.getMediaType(); - if (mediaType != null) { - // Append charset - assert MediaType.APPLICATION_JSON_TYPE.equals(mediaType); - response.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, - mediaType.withCharset(CHARSET)); - } - - Response.StatusType status = response.getStatusInfo(); - if (status.getStatusCode() < 400) { - // No need to transform if normal response without error - return response; - } - - if (mediaType == null || !JSON.equals(mediaType.getSubtype())) { - String message = response.readEntity(String.class); - throw new HugeGremlinException(status.getStatusCode(), - ImmutableMap.of("message", message)); - } - - @SuppressWarnings("unchecked") - Map map = response.readEntity(Map.class); - String exClassName = (String) map.get("Exception-Class"); - if (FORBIDDEN_REQUEST_EXCEPTIONS.contains(exClassName)) { - status = Response.Status.FORBIDDEN; - } else if (matchBadRequestException(exClassName)) { - status = Response.Status.BAD_REQUEST; - } - throw new HugeGremlinException(status.getStatusCode(), map); - } - - private static boolean matchBadRequestException(String exClass) { - if (exClass == null) { - return false; - } - if (BAD_REQUEST_EXCEPTIONS.contains(exClass)) { - return true; - } - return BAD_REQUEST_EXCEPTIONS.stream().anyMatch(exClass::startsWith); - } } diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinQueryAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinQueryAPI.java new file mode 100644 index 0000000000..5a072e095a --- /dev/null +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/GremlinQueryAPI.java @@ -0,0 +1,90 @@ +package com.baidu.hugegraph.api.gremlin; + +import java.util.Map; +import java.util.Set; + +import com.baidu.hugegraph.api.API; +import com.baidu.hugegraph.config.HugeConfig; +import com.baidu.hugegraph.config.ServerOptions; +import com.baidu.hugegraph.exception.HugeGremlinException; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import jakarta.inject.Provider; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +public class GremlinQueryAPI extends API { + + private static final Set FORBIDDEN_REQUEST_EXCEPTIONS = + ImmutableSet.of("java.lang.SecurityException", + "jakarta.ws.rs.ForbiddenException"); + private static final Set BAD_REQUEST_EXCEPTIONS = ImmutableSet.of( + "java.lang.IllegalArgumentException", + "java.util.concurrent.TimeoutException", + "groovy.lang.", + "org.codehaus.", + "com.baidu.hugegraph." + ); + + @Context + private Provider configProvider; + + private GremlinClient client; + + public GremlinClient client() { + if (this.client != null) { + return this.client; + } + HugeConfig config = this.configProvider.get(); + String url = config.get(ServerOptions.GREMLIN_SERVER_URL); + int timeout = config.get(ServerOptions.GREMLIN_SERVER_TIMEOUT) * 1000; + int maxRoutes = config.get(ServerOptions.GREMLIN_SERVER_MAX_ROUTE); + this.client = new GremlinClient(url, timeout, maxRoutes, maxRoutes); + return this.client; + } + + protected static Response transformResponseIfNeeded(Response response) { + MediaType mediaType = response.getMediaType(); + if (mediaType != null) { + // Append charset + assert MediaType.APPLICATION_JSON_TYPE.equals(mediaType); + response.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, + mediaType.withCharset(CHARSET)); + } + + Response.StatusType status = response.getStatusInfo(); + if (status.getStatusCode() < 400) { + // No need to transform if normal response without error + return response; + } + + if (mediaType == null || !JSON.equals(mediaType.getSubtype())) { + String message = response.readEntity(String.class); + throw new HugeGremlinException(status.getStatusCode(), + ImmutableMap.of("message", message)); + } + + @SuppressWarnings("unchecked") + Map map = response.readEntity(Map.class); + String exClassName = (String) map.get("Exception-Class"); + if (FORBIDDEN_REQUEST_EXCEPTIONS.contains(exClassName)) { + status = Response.Status.FORBIDDEN; + } else if (matchBadRequestException(exClassName)) { + status = Response.Status.BAD_REQUEST; + } + throw new HugeGremlinException(status.getStatusCode(), map); + } + + private static boolean matchBadRequestException(String exClass) { + if (exClass == null) { + return false; + } + if (BAD_REQUEST_EXCEPTIONS.contains(exClass)) { + return true; + } + return BAD_REQUEST_EXCEPTIONS.stream().anyMatch(exClass::startsWith); + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java new file mode 100644 index 0000000000..f9bde5eb63 --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * 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 com.baidu.hugegraph.api; + +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import com.baidu.hugegraph.testutil.Assert; +import com.google.common.collect.ImmutableMap; + +import jakarta.ws.rs.core.Response; + +public class CypherApiTest extends BaseApiTest { + + private static final String path = "/graphs/hugegraph/cypher"; + + @Before + public void prepareSchema() { + BaseApiTest.initPropertyKey(); + BaseApiTest.initVertexLabel(); + BaseApiTest.initIndexLabel(); + BaseApiTest.initVertex(); + } + + @Test + public void testPost() { + String body = "MATCH (n:person) where n.city ='Beijing' return n"; + assertResponseStatus(200, client().post(path, body)); + } + + @Test + public void testGet() { + Map params = ImmutableMap.of("cypher", + "MATCH (n:person) where n.city ='Beijing' return n"); + Response r = client().get(path, params); + Assert.assertEquals(r.readEntity(String.class), 200, r.getStatus()); + } +} From b125ff05bf11ab8b36d0e10b5ce231702c453939 Mon Sep 17 00:00:00 2001 From: jadepeng Date: Mon, 9 May 2022 19:51:08 +0800 Subject: [PATCH 2/5] add more note and test case --- .../hugegraph/api/gremlin/CypherAPI.java | 8 +++- .../com/baidu/hugegraph/api/BaseApiTest.java | 2 +- .../baidu/hugegraph/api/CypherApiTest.java | 45 +++++++++++++++---- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java index 02bd53f7de..9eb9d3326c 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java @@ -62,7 +62,7 @@ private Response queryByCypher(String graph, "The cypher parameter can't be null or empty"); String gremlin = this.translateCpyher2Gremlin(graph, cypher); - LOG.debug("translated gremlin is {}", gremlin); + LOG.info("translated gremlin is {}", gremlin); String auth = headers.getHeaderString(HttpHeaders.AUTHORIZATION); MultivaluedMap params = new MultivaluedHashMap<>(); @@ -79,9 +79,13 @@ private String translateCpyher2Gremlin(String graph, String cypher) { } private String buildQueryableGremlin(String graph, String gremlin) { + // init g by graph name gremlin = "g = " + graph + ".traversal()\n" + gremlin; - // hg not support single + // CREATE (a:person { name : "test", age: 20, city: "Hefei" }) return a + // translate to : + // g.addV('person').as('a').property(single, 'name', 'test') ... + // NOTE: ".property(single" will raise error gremlin = gremlin.replace(".property(single,", ".property("); return gremlin; diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/BaseApiTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/BaseApiTest.java index ffe8a08524..b1b2d1296e 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/BaseApiTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/BaseApiTest.java @@ -61,7 +61,7 @@ public class BaseApiTest { private static final String USERNAME = "admin"; private static final String PASSWORD = "pa"; - private static final String URL_PREFIX = "graphs/" + GRAPH; + protected static final String URL_PREFIX = "graphs/" + GRAPH; private static final String SCHEMA_PKS = "/schema/propertykeys"; private static final String SCHEMA_VLS = "/schema/vertexlabels"; private static final String SCHEMA_ELS = "/schema/edgelabels"; diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java index f9bde5eb63..1ac07fc69b 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java @@ -19,6 +19,8 @@ package com.baidu.hugegraph.api; +import static com.baidu.hugegraph.testutil.Assert.assertContains; + import java.util.Map; import org.junit.Before; @@ -31,27 +33,54 @@ public class CypherApiTest extends BaseApiTest { - private static final String path = "/graphs/hugegraph/cypher"; + private static final String path = URL_PREFIX + "/cypher"; + private static final String query = "MATCH (n:person) where n.city ='Beijing' return n"; + private static final String queryResult = "Beijing"; @Before public void prepareSchema() { BaseApiTest.initPropertyKey(); BaseApiTest.initVertexLabel(); + BaseApiTest.initEdgeLabel(); BaseApiTest.initIndexLabel(); BaseApiTest.initVertex(); + BaseApiTest.initEdge(); + } + + @Test + public void testGet() { + Map params = ImmutableMap.of("cypher", query); + Response r = client().get(path, params); + + this.validStatusAndTextContains(queryResult, r); } @Test public void testPost() { - String body = "MATCH (n:person) where n.city ='Beijing' return n"; - assertResponseStatus(200, client().post(path, body)); + this.testCypherQueryAndContains(query, "Beijing"); } @Test - public void testGet() { - Map params = ImmutableMap.of("cypher", - "MATCH (n:person) where n.city ='Beijing' return n"); - Response r = client().get(path, params); - Assert.assertEquals(r.readEntity(String.class), 200, r.getStatus()); + public void testCreate() { + this.testCypherQueryAndContains("CREATE (n:person { name : 'test', age: 20, city: 'Hefei' }) return n", + "Hefei"); + } + + @Test + public void testRelationQuery() { + String cypher = "MATCH (n:person)-[r:knows]->(friend:person)\n" + + "WHERE n.name = 'marko'\n" + + "RETURN n, friend.name AS friend"; + this.testCypherQueryAndContains(cypher, "friend"); + } + + private void testCypherQueryAndContains(String cypher, String containsText) { + Response r = client().post(path, cypher); + this.validStatusAndTextContains(containsText, r); + } + + private void validStatusAndTextContains(String value, Response r) { + String content = assertResponseStatus(200, r); + assertContains(value, content); } } From 3565f60970bc53c4daf17d5a49ec64fc4da87c8b Mon Sep 17 00:00:00 2001 From: jadepeng Date: Tue, 10 May 2022 11:57:30 +0800 Subject: [PATCH 3/5] improve --- .../hugegraph/api/gremlin/CypherAPI.java | 30 +++++++++---------- .../baidu/hugegraph/api/CypherApiTest.java | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java index 9eb9d3326c..69f1958d13 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java @@ -1,7 +1,5 @@ package com.baidu.hugegraph.api.gremlin; -import java.util.Collections; - import org.opencypher.gremlin.translation.TranslationFacade; import org.slf4j.Logger; @@ -20,8 +18,6 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.MultivaluedHashMap; -import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response; @Path("graphs/{graph}/cypher") @@ -62,12 +58,16 @@ private Response queryByCypher(String graph, "The cypher parameter can't be null or empty"); String gremlin = this.translateCpyher2Gremlin(graph, cypher); - LOG.info("translated gremlin is {}", gremlin); + LOG.debug("translated gremlin is {}", gremlin); String auth = headers.getHeaderString(HttpHeaders.AUTHORIZATION); - MultivaluedMap params = new MultivaluedHashMap<>(); - params.put("gremlin", Collections.singletonList(gremlin)); - Response response = this.client().doGetRequest(auth, params); + String request = "{" + + "\"gremlin\":\"" + gremlin + "\"," + + "\"bindings\":{}," + + "\"language\":\"gremlin-groovy\"," + + "\"aliases\":{\"g\":\"__g_" + graph + "\"}}"; + + Response response = this.client().doPostRequest(auth, request); return transformResponseIfNeeded(response); } @@ -79,13 +79,13 @@ private String translateCpyher2Gremlin(String graph, String cypher) { } private String buildQueryableGremlin(String graph, String gremlin) { - // init g by graph name - gremlin = "g = " + graph + ".traversal()\n" + gremlin; - - // CREATE (a:person { name : "test", age: 20, city: "Hefei" }) return a - // translate to : - // g.addV('person').as('a').property(single, 'name', 'test') ... - // NOTE: ".property(single" will raise error + /* + * `CREATE (a:person { name : 'test', age: 20) return a` + * would be translated to : + * `g.addV('person').as('a').property(single, 'name', 'test') ...`, + * but hugegraph don't support `.property(single, k, v)`, + * so we replace it to .property(k, v) here + */ gremlin = gremlin.replace(".property(single,", ".property("); return gremlin; diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java index 1ac07fc69b..c2841e9bbb 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/CypherApiTest.java @@ -57,7 +57,7 @@ public void testGet() { @Test public void testPost() { - this.testCypherQueryAndContains(query, "Beijing"); + this.testCypherQueryAndContains(query, queryResult); } @Test From e21faff62f302d5f1334f946e909ac49db43f223 Mon Sep 17 00:00:00 2001 From: jadepeng Date: Tue, 10 May 2022 17:40:48 +0800 Subject: [PATCH 4/5] improve --- .../main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java | 4 ++-- .../src/main/java/com/baidu/hugegraph/version/ApiVersion.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java index 69f1958d13..f85ae03785 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/gremlin/CypherAPI.java @@ -81,10 +81,10 @@ private String translateCpyher2Gremlin(String graph, String cypher) { private String buildQueryableGremlin(String graph, String gremlin) { /* * `CREATE (a:person { name : 'test', age: 20) return a` - * would be translated to : + * would be translated to: * `g.addV('person').as('a').property(single, 'name', 'test') ...`, * but hugegraph don't support `.property(single, k, v)`, - * so we replace it to .property(k, v) here + * so we replace it to `.property(k, v)` here */ gremlin = gremlin.replace(".property(single,", ".property("); diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java index 14e2eba7d8..dc43e93b19 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java @@ -118,10 +118,11 @@ public final class ApiVersion { * [0.66] Issue-1567: Support get schema RESTful API * [0.67] Issue-1065: Support dynamically add/remove graph * [0.68] Issue-1763: Support adamic-adar & resource-allocation API + * [0.69] Issue-1748: Support Cypher query RESTful API */ // The second parameter of Version.of() is for IDE running without JAR - public static final Version VERSION = Version.of(ApiVersion.class, "0.68"); + public static final Version VERSION = Version.of(ApiVersion.class, "0.69"); public static void check() { // Check version of hugegraph-core. Firstly do check from version 0.3 From 7ad788d6601ea1f75ca46836a2366090338f7b29 Mon Sep 17 00:00:00 2001 From: jadepeng Date: Wed, 11 May 2022 14:25:34 +0800 Subject: [PATCH 5/5] update Implementation-Version --- hugegraph-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugegraph-api/pom.xml b/hugegraph-api/pom.xml index 4bd6ecc1a5..aab9d0292b 100644 --- a/hugegraph-api/pom.xml +++ b/hugegraph-api/pom.xml @@ -159,7 +159,7 @@ - 0.67.0.0 + 0.69.0.0