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 2023/10/13 16:13:12 UTC

[tinkerpop] branch master updated: TINKERPOP-3000 Fixed bug in union() start

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 7be80b3082 TINKERPOP-3000 Fixed bug in union() start
7be80b3082 is described below

commit 7be80b3082303124a682f56ff0272eb23ffa85a2
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Fri Oct 13 12:12:13 2023 -0400

    TINKERPOP-3000 Fixed bug in union() start
    
    Path history should start with the child traversals to union() CTR
---
 .../process/traversal/step/branch/UnionStep.java   | 36 ++++++++-
 .../traverser/B_LP_O_P_S_SE_SL_Traverser.java      |  5 ++
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  6 +-
 gremlin-go/driver/cucumber/gremlin.go              |  6 +-
 .../gremlin-javascript/test/cucumber/gremlin.js    |  6 +-
 gremlin-python/src/main/python/radish/gremlin.py   |  6 +-
 .../gremlin/test/features/branch/Union.feature     | 91 +++++++++++++++++-----
 7 files changed, 132 insertions(+), 24 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
index 96060821c8..eb4a32c9d8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
@@ -34,9 +34,21 @@ import java.util.Iterator;
  */
 public class UnionStep<S, E> extends BranchStep<S, E, Pick> {
 
+    /**
+     * Determines if this step is configured to be used as a start step.
+     */
     private final boolean isStart;
+
+    /**
+     * Is this the first iteration through the step.
+     */
     protected boolean first = true;
 
+    /**
+     * A placeholder object used to kick off the first traverser in the union.
+     */
+    static final Object UNION_STARTER = new Object();
+
     public UnionStep(final Traversal.Admin traversal, final boolean isStart, final Traversal.Admin<?, E>... unionTraversals) {
         super(traversal);
         this.isStart = isStart;
@@ -50,15 +62,35 @@ public class UnionStep<S, E> extends BranchStep<S, E, Pick> {
         this(traversal, false, unionTraversals);
     }
 
+    public boolean isStart() {
+        return isStart;
+    }
+
     @Override
     protected Traverser.Admin<E> processNextStart() {
         // when it's a start step a traverser needs to be created to kick off the traversal.
         if (isStart && first) {
             first = false;
             final TraverserGenerator generator = this.getTraversal().getTraverserGenerator();
-            this.addStart(generator.generate(false, (Step) this, 1L));
+            final Traverser.Admin<S> traverser = generator.generate(UNION_STARTER, (Step) this, 1L);
+
+            // immediately drop the path which would include "false" otherwise. let the path start with the
+            // traversers produced from the children to the union()
+            traverser.dropPath();
+            this.addStart(traverser);
+        }
+
+        // if this isStart then loop through the next starts until we find one that doesn't hold the
+        // UNION_STARTER and return that. this deals with inject() which is always a start step even
+        // when used mid-traversal.
+        Traverser.Admin<E> t = super.processNextStart();
+        if (isStart) {
+            while (t != null && t.get() == UNION_STARTER) {
+                t = super.processNextStart();
+            }
         }
-        return super.processNextStart();
+
+        return t;
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_P_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_P_S_SE_SL_Traverser.java
index 7e603dc44c..ae9fef3d6a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_P_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_P_S_SE_SL_Traverser.java
@@ -73,6 +73,11 @@ public class B_LP_O_P_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> {
         return clone;
     }
 
+    @Override
+    public void dropPath() {
+        path = ImmutablePath.make();
+    }
+
     @Override
     public void addLabels(final Set<String> labels) {
         this.path = this.path.extend(labels);
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index c61ad4a975..a763f02f91 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -117,10 +117,13 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Repeat("a",__.Out("knows").Repeat("b",__.Out("created").Filter(__.Loops("a").Is(0))).Emit()).Emit().Values<object>("lang")}}, 
                {"g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid6"]).Repeat("a",__.Both("created").SimplePath()).Emit(__.Repeat("b",__.Both("knows")).Until(__.Loops("b").As("b").Where(__.Loops("a").As("b"))).Has("name","vadas")).Dedup().Values<object>("name")}}, 
                {"g_unionXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>()}}, 
-               {"g_unionXconstantX1X_constantX2X_constantX3XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.Constant<object>(p["xx1"]),__.Constant<object>(p["xx2"]),__.Constant<object>(p["xx3"]))}}, 
                {"g_unionXV_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.V().Values<object>("name"))}}, 
                {"g_unionXVXv1X_VX4XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.V((Vertex) p["v1"]),__.V((Vertex) p["v4"])).Values<object>("name")}}, 
                {"g_unionXV_hasLabelXsoftwareX_V_hasLabelXpersonXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.V().HasLabel("software"),__.V().HasLabel("person")).Values<object>("name")}}, 
+               {"g_unionXV_out_out_V_hasLabelXsoftwareXX_path", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.V().Out().Out(),__.V().HasLabel("software")).Path()}}, 
+               {"g_unionXV_out_out_V_hasLabelXsoftwareXX_path_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.V().Out().Out(),__.V().HasLabel("software")).Path().By("name")}}, 
+               {"g_unionXunionXV_out_outX_V_hasLabelXsoftwareXX_path_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.Union<object>(__.V().Out().Out()),__.V().HasLabel("software")).Path().By("name")}}, 
+               {"g_unionXinjectX1X_injectX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.Inject(1),__.Inject(2))}}, 
                {"g_V_unionXconstantX1X_constantX2X_constantX3XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v2"]).Union<object>(__.Constant<object>(p["xx1"]),__.Constant<object>(p["xx2"]),__.Constant<object>(p["xx3"]))}}, 
                {"g_V_unionXout__inX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Union<object>(__.Out(),__.In()).Values<object>("name")}}, 
                {"g_VX1X_unionXrepeatXoutX_timesX2X__outX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Union<object>(__.Repeat(__.Out()).Times(2),__.Out()).Values<object>("name")}}, 
@@ -130,6 +133,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Union<object>(__.OutE().Count(),__.InE().Count(),__.OutE().Values<object>("weight").Sum<object>())}}, 
                {"g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Local<object>(__.Union<object>(__.OutE().Count(),__.InE().Count(),__.OutE().Values<object>("weight").Sum<object>()))}}, 
                {"g_VX1_2X_localXunionXcountXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Local<object>(__.Union<object>(__.Count()))}}, 
+               {"g_unionXaddVXpersonX_propertyXname_aliceX_addVXpersonX_propertyXname_bobX_addVXpersonX_propertyXname_chrisX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Union<object>(__.AddV("person").Property("name","alice"),__.AddV("person").Property("name","bob"),__.AddV("person").Property("name","chris")).Values<object>("name")}}, 
                {"g_V_valuesXageX_allXgtX32XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").All(P.Gt(32))}}, 
                {"g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXgtX33XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(__.Is(P.Gt(33))).Fold().All(P.Gt(33))}}, 
                {"g_V_valuesXageX_order_byXdescX_fold_allXgtX10XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().By(Order.Desc).Fold().All(P.Gt(10))}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index e2f3134328..458abafba2 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -88,10 +88,13 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Repeat("a", gremlingo.T__.Out("knows").Repeat("b", gremlingo.T__.Out("created").Filter(gremlingo.T__.Loops("a").Is(0))).Emit()).Emit().Values("lang")}}, 
     "g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid6"]).Repeat("a", gremlingo.T__.Both("created").SimplePath()).Emit(gremlingo.T__.Repeat("b", gremlingo.T__.Both("knows")).Until(gremlingo.T__.Loops("b").As("b").Where(gremlingo.T__.Loops("a").As("b"))).Has("name", "vadas")).Dedup().Value [...]
     "g_unionXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union()}}, 
-    "g_unionXconstantX1X_constantX2X_constantX3XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.Constant(p["xx1"]), gremlingo.T__.Constant(p["xx2"]), gremlingo.T__.Constant(p["xx3"]))}}, 
     "g_unionXV_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.V().Values("name"))}}, 
     "g_unionXVXv1X_VX4XX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.V(p["v1"]), gremlingo.T__.V(p["v4"])).Values("name")}}, 
     "g_unionXV_hasLabelXsoftwareX_V_hasLabelXpersonXX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.V().HasLabel("software"), gremlingo.T__.V().HasLabel("person")).Values("name")}}, 
+    "g_unionXV_out_out_V_hasLabelXsoftwareXX_path": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.V().Out().Out(), gremlingo.T__.V().HasLabel("software")).Path()}}, 
+    "g_unionXV_out_out_V_hasLabelXsoftwareXX_path_byXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.V().Out().Out(), gremlingo.T__.V().HasLabel("software")).Path().By("name")}}, 
+    "g_unionXunionXV_out_outX_V_hasLabelXsoftwareXX_path_byXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.Union(gremlingo.T__.V().Out().Out()), gremlingo.T__.V().HasLabel("software")).Path().By("name")}}, 
+    "g_unionXinjectX1X_injectX2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.Inject(1), gremlingo.T__.Inject(2))}}, 
     "g_V_unionXconstantX1X_constantX2X_constantX3XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["v2"]).Union(gremlingo.T__.Constant(p["xx1"]), gremlingo.T__.Constant(p["xx2"]), gremlingo.T__.Constant(p["xx3"]))}}, 
     "g_V_unionXout__inX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Union(gremlingo.T__.Out(), gremlingo.T__.In()).Values("name")}}, 
     "g_VX1X_unionXrepeatXoutX_timesX2X__outX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Union(gremlingo.T__.Repeat(gremlingo.T__.Out()).Times(2), gremlingo.T__.Out()).Values("name")}}, 
@@ -101,6 +104,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Union(gremlingo.T__.OutE().Count(), gremlingo.T__.InE().Count(), gremlingo.T__.OutE().Values("weight").Sum())}}, 
     "g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Local(gremlingo.T__.Union(gremlingo.T__.OutE().Count(), gremlingo.T__.InE().Count(), gremlingo.T__.OutE().Values("weight").Sum()))}}, 
     "g_VX1_2X_localXunionXcountXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Local(gremlingo.T__.Union(gremlingo.T__.Count()))}}, 
+    "g_unionXaddVXpersonX_propertyXname_aliceX_addVXpersonX_propertyXname_bobX_addVXpersonX_propertyXname_chrisX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Union(gremlingo.T__.AddV("person").Property("name", "alice"), gremlingo.T__.AddV("person").Property("name", "bob"), gremlingo.T__.AddV("person").Property("name", "chris")).Values("name")}}, 
     "g_V_valuesXageX_allXgtX32XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").All(gremlingo.P.Gt(32))}}, 
     "g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXgtX33XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.T__.Is(gremlingo.P.Gt(33))).Fold().All(gremlingo.P.Gt(33))}}, 
     "g_V_valuesXageX_order_byXdescX_fold_allXgtX10XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().By(gremlingo.Order.Desc).Fold().All(gremlingo.P.Gt(10))}}, 
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 5b7715da9f..d1ecb4216b 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
@@ -108,10 +108,13 @@ const gremlins = {
     g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang: [function({g}) { return g.V().repeat("a",__.out("knows").repeat("b",__.out("created").filter(__.loops("a").is(0))).emit()).emit().values("lang") }], 
     g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name: [function({g, vid6}) { return g.V(vid6).repeat("a",__.both("created").simplePath()).emit(__.repeat("b",__.both("knows")).until(__.loops("b").as("b").where(__.loops("a").as("b"))).has("name","vadas")).dedup().values("name") }], 
     g_unionXX: [function({g}) { return g.union() }], 
-    g_unionXconstantX1X_constantX2X_constantX3XX: [function({g, xx1, xx3, xx2}) { return g.union(__.constant(xx1),__.constant(xx2),__.constant(xx3)) }], 
     g_unionXV_name: [function({g}) { return g.union(__.V().values("name")) }], 
     g_unionXVXv1X_VX4XX_name: [function({g, v4, v1}) { return g.union(__.V(v1),__.V(v4)).values("name") }], 
     g_unionXV_hasLabelXsoftwareX_V_hasLabelXpersonXX_name: [function({g}) { return g.union(__.V().hasLabel("software"),__.V().hasLabel("person")).values("name") }], 
+    g_unionXV_out_out_V_hasLabelXsoftwareXX_path: [function({g}) { return g.union(__.V().out().out(),__.V().hasLabel("software")).path() }], 
+    g_unionXV_out_out_V_hasLabelXsoftwareXX_path_byXnameX: [function({g}) { return g.union(__.V().out().out(),__.V().hasLabel("software")).path().by("name") }], 
+    g_unionXunionXV_out_outX_V_hasLabelXsoftwareXX_path_byXnameX: [function({g}) { return g.union(__.union(__.V().out().out()),__.V().hasLabel("software")).path().by("name") }], 
+    g_unionXinjectX1X_injectX2X: [function({g}) { return g.union(__.inject(1),__.inject(2)) }], 
     g_V_unionXconstantX1X_constantX2X_constantX3XX: [function({g, xx1, xx3, xx2, v2}) { return g.V(v2).union(__.constant(xx1),__.constant(xx2),__.constant(xx3)) }], 
     g_V_unionXout__inX_name: [function({g}) { return g.V().union(__.out(),__.in_()).values("name") }], 
     g_VX1X_unionXrepeatXoutX_timesX2X__outX_name: [function({g, vid1}) { return g.V(vid1).union(__.repeat(__.out()).times(2),__.out()).values("name") }], 
@@ -121,6 +124,7 @@ const gremlins = {
     g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).union(__.outE().count(),__.inE().count(),__.outE().values("weight").sum()) }], 
     g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).local(__.union(__.outE().count(),__.inE().count(),__.outE().values("weight").sum())) }], 
     g_VX1_2X_localXunionXcountXX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).local(__.union(__.count())) }], 
+    g_unionXaddVXpersonX_propertyXname_aliceX_addVXpersonX_propertyXname_bobX_addVXpersonX_propertyXname_chrisX_name: [function({g}) { return g.union(__.addV("person").property("name","alice"),__.addV("person").property("name","bob"),__.addV("person").property("name","chris")).values("name") }], 
     g_V_valuesXageX_allXgtX32XX: [function({g}) { return g.V().values("age").all(P.gt(32)) }], 
     g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXgtX33XX: [function({g}) { return g.V().values("age").where(__.is(P.gt(33))).fold().all(P.gt(33)) }], 
     g_V_valuesXageX_order_byXdescX_fold_allXgtX10XX: [function({g}) { return g.V().values("age").order().by(Order.desc).fold().all(P.gt(10)) }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 3865df63c5..6a1f704358 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -90,10 +90,13 @@ world.gremlins = {
     'g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang': [(lambda g:g.V().repeat('a',__.out('knows').repeat('b',__.out('created').filter_(__.loops('a').is_(0))).emit()).emit().lang)], 
     'g_VX6X_repeatXa_bothXcreatedX_simplePathX_emitXrepeatXb_bothXknowsXX_untilXloopsXbX_asXb_whereXloopsXaX_asXbX_hasXname_vadasXX_dedup_name': [(lambda g, vid6=None:g.V(vid6).repeat('a',__.both('created').simplePath()).emit(__.repeat('b',__.both('knows')).until(__.loops('b').as_('b').where(__.loops('a').as_('b'))).has('name','vadas')).dedup().name)], 
     'g_unionXX': [(lambda g:g.union())], 
-    'g_unionXconstantX1X_constantX2X_constantX3XX': [(lambda g, xx1=None,xx3=None,xx2=None:g.union(__.constant(xx1),__.constant(xx2),__.constant(xx3)))], 
     'g_unionXV_name': [(lambda g:g.union(__.V().name))], 
     'g_unionXVXv1X_VX4XX_name': [(lambda g, v4=None,v1=None:g.union(__.V(v1),__.V(v4)).name)], 
     'g_unionXV_hasLabelXsoftwareX_V_hasLabelXpersonXX_name': [(lambda g:g.union(__.V().hasLabel('software'),__.V().hasLabel('person')).name)], 
+    'g_unionXV_out_out_V_hasLabelXsoftwareXX_path': [(lambda g:g.union(__.V().out().out(),__.V().hasLabel('software')).path())], 
+    'g_unionXV_out_out_V_hasLabelXsoftwareXX_path_byXnameX': [(lambda g:g.union(__.V().out().out(),__.V().hasLabel('software')).path().by('name'))], 
+    'g_unionXunionXV_out_outX_V_hasLabelXsoftwareXX_path_byXnameX': [(lambda g:g.union(__.union(__.V().out().out()),__.V().hasLabel('software')).path().by('name'))], 
+    'g_unionXinjectX1X_injectX2X': [(lambda g:g.union(__.inject(1),__.inject(2)))], 
     'g_V_unionXconstantX1X_constantX2X_constantX3XX': [(lambda g, xx1=None,xx3=None,xx2=None,v2=None:g.V(v2).union(__.constant(xx1),__.constant(xx2),__.constant(xx3)))], 
     'g_V_unionXout__inX_name': [(lambda g:g.V().union(__.out(),__.in_()).name)], 
     'g_VX1X_unionXrepeatXoutX_timesX2X__outX_name': [(lambda g, vid1=None:g.V(vid1).union(__.repeat(__.out()).times(2),__.out()).name)], 
@@ -103,6 +106,7 @@ world.gremlins = {
     'g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).union(__.outE().count(),__.inE().count(),__.outE().weight.sum_()))], 
     'g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).local(__.union(__.outE().count(),__.inE().count(),__.outE().weight.sum_())))], 
     'g_VX1_2X_localXunionXcountXX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).local(__.union(__.count())))], 
+    'g_unionXaddVXpersonX_propertyXname_aliceX_addVXpersonX_propertyXname_bobX_addVXpersonX_propertyXname_chrisX_name': [(lambda g:g.union(__.addV('person').property('name','alice'),__.addV('person').property('name','bob'),__.addV('person').property('name','chris')).name)], 
     'g_V_valuesXageX_allXgtX32XX': [(lambda g:g.V().age.all_(P.gt(32)))], 
     'g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXgtX33XX': [(lambda g:g.V().age.where(__.is_(P.gt(33))).fold().all_(P.gt(33)))], 
     'g_V_valuesXageX_order_byXdescX_fold_allXgtX10XX': [(lambda g:g.V().age.order().by(Order.desc).fold().all_(P.gt(10)))], 
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Union.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Union.feature
index c5a99a13c2..c30662afc9 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Union.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Union.feature
@@ -27,24 +27,6 @@ Feature: Step - union()
     When iterated to list
     Then the result should be empty
 
-  # this use of union() is a bit like inject() so just gonna use that tag to ignore
-  @GraphComputerVerificationInjectionNotSupported
-  Scenario: g_unionXconstantX1X_constantX2X_constantX3XX
-    Given the modern graph
-    And using the parameter xx1 defined as "d[1].i"
-    And using the parameter xx2 defined as "d[2].i"
-    And using the parameter xx3 defined as "d[3].i"
-    And the traversal of
-       """
-       g.union(constant(xx1), constant(xx2), constant(xx3))
-       """
-    When iterated to list
-    Then the result should be unordered
-       | result |
-       | d[1].i |
-       | d[2].i |
-       | d[3].i |
-
   @GraphComputerVerificationMidVNotSupported
   Scenario: g_unionXV_name
     Given the modern graph
@@ -94,6 +76,64 @@ Feature: Step - union()
       | ripple |
       | peter  |
 
+  @GraphComputerVerificationMidVNotSupported
+  Scenario: g_unionXV_out_out_V_hasLabelXsoftwareXX_path
+    Given the modern graph
+    And the traversal of
+       """
+       g.union(__.V().out().out(), __.V().hasLabel("software")).path()
+       """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | p[v[marko],v[josh],v[ripple]] |
+      | p[v[marko],v[josh],v[lop]] |
+      | p[v[lop]] |
+      | p[v[ripple]] |
+
+  @GraphComputerVerificationMidVNotSupported
+  Scenario: g_unionXV_out_out_V_hasLabelXsoftwareXX_path_byXnameX
+    Given the modern graph
+    And the traversal of
+       """
+       g.union(__.V().out().out(), __.V().hasLabel("software")).path().by("name")
+       """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | p[marko,josh,ripple] |
+      | p[marko,josh,lop] |
+      | p[lop] |
+      | p[ripple] |
+
+  @GraphComputerVerificationMidVNotSupported
+  Scenario: g_unionXunionXV_out_outX_V_hasLabelXsoftwareXX_path_byXnameX
+    Given the modern graph
+    And the traversal of
+       """
+       g.union(__.union(__.V().out().out()), __.V().hasLabel("software")).path().by("name")
+       """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | p[marko,josh,ripple] |
+      | p[marko,josh,lop] |
+      | p[lop] |
+      | p[ripple] |
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_unionXinjectX1X_injectX2X
+    Given the modern graph
+    And the traversal of
+       """
+       g.union(__.inject(1), __.inject(2))
+       """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[1].i |
+      | d[2].i |
+
   Scenario: g_V_unionXconstantX1X_constantX2X_constantX3XX
     Given the modern graph
     And using the parameter xx1 defined as "d[1].i"
@@ -245,3 +285,18 @@ Feature: Step - union()
       | result |
       | d[1].l   |
       | d[1].l   |
+
+  Scenario: g_unionXaddVXpersonX_propertyXname_aliceX_addVXpersonX_propertyXname_bobX_addVXpersonX_propertyXname_chrisX_name
+    Given the empty graph
+    And the traversal of
+      """
+      g.union(__.addV("person").property("name", "alice"),
+              __.addV("person").property("name", "bob"),
+              __.addV("person").property("name", "chris")).values("name")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | alice |
+      | bob |
+      | chris |
\ No newline at end of file