added support for g.addE().to().from() as well as to(vertex) and from(vertex). 
This makes things a little easier on the eyes.


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/0c926872
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/0c926872
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/0c926872

Branch: refs/heads/TINKERPOP-1682
Commit: 0c92687229955fdb13dc4e3e9a51da1f3b95ae97
Parents: 86edf56
Author: Marko A. Rodriguez <[email protected]>
Authored: Wed Aug 2 15:59:19 2017 -0600
Committer: Marko A. Rodriguez <[email protected]>
Committed: Wed Aug 2 15:59:19 2017 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   2 +
 docs/src/reference/the-traversal.asciidoc       |   6 +
 .../traversal/dsl/graph/GraphTraversal.java     |  30 ++++
 .../dsl/graph/GraphTraversalSource.java         |   8 +
 .../traversal/step/map/AddEdgeStartStep.java    | 161 +++++++++++++++++++
 .../process/traversal/step/map/AddEdgeTest.java |  54 ++++++-
 6 files changed, 260 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0c926872/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index cbf0621..8117637 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,8 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.3.0 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Added `GraphTraversalSource.addE(String)` in support of 
`g.addE().from().to()`.
+* Added support for `to(Vertex)` and `from(Vertex)` as a shorthand for 
`to(V(a))` and `from(V(b))`.
 * Bumped to support Giraph 1.2.0.
 * Bumped to support Spark 2.2.0.
 * Detected if type checking was required in `GremlinGroovyScriptEngine` and 
disabled related infrastructure if not.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0c926872/docs/src/reference/the-traversal.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index 7db09d2..6829df4 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -208,6 +208,10 @@ g.V().match(
       addE('friendlyCollaborator').from('a').to('b').
         property(id,23).property('project',select('c').values('name')) <5>
 g.E(23).valueMap()
+marko = g.V().has('name','marko').next()
+peter = g.V().has('name','peter').next()
+g.V(marko).addE('knows').to(peter) <6>
+g.addE('knows').from(marko).to(peter) <7>
 ----
 
 <1> Add a co-developer edge with a year-property between marko and his 
collaborators.
@@ -216,6 +220,8 @@ g.E(23).valueMap()
 <4> The newly created edge is a traversable object.
 <5> Two arbitrary bindings in a traversal can be joined `from()`->`to()`, 
where `id` can be provided for graphs that
 supports user provided ids.
+<6> Add an edge between marko and peter given the directed (detached) vertex 
references.
+<7> Add an edge between marko and peter given the directed (detached) vertex 
references.
 
 [[addvertex-step]]
 AddVertex Step

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0c926872/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index dcee467..99be547 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -1042,6 +1042,36 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
         return this;
     }
 
+    /**
+     * When used as a modifier to {@link #addE(String)} this method specifies 
the traversal to use for selecting the
+     * incoming vertex of the newly added {@link Edge}.
+     *
+     * @param toVertex the vertex for selecting the incoming vertex
+     * @return the traversal with the modified {@link AddEdgeStep}
+     * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step";
 target="_blank">Reference Documentation - From Step</a>
+     * @since 3.3.0
+     */
+    public default GraphTraversal<S, E> to(final Vertex toVertex) {
+        this.asAdmin().getBytecode().addStep(Symbols.to, toVertex);
+        ((FromToModulating) 
this.asAdmin().getEndStep()).addTo(__.constant(toVertex).asAdmin());
+        return this;
+    }
+
+    /**
+     * When used as a modifier to {@link #addE(String)} this method specifies 
the traversal to use for selecting the
+     * outgoing vertex of the newly added {@link Edge}.
+     *
+     * @param fromVertex the vertex for selecting the outgoing vertex
+     * @return the traversal with the modified {@link AddEdgeStep}
+     * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step";
 target="_blank">Reference Documentation - From Step</a>
+     * @since 3.3.0
+     */
+    public default GraphTraversal<S, E> from(final Vertex fromVertex) {
+        this.asAdmin().getBytecode().addStep(Symbols.from, fromVertex);
+        ((FromToModulating) 
this.asAdmin().getEndStep()).addFrom(__.constant(fromVertex).asAdmin());
+        return this;
+    }
+
     ///////////////////// FILTER STEPS /////////////////////
 
     /**

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0c926872/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
index f820c59..2d4b94f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
@@ -31,6 +31,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import 
org.apache.tinkerpop.gremlin.process.traversal.engine.ComputerTraversalEngine;
 import 
org.apache.tinkerpop.gremlin.process.traversal.engine.StandardTraversalEngine;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStartStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStartStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
@@ -267,6 +268,13 @@ public class GraphTraversalSource implements 
TraversalSource {
         return traversal.addStep(new AddVertexStartStep(traversal, null));
     }
 
+    public GraphTraversal<Edge, Edge> addE(final String label) {
+        final GraphTraversalSource clone = this.clone();
+        clone.bytecode.addStep(GraphTraversal.Symbols.addE, label);
+        final GraphTraversal.Admin<Edge, Edge> traversal = new 
DefaultGraphTraversal<>(clone);
+        return traversal.addStep(new AddEdgeStartStep(traversal, label));
+    }
+
     public <S> GraphTraversal<S, S> inject(S... starts) {
         final GraphTraversalSource clone = this.clone();
         clone.bytecode.addStep(GraphTraversal.Symbols.inject, starts);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0c926872/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java
new file mode 100644
index 0000000..9d2eec5
--- /dev/null
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java
@@ -0,0 +1,161 @@
+/*
+ *  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 org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Parameterizing;
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.TraverserGenerator;
+import org.apache.tinkerpop.gremlin.process.traversal.step.FromToModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ListCallbackRegistry;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import 
org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+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.util.Attachable;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class AddEdgeStartStep extends AbstractStep<Edge, Edge>
+        implements Mutating<Event.EdgeAddedEvent>, TraversalParent, 
Parameterizing, Scoping, FromToModulating {
+
+    private static final String FROM = Graph.Hidden.hide("from");
+    private static final String TO = Graph.Hidden.hide("to");
+
+    private boolean first = true;
+    private Parameters parameters = new Parameters();
+    private CallbackRegistry<Event.EdgeAddedEvent> callbackRegistry;
+
+    public AddEdgeStartStep(final Traversal.Admin traversal, final String 
edgeLabel) {
+        super(traversal);
+        this.parameters.set(this, T.label, edgeLabel);
+    }
+
+    @Override
+    public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+        return this.parameters.getTraversals();
+    }
+
+    @Override
+    public Parameters getParameters() {
+        return this.parameters;
+    }
+
+    @Override
+    public Set<String> getScopeKeys() {
+        return this.parameters.getReferencedLabels();
+    }
+
+    @Override
+    public void addPropertyMutations(final Object... keyValues) {
+        this.parameters.set(this, keyValues);
+    }
+
+    @Override
+    public void addTo(final Traversal.Admin<?, ?> toObject) {
+        this.parameters.set(this, TO, toObject);
+    }
+
+    @Override
+    public void addFrom(final Traversal.Admin<?, ?> fromObject) {
+        this.parameters.set(this, FROM, fromObject);
+    }
+
+    @Override
+    protected Traverser.Admin<Edge> processNextStart() {
+        if (this.first) {
+            this.first = false;
+            final TraverserGenerator generator = 
this.getTraversal().getTraverserGenerator();
+            final Traverser.Admin traverser = generator.generate(1, (Step) 
this, 1); // a dead traverser to trigger the traversal
+            Vertex toVertex = (Vertex) this.parameters.get(traverser, TO, 
Collections::emptyList).get(0);
+            Vertex fromVertex = (Vertex) this.parameters.get(traverser, FROM, 
Collections::emptyList).get(0);
+            if (toVertex instanceof Attachable)
+                toVertex = ((Attachable<Vertex>) toVertex)
+                        
.attach(Attachable.Method.get(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
+            if (fromVertex instanceof Attachable)
+                fromVertex = ((Attachable<Vertex>) fromVertex)
+                        
.attach(Attachable.Method.get(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
+            final String edgeLabel = this.parameters.get(T.label, () -> 
Edge.DEFAULT_LABEL).get(0);
+
+            final Edge edge = fromVertex.addEdge(edgeLabel, toVertex, 
this.parameters.getKeyValues(traverser, TO, FROM, T.label));
+            if (callbackRegistry != null) {
+                final Event.EdgeAddedEvent vae = new 
Event.EdgeAddedEvent(DetachedFactory.detach(edge, true));
+                callbackRegistry.getCallbacks().forEach(c -> c.accept(vae));
+            }
+            return generator.generate(edge, this, 1L);
+        } else
+            throw FastNoSuchElementException.instance();
+
+
+    }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements(TraverserRequirement.OBJECT);
+    }
+
+    @Override
+    public CallbackRegistry<Event.EdgeAddedEvent> 
getMutatingCallbackRegistry() {
+        if (null == this.callbackRegistry) this.callbackRegistry = new 
ListCallbackRegistry<>();
+        return this.callbackRegistry;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ this.parameters.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.stepString(this, this.parameters.toString());
+    }
+
+    @Override
+    public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+        super.setTraversal(parentTraversal);
+        this.parameters.getTraversals().forEach(this::integrateChild);
+    }
+
+    @Override
+    public AddEdgeStartStep clone() {
+        final AddEdgeStartStep clone = (AddEdgeStartStep) super.clone();
+        clone.parameters = this.parameters.clone();
+        return clone;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0c926872/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
index 46d1766..337c09f 100644
--- 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
+++ 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeTest.java
@@ -30,7 +30,6 @@ import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -65,6 +64,10 @@ public abstract class AddEdgeTest extends 
AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, Edge> 
get_g_withSideEffectXb_bX_VXaX_addEXknowsX_toXbX_propertyXweight_0_5X();
 
+    public abstract Traversal<Vertex, Edge> 
get_g_VXaX_addEXknowsX_toXbX_propertyXweight_0_1X();
+
+    public abstract Traversal<Edge, Edge> 
get_g_addEXknowsX_fromXaX_toXbX_propertyXweight_0_1X();
+
     ///////
 
     @Test
@@ -211,6 +214,41 @@ public abstract class AddEdgeTest extends 
AbstractGremlinProcessTest {
         assertEquals(Arrays.asList(1L, 1L, 1L, 1L, 1L, 1L), 
g.V().map(outE().count()).toList());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, 
feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
+    public void g_VXaX_addEXknowsX_toXbX_propertyXweight_0_1X() {
+        final Traversal<Vertex, Edge> traversal = 
get_g_VXaX_addEXknowsX_toXbX_propertyXweight_0_1X();
+        printTraversalForm(traversal);
+        final Edge edge = traversal.next();
+        assertEquals(edge.outVertex(), convertToVertex(graph, "marko"));
+        assertEquals(edge.inVertex(), convertToVertex(graph, "peter"));
+        assertEquals("knows", edge.label());
+        assertEquals(1, IteratorUtils.count(edge.properties()));
+        assertEquals(0.1d, edge.value("weight"), 0.1d);
+        assertEquals(6L, g.V().count().next().longValue());
+        assertEquals(7L, g.E().count().next().longValue());
+
+
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, 
feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
+    public void g_addEXknowsX_fromXaX_toXbX_propertyXweight_0_1X() {
+        final Traversal<Edge, Edge> traversal = 
get_g_addEXknowsX_fromXaX_toXbX_propertyXweight_0_1X();
+        printTraversalForm(traversal);
+        final Edge edge = traversal.next();
+        assertEquals(edge.outVertex(), convertToVertex(graph, "marko"));
+        assertEquals(edge.inVertex(), convertToVertex(graph, "peter"));
+        assertEquals("knows", edge.label());
+        assertEquals(1, IteratorUtils.count(edge.properties()));
+        assertEquals(0.1d, edge.value("weight"), 0.1d);
+        assertEquals(6L, g.V().count().next().longValue());
+        assertEquals(7L, g.E().count().next().longValue());
+
+
+    }
 
     public static class Traversals extends AddEdgeTest {
 
@@ -250,5 +288,19 @@ public abstract class AddEdgeTest extends 
AbstractGremlinProcessTest {
         public Traversal<Vertex, Edge> 
get_g_addV_asXfirstX_repeatXaddEXnextX_toXaddVX_inVX_timesX5X_addEXnextX_toXselectXfirstXX()
 {
             return 
g.addV().as("first").repeat(__.addE("next").to(__.addV()).inV()).times(5).addE("next").to(select("first"));
         }
+
+        @Override
+        public Traversal<Vertex, Edge> 
get_g_VXaX_addEXknowsX_toXbX_propertyXweight_0_1X() {
+            final Vertex a = g.V().has("name", "marko").next();
+            final Vertex b = g.V().has("name", "peter").next();
+            return g.V(a).addE("knows").to(b).property("weight", 0.1d);
+        }
+
+        @Override
+        public Traversal<Edge, Edge> 
get_g_addEXknowsX_fromXaX_toXbX_propertyXweight_0_1X() {
+            final Vertex a = g.V().has("name", "marko").next();
+            final Vertex b = g.V().has("name", "peter").next();
+            return g.addE("knows").from(a).to(b).property("weight", 0.1d);
+        }
     }
 }

Reply via email to