You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by dk...@apache.org on 2019/09/04 15:04:24 UTC

[tinkerpop] 01/01: TINKERPOP-2159 Fixed multi-valued property handling in EventStrategy / AddPropertyStep.

This is an automated email from the ASF dual-hosted git repository.

dkuppitz pushed a commit to branch TINKERPOP-2159
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 6555210592d9d3fcbdd713639d2487130c7acd50
Author: Daniel Kuppitz <da...@hotmail.com>
AuthorDate: Mon Feb 18 07:30:48 2019 -0700

    TINKERPOP-2159 Fixed multi-valued property handling in EventStrategy / AddPropertyStep.
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/reference/the-traversal.asciidoc          |  6 ++
 docs/src/upgrade/release-3.3.x.asciidoc            | 13 ++++
 .../traversal/step/sideEffect/AddPropertyStep.java | 77 +++++++++++++++-------
 .../tinkergraph/structure/TinkerGraphPlayTest.java | 37 +++++++----
 5 files changed, 97 insertions(+), 37 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index fcb26b1..366d759 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Modified Java driver to use IP address rather than hostname to create connections.
 * Fixed potential for `NullPointerException` with empty identifiers in `GraphStep`.
 * Postpone the timing of transport creation to `connection.write` in Gremlin Python.
+* Made `EventStrategy` compatible with multi-valued properties.
 
 [[release-3-3-8]]
 === TinkerPop 3.3.8 (Release Date: August 5, 2019)
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 84b4b30..de27507 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -3484,6 +3484,12 @@ l = new ConsoleMutationListener(graph)
 strategy = EventStrategy.build().addListener(l).create()
 g = graph.traversal().withStrategies(strategy)
 g.addV().property('name','stephen')
+g.V().has('name','stephen').
+  property(list, 'location', 'centreville', 'startTime', 1990, 'endTime', 2000).
+  property(list, 'location', 'dulles', 'startTime', 2000, 'endTime', 2006).
+  property(list, 'location', 'purcellville', 'startTime', 2006)
+g.V().has('name','stephen').
+  property(set, 'location', 'purcellville', 'startTime', 2006, 'endTime', 2019)
 g.E().drop()
 ----
 
diff --git a/docs/src/upgrade/release-3.3.x.asciidoc b/docs/src/upgrade/release-3.3.x.asciidoc
index f3f1aac..5cd0a01 100644
--- a/docs/src/upgrade/release-3.3.x.asciidoc
+++ b/docs/src/upgrade/release-3.3.x.asciidoc
@@ -113,6 +113,19 @@ gremlin> g.V().hasLabel('person').aggregate('p').out('created').union(fold(),cap
 
 link:https://issues.apache.org/jira/browse/TINKERPOP-2265[TINKERPOP-2265]
 
+==== EventStrategy
+
+Prior TinkerPop 3.3.6 `EventStrategy` did not work with multi-properties. The `EventStrategy` behavior for single-valued properties has not changed; if a property is added to a multi-valued
+`VertexProperty`, then a `VertexPropertyChangedEvent` will be now be fired. The arguments passed to the event depend on the cardinality type.
+
+[width="100%",cols="2"]
+|=========================================================
+|`Cardinality.list` | Since properties will always be added and never be overwritten, the old property passed to the change event will always be an empty property.
+|`Cardinality.set`  | The old property passed to the change event will be empty if no other property with the same value exists, otherwise, it will be the existing property.
+|=========================================================
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2159[TINKERPOP-2159]
+
 == TinkerPop 3.3.7
 
 *Release Date: May 28, 2019*
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
index 7509f86..27ffe4e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
@@ -41,7 +41,9 @@ import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
 
+import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -93,29 +95,58 @@ public final class AddPropertyStep<S extends Element> extends SideEffectStep<S>
         final Element element = traverser.get();
 
         if (this.callbackRegistry != null) {
-            final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
-            final Property currentProperty = traverser.get().property(key);
-            final boolean newProperty = element instanceof Vertex ? currentProperty == VertexProperty.empty() : currentProperty == Property.empty();
-            final Event.ElementPropertyChangedEvent evt;
-            if (element instanceof Vertex)
-                evt = new Event.VertexPropertyChangedEvent(eventStrategy.detach((Vertex) element),
-                        newProperty ?
-                                eventStrategy.empty(element, key) :
-                                eventStrategy.detach((VertexProperty) currentProperty), value, vertexPropertyKeyValues);
-            else if (element instanceof Edge)
-                evt = new Event.EdgePropertyChangedEvent(eventStrategy.detach((Edge) element),
-                        newProperty ?
-                                eventStrategy.empty(element, key) :
-                                eventStrategy.detach(currentProperty), value);
-            else if (element instanceof VertexProperty)
-                evt = new Event.VertexPropertyPropertyChangedEvent(eventStrategy.detach((VertexProperty) element),
-                        newProperty ?
-                                eventStrategy.empty(element, key) :
-                                eventStrategy.detach(currentProperty), value);
-            else
-                throw new IllegalStateException(String.format("The incoming object cannot be processed by change eventing in %s:  %s", AddPropertyStep.class.getName(), element));
-
-            this.callbackRegistry.getCallbacks().forEach(c -> c.accept(evt));
+            getTraversal().getStrategies().getStrategy(EventStrategy.class)
+                    .ifPresent(eventStrategy -> {
+                        Event.ElementPropertyChangedEvent evt = null;
+                        if (element instanceof Vertex) {
+                            final VertexProperty.Cardinality cardinality = this.cardinality != null
+                                    ? this.cardinality
+                                    : element.graph().features().vertex().getCardinality(key);
+
+                            if (cardinality == VertexProperty.Cardinality.list) {
+                                evt = new Event.VertexPropertyChangedEvent(eventStrategy.detach((Vertex) element),
+                                        eventStrategy.empty(element, key), value, vertexPropertyKeyValues);
+                            }
+                            else if (cardinality == VertexProperty.Cardinality.set) {
+                                Property currentProperty = VertexProperty.empty();
+                                final Iterator<? extends Property> properties = traverser.get().properties(key);
+                                while (properties.hasNext()) {
+                                    final Property property = properties.next();
+                                    if (Objects.equals(property.value(), value)) {
+                                        currentProperty = property;
+                                        break;
+                                    }
+                                }
+                                evt = new Event.VertexPropertyChangedEvent(eventStrategy.detach((Vertex) element),
+                                        currentProperty == VertexProperty.empty() ?
+                                                eventStrategy.empty(element, key) :
+                                                eventStrategy.detach((VertexProperty) currentProperty), value, vertexPropertyKeyValues);
+                            }
+                        }
+                        if (evt == null) {
+                            final Property currentProperty = traverser.get().property(key);
+                            final boolean newProperty = element instanceof Vertex ? currentProperty == VertexProperty.empty() : currentProperty == Property.empty();
+                            if (element instanceof Vertex)
+                                evt = new Event.VertexPropertyChangedEvent(eventStrategy.detach((Vertex) element),
+                                        newProperty ?
+                                                eventStrategy.empty(element, key) :
+                                                eventStrategy.detach((VertexProperty) currentProperty), value, vertexPropertyKeyValues);
+                            else if (element instanceof Edge)
+                                evt = new Event.EdgePropertyChangedEvent(eventStrategy.detach((Edge) element),
+                                        newProperty ?
+                                                eventStrategy.empty(element, key) :
+                                                eventStrategy.detach(currentProperty), value);
+                            else if (element instanceof VertexProperty)
+                                evt = new Event.VertexPropertyPropertyChangedEvent(eventStrategy.detach((VertexProperty) element),
+                                        newProperty ?
+                                                eventStrategy.empty(element, key) :
+                                                eventStrategy.detach(currentProperty), value);
+                            else
+                                throw new IllegalStateException(String.format("The incoming object cannot be processed by change eventing in %s:  %s", AddPropertyStep.class.getName(), element));
+                        }
+                        final Event.ElementPropertyChangedEvent event = evt;
+                        this.callbackRegistry.getCallbacks().forEach(c -> c.accept(event));
+                    });
         }
 
         if (null != this.cardinality)
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
index 31c332b..7f676ac 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
@@ -24,11 +24,14 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ConsoleMutationListener;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.io.graphml.GraphMLIo;
 import org.apache.tinkerpop.gremlin.util.TimeUtil;
 import org.junit.Ignore;
@@ -137,19 +140,25 @@ public class TinkerGraphPlayTest {
     @Ignore
     public void testPlayDK() throws Exception {
 
-        GraphTraversalSource g = TinkerFactory.createModern().traversal();
-        System.out.println(g./*withComputer().*/V().hasLabel("person")
-                .project("name", "age", "comments")
-                    .by("name")
-                    .by("age")
-                    .by(branch(values("age"))
-                            .option(TraversalOptionParent.Pick.any, constant("foo"))
-                            .option(29, constant("almost old"))
-                            .option(__.is(32), constant("looks like josh"))
-                            .option(lt(29), constant("pretty young"))
-                            .option(lt(35), constant("younger than peter"))
-                            .option(gte(30), constant("pretty old")).fold()).explain());
-                //.forEachRemaining(System.out::println);
+        final Graph graph = TinkerGraph.open();
+        final EventStrategy strategy = EventStrategy.build().addListener(new ConsoleMutationListener(graph)).create();
+        final GraphTraversalSource g = graph.traversal().withStrategies(strategy);
+
+        g.addV().property(T.id, 1).iterate();
+        g.V(1).property("name", "name1").iterate();
+        g.V(1).property("name", "name2").iterate();
+        g.V(1).property("name", "name2").iterate();
+
+        g.addV().property(T.id, 2).iterate();
+        g.V(2).property(VertexProperty.Cardinality.list, "name", "name1").iterate();
+        g.V(2).property(VertexProperty.Cardinality.list, "name", "name2").iterate();
+        g.V(2).property(VertexProperty.Cardinality.list, "name", "name2").iterate();
+
+
+        g.addV().property(T.id, 3).iterate();
+        g.V(3).property(VertexProperty.Cardinality.set, "name", "name1", "ping", "pong").iterate();
+        g.V(3).property(VertexProperty.Cardinality.set, "name", "name2", "ping", "pong").iterate();
+        g.V(3).property(VertexProperty.Cardinality.set, "name", "name2", "pong", "ping").iterate();
     }
 
     @Test