Add tests and changelog for TINKERPOP-2931 CTR
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 2e26688..94e3507 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -36,6 +36,7 @@
* Improved performance of comparison (equals) between not compatible types and nulls.
* Fixed MergeV/MergeE steps to work when onCreate is immutable map.
* Introduced `Writing` and `Deleting` marker interfaces to identify whether a step can perform write or delete or both on Graph.
+* For mergeV/mergeE, added checks for illegal hidden keys and refactored searchVertices to allow subclasses to override search criteria.
* Added static map capturing possible Traversal steps that shall be added to traversal for a given operator
* Fixed bug which caused some traversals to throw `GremlinTypeErrorException` to users.
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStepTest.java
index cc75190..f5d6406 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStepTest.java
@@ -104,4 +104,60 @@
assertEquals(CollectionFactory.asMap("key1", "value1", "key2", "value2"), onCreateMap);
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithNullKey() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ null, "person");
+ MergeVertexStep.validateMapInput(m, true);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithNullLabelValue() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ T.label, null);
+ MergeVertexStep.validateMapInput(m, false);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithObjectAsLabelValue() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ T.label, new Object());
+ MergeVertexStep.validateMapInput(m, false);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithNullIdValue() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ T.id, null);
+ MergeVertexStep.validateMapInput(m, false);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithNullDirectionValue() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ Direction.IN, null);
+ MergeVertexStep.validateMapInput(m, false);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithHiddenIdKey() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ "~id", 10000);
+ MergeVertexStep.validateMapInput(m, false);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithHiddenLabelKey() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ "~label", "person");
+ MergeVertexStep.validateMapInput(m, false);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldFailToValidateWithHiddenLabelValue() {
+ final Map<Object,Object> m = CollectionFactory.asMap("k", "v",
+ T.label, "~person");
+ MergeVertexStep.validateMapInput(m, false);
+ }
}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index dfc35d0..6580b19 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -698,6 +698,15 @@
{"g_mergeV_onCreate_inheritance_new_2", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"]), (g,p) =>g.V(), (g,p) =>g.V(1).Has("person","name","mike")}},
{"g_mergeV_label_override_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"])}},
{"g_mergeV_id_override_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"]).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx2"])}},
+ {"g_mergeV_hidden_id_key_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_label_key_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_label_value_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_id_key_onCreate_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) new Dictionary<object,object> {}).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_label_key_onCreate_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) new Dictionary<object,object> {}).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_label_value_onCreate_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.MergeV((IDictionary<object,object>) new Dictionary<object,object> {}).Option(Merge.OnCreate, (IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_id_key_onMatch_matched_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("vertex"), (g,p) =>g.MergeV((IDictionary<object,object>) new Dictionary<object,object> {}).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("vertex"), (g,p) =>g.MergeV((IDictionary<object,object>) new Dictionary<object,object> {}).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx1"])}},
+ {"g_mergeV_hidden_label_value_onMatch_matched_prohibited", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("vertex"), (g,p) =>g.MergeV((IDictionary<object,object>) new Dictionary<object,object> {}).Option(Merge.OnMatch, (IDictionary<object,object>) p["xx1"])}},
{"g_V_age_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Min<object>()}},
{"g_V_foo_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("foo").Min<object>()}},
{"g_V_name_min", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Min<object>()}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 4ae84dc..1444206 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -669,6 +669,15 @@
"g_mergeV_onCreate_inheritance_new_2": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).Option(gremlingo.Merge.OnCreate, p["xx2"])}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(1).Has("person", "name", "mike")}},
"g_mergeV_label_override_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).Option(gremlingo.Merge.OnCreate, p["xx2"])}},
"g_mergeV_id_override_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"]).Option(gremlingo.Merge.OnCreate, p["xx2"])}},
+ "g_mergeV_hidden_id_key_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"])}},
+ "g_mergeV_hidden_label_key_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"])}},
+ "g_mergeV_hidden_label_value_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(p["xx1"])}},
+ "g_mergeV_hidden_id_key_onCreate_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnCreate, p["xx1"])}},
+ "g_mergeV_hidden_label_key_onCreate_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnCreate, p["xx1"])}},
+ "g_mergeV_hidden_label_value_onCreate_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnCreate, p["xx1"])}},
+ "g_mergeV_hidden_id_key_onMatch_matched_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("vertex")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, p["xx1"])}},
+ "g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("vertex")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, p["xx1"])}},
+ "g_mergeV_hidden_label_value_onMatch_matched_prohibited": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("vertex")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.MergeV(map[interface{}]interface{}{}).Option(gremlingo.Merge.OnMatch, p["xx1"])}},
"g_V_age_min": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Min()}},
"g_V_foo_min": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("foo").Min()}},
"g_V_name_min": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Min()}},
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 e5d0a51..513042b 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
@@ -688,6 +688,15 @@
g_mergeV_onCreate_inheritance_new_2: [function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onCreate,xx2) }, function({g, xx1, xx2}) { return g.V() }, function({g, xx1, xx2}) { return g.V(1).has("person","name","mike") }],
g_mergeV_label_override_prohibited: [function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onCreate,xx2) }],
g_mergeV_id_override_prohibited: [function({g, xx1, xx2}) { return g.mergeV(xx1).option(Merge.onCreate,xx2) }],
+ g_mergeV_hidden_id_key_prohibited: [function({g, xx1}) { return g.mergeV(xx1) }],
+ g_mergeV_hidden_label_key_prohibited: [function({g, xx1}) { return g.mergeV(xx1) }],
+ g_mergeV_hidden_label_value_prohibited: [function({g, xx1}) { return g.mergeV(xx1) }],
+ g_mergeV_hidden_id_key_onCreate_prohibited: [function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onCreate,xx1) }],
+ g_mergeV_hidden_label_key_onCreate_prohibited: [function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onCreate,xx1) }],
+ g_mergeV_hidden_label_value_onCreate_prohibited: [function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onCreate,xx1) }],
+ g_mergeV_hidden_id_key_onMatch_matched_prohibited: [function({g, xx1}) { return g.addV("vertex") }, function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onMatch,xx1) }],
+ g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited: [function({g, xx1}) { return g.addV("vertex") }, function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onMatch,xx1) }],
+ g_mergeV_hidden_label_value_onMatch_matched_prohibited: [function({g, xx1}) { return g.addV("vertex") }, function({g, xx1}) { return g.mergeV(new Map([])).option(Merge.onMatch,xx1) }],
g_V_age_min: [function({g}) { return g.V().values("age").min() }],
g_V_foo_min: [function({g}) { return g.V().values("foo").min() }],
g_V_name_min: [function({g}) { return g.V().values("name").min() }],
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 188321d..998289b 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -670,6 +670,15 @@
'g_mergeV_onCreate_inheritance_new_2': [(lambda g, xx1=None,xx2=None:g.merge_v(xx1).option(Merge.on_create,xx2)), (lambda g, xx1=None,xx2=None:g.V()), (lambda g, xx1=None,xx2=None:g.V(1).has('person','name','mike'))],
'g_mergeV_label_override_prohibited': [(lambda g, xx1=None,xx2=None:g.merge_v(xx1).option(Merge.on_create,xx2))],
'g_mergeV_id_override_prohibited': [(lambda g, xx1=None,xx2=None:g.merge_v(xx1).option(Merge.on_create,xx2))],
+ 'g_mergeV_hidden_id_key_prohibited': [(lambda g, xx1=None:g.merge_v(xx1))],
+ 'g_mergeV_hidden_label_key_prohibited': [(lambda g, xx1=None:g.merge_v(xx1))],
+ 'g_mergeV_hidden_label_value_prohibited': [(lambda g, xx1=None:g.merge_v(xx1))],
+ 'g_mergeV_hidden_id_key_onCreate_prohibited': [(lambda g, xx1=None:g.merge_v({}).option(Merge.on_create,xx1))],
+ 'g_mergeV_hidden_label_key_onCreate_prohibited': [(lambda g, xx1=None:g.merge_v({}).option(Merge.on_create,xx1))],
+ 'g_mergeV_hidden_label_value_onCreate_prohibited': [(lambda g, xx1=None:g.merge_v({}).option(Merge.on_create,xx1))],
+ 'g_mergeV_hidden_id_key_onMatch_matched_prohibited': [(lambda g, xx1=None:g.addV('vertex')), (lambda g, xx1=None:g.merge_v({}).option(Merge.on_match,xx1))],
+ 'g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited': [(lambda g, xx1=None:g.addV('vertex')), (lambda g, xx1=None:g.merge_v({}).option(Merge.on_match,xx1))],
+ 'g_mergeV_hidden_label_value_onMatch_matched_prohibited': [(lambda g, xx1=None:g.addV('vertex')), (lambda g, xx1=None:g.merge_v({}).option(Merge.on_match,xx1))],
'g_V_age_min': [(lambda g:g.V().age.min_())],
'g_V_foo_min': [(lambda g:g.V().foo.min_())],
'g_V_name_min': [(lambda g:g.V().name.min_())],
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature
index 860918b..91de838 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature
@@ -732,3 +732,113 @@
When iterated to list
Then the traversal will raise an error
+ # cannot use hidden namespace for id key
+ Scenario: g_mergeV_hidden_id_key_prohibited
+ Given the empty graph
+ And using the parameter xx1 defined as "m[{\"~id\": 1}]"
+ And the traversal of
+ """
+ g.mergeV(xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for label key
+ Scenario: g_mergeV_hidden_label_key_prohibited
+ Given the empty graph
+ And using the parameter xx1 defined as "m[{\"~label\":\"vertex\"}]"
+ And the traversal of
+ """
+ g.mergeV(xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for label value
+ Scenario: g_mergeV_hidden_label_value_prohibited
+ Given the empty graph
+ And using the parameter xx1 defined as "m[{\"t[label]\":\"~vertex\"}]"
+ And the traversal of
+ """
+ g.mergeV(xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for id key for onCreate
+ Scenario: g_mergeV_hidden_id_key_onCreate_prohibited
+ Given the empty graph
+ And using the parameter xx1 defined as "m[{\"~id\": 1}]"
+ And the traversal of
+ """
+ g.mergeV([:]).option(Merge.onCreate, xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for label key for onCreate
+ Scenario: g_mergeV_hidden_label_key_onCreate_prohibited
+ Given the empty graph
+ And using the parameter xx1 defined as "m[{\"~label\":\"vertex\"}]"
+ And the traversal of
+ """
+ g.mergeV([:]).option(Merge.onCreate, xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for label value for onCreate
+ Scenario: g_mergeV_hidden_label_value_onCreate_prohibited
+ Given the empty graph
+ And using the parameter xx1 defined as "m[{\"t[label]\":\"~vertex\"}]"
+ And the traversal of
+ """
+ g.mergeV([:]).option(Merge.onCreate, xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for id key for onMatch
+ Scenario: g_mergeV_hidden_id_key_onMatch_matched_prohibited
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("vertex")
+ """
+ And using the parameter xx1 defined as "m[{\"~id\": 1}]"
+ And the traversal of
+ """
+ g.mergeV([:]).option(Merge.onMatch, xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for label key for onMatch
+ Scenario: g_mergeV_hidden_label_key_matched_onMatch_matched_prohibited
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("vertex")
+ """
+ And using the parameter xx1 defined as "m[{\"~label\":\"vertex\"}]"
+ And the traversal of
+ """
+ g.mergeV([:]).option(Merge.onMatch, xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error
+
+ # cannot use hidden namespace for label value for onMatch
+ Scenario: g_mergeV_hidden_label_value_onMatch_matched_prohibited
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("vertex")
+ """
+ And using the parameter xx1 defined as "m[{\"t[label]\":\"~vertex\"}]"
+ And the traversal of
+ """
+ g.mergeV([:]).option(Merge.onMatch, xx1)
+ """
+ When iterated to list
+ Then the traversal will raise an error