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 2022/02/07 12:30:12 UTC

[tinkerpop] 01/02: Prevent creation of vertices if they do not exist for mergeE()

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

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

commit 2337b5a96b18600b3b684da09c2fe22983d31975
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Sat Feb 5 09:52:48 2022 -0500

    Prevent creation of vertices if they do not exist for mergeE()
---
 .../process/traversal/step/map/MergeEdgeStep.java  | 28 +++++++++++----
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  5 +--
 .../gremlin-javascript/test/cucumber/gremlin.js    |  5 +--
 gremlin-python/src/main/python/radish/gremlin.py   |  5 +--
 gremlin-test/features/map/MergeEdge.feature        | 40 ++++++++++++++++------
 .../process/traversal/step/map/MergeEdgeTest.java  | 17 +++++----
 6 files changed, 71 insertions(+), 29 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
index 94d4273..7734f95 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
@@ -279,6 +279,13 @@ public class MergeEdgeStep<S> extends FlatMapStep<S, Edge> implements Mutating<E
             // searchCreate should have alredy been validated so only do it if it is overridden
             if (useOnCreate) validateMapInput(m, false);
 
+            // check if from/to were already determined by traverser/searchMatch, and if not, then at least ensure that
+            // the from/to is set in m
+            if (outV == PLACEHOLDER_VERTEX && !m.containsKey(Direction.OUT))
+                throw new IllegalArgumentException("Out Vertex not specified - edge cannot be created");
+            if (inV == PLACEHOLDER_VERTEX && !m.containsKey(Direction.IN))
+                throw new IllegalArgumentException("In Vertex not specified - edge cannot be created");
+
             final List<Object> keyValues = new ArrayList<>();
             String label = Edge.DEFAULT_LABEL;
 
@@ -292,11 +299,9 @@ public class MergeEdgeStep<S> extends FlatMapStep<S, Edge> implements Mutating<E
                     // only override if onCreate was specified otherwise stick to however traverser/searchMatch
                     // was resolved
                     if (useOnCreate && entry.getKey().equals(Direction.IN)) {
-                        toV = ((Attachable<Vertex>) entry.getValue())
-                                .attach(Attachable.Method.getOrCreate(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
+                        toV = tryAttachVertex((Attachable<Vertex>) entry.getValue());
                     } else if (useOnCreate && entry.getKey().equals(Direction.OUT)) {
-                        fromV = ((Attachable<Vertex>) entry.getValue())
-                                .attach(Attachable.Method.getOrCreate(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
+                        fromV = tryAttachVertex((Attachable<Vertex>) entry.getValue());
                     }
                 } else if (entry.getKey().equals(T.label)) {
                     label = (String) entry.getValue();
@@ -335,14 +340,25 @@ public class MergeEdgeStep<S> extends FlatMapStep<S, Edge> implements Mutating<E
         final Object o = searchCreate.getOrDefault(direction, possibleVertex);
         final Vertex v = o instanceof Vertex ? (Vertex) o : new ReferenceVertex(o);
         if (v != PLACEHOLDER_VERTEX && v instanceof Attachable) {
-            return ((Attachable<Vertex>) v)
-                    .attach(Attachable.Method.getOrCreate(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
+            return tryAttachVertex((Attachable<Vertex>) v);
         } else {
             return v;
         }
     }
 
     /**
+     * Tries to attach a {@link Vertex} to its host {@link Graph} of the traversal. If the {@link Vertex} cannot be
+     * found then an {@code IllegalArgumentException} is expected.
+     */
+    protected Vertex tryAttachVertex(final Attachable<Vertex> attachable) {
+        try {
+            return attachable.attach(Attachable.Method.get(this.getTraversal().getGraph().orElse(EmptyGraph.instance())));
+        } catch (IllegalStateException ise) {
+            throw new IllegalArgumentException(String.format("%s could not be found and edge could not be created", attachable));
+        }
+    }
+
+    /**
      * Validates input to any {@code Map} arguments to this step. For {@link Merge#onMatch} updates cannot be applied
      * to immutable parts of an {@link Edge} (id, label, incident vertices) so those can be ignored in the validation.
      */
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index d600ff9..95c4069 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -505,8 +505,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_withSideEffectXa_label_knows_out_marko_in_vadasX_mergeEXselectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").AddV("person").Property(T.Id,101).Property("name","vadas"), (g,p) =>g.WithSideEffect("a",p["xx1"]).MergeE((IDictionary<object,object>) __.Select<object>("a")), (g,p) =>g.V().Has("person","name","marko").Out("knows").Has("person","name","vadas")}}, 
                {"g_mergeEXlabel_knows_out_marko1_in_vadas1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").AddV("person").Property(T.Id,101).Property("name","vadas"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko").Out("knows").Has("person","name","vadas")}}, 
                {"g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X_exists", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko").OutE("knows").Has("weight",0.5).InV().Has("person","name"," [...]
-               {"g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("weight",0.5)}}, 
-               {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"]).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx3"]), (g,p) =>g.V(), (g,p) =>g.E().HasLabel("knows").Has("created","Y"), (g,p) =>g.E().HasLabel("knows").Has("created","N")}}, 
+               {"g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"])}}, 
+               {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"]).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx3"])}}, 
                {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"] [...]
                {"g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b").Property("created","Y"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDic [...]
                {"g_V_hasXperson_name_marko_X_mergeEXlabel_knowsX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b").AddE("knows").From("a").To("b").Property("created","Y").AddE("knows").From("a").To("b"), (g,p) =>g.V().Has("person","name","marko").Me [...]
@@ -519,6 +519,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_withSideEffectXc_created_YX_withSideEffectXm_matchedX_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_selectXcXX_optionXonMatch_selectXmXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").As("a").AddV("person").Property(T.Id,101).Property("name","vadas").As("b"), (g,p) =>g.WithSideEffect("c",p["xx2"]).WithSideEffect("m",p["xx3"]).MergeE((IDictionary<object,object [...]
                {"g_V_mapXmergeEXlabel_self_weight_05XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.V().Map<object>(__.MergeE((IDictionary<object,object>) p["xx1"])), (g,p) =>g.E(), (g,p) =>g.V(), (g,p) =>g.V().Has("person","name","marko").As("a").OutE("self").Has("weight",0.5).InV().Where(P.Eq("a"))}}, 
                {"g_mergeEXlabel_knows_out_marko_in_vadasX_aliased_direction", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").AddV("person").Property(T.Id,101).Property("name","vadas"), (g,p) =>g.MergeE((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko").Out("knows").Has("person","name","vadas")}}, 
+               {"g_injectXlabel_knows_out_marko_in_vadas_label_self_out_vadas_in_vadasX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,100).Property("name","marko").AddV("person").Property(T.Id,101).Property("name","vadas"), (g,p) =>g.Inject(p["xx1"],p["xx2"]).MergeE(), (g,p) =>g.V(), (g,p) =>g.E(), (g,p) =>g.V().Has("person","name","marko").Out("knows").Has("person","name","vadas"), (g,p) =>g.V().Has("person","name [...]
                {"g_mergeVXlabel_person_name_stephenX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","stephen")}}, 
                {"g_mergeVXlabel_person_name_markoX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]), (g,p) =>g.V().Has("person","name","marko")}}, 
                {"g_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29), (g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"]), (g,p) =>g.V().Has("person","name","stephen").Has("age",19)}}, 
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index cfc914c..58b4316 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -496,8 +496,8 @@ const gremlins = {
     g_withSideEffectXa_label_knows_out_marko_in_vadasX_mergeEXselectXaXX: [function({g, xx1}) { return g.addV("person").property(T.id,100).property("name","marko").addV("person").property(T.id,101).property("name","vadas") }, function({g, xx1}) { return g.withSideEffect("a",xx1).mergeE(__.select("a")) }, function({g, xx1}) { return g.V().has("person","name","marko").out("knows").has("person","name","vadas") }], 
     g_mergeEXlabel_knows_out_marko1_in_vadas1X: [function({g, xx1}) { return g.addV("person").property(T.id,100).property("name","marko").addV("person").property(T.id,101).property("name","vadas") }, function({g, xx1}) { return g.mergeE(xx1) }, function({g, xx1}) { return g.V().has("person","name","marko").out("knows").has("person","name","vadas") }], 
     g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X_exists: [function({g, xx1}) { return g.addV("person").property(T.id,100).property("name","marko").as("a").addV("person").property(T.id,101).property("name","vadas").as("b").addE("knows").from_("a").to("b") }, function({g, xx1}) { return g.mergeE(xx1) }, function({g, xx1}) { return g.V().has("person","name","marko").outE("knows").has("weight",0.5).inV().has("person","name","vadas") }, function({g, xx1}) { return g.V().has("person","na [...]
-    g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X: [function({g, xx1}) { return g.mergeE(xx1) }, function({g, xx1}) { return g.V() }, function({g, xx1}) { return g.E().hasLabel("knows").has("weight",0.5) }], 
-    g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX: [function({g, xx1, xx3, xx2}) { return g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3) }, function({g, xx1, xx3, xx2}) { return g.V() }, function({g, xx1, xx3, xx2}) { return g.E().hasLabel("knows").has("created","Y") }, function({g, xx1, xx3, xx2}) { return g.E().hasLabel("knows").has("created","N") }], 
+    g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X: [function({g, xx1}) { return g.mergeE(xx1) }], 
+    g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX: [function({g, xx1, xx3, xx2}) { return g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3) }], 
     g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists: [function({g, xx1, xx3, xx2}) { return g.addV("person").property(T.id,100).property("name","marko").as("a").addV("person").property(T.id,101).property("name","vadas").as("b").addE("knows").from_("a").to("b") }, function({g, xx1, xx3, xx2}) { return g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3) }, function({g, xx1, xx3, xx2}) { return g.V() }, function({g, xx1, xx [...]
     g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated: [function({g, xx1, xx3, xx2}) { return g.addV("person").property(T.id,100).property("name","marko").as("a").addV("person").property(T.id,101).property("name","vadas").as("b").addE("knows").from_("a").to("b").property("created","Y") }, function({g, xx1, xx3, xx2}) { return g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3) }, function({g, xx1, xx3, xx2}) { retu [...]
     g_V_hasXperson_name_marko_X_mergeEXlabel_knowsX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated: [function({g, xx1, xx3, xx2}) { return g.addV("person").property(T.id,100).property("name","marko").as("a").addV("person").property(T.id,101).property("name","vadas").as("b").addE("knows").from_("a").to("b").property("created","Y").addE("knows").from_("a").to("b") }, function({g, xx1, xx3, xx2}) { return g.V().has("person","name","marko").mergeE(xx1).option(Merge.onCre [...]
@@ -510,6 +510,7 @@ const gremlins = {
     g_withSideEffectXc_created_YX_withSideEffectXm_matchedX_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_selectXcXX_optionXonMatch_selectXmXX: [function({g, xx1, xx3, xx2}) { return g.addV("person").property(T.id,100).property("name","marko").as("a").addV("person").property(T.id,101).property("name","vadas").as("b") }, function({g, xx1, xx3, xx2}) { return g.withSideEffect("c",xx2).withSideEffect("m",xx3).mergeE(xx1).option(Merge.onCreate,__.select("c")).option(Merge.onMatch,__ [...]
     g_V_mapXmergeEXlabel_self_weight_05XX: [function({g, xx1}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1}) { return g.V().map(__.mergeE(xx1)) }, function({g, xx1}) { return g.E() }, function({g, xx1}) { return g.V() }, function({g, xx1}) { return g.V().has("person","name","marko").as("a").outE("self").has("weight",0.5).inV().where(P.eq("a")) }], 
     g_mergeEXlabel_knows_out_marko_in_vadasX_aliased_direction: [function({g, xx1}) { return g.addV("person").property(T.id,100).property("name","marko").addV("person").property(T.id,101).property("name","vadas") }, function({g, xx1}) { return g.mergeE(xx1) }, function({g, xx1}) { return g.V().has("person","name","marko").out("knows").has("person","name","vadas") }], 
+    g_injectXlabel_knows_out_marko_in_vadas_label_self_out_vadas_in_vadasX: [function({g, xx1, xx2}) { return g.addV("person").property(T.id,100).property("name","marko").addV("person").property(T.id,101).property("name","vadas") }, function({g, xx1, xx2}) { return g.inject(xx1,xx2).mergeE() }, function({g, xx1, xx2}) { return g.V() }, function({g, xx1, xx2}) { return g.E() }, function({g, xx1, xx2}) { return g.V().has("person","name","marko").out("knows").has("person","name","vadas") }, [...]
     g_mergeVXlabel_person_name_stephenX: [function({g, xx1}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1}) { return g.mergeV(xx1) }, function({g, xx1}) { return g.V().has("person","name","stephen") }], 
     g_mergeVXlabel_person_name_markoX: [function({g, xx1}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1}) { return g.mergeV(xx1) }, function({g, xx1}) { return g.V().has("person","name","marko") }], 
     g_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option: [function({g, xx1, xx2}) { return g.addV("person").property("name","marko").property("age",29) }, function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onCreate,xx2) }, function({g, xx1, xx2}) { return g.V().has("person","name","stephen").has("age",19) }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 761ad00..0199247 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -478,8 +478,8 @@ world.gremlins = {
     'g_withSideEffectXa_label_knows_out_marko_in_vadasX_mergeEXselectXaXX': [(lambda g, xx1=None:g.addV('person').property(T.id_,100).property('name','marko').addV('person').property(T.id_,101).property('name','vadas')), (lambda g, xx1=None:g.withSideEffect('a',xx1).mergeE(__.select('a'))), (lambda g, xx1=None:g.V().has('person','name','marko').out('knows').has('person','name','vadas'))], 
     'g_mergeEXlabel_knows_out_marko1_in_vadas1X': [(lambda g, xx1=None:g.addV('person').property(T.id_,100).property('name','marko').addV('person').property(T.id_,101).property('name','vadas')), (lambda g, xx1=None:g.mergeE(xx1)), (lambda g, xx1=None:g.V().has('person','name','marko').out('knows').has('person','name','vadas'))], 
     'g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X_exists': [(lambda g, xx1=None:g.addV('person').property(T.id_,100).property('name','marko').as_('a').addV('person').property(T.id_,101).property('name','vadas').as_('b').addE('knows').from_('a').to('b')), (lambda g, xx1=None:g.mergeE(xx1)), (lambda g, xx1=None:g.V().has('person','name','marko').outE('knows').has('weight',float(0.5)).inV().has('person','name','vadas')), (lambda g, xx1=None:g.V().has('person','name','marko').out('know [...]
-    'g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X': [(lambda g, xx1=None:g.mergeE(xx1)), (lambda g, xx1=None:g.V()), (lambda g, xx1=None:g.E().hasLabel('knows').has('weight',float(0.5)))], 
-    'g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX': [(lambda g, xx1=None,xx3=None,xx2=None:g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3)), (lambda g, xx1=None,xx3=None,xx2=None:g.V()), (lambda g, xx1=None,xx3=None,xx2=None:g.E().hasLabel('knows').has('created','Y')), (lambda g, xx1=None,xx3=None,xx2=None:g.E().hasLabel('knows').has('created','N'))], 
+    'g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X': [(lambda g, xx1=None:g.mergeE(xx1))], 
+    'g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX': [(lambda g, xx1=None,xx3=None,xx2=None:g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3))], 
     'g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists': [(lambda g, xx1=None,xx3=None,xx2=None:g.addV('person').property(T.id_,100).property('name','marko').as_('a').addV('person').property(T.id_,101).property('name','vadas').as_('b').addE('knows').from_('a').to('b')), (lambda g, xx1=None,xx3=None,xx2=None:g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3)), (lambda g, xx1=None,xx3=None,xx2=None:g.V()), (lambda g, xx1=No [...]
     'g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated': [(lambda g, xx1=None,xx3=None,xx2=None:g.addV('person').property(T.id_,100).property('name','marko').as_('a').addV('person').property(T.id_,101).property('name','vadas').as_('b').addE('knows').from_('a').to('b').property('created','Y')), (lambda g, xx1=None,xx3=None,xx2=None:g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3)), (lambda g, xx1=None,xx3=None,xx [...]
     'g_V_hasXperson_name_marko_X_mergeEXlabel_knowsX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists_updated': [(lambda g, xx1=None,xx3=None,xx2=None:g.addV('person').property(T.id_,100).property('name','marko').as_('a').addV('person').property(T.id_,101).property('name','vadas').as_('b').addE('knows').from_('a').to('b').property('created','Y').addE('knows').from_('a').to('b')), (lambda g, xx1=None,xx3=None,xx2=None:g.V().has('person','name','marko').mergeE(xx1).option(Merge. [...]
@@ -492,6 +492,7 @@ world.gremlins = {
     'g_withSideEffectXc_created_YX_withSideEffectXm_matchedX_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_selectXcXX_optionXonMatch_selectXmXX': [(lambda g, xx1=None,xx3=None,xx2=None:g.addV('person').property(T.id_,100).property('name','marko').as_('a').addV('person').property(T.id_,101).property('name','vadas').as_('b')), (lambda g, xx1=None,xx3=None,xx2=None:g.withSideEffect('c',xx2).withSideEffect('m',xx3).mergeE(xx1).option(Merge.onCreate,__.select('c')).option(Merge.onMat [...]
     'g_V_mapXmergeEXlabel_self_weight_05XX': [(lambda g, xx1=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None:g.V().map(__.mergeE(xx1))), (lambda g, xx1=None:g.E()), (lambda g, xx1=None:g.V()), (lambda g, xx1=None:g.V().has('person','name','marko').as_('a').outE('self').has('weight',float(0.5)).inV().where(P.eq('a')))], 
     'g_mergeEXlabel_knows_out_marko_in_vadasX_aliased_direction': [(lambda g, xx1=None:g.addV('person').property(T.id_,100).property('name','marko').addV('person').property(T.id_,101).property('name','vadas')), (lambda g, xx1=None:g.mergeE(xx1)), (lambda g, xx1=None:g.V().has('person','name','marko').out('knows').has('person','name','vadas'))], 
+    'g_injectXlabel_knows_out_marko_in_vadas_label_self_out_vadas_in_vadasX': [(lambda g, xx1=None,xx2=None:g.addV('person').property(T.id_,100).property('name','marko').addV('person').property(T.id_,101).property('name','vadas')), (lambda g, xx1=None,xx2=None:g.inject(xx1,xx2).mergeE()), (lambda g, xx1=None,xx2=None:g.V()), (lambda g, xx1=None,xx2=None:g.E()), (lambda g, xx1=None,xx2=None:g.V().has('person','name','marko').out('knows').has('person','name','vadas')), (lambda g, xx1=None, [...]
     'g_mergeVXlabel_person_name_stephenX': [(lambda g, xx1=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None:g.mergeV(xx1)), (lambda g, xx1=None:g.V().has('person','name','stephen'))], 
     'g_mergeVXlabel_person_name_markoX': [(lambda g, xx1=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None:g.mergeV(xx1)), (lambda g, xx1=None:g.V().has('person','name','marko'))], 
     'g_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option': [(lambda g, xx1=None,xx2=None:g.addV('person').property('name','marko').property('age',29)), (lambda g, xx1=None,xx2=None:g.mergeV(xx1).option(Merge.onCreate,xx2)), (lambda g, xx1=None,xx2=None:g.V().has('person','name','stephen').has('age',19))], 
diff --git a/gremlin-test/features/map/MergeEdge.feature b/gremlin-test/features/map/MergeEdge.feature
index 4d9304a..b696e05 100644
--- a/gremlin-test/features/map/MergeEdge.feature
+++ b/gremlin-test/features/map/MergeEdge.feature
@@ -44,11 +44,11 @@ Feature: Step - mergeE()
   # g_mergeEXlabel_knows_out_marko_in_vadas_weight_05X
   #   - mergeE(Map) specifying out/in for vertices in the match/create with no option()
   #   - no vertices/edges in graph
-  #   - results in two new vertices and one new edge
+  #   - results in error as vertices don't exist
   # g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX
   #   - mergeE(Map) specifying out/in for vertices in the match/create with option(Map)
   #   - no vertices/edges in graph
-  #   - results in two new vertices and one new edge
+  #   - results in error as vertices don't exist
   # g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists
   #   - mergeE(Map) specifying out/in for vertices in the match/create with option(Map)
   #   - vertices and edge already exist
@@ -89,6 +89,10 @@ Feature: Step - mergeE()
   #   - mergeE(Map) using the vertex of current traverser as reference - testing child traversal
   #   - vertex already exists
   #   - results in a self edge
+  # g_injectXlabel_knows_out_marko_in_vadas_label_self_out_vadas_in_vadasX
+  #   - mergeE() using the map of current traverser as reference
+  #   - vertices already exists
+  #   - results in two new edges
 
   Scenario: g_V_mergeEXlabel_self_weight_05X
     Given the empty graph
@@ -186,9 +190,7 @@ Feature: Step - mergeE()
       g.mergeE(xx1)
       """
     When iterated to list
-    Then the result should have a count of 1
-    And the graph should return 2 for count of "g.V()"
-    And the graph should return 1 for count of "g.E().hasLabel(\"knows\").has(\"weight\",0.5)"
+    Then the traversal will raise an error
 
   @UserSuppliedVertexIds
   Scenario: g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX
@@ -201,10 +203,7 @@ Feature: Step - mergeE()
       g.mergeE(xx1).option(Merge.onCreate,xx2).option(Merge.onMatch,xx3)
       """
     When iterated to list
-    Then the result should have a count of 1
-    And the graph should return 2 for count of "g.V()"
-    And the graph should return 1 for count of "g.E().hasLabel(\"knows\").has(\"created\",\"Y\")"
-    And the graph should return 0 for count of "g.E().hasLabel(\"knows\").has(\"created\",\"N\")"
+    Then the traversal will raise an error
 
   @UserSuppliedVertexIds
   Scenario: g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX_exists
@@ -460,4 +459,25 @@ Feature: Step - mergeE()
       """
     When iterated to list
     Then the result should have a count of 1
-    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").out(\"knows\").has(\"person\",\"name\",\"vadas\")"
\ No newline at end of file
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").out(\"knows\").has(\"person\",\"name\",\"vadas\")"
+
+  @UserSuppliedVertexIds
+  Scenario: g_injectXlabel_knows_out_marko_in_vadas_label_self_out_vadas_in_vadasX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property(T.id, 100).property("name", "marko").
+        addV("person").property(T.id, 101).property("name", "vadas")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"knows\", \"D[OUT]\":\"v[100]\", \"D[IN]\":\"v[101]\"}]"
+    And using the parameter xx2 defined as "m[{\"t[label]\": \"self\", \"D[OUT]\":\"v[101]\", \"D[IN]\":\"v[101]\"}]"
+    And the traversal of
+      """
+      g.inject(xx1, xx2).mergeE()
+      """
+    When iterated to list
+    Then the result should have a count of 2
+    And the graph should return 2 for count of "g.V()"
+    And the graph should return 2 for count of "g.E()"
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").out(\"knows\").has(\"person\",\"name\",\"vadas\")"
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"vadas\").out(\"self\").has(\"person\",\"name\",\"vadas\")"
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeTest.java
index c30201c..15dffee 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeTest.java
@@ -37,8 +37,11 @@ import org.junit.runner.RunWith;
 import java.util.Map;
 
 import static org.apache.tinkerpop.gremlin.util.tools.CollectionFactory.asMap;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringEndsWith.endsWith;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
 
 @RunWith(GremlinProcessRunner.class)
 public abstract class MergeEdgeTest extends AbstractGremlinTest {
@@ -112,13 +115,13 @@ public abstract class MergeEdgeTest extends AbstractGremlinTest {
     public void g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX() {
         final Traversal<Edge, Edge> traversal = get_g_mergeEXlabel_knows_out_marko_in_vadasX_optionXonCreate_created_YX_optionXonMatch_created_NX();
         printTraversalForm(traversal);
-        final Edge edge = traversal.next();
-        assertEquals("knows", edge.label());
-        assertEquals(100, edge.outVertex().id());
-        assertEquals(101, edge.inVertex().id());
-        assertEquals("Y", edge.<String>value("created"));
-        assertFalse(traversal.hasNext());
-        assertEquals(1, IteratorUtils.count(g.E()));
+        try {
+            traversal.next();
+            fail("Should have failed as vertices are not created");
+        } catch (Exception ex) {
+            assertThat(ex.getMessage(), endsWith("could not be found and edge could not be created"));
+        }
+        assertEquals(0, IteratorUtils.count(g.E()));
     }
 
     @Test