diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/schema/PropertyKey.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/schema/PropertyKey.java index 7cce866b87..d300abd179 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/schema/PropertyKey.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/schema/PropertyKey.java @@ -255,9 +255,12 @@ public Object serialValue(V value, boolean encodeNumber) { E.checkArgument(this.cardinality.single(), "The cardinality can't be '%s' for navigation key '%s'", this.cardinality, this.name()); - if (encodeNumber && - (this.dataType.isNumber() || this.dataType.isDate())) { - return LongEncoding.encodeNumber(validValue); + if (this.dataType.isNumber() || this.dataType.isDate()) { + if (encodeNumber) { + return LongEncoding.encodeNumber(validValue); + } else { + return validValue.toString(); + } } return validValue; } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeEdge.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeEdge.java index 425bf91202..5f8c248525 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeEdge.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeEdge.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.List; +import org.apache.logging.log4j.util.Strings; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Property; @@ -33,7 +34,7 @@ import com.baidu.hugegraph.HugeGraph; import com.baidu.hugegraph.backend.id.EdgeId; import com.baidu.hugegraph.backend.id.Id; -import com.baidu.hugegraph.backend.id.SplicingIdGenerator; +import com.baidu.hugegraph.backend.query.ConditionQuery; import com.baidu.hugegraph.backend.query.QueryResults; import com.baidu.hugegraph.backend.serializer.BytesBuffer; import com.baidu.hugegraph.backend.tx.GraphTransaction; @@ -98,7 +99,12 @@ public EdgeLabel schemaLabel() { @Override public String name() { if (this.name == null) { - this.name = SplicingIdGenerator.concatValues(sortValues()); + List sortValues = this.sortValues(); + if (sortValues.isEmpty()) { + this.name = Strings.EMPTY; + } else { + this.name = ConditionQuery.concatValues(sortValues); + } } return this.name; } @@ -154,7 +160,7 @@ public EdgeId idWithDirection() { } @Watched(prefix = "edge") - public List sortValues() { + protected List sortValues() { List sortKeys = this.schemaLabel().sortKeys(); if (sortKeys.isEmpty()) { return ImmutableList.of(); @@ -164,7 +170,11 @@ public List sortValues() { HugeProperty property = this.getProperty(sk); E.checkState(property != null, "The value of sort key '%s' can't be null", sk); - propValues.add(property.serialValue(true)); + Object propValue = property.serialValue(true); + if (Strings.EMPTY.equals(propValue)) { + propValue = ConditionQuery.INDEX_VALUE_EMPTY; + } + propValues.add(propValue); } return propValues; } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeVertex.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeVertex.java index cd7be645d8..59d3645e8d 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeVertex.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/structure/HugeVertex.java @@ -28,6 +28,7 @@ import java.util.Set; import org.apache.commons.collections.CollectionUtils; +import org.apache.logging.log4j.util.Strings; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.T; @@ -42,6 +43,7 @@ import com.baidu.hugegraph.backend.id.IdGenerator; import com.baidu.hugegraph.backend.id.SnowflakeIdGenerator; import com.baidu.hugegraph.backend.id.SplicingIdGenerator; +import com.baidu.hugegraph.backend.query.ConditionQuery; import com.baidu.hugegraph.backend.query.Query; import com.baidu.hugegraph.backend.query.QueryResults; import com.baidu.hugegraph.backend.serializer.BytesBuffer; @@ -121,7 +123,7 @@ public String name() { E.checkState(!propValues.isEmpty(), "Primary values must not be empty " + "(has properties %s)", hasProperties()); - name = SplicingIdGenerator.concatValues(propValues); + name = ConditionQuery.concatValues(propValues); E.checkArgument(!name.isEmpty(), "The value of primary key can't be empty"); } @@ -193,7 +195,7 @@ public void correctVertexLabel(VertexLabel correctLabel) { } @Watched(prefix = "vertex") - public List primaryValues() { + protected List primaryValues() { E.checkArgument(this.label.idStrategy() == IdStrategy.PRIMARY_KEY, "The id strategy '%s' don't have primary keys", this.label.idStrategy()); @@ -210,7 +212,11 @@ public List primaryValues() { E.checkState(property != null, "The value of primary key '%s' can't be null", this.graph().propertyKey(pk).name()); - propValues.add(property.serialValue(encodeNumber)); + Object propValue = property.serialValue(encodeNumber); + if (Strings.EMPTY.equals(propValue)) { + propValue = ConditionQuery.INDEX_VALUE_EMPTY; + } + propValues.add(propValue); } return propValues; } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java index 287e983e6e..b08989e58b 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java @@ -471,7 +471,7 @@ public void testAddEdgeWithLargeSortkey() { Assert.assertThrows(IllegalArgumentException.class, () -> { final int LEN = BytesBuffer.BIG_ID_LEN_MAX; - String largeTime = new String(new byte[LEN]) + "{large-time}"; + String largeTime = "{large-time}" + new String(new byte[LEN]); james.addEdge("write", book, "time", largeTime); graph.tx().commit(); }, e -> { @@ -490,6 +490,14 @@ public void testAddEdgeWithInvalidSortkey() { Vertex book = graph.addVertex(T.label, "book", "name", "Test-Book-1"); graph.tx().commit(); + Assert.assertThrows(IllegalArgumentException.class, () -> { + james.addEdge("write", book, "time", "\u00002017-5-27"); + graph.tx().commit(); + }, e -> { + Assert.assertContains("Illegal leading char '\\u0' in index", + e.getMessage()); + }); + String backend = graph.backend(); if (backend.equals("postgresql")) { Assert.assertThrows(BackendException.class, () -> { @@ -2620,6 +2628,9 @@ public void testQueryEdgesByIdWithGraphAPI() { Object id = graph.traversal().E().toList().get(0).id(); List edges = ImmutableList.copyOf(graph.edges(id)); Assert.assertEquals(1, edges.size()); + + edges = ImmutableList.copyOf(graph.edges(id, id)); + Assert.assertEquals(2, edges.size()); } @Test @@ -2630,12 +2641,17 @@ public void testQueryEdgesByIdWithGraphAPIAndNotCommitedUpdate() { Edge edge = graph.traversal().E().hasLabel("look").toList().get(0); Object id = edge.id(); Assert.assertTrue(graph.edges(id).hasNext()); + Assert.assertTrue(graph.edges(id, id).hasNext()); edge.property("score", 101); List edges = ImmutableList.copyOf(graph.edges(id)); Assert.assertEquals(1, edges.size()); Assert.assertEquals(101, (int) edges.get(0).value("score")); + + edges = ImmutableList.copyOf(graph.edges(id, id)); + Assert.assertEquals(2, edges.size()); + Assert.assertEquals(101, (int) edges.get(1).value("score")); } @Test @@ -2643,15 +2659,23 @@ public void testQueryEdgesByIdWithGraphAPIAndNotCommitedRemoved() { HugeGraph graph = graph(); init18Edges(); - Edge edge = graph.traversal().E().toList().get(0); - Object id = edge.id(); - Assert.assertTrue(graph.edges(id).hasNext()); + List edges = graph.traversal().E().toList(); - edge.remove(); - Assert.assertFalse(graph.edges(id).hasNext()); + Edge edge1 = edges.get(0); + Edge edge2 = edges.get(1); + Assert.assertTrue(graph.edges(edge1.id()).hasNext()); + Assert.assertTrue(graph.edges(edge2.id()).hasNext()); + + edge1.remove(); + edge2.remove(); + Assert.assertFalse(graph.edges(edge1.id()).hasNext()); + Assert.assertFalse(graph.edges(edge2.id()).hasNext()); + Assert.assertFalse(graph.edges(edge1.id(), edge2.id()).hasNext()); graph.tx().rollback(); - Assert.assertTrue(graph.edges(id).hasNext()); + Assert.assertTrue(graph.edges(edge1.id()).hasNext()); + Assert.assertTrue(graph.edges(edge2.id()).hasNext()); + Assert.assertTrue(graph.edges(edge1.id(), edge2.id()).hasNext()); } @Test diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexCoreTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexCoreTest.java index af4c9987b1..674f0e1ec5 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexCoreTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/VertexCoreTest.java @@ -2938,6 +2938,68 @@ public void testQueryByIdNotFound() { }); } + @Test + public void testQueryByIdWithGraphAPI() { + HugeGraph graph = graph(); + init10Vertices(); + + Object id = graph.traversal().V().toList().get(0).id(); + List vertices = ImmutableList.copyOf(graph.vertices(id)); + Assert.assertEquals(1, vertices.size()); + + vertices = ImmutableList.copyOf(graph.vertices(id, id)); + Assert.assertEquals(2, vertices.size()); + } + + @Test + public void testQueryByIdWithGraphAPIAndNotCommitedUpdate() { + HugeGraph graph = graph(); + init10Vertices(); + + Vertex vertex = graph.traversal().V() + .hasLabel("author") + .has("id", 1).next(); + Object id = vertex.id(); + Assert.assertTrue(graph.vertices(id).hasNext()); + Assert.assertTrue(graph.vertices(id, id).hasNext()); + + vertex.property("age", 66); + + List vertices = ImmutableList.copyOf(graph.vertices(id)); + Assert.assertEquals(1, vertices.size()); + Assert.assertEquals(66, (int) vertices.get(0).value("age")); + + vertices = ImmutableList.copyOf(graph.vertices(id, id)); + Assert.assertEquals(2, vertices.size()); + Assert.assertEquals(66, (int) vertices.get(1).value("age")); + } + + @Test + public void testQueryByIdWithGraphAPIAndNotCommitedRemoved() { + HugeGraph graph = graph(); + init10Vertices(); + + List vertices = graph.traversal().V() + .hasLabel("author").toList(); + + Vertex vertex1 = vertices.get(0); + Vertex vertex2 = vertices.get(1); + Assert.assertTrue(graph.vertices(vertex1.id()).hasNext()); + Assert.assertTrue(graph.vertices(vertex2.id()).hasNext()); + + vertex1.remove(); + vertex2.remove(); + Assert.assertFalse(graph.vertices(vertex1.id()).hasNext()); + Assert.assertFalse(graph.vertices(vertex2.id()).hasNext()); + Assert.assertFalse(graph.vertices(vertex1.id(), vertex2.id()) + .hasNext()); + + graph.tx().rollback(); + Assert.assertTrue(graph.vertices(vertex1.id()).hasNext()); + Assert.assertTrue(graph.vertices(vertex2.id()).hasNext()); + Assert.assertTrue(graph.vertices(vertex1.id(), vertex2.id()).hasNext()); + } + @Test public void testQueryByInvalidSysprop() { HugeGraph graph = graph(); @@ -8664,54 +8726,165 @@ public void testQueryByHasIdEmptyListInPage() { } @Test - public void testQueryBySearchIndexWithSpecialSymbol() { + public void testAddVertexWithSpecialSymbolInPrimaryValues() { HugeGraph graph = graph(); - graph.schema().indexLabel("personByName").onV("person") - .by("name").search().ifNotExist().create(); - - Vertex vertex = graph.addVertex(T.label, "person", "name", - "xyz\u0002abc", "city", "Hongkong", - "age", 15); + Vertex vertex1 = graph.addVertex(T.label, "person", "name", + "xyz\u0001abc", "city", "Hongkong", + "age", 11); Vertex vertex2 = graph.addVertex(T.label, "person", "name", - "\u0002", "city", "Hongkong", - "age", 15); + "xyz\u0002abc", "city", "Hongkong", + "age", 12); Vertex vertex3 = graph.addVertex(T.label, "person", "name", "xyz\u0003abc", "city", "Hongkong", + "age", 13); + graph.tx().commit(); + + GraphTraversalSource g = graph.traversal(); + + Assert.assertEquals(vertex1, g.V().hasLabel("person") + .has("name", "xyz\u0001abc").next()); + Assert.assertEquals(vertex2, g.V().hasLabel("person") + .has("name", "xyz\u0002abc").next()); + Assert.assertEquals(vertex3, g.V().hasLabel("person") + .has("name", "xyz\u0003abc").next()); + + if (!graph.backend().equals("postgresql")) { + Vertex vertex0 = graph.addVertex(T.label, "person", "name", + "xyz\u0000abc", "city", "Hongkong", + "age", 10); + Assert.assertEquals(vertex0, g.V().hasLabel("person") + .has("name", "xyz\u0000abc").next()); + } + + Assert.assertThrows(IllegalArgumentException.class, () -> { + graph.addVertex(T.label, "person", "name", + "\u0000", "city", "Hongkong", + "age", 15); + }, e -> { + graph.tx().rollback(); + Assert.assertContains("Illegal leading char '\\u0' in index", + e.getMessage()); + }); + + Assert.assertThrows(IllegalArgumentException.class, () -> { + graph.addVertex(T.label, "person", "name", + "\u0001", "city", "Hongkong", + "age", 15); + }, e -> { + graph.tx().rollback(); + Assert.assertContains("Illegal leading char '\\u1' in index", + e.getMessage()); + }); + + Assert.assertThrows(IllegalArgumentException.class, () -> { + graph.addVertex(T.label, "person", "name", + "\u0002", "city", "Hongkong", + "age", 15); + }, e -> { + graph.tx().rollback(); + Assert.assertContains("Illegal leading char '\\u2' in index", + e.getMessage()); + }); + + Assert.assertThrows(IllegalArgumentException.class, () -> { + graph.addVertex(T.label, "person", "name", + "\u0003", "city", "Hongkong", + "age", 15); + }, e -> { + graph.tx().rollback(); + Assert.assertContains("Illegal leading char '\\u3' in index", + e.getMessage()); + }); + } + + @Test + public void testQueryBySearchIndexWithSpecialSymbol() { + HugeGraph graph = graph(); + + graph.schema().indexLabel("personByCity") + .onV("person") + .by("city") + .search() + .ifNotExist().create(); + + Vertex vertex1 = graph.addVertex(T.label, "person", "name", "1", + "city", "xyz\u0002abc", "age", 15); - Vertex vertex4 = graph.addVertex(T.label, "person", "name", - "\u0003", "city", "Hongkong", + Vertex vertex2 = graph.addVertex(T.label, "person", "name", "2", + "city", "\u0002", "age", 15); - Vertex vertex5 = graph.addVertex(T.label, "person", "name", - "xyz\u0001abc", "city", "Hongkong", + Vertex vertex3 = graph.addVertex(T.label, "person", "name", "3", + "city", "xyz\u0003abc", + "age", 15); + Vertex vertex4 = graph.addVertex(T.label, "person", "name", "4", + "city", "\u0003", "age", 15); - Vertex vertex6 = graph.addVertex(T.label, "person", "name", - "\u0001", "city", "Hongkong", + Vertex vertex5 = graph.addVertex(T.label, "person", "name", "5", + "city", "xyz\u0001abc", + "age", 15); + Vertex vertex6 = graph.addVertex(T.label, "person", "name", "6", + "city", "\u0001", "age", 15); graph.tx().commit(); GraphTraversalSource g = graph.traversal(); + String city;; + city = g.V().hasLabel("person").has("name", "1") + .next().value("city"); + Assert.assertEquals(vertex1.value("city"), city); + + city = g.V().hasLabel("person").has("name", "2") + .next().value("city"); + Assert.assertEquals(vertex2.value("city"), city); + + city = g.V().hasLabel("person").has("name", "3") + .next().value("city"); + Assert.assertEquals(vertex3.value("city"), city); + + city = g.V().hasLabel("person").has("name", "4") + .next().value("city"); + Assert.assertEquals(vertex4.value("city"), city); + + city = g.V().hasLabel("person").has("name", "5") + .next().value("city"); + Assert.assertEquals(vertex5.value("city"), city); + + city = g.V().hasLabel("person").has("name", "6") + .next().value("city"); + Assert.assertEquals(vertex6.value("city"), city); + List vertices; - vertices = g.V().has("name", Text.contains("abc")).toList(); + vertices = g.V().has("city", Text.contains("abc")).toList(); Assert.assertEquals(3, vertices.size()); - Assert.assertTrue(vertices.contains(vertex)); + Assert.assertTrue(vertices.contains(vertex1)); Assert.assertTrue(vertices.contains(vertex3)); Assert.assertTrue(vertices.contains(vertex5)); - vertices = g.V().has("name", Text.contains("\u0002")).toList(); + vertices = g.V().has("city", Text.contains("\u0002")).toList(); Assert.assertEquals(0, vertices.size()); - vertices = g.V().has("name", Text.contains("\u0003")).toList(); + vertices = g.V().has("city", Text.contains("\u0003")).toList(); Assert.assertEquals(0, vertices.size()); - vertices = g.V().has("name", Text.contains("\u0001")).toList(); + vertices = g.V().has("city", Text.contains("\u0001")).toList(); Assert.assertEquals(0, vertices.size()); - if (graph.backend().equals("postgresql")) { + String backend = graph.backend(); + if (ImmutableSet.of("rocksdb", "hbase").contains(backend)) { + Assert.assertThrows(Exception.class, () -> { + graph.addVertex(T.label, "person", "name", "0", + "city", "xyz\u0000efg", "age", 0); + graph.tx().commit(); + }, e -> { + Assert.assertContains("can't contains byte '0x00'", + e.getMessage()); + }); + } else if (backend.equals("postgresql")) { Assert.assertThrows(BackendException.class, () -> { - graph.addVertex(T.label, "person", "name", - "\u0000", "city", "Hongkong", + graph.addVertex(T.label, "person", "name", "7", + "city", "xyz\u0000efg", "age", 15); graph.tx().commit(); }, e -> { @@ -8721,16 +8894,20 @@ public void testQueryBySearchIndexWithSpecialSymbol() { e.getCause().getMessage()); }); } else { - graph.addVertex(T.label, "person", "name", - "xyz\u0000abc", "city", "Hongkong", + graph.addVertex(T.label, "person", "name", "8", + "city", "xyz\u0000efg", "age", 15); - - graph.addVertex(T.label, "person", "name", - "\u0000", "city", "Hongkong", + graph.addVertex(T.label, "person", "name", "9", + "city", "\u0000", "age", 15); + graph.tx().commit(); - vertices = g.V().has("name", Text.contains("\u0000")).toList(); - Assert.assertEquals(0, vertices.size()); + Assert.assertTrue(g.V().hasLabel("person") + .has("city", Text.contains("efg")) + .hasNext()); + Assert.assertFalse(g.V().hasLabel("person") + .has("city", Text.contains("u0000")) + .hasNext()); } }