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