You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2018/05/10 13:16:32 UTC
tinkerpop git commit: TINKERPOP-1685 Added supportUpsert() feature
Repository: tinkerpop
Updated Branches:
refs/heads/TINKERPOP-1685 [created] 384718cdc
TINKERPOP-1685 Added supportUpsert() feature
Added to both VertexFeatures and EdgeFeatures. Gives graph providers a more explicit option for providing this type of capability.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/384718cd
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/384718cd
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/384718cd
Branch: refs/heads/TINKERPOP-1685
Commit: 384718cdc93330cad8b2b78a3021220be3c9bebc
Parents: 31d2063
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Apr 11 07:02:43 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu May 10 09:16:19 2018 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 1 +
docs/src/upgrade/release-3.4.x.asciidoc | 19 ++++++
.../tinkerpop/gremlin/structure/Graph.java | 31 ++++++++++
.../tinkerpop/gremlin/structure/GraphTest.java | 35 ++++++++++-
.../tinkerpop/gremlin/structure/VertexTest.java | 62 ++++++++++++++++----
5 files changed, 132 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/384718cd/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 0c350c8..b66df78 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
This release also includes changes from <<release-3-3-3, 3.3.3>>.
+* Added `supportsUpsert()` option to `VertexFeatures` and `EdgeFeatures`.
* `min()` and `max()` now support all types implementing `Comparable`.
* Change the `toString()` of `Path` to be standardized as other graph elements are.
* `hadoop-gremlin` no longer generates a test artifact.
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/384718cd/docs/src/upgrade/release-3.4.x.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.4.x.asciidoc b/docs/src/upgrade/release-3.4.x.asciidoc
index a3de9e7..3c881c3 100644
--- a/docs/src/upgrade/release-3.4.x.asciidoc
+++ b/docs/src/upgrade/release-3.4.x.asciidoc
@@ -230,3 +230,22 @@ long ago moved to the `Computer` infrastructure as methods for constructing a `T
`TraversalEngine` were long ago removed.
See: link:https://issues.apache.org/jira/browse/TINKERPOP-1143[TINKERPOP-1143]
+
+==== Upsert Graph Feature
+
+Some `Graph` implementations may be able to offer upsert functionality for vertices and edges, which can help improve
+usability and performance. To help make it clear to users that a graph operates in this fashion, the `supportsUpsert()`
+feature has been added to both `Graph.VertexFeatures` and `Graph.EdgeFeatures`. By default, both of these methods will
+return `false`.
+
+Should a provider wish to support this feature, the behavior of `addV()` and/or `addE()` should change such that when
+a vertex or edge with the same identifier is provided, the respective step will insert the new element if that value
+is not present or update an existing element if it is found. The method by which the provider "identifies" an element
+is completely up to the capabilities of that provider. In the most simple fashion, a graph could simply check the
+value of the supplied `T.id`, however graphs that support some form of schema will likely have other methods for
+determining whether or not an existing element is present.
+
+The extent to which TinkerPop tests "upsert" is fairly narrow. Graph providers that choose to support this feature
+should consider their own test suites carefully to ensure appropriate coverage.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1685[TINKERPOP-1685]
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/384718cd/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
index b142a9a..494ca8c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
@@ -504,6 +504,7 @@ public interface Graph extends AutoCloseable, Host {
public static final String FEATURE_DUPLICATE_MULTI_PROPERTIES = "DuplicateMultiProperties";
public static final String FEATURE_META_PROPERTIES = "MetaProperties";
public static final String FEATURE_REMOVE_VERTICES = "RemoveVertices";
+ public static final String FEATURE_UPSERT = "Upsert";
/**
* Gets the {@link VertexProperty.Cardinality} for a key. By default, this method will return
@@ -565,6 +566,20 @@ public interface Graph extends AutoCloseable, Host {
}
/**
+ * Determines if the {@code Graph} implementation uses upsert functionality as opposed to insert
+ * functionality for {@link #addVertex(String)}. This feature gives graph providers some flexibility as
+ * to how graph mutations are treated. For graph providers, testing of this feature (as far as TinkerPop
+ * is concerned) only covers graphs that can support user supplied identifiers as there is no other way
+ * for TinkerPop to know what aspect of a vertex is unique to appropriately apply assertions. Graph
+ * providers, especially those who support schema features, may have other methods for uniquely identifying
+ * a vertex and should therefore resort to their own body of tests to validate this feature.
+ */
+ @FeatureDescriptor(name = FEATURE_UPSERT)
+ public default boolean supportsUpsert() {
+ return false;
+ }
+
+ /**
* Gets features related to "properties" on a {@link Vertex}.
*/
public default VertexPropertyFeatures properties() {
@@ -579,6 +594,7 @@ public interface Graph extends AutoCloseable, Host {
public interface EdgeFeatures extends ElementFeatures {
public static final String FEATURE_ADD_EDGES = "AddEdges";
public static final String FEATURE_REMOVE_EDGES = "RemoveEdges";
+ public static final String FEATURE_UPSERT = "Upsert";
/**
* Determines if an {@link Edge} can be added to a {@code Vertex}.
@@ -597,6 +613,21 @@ public interface Graph extends AutoCloseable, Host {
}
/**
+ * Determines if the {@code Graph} implementation uses upsert functionality as opposed to insert
+ * functionality for {@link Vertex#addEdge(String, Vertex, Object...)}. This feature gives graph providers
+ * some flexibility as to how graph mutations are treated. For graph providers, testing of this feature
+ * (as far as TinkerPop is concerned) only covers graphs that can support user supplied identifiers as
+ * there is no other way for TinkerPop to know what aspect of a edge is unique to appropriately apply
+ * assertions. Graph providers, especially those who support schema features, may have other methods for
+ * uniquely identifying a edge and should therefore resort to their own body of tests to validate this
+ * feature.
+ */
+ @FeatureDescriptor(name = FEATURE_UPSERT)
+ public default boolean supportsUpsert() {
+ return false;
+ }
+
+ /**
* Gets features related to "properties" on an {@link Edge}.
*/
public default EdgePropertyFeatures properties() {
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/384718cd/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
index a667e6f..d8f0817 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
@@ -49,7 +49,12 @@ import java.util.stream.IntStream;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author Stephen Mallette (http://stephen.genoprime.com)
@@ -118,11 +123,12 @@ public class GraphTest extends AbstractGremlinTest {
@Test
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_USER_SUPPLIED_IDS)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_UPSERT, supported = false)
public void shouldHaveExceptionConsistencyWhenAssigningSameIdOnVertex() {
final Object o = graphProvider.convertId("1", Vertex.class);
- graph.addVertex(T.id, o);
+ graph.addVertex(T.id, o, "name", "marko");
try {
- graph.addVertex(T.id, o);
+ graph.addVertex(T.id, o, "name", "stephen");
fail("Assigning the same ID to an Element should throw an exception");
} catch (Exception ex) {
assertThat(ex, instanceOf(Graph.Exceptions.vertexWithIdAlreadyExists(0).getClass()));
@@ -132,6 +138,29 @@ public class GraphTest extends AbstractGremlinTest {
@Test
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_USER_SUPPLIED_IDS)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_UPSERT)
+ public void shouldUpsertWhenAssigningSameIdOnVertex() {
+ final Object o = graphProvider.convertId("1", Vertex.class);
+ graph.addVertex(T.id, o, "name", "marko");
+ tryCommit(graph, graph -> {
+ final Vertex v = graph.vertices(o).next();
+ assertEquals(o, v.id());
+ assertEquals("marko", v.value("name"));
+ assertVertexEdgeCounts(graph, 1, 0);
+ });
+
+ graph.addVertex(T.id, o, "name", "stephen");
+ tryCommit(graph, graph -> {
+ final Vertex v = graph.vertices(o).next();
+ assertEquals(o, v.id());
+ assertEquals("stephen", v.value("name"));
+ assertVertexEdgeCounts(graph, 1, 0);
+ });
+ }
+
+ @Test
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_USER_SUPPLIED_IDS)
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_NUMERIC_IDS)
public void shouldAddVertexWithUserSuppliedNumericId() {
graph.addVertex(T.id, 1000l);
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/384718cd/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
index 8062fd1..6108456 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
@@ -37,9 +37,20 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
-import static org.apache.tinkerpop.gremlin.structure.Graph.Features.PropertyFeatures.*;
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_BOOLEAN_VALUES;
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_DOUBLE_VALUES;
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_FLOAT_VALUES;
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_INTEGER_VALUES;
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_LONG_VALUES;
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_STRING_VALUES;
import static org.apache.tinkerpop.gremlin.structure.Graph.Features.VertexFeatures.FEATURE_USER_SUPPLIED_IDS;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -56,10 +67,10 @@ public class VertexTest {
@FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_NUMERIC_IDS)
public void shouldAddEdgeWithUserSuppliedNumericId() {
final Vertex v = graph.addVertex();
- v.addEdge("self", v, T.id, 1000l);
+ v.addEdge("self", v, T.id, 1000L);
tryCommit(graph, graph -> {
- final Edge e = graph.edges(1000l).next();
- assertEquals(1000l, e.id());
+ final Edge e = graph.edges(1000L).next();
+ assertEquals(1000L, e.id());
});
}
@@ -251,18 +262,43 @@ public class VertexTest {
@FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
@FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_USER_SUPPLIED_IDS)
+ @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_UPSERT, supported = false)
public void shouldHaveExceptionConsistencyWhenAssigningSameIdOnEdge() {
final Vertex v = graph.addVertex();
final Object o = graphProvider.convertId("1", Edge.class);
- v.addEdge("self", v, T.id, o);
+ v.addEdge("self", v, T.id, o, "weight", 1);
try {
- v.addEdge("self", v, T.id, o);
+ v.addEdge("self", v, T.id, o, "weight", 1);
fail("Assigning the same ID to an Element should throw an exception");
} catch (Exception ex) {
validateException(Graph.Exceptions.edgeWithIdAlreadyExists(o), ex);
}
+ }
+ @Test
+ @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
+ @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_USER_SUPPLIED_IDS)
+ @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_UPSERT)
+ public void shouldUpsertWhenAssigningSameIdOnEdge() {
+ final Vertex v = graph.addVertex();
+ final Object o = graphProvider.convertId("1", Edge.class);
+ v.addEdge("self", v, T.id, o, "weight", 1);
+ tryCommit(graph, graph -> {
+ final Edge e = graph.edges(o).next();
+ assertEquals(o, e.id());
+ assertEquals(1, (int) e.value("weight"));
+ assertVertexEdgeCounts(graph, 1, 1);
+ });
+
+ v.addEdge("self", v, T.id, o, "weight", 2);
+ tryCommit(graph, graph -> {
+ final Edge e = graph.edges(o).next();
+ assertEquals(o, e.id());
+ assertEquals(2, (int) e.value("weight"));
+ assertVertexEdgeCounts(graph, 1, 1);
+ });
}
@Test
@@ -289,8 +325,8 @@ public class VertexTest {
@Test
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_PROPERTY)
- @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = Graph.Features.VertexPropertyFeatures.FEATURE_STRING_VALUES)
- @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = Graph.Features.VertexPropertyFeatures.FEATURE_INTEGER_VALUES)
+ @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = FEATURE_STRING_VALUES)
+ @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = FEATURE_INTEGER_VALUES)
public void shouldHaveStandardStringRepresentationWithProperties() {
final Vertex v = graph.addVertex("name", "marko", "age", 34);
assertEquals(StringFactory.vertexString(v), v.toString());
@@ -462,9 +498,9 @@ public class VertexTest {
@FeatureRequirement(featureClass = VertexPropertyFeatures.class, feature = FEATURE_LONG_VALUES)
public void shouldAutotypeLongProperties() {
final Vertex v = graph.addVertex();
- v.property(VertexProperty.Cardinality.single, "long", 1l);
+ v.property(VertexProperty.Cardinality.single, "long", 1L);
final Long best = v.value("long");
- assertEquals(best, Long.valueOf(1l));
+ assertEquals(best, Long.valueOf(1L));
}
@Test
@@ -516,9 +552,9 @@ public class VertexTest {
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
@FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_PROPERTY)
- @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = Graph.Features.VertexPropertyFeatures.FEATURE_INTEGER_VALUES)
+ @FeatureRequirement(featureClass = Graph.Features.VertexPropertyFeatures.class, feature = FEATURE_INTEGER_VALUES)
@FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_PROPERTY)
- @FeatureRequirement(featureClass = Graph.Features.EdgePropertyFeatures.class, feature = Graph.Features.EdgePropertyFeatures.FEATURE_INTEGER_VALUES)
+ @FeatureRequirement(featureClass = Graph.Features.EdgePropertyFeatures.class, feature = FEATURE_INTEGER_VALUES)
@FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_REMOVE_VERTICES)
public void shouldNotGetConcurrentModificationException() {
for (int i = 0; i < 25; i++) {