Skip to content

Commit 0f90b39

Browse files
committed
TINKERPOP-3223 Fixed bug in SubgraphStrategy
When both edge and vertex filter are supplied, wrapped both in a TraversalFilter so that if someone gets fancy with map-like steps it doesn't break the traversal pipeline. Added docs to say that its not recommended that you do stuff like that, even if it works. CTR
1 parent 61c37a1 commit 0f90b39

8 files changed

Lines changed: 27 additions & 2 deletions

File tree

CHANGELOG.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
2424
=== TinkerPop 3.7.6 (NOT OFFICIALLY RELEASED YET)
2525
2626
* Integrated Python driver examples into automated build process to ensure examples remain functional.
27+
* Fixed bug in `SubgraphStrategy` where specifying `edges` and `vertices` filters that had `map`-type steps could generate an error.
2728
* Added `closeSessionPostGraphOp` to the Gremlin Server settings to indicate that the `Session` should be closed on either a successful commit or rollback.
2829
2930
[[release-3-7-5]]

docs/src/reference/the-traversal.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6058,6 +6058,9 @@ g.V().outE().inV().
60586058
by('name')
60596059
----
60606060
6061+
WARNING: It is not advisable to provide filtering traversals that do more than just filter (e.g. mutation steps,
6062+
side-effects, etc.) - prefer use of the standard `has()` step variations for best results.
6063+
60616064
=== VertexProgramDenyStrategy
60626065
60636066
Like the `ReadOnlyStrategy`, the `VertexProgramDenyStrategy` denies the execution of specific traversals. A `Traversal`

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.tinkerpop.gremlin.process.traversal.Step;
2424
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
2525
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
26+
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
2627
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
2728
import org.apache.tinkerpop.gremlin.process.traversal.lambda.ValueTraversal;
2829
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
@@ -289,7 +290,8 @@ public void apply(final Traversal.Admin<?, ?> traversal) {
289290
TraversalHelper.applyTraversalRecursively(t -> t.getStartStep().addLabel(MARKER), vertexPredicate);
290291
return Optional.of(vertexPredicate);
291292
} else {
292-
final Traversal.Admin<Edge, ?> ec = edgeCriterion.clone();
293+
final Traversal.Admin<Edge, ?> ec = new DefaultGraphTraversal<>();
294+
ec.addStep(new TraversalFilterStep<>(ec, edgeCriterion.clone()));
293295
ec.addStep(new TraversalFilterStep<>(ec, vertexPredicate));
294296
TraversalHelper.applyTraversalRecursively(t -> t.getStartStep().addLabel(MARKER), ec);
295297
return Optional.of(ec);

gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ private static IDictionary<string, List<Func<GraphTraversalSource, IDictionary<s
499499
{"g_withStrategiesXSubgraphStrategyXsubgraphDXX_EX12X_bothV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new SubgraphStrategy(checkAdjacentVertices: false, vertices: __.Has("name",P.Within(new List<object> {"josh", "lop", "ripple"})), edges: __.Or(__.Has("weight",0.4).HasLabel("created"),__.Has("weight",1.0).HasLabel("created")))).E(p["eid12"]).BothV()}},
500500
{"g_withStrategiesXSubgraphStrategyXsubgraphDXX_EX9X_bothV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new SubgraphStrategy(checkAdjacentVertices: false, vertices: __.Has("name",P.Within(new List<object> {"josh", "lop", "ripple"})), edges: __.Or(__.Has("weight",0.4).HasLabel("created"),__.Has("weight",1.0).HasLabel("created")))).E(p["eid9"]).BothV()}},
501501
{"g_withStrategiesXSubgraphStrategyXcheckAdjacentVertices_subgraphDXX_EX9X_bothV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new SubgraphStrategy(checkAdjacentVertices: true, vertices: __.Has("name",P.Within(new List<object> {"josh", "lop", "ripple"})), edges: __.Or(__.Has("weight",0.4).HasLabel("created"),__.Has("weight",1.0).HasLabel("created")))).E(p["eid9"]).BothV()}},
502+
{"g_withStrategiesXSubgraphStrategyXuseMapStepsInFilterX_E", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithStrategies(new SubgraphStrategy(checkAdjacentVertices: true, vertices: __.Values<object>("name").Is(P.Within(new List<object> {"lop", "josh"})), edges: __.Label().Is(P.Eq("created")))).E()}},
502503
{"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko").AddV("person").Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property("name","lop").Property("lang","java").As("lop").AddV("person").Property("name","josh").Property("age",32).As("josh").AddV("software").Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight",0.5).AddE("knows").From("marko").To("josh").Property("weight",1.0).AddE("created").From("marko").To("lop").Property("weight",0.4).AddE("created").From("josh").To("ripple").Property("weight",1.0).AddE("created").From("josh").To("lop").Property("weight",0.4).AddE("created").From("peter").To("lop").Property("weight",0.2), (g,p) =>g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a"), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).InE()}},
503504
{"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko").AddV("person").Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property("name","lop").Property("lang","java").As("lop").AddV("person").Property("name","josh").Property("age",32).As("josh").AddV("software").Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight",0.5).AddE("knows").From("marko").To("josh").Property("weight",1.0).AddE("created").From("marko").To("lop").Property("weight",0.4).AddE("created").From("josh").To("ripple").Property("weight",1.0).AddE("created").From("josh").To("lop").Property("weight",0.4).AddE("created").From("peter").To("lop").Property("weight",0.2), (g,p) =>g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a").Property("weight",2.0), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).BothE(), (g,p) =>g.V(p["vid1"]).InE().Has("weight",2.0)}},
504505
{"g_V_outE_propertyXweight_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name","marko").Property("age",29).As("marko").AddV("person").Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property("name","lop").Property("lang","java").As("lop").AddV("person").Property("name","josh").Property("age",32).As("josh").AddV("software").Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight",0.5).AddE("knows").From("marko").To("josh").Property("weight",1.0).AddE("created").From("marko").To("lop").Property("weight",0.4).AddE("created").From("josh").To("ripple").Property("weight",1.0).AddE("created").From("josh").To("lop").Property("weight",0.4).AddE("created").From("peter").To("lop").Property("weight",0.2), (g,p) =>g.V().OutE().Property("weight",null), (g,p) =>g.E().Properties<object>("weight")}},

gremlin-go/driver/cucumber/gremlin.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
470470
"g_withStrategiesXSubgraphStrategyXsubgraphDXX_EX12X_bothV": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.SubgraphStrategy(gremlingo.SubgraphStrategyConfig{CheckAdjacentVertices: false, Vertices: gremlingo.T__.Has("name", gremlingo.P.Within([]interface{}{"josh", "lop", "ripple"})), Edges: gremlingo.T__.Or(gremlingo.T__.Has("weight", 0.4).HasLabel("created"), gremlingo.T__.Has("weight", 1.0).HasLabel("created"))})).E(p["eid12"]).BothV()}},
471471
"g_withStrategiesXSubgraphStrategyXsubgraphDXX_EX9X_bothV": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.SubgraphStrategy(gremlingo.SubgraphStrategyConfig{CheckAdjacentVertices: false, Vertices: gremlingo.T__.Has("name", gremlingo.P.Within([]interface{}{"josh", "lop", "ripple"})), Edges: gremlingo.T__.Or(gremlingo.T__.Has("weight", 0.4).HasLabel("created"), gremlingo.T__.Has("weight", 1.0).HasLabel("created"))})).E(p["eid9"]).BothV()}},
472472
"g_withStrategiesXSubgraphStrategyXcheckAdjacentVertices_subgraphDXX_EX9X_bothV": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.SubgraphStrategy(gremlingo.SubgraphStrategyConfig{CheckAdjacentVertices: true, Vertices: gremlingo.T__.Has("name", gremlingo.P.Within([]interface{}{"josh", "lop", "ripple"})), Edges: gremlingo.T__.Or(gremlingo.T__.Has("weight", 0.4).HasLabel("created"), gremlingo.T__.Has("weight", 1.0).HasLabel("created"))})).E(p["eid9"]).BothV()}},
473+
"g_withStrategiesXSubgraphStrategyXuseMapStepsInFilterX_E": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithStrategies(gremlingo.SubgraphStrategy(gremlingo.SubgraphStrategyConfig{CheckAdjacentVertices: true, Vertices: gremlingo.T__.Values("name").Is(gremlingo.P.Within([]interface{}{"lop", "josh"})), Edges: gremlingo.T__.Label().Is(gremlingo.P.Eq("created"))})).E()}},
473474
"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property("weight", 1.0).AddE("created").From("marko").To("lop").Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property("weight", 1.0).AddE("created").From("josh").To("lop").Property("weight", 0.4).AddE("created").From("peter").To("lop").Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).InE()}},
474475
"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property("weight", 1.0).AddE("created").From("marko").To("lop").Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property("weight", 1.0).AddE("created").From("josh").To("lop").Property("weight", 0.4).AddE("created").From("peter").To("lop").Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a").Property("weight", 2.0)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).BothE()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).InE().Has("weight", 2.0)}},
475476
"g_V_outE_propertyXweight_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property("weight", 1.0).AddE("created").From("marko").To("lop").Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property("weight", 1.0).AddE("created").From("josh").To("lop").Property("weight", 0.4).AddE("created").From("peter").To("lop").Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().OutE().Property("weight", nil)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Properties("weight")}},

gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)