This is an automated email from the ASF dual-hosted git repository.
colegreer 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 d9ab91229d Make range() and related steps parameterizable (#2981)
d9ab91229d is described below
commit d9ab91229d56b9a09e910c41d70566422ee15d6b
Author: Cole Greer <[email protected]>
AuthorDate: Thu Jan 16 16:11:46 2025 -0800
Make range() and related steps parameterizable (#2981)
Extends GValue Parameterization to range(), limit(), skip(), and tail()
steps.
---
docs/src/reference/the-traversal.asciidoc | 4 +
.../gremlin/language/grammar/ArgumentVisitor.java | 28 +++++
.../language/grammar/TraversalMethodVisitor.java | 84 +++++++++++---
.../traversal/dsl/graph/GraphTraversal.java | 125 +++++++++++++++++++++
.../gremlin/process/traversal/dsl/graph/__.java | 56 +++++++++
.../traversal/step/filter/RangeGlobalStep.java | 35 +++---
.../traversal/step/filter/TailGlobalStep.java | 21 ++--
.../process/traversal/step/map/RangeLocalStep.java | 21 ++--
.../process/traversal/step/map/TailLocalStep.java | 13 ++-
.../language/grammar/ArgumentVisitorTest.java | 17 +++
.../gremlin-javascript/test/cucumber/gremlin.js | 8 ++
gremlin-language/src/main/antlr4/Gremlin.g4 | 16 +--
gremlin-python/src/main/python/radish/gremlin.py | 8 ++
.../gremlin/test/features/filter/Range.feature | 86 ++++++++++++++
.../gremlin/test/features/filter/Tail.feature | 26 +++++
15 files changed, 491 insertions(+), 57 deletions(-)
diff --git a/docs/src/reference/the-traversal.asciidoc
b/docs/src/reference/the-traversal.asciidoc
index cae5e05960..eeafb56e9c 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -5210,6 +5210,7 @@ a comparatively slow script compilation, which makes
parameterization essential
|<<vertex-steps,in()>> | String...edgeLabels
|<<vertex-steps,inE()>> | String...edgeLabels
|<<intersect-step,intersect()>> | Object values
+|<<limit-step,limit()>> | Long limit
|<<merge-step,merge()>> | Object values
|<<mergeedge-step,mergeE()>> | Map searchCreate
|<<mergevertex-step,mergeV()>> | Map searchCreate
@@ -5217,6 +5218,9 @@ a comparatively slow script compilation, which makes
parameterization essential
|<<vertex-steps,out()>> | String...edgeLabels
|<<vertex-steps,outE()>> | String...edgeLabels
|<<product-step,product()>> | Object values
+|<<range-step,range()>> | Long low, Long high
+|<<skip-step,skip()>> | Long limit
+|<<tail-step,tail()>> | Long limit
|<<to-step,to()>> | String... edgeLabels, Vertex toVertex
|<<vertex-steps,toE()>> | String...edgeLabels
|===
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java
index e9eec826f4..519563451e 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java
@@ -18,6 +18,7 @@
*/
package org.apache.tinkerpop.gremlin.language.grammar;
+import
org.apache.tinkerpop.gremlin.process.traversal.GremlinTypeErrorException;
import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
@@ -100,6 +101,33 @@ public class ArgumentVisitor extends
DefaultGremlinBaseVisitor<Object> {
}
}
+ /**
+ * Equivalent to {@link
ArgumentVisitor#visitIntegerArgument(GremlinParser.IntegerArgumentContext)}
except this
+ * method promotes output types to either Long or GValue<Long>.
(visitIntegerArgument() may produce byte, short,
+ * int, or long depending on the input script)
+ */
+ public Object parseLong(final GremlinParser.IntegerArgumentContext ctx) {
+ if (ctx.integerLiteral() != null) {
+ return
antlr.genericVisitor.parseIntegral(ctx.integerLiteral()).longValue();
+ } else {
+ Object var = visitVariable(ctx.variable());
+ if (var instanceof Number) {
+ return ((Number) var).longValue();
+ }
+ if (GValue.valueInstanceOf(var, GType.LONG)) {
+ return var;
+ } else if (GValue.valueInstanceOf(var, GType.INTEGER)) {
+ return GValue.ofLong(((GValue<Integer>) var).getName(),
((GValue<Integer>) var).get().longValue());
+ } else if (GValue.valueInstanceOf(var, GType.SHORT)) {
+ return GValue.ofLong(((GValue<Short>) var).getName(),
((GValue<Short>) var).get().longValue());
+ } else if (GValue.valueInstanceOf(var, GType.BYTE)) {
+ return GValue.ofLong(((GValue<Byte>) var).getName(),
((GValue<Byte>) var).get().longValue());
+ } else {
+ throw new GremlinParserException(String.format("Expected
variable [%s] to resolve to an integer type, instead found: %s",
ctx.variable().Identifier().getSymbol(), var.getClass().getName()));
+ }
+ }
+ }
+
@Override
public Object visitBooleanArgument(final
GremlinParser.BooleanArgumentContext ctx) {
if (ctx.booleanLiteral() != null) {
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
index 066b550b67..f7389aa82f 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
@@ -1022,8 +1022,14 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_limit_Scope_long(final
GremlinParser.TraversalMethod_limit_Scope_longContext ctx) {
- return
graphTraversal.limit(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
-
antlr.genericVisitor.parseIntegral(ctx.integerLiteral()).longValue());
+ final Object literalOrVar =
antlr.argumentVisitor.parseLong(ctx.integerArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.LONG)) {
+ return
graphTraversal.limit(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (GValue<Long>) literalOrVar);
+ } else {
+ return
graphTraversal.limit(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (Long) literalOrVar);
+ }
}
/**
@@ -1031,7 +1037,12 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_limit_long(final
GremlinParser.TraversalMethod_limit_longContext ctx) {
- return
graphTraversal.limit(antlr.genericVisitor.parseIntegral(ctx.integerLiteral()).longValue());
+ final Object literalOrVar =
antlr.argumentVisitor.parseLong(ctx.integerArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.LONG)) {
+ return graphTraversal.limit((GValue<Long>) literalOrVar);
+ } else {
+ return graphTraversal.limit((Long) literalOrVar);
+ }
}
/**
@@ -1469,9 +1480,21 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_range_Scope_long_long(final
GremlinParser.TraversalMethod_range_Scope_long_longContext ctx) {
- return
graphTraversal.range(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
-
antlr.genericVisitor.parseIntegral(ctx.integerLiteral(0)).longValue(),
-
antlr.genericVisitor.parseIntegral(ctx.integerLiteral(1)).longValue());
+ Object low = antlr.argumentVisitor.parseLong(ctx.integerArgument(0));
+ Object high = antlr.argumentVisitor.parseLong(ctx.integerArgument(1));
+ if (GValue.valueInstanceOf(low, GType.LONG) ||
GValue.valueInstanceOf(high, GType.LONG)) {
+ if (!GValue.valueInstanceOf(low, GType.LONG)) {
+ low = GValue.ofLong(null, (Long) low);
+ }
+ if (!GValue.valueInstanceOf(high, GType.LONG)) {
+ high = GValue.ofLong(null, (Long) high);
+ }
+ return
graphTraversal.range(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (GValue<Long>) low, (GValue<Long>) high);
+ } else {
+ return
graphTraversal.range(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (Long) low, (Long) high);
+ }
}
/**
@@ -1479,8 +1502,19 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_range_long_long(final
GremlinParser.TraversalMethod_range_long_longContext ctx) {
- return
graphTraversal.range(antlr.genericVisitor.parseIntegral(ctx.integerLiteral(0)).longValue(),
-
antlr.genericVisitor.parseIntegral(ctx.integerLiteral(1)).longValue());
+ Object low = antlr.argumentVisitor.parseLong(ctx.integerArgument(0));
+ Object high = antlr.argumentVisitor.parseLong(ctx.integerArgument(1));
+ if (GValue.valueInstanceOf(low, GType.LONG) ||
GValue.valueInstanceOf(high, GType.LONG)) {
+ if (!GValue.valueInstanceOf(low, GType.LONG)) {
+ low = GValue.ofLong(null, (Long) low);
+ }
+ if (!GValue.valueInstanceOf(high, GType.LONG)) {
+ high = GValue.ofLong(null, (Long) high);
+ }
+ return graphTraversal.range((GValue<Long>) low, (GValue<Long>)
high);
+ } else {
+ return graphTraversal.range((Long) low, (Long) high);
+ }
}
/**
@@ -1594,8 +1628,14 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_skip_Scope_long(final
GremlinParser.TraversalMethod_skip_Scope_longContext ctx) {
- return
graphTraversal.skip(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
-
antlr.genericVisitor.parseIntegral(ctx.integerLiteral()).longValue());
+ final Object literalOrVar =
antlr.argumentVisitor.parseLong(ctx.integerArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.LONG)) {
+ return
graphTraversal.skip(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (GValue<Long>) literalOrVar);
+ } else {
+ return
graphTraversal.skip(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (Long) literalOrVar);
+ }
}
/**
@@ -1603,7 +1643,12 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_skip_long(final
GremlinParser.TraversalMethod_skip_longContext ctx) {
- return
graphTraversal.skip(antlr.genericVisitor.parseIntegral(ctx.integerLiteral()).longValue());
+ final Object literalOrVar =
antlr.argumentVisitor.parseLong(ctx.integerArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.LONG)) {
+ return graphTraversal.skip((GValue<Long>) literalOrVar);
+ } else {
+ return graphTraversal.skip((Long) literalOrVar);
+ }
}
/**
@@ -1659,8 +1704,14 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_tail_Scope_long(final
GremlinParser.TraversalMethod_tail_Scope_longContext ctx) {
- return
graphTraversal.tail(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
-
antlr.genericVisitor.parseIntegral(ctx.integerLiteral()).longValue());
+ final Object literalOrVar =
antlr.argumentVisitor.parseLong(ctx.integerArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.LONG)) {
+ return
graphTraversal.tail(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (GValue<Long>) literalOrVar);
+ } else {
+ return
graphTraversal.tail(TraversalEnumParser.parseTraversalEnumFromContext(Scope.class,
ctx.traversalScope()),
+ (Long) literalOrVar);
+ }
}
/**
@@ -1668,7 +1719,12 @@ public class TraversalMethodVisitor extends
TraversalRootVisitor<GraphTraversal>
*/
@Override
public GraphTraversal visitTraversalMethod_tail_long(final
GremlinParser.TraversalMethod_tail_longContext ctx) {
- return
graphTraversal.tail(antlr.genericVisitor.parseIntegral(ctx.integerLiteral()).longValue());
+ final Object literalOrVar =
antlr.argumentVisitor.parseLong(ctx.integerArgument());
+ if (GValue.valueInstanceOf(literalOrVar, GType.LONG)) {
+ return graphTraversal.tail((GValue<Long>) literalOrVar);
+ } else {
+ return graphTraversal.tail((Long) literalOrVar);
+ }
}
/**
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index a876193578..c93b150002 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -3112,6 +3112,21 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
return this.asAdmin().addStep(new RangeGlobalStep<>(this.asAdmin(),
low, high));
}
+ /**
+ * Filter the objects in the traversal by the number of them to pass
through the stream. Those before the value
+ * of {@code low} do not pass through and those that exceed the value of
{@code high} will end the iteration.
+ *
+ * @param low the number at which to start allowing objects through the
stream
+ * @param high the number at which to end the stream - use {@code -1} to
emit all remaining objects
+ * @return the traversal with an appended {@link RangeGlobalStep}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#range-step"
target="_blank">Reference Documentation - Range Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> range(final GValue<Long> low, final
GValue<Long> high) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.range, low, high);
+ return this.asAdmin().addStep(new RangeGlobalStep<>(this.asAdmin(),
low, high));
+ }
+
/**
* Filter the objects in the traversal by the number of them to pass
through the stream as constrained by the
* {@link Scope}. Those before the value of {@code low} do not pass
through and those that exceed the value of
@@ -3131,6 +3146,25 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
: new RangeLocalStep<>(this.asAdmin(), low, high));
}
+ /**
+ * Filter the objects in the traversal by the number of them to pass
through the stream as constrained by the
+ * {@link Scope}. Those before the value of {@code low} do not pass
through and those that exceed the value of
+ * {@code high} will end the iteration.
+ *
+ * @param scope the scope of how to apply the {@code range}
+ * @param low the number at which to start allowing objects through the
stream
+ * @param high the number at which to end the stream - use {@code -1} to
emit all remaining objects
+ * @return the traversal with an appended {@link RangeGlobalStep} or
{@link RangeLocalStep} depending on {@code scope}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#range-step"
target="_blank">Reference Documentation - Range Step</a>
+ * @since 4.0.0
+ */
+ public default <E2> GraphTraversal<S, E2> range(final Scope scope, final
GValue<Long> low, final GValue<Long> high) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.range, scope, low,
high);
+ return this.asAdmin().addStep(scope.equals(Scope.global)
+ ? new RangeGlobalStep<>(this.asAdmin(), low, high)
+ : new RangeLocalStep<>(this.asAdmin(), low, high));
+ }
+
/**
* Filter the objects in the traversal by the number of them to pass
through the stream, where only the first
* {@code n} objects are allowed as defined by the {@code limit} argument.
@@ -3145,6 +3179,20 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
return this.asAdmin().addStep(new RangeGlobalStep<>(this.asAdmin(), 0,
limit));
}
+ /**
+ * Filter the objects in the traversal by the number of them to pass
through the stream, where only the first
+ * {@code n} objects are allowed as defined by the {@code limit} argument.
+ *
+ * @param limit the number at which to end the stream
+ * @return the traversal with an appended {@link RangeGlobalStep}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#limit-step"
target="_blank">Reference Documentation - Limit Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> limit(final GValue<Long> limit) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.limit, limit);
+ return this.asAdmin().addStep(new RangeGlobalStep<>(this.asAdmin(),
GValue.ofLong(null, 0L), limit));
+ }
+
/**
* Filter the objects in the traversal by the number of them to pass
through the stream given the {@link Scope},
* where only the first {@code n} objects are allowed as defined by the
{@code limit} argument.
@@ -3162,6 +3210,23 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
: new RangeLocalStep<>(this.asAdmin(), 0, limit));
}
+ /**
+ * Filter the objects in the traversal by the number of them to pass
through the stream given the {@link Scope},
+ * where only the first {@code n} objects are allowed as defined by the
{@code limit} argument.
+ *
+ * @param scope the scope of how to apply the {@code limit}
+ * @param limit the number at which to end the stream
+ * @return the traversal with an appended {@link RangeGlobalStep} or
{@link RangeLocalStep} depending on {@code scope}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#limit-step"
target="_blank">Reference Documentation - Limit Step</a>
+ * @since 4.0.0
+ */
+ public default <E2> GraphTraversal<S, E2> limit(final Scope scope, final
GValue<Long> limit) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.limit, scope, limit);
+ return this.asAdmin().addStep(scope.equals(Scope.global)
+ ? new RangeGlobalStep<>(this.asAdmin(), GValue.ofLong(null,
0L), limit)
+ : new RangeLocalStep<>(this.asAdmin(), GValue.ofLong(null,
0L), limit));
+ }
+
/**
* Filters the objects in the traversal emitted as being last objects in
the stream. In this case, only the last
* object will be returned.
@@ -3189,6 +3254,20 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
return this.asAdmin().addStep(new TailGlobalStep<>(this.asAdmin(),
limit));
}
+ /**
+ * Filters the objects in the traversal emitted as being last objects in
the stream. In this case, only the last
+ * {@code n} objects will be returned as defined by the {@code limit}.
+ *
+ * @param limit the number at which to end the stream
+ * @return the traversal with an appended {@link TailGlobalStep}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#tail-step"
target="_blank">Reference Documentation - Tail Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> tail(final GValue<Long> limit) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.tail, limit);
+ return this.asAdmin().addStep(new TailGlobalStep<>(this.asAdmin(),
limit));
+ }
+
/**
* Filters the objects in the traversal emitted as being last objects in
the stream given the {@link Scope}. In
* this case, only the last object in the stream will be returned.
@@ -3222,6 +3301,23 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
: new TailLocalStep<>(this.asAdmin(), limit));
}
+ /**
+ * Filters the objects in the traversal emitted as being last objects in
the stream given the {@link Scope}. In
+ * this case, only the last {@code n} objects will be returned as defined
by the {@code limit}.
+ *
+ * @param scope the scope of how to apply the {@code tail}
+ * @param limit the number at which to end the stream
+ * @return the traversal with an appended {@link TailGlobalStep} or {@link
TailLocalStep} depending on {@code scope}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#tail-step"
target="_blank">Reference Documentation - Tail Step</a>
+ * @since 4.0.0
+ */
+ public default <E2> GraphTraversal<S, E2> tail(final Scope scope, final
GValue<Long> limit) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.tail, scope, limit);
+ return this.asAdmin().addStep(scope.equals(Scope.global)
+ ? new TailGlobalStep<>(this.asAdmin(), limit)
+ : new TailLocalStep<>(this.asAdmin(), limit));
+ }
+
/**
* Filters out the first {@code n} objects in the traversal.
*
@@ -3235,6 +3331,19 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
return this.asAdmin().addStep(new RangeGlobalStep<>(this.asAdmin(),
skip, -1));
}
+ /**
+ * Filters out the first {@code n} objects in the traversal.
+ *
+ * @param skip the number of objects to skip
+ * @return the traversal with an appended {@link RangeGlobalStep}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#skip-step"
target="_blank">Reference Documentation - Skip Step</a>
+ * @since 4.0.0
+ */
+ public default GraphTraversal<S, E> skip(final GValue<Long> skip) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.skip, skip);
+ return this.asAdmin().addStep(new RangeGlobalStep<>(this.asAdmin(),
skip, GValue.ofLong(null, -1L)));
+ }
+
/**
* Filters out the first {@code n} objects in the traversal.
*
@@ -3251,6 +3360,22 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
: new RangeLocalStep<>(this.asAdmin(), skip, -1));
}
+ /**
+ * Filters out the first {@code n} objects in the traversal.
+ *
+ * @param scope the scope of how to apply the {@code tail}
+ * @param skip the number of objects to skip
+ * @return the traversal with an appended {@link RangeGlobalStep} or
{@link RangeLocalStep} depending on {@code scope}
+ * @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#skip-step"
target="_blank">Reference Documentation - Skip Step</a>
+ * @since 4.0.0
+ */
+ public default <E2> GraphTraversal<S, E2> skip(final Scope scope, final
GValue<Long> skip) {
+ this.asAdmin().getGremlinLang().addStep(Symbols.skip, scope, skip);
+ return this.asAdmin().addStep(scope.equals(Scope.global)
+ ? new RangeGlobalStep<>(this.asAdmin(), skip,
GValue.ofLong(null, -1L))
+ : new RangeLocalStep<>(this.asAdmin(), skip,
GValue.ofLong(null, -1L)));
+ }
+
/**
* Once the first {@link Traverser} hits this step, a count down is
started. Once the time limit is up, all remaining traversers are filtered out.
*
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index ac882fe31a..b2285f087e 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -1306,6 +1306,13 @@ public class __ {
return __.<A>start().range(low, high);
}
+ /**
+ * @see GraphTraversal#range(GValue, GValue)
+ */
+ public static <A> GraphTraversal<A, A> range(final GValue<Long> low, final
GValue<Long> high) {
+ return __.<A>start().range(low, high);
+ }
+
/**
* @see GraphTraversal#range(Scope, long, long)
*/
@@ -1313,6 +1320,13 @@ public class __ {
return __.<A>start().range(scope, low, high);
}
+ /**
+ * @see GraphTraversal#range(Scope, GValue, GValue)
+ */
+ public static <A> GraphTraversal<A, A> range(final Scope scope, final
GValue<Long> low, final GValue<Long> high) {
+ return __.<A>start().range(scope, low, high);
+ }
+
/**
* @see GraphTraversal#limit(long)
*/
@@ -1320,6 +1334,13 @@ public class __ {
return __.<A>start().limit(limit);
}
+ /**
+ * @see GraphTraversal#limit(GValue)
+ */
+ public static <A> GraphTraversal<A, A> limit(final GValue<Long> limit) {
+ return __.<A>start().limit(limit);
+ }
+
/**
* @see GraphTraversal#limit(Scope, long)
*/
@@ -1327,6 +1348,13 @@ public class __ {
return __.<A>start().limit(scope, limit);
}
+ /**
+ * @see GraphTraversal#limit(Scope, GValue)
+ */
+ public static <A> GraphTraversal<A, A> limit(final Scope scope, final
GValue<Long> limit) {
+ return __.<A>start().limit(scope, limit);
+ }
+
/**
* @see GraphTraversal#skip(long)
*/
@@ -1334,6 +1362,13 @@ public class __ {
return __.<A>start().skip(skip);
}
+ /**
+ * @see GraphTraversal#skip(GValue)
+ */
+ public static <A> GraphTraversal<A, A> skip(final GValue<Long> skip) {
+ return __.<A>start().skip(skip);
+ }
+
/**
* @see GraphTraversal#skip(Scope, long)
*/
@@ -1341,6 +1376,13 @@ public class __ {
return __.<A>start().skip(scope, skip);
}
+ /**
+ * @see GraphTraversal#skip(Scope, GValue)
+ */
+ public static <A> GraphTraversal<A, A> skip(final Scope scope, final
GValue<Long> skip) {
+ return __.<A>start().skip(scope, skip);
+ }
+
/**
* @see GraphTraversal#tail()
*/
@@ -1355,6 +1397,13 @@ public class __ {
return __.<A>start().tail(limit);
}
+ /**
+ * @see GraphTraversal#tail(GValue)
+ */
+ public static <A> GraphTraversal<A, A> tail(final GValue<Long> limit) {
+ return __.<A>start().tail(limit);
+ }
+
/**
* @see GraphTraversal#tail(Scope)
*/
@@ -1369,6 +1418,13 @@ public class __ {
return __.<A>start().tail(scope, limit);
}
+ /**
+ * @see GraphTraversal#tail(Scope, GValue)
+ */
+ public static <A> GraphTraversal<A, A> tail(final Scope scope, final
GValue<Long> limit) {
+ return __.<A>start().tail(scope, limit);
+ }
+
/**
* @see GraphTraversal#simplePath()
*/
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java
index 9824332785..7b6fc721ab 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java
@@ -23,6 +23,7 @@ import
org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
import org.apache.tinkerpop.gremlin.process.traversal.step.Bypassing;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.Ranging;
import
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
@@ -44,14 +45,18 @@ import java.util.function.BinaryOperator;
*/
public final class RangeGlobalStep<S> extends FilterStep<S> implements
Ranging, Bypassing, Barrier<TraverserSet<S>> {
- private long low;
- private final long high;
+ private GValue<Long> low;
+ private final GValue<Long> high;
private AtomicLong counter = new AtomicLong(0l);
private boolean bypass;
public RangeGlobalStep(final Traversal.Admin traversal, final long low,
final long high) {
+ this(traversal, GValue.ofLong(null, low), GValue.ofLong(null, high));
+ }
+
+ public RangeGlobalStep(final Traversal.Admin traversal, final GValue<Long>
low, final GValue<Long> high) {
super(traversal);
- if (low != -1 && high != -1 && low > high) {
+ if (low.get() != -1 && high.get() != -1 && low.get() > high.get()) {
throw new IllegalArgumentException("Not a legal range: [" + low +
", " + high + ']');
}
this.low = low;
@@ -62,12 +67,12 @@ public final class RangeGlobalStep<S> extends FilterStep<S>
implements Ranging,
protected boolean filter(final Traverser.Admin<S> traverser) {
if (this.bypass) return true;
- if (this.high != -1 && this.counter.get() >= this.high) {
+ if (this.high.get() != -1 && this.counter.get() >= this.high.get()) {
throw FastNoSuchElementException.instance();
}
long avail = traverser.bulk();
- if (this.counter.get() + avail <= this.low) {
+ if (this.counter.get() + avail <= this.low.get()) {
// Will not surpass the low w/ this traverser. Skip and filter the
whole thing.
this.counter.getAndAdd(avail);
return false;
@@ -76,13 +81,13 @@ public final class RangeGlobalStep<S> extends FilterStep<S>
implements Ranging,
// Skip for the low and trim for the high. Both can happen at once.
long toSkip = 0;
- if (this.counter.get() < this.low) {
- toSkip = this.low - this.counter.get();
+ if (this.counter.get() < this.low.get()) {
+ toSkip = this.low.get() - this.counter.get();
}
long toTrim = 0;
- if (this.high != -1 && this.counter.get() + avail >= this.high) {
- toTrim = this.counter.get() + avail - this.high;
+ if (this.high.get() != -1 && this.counter.get() + avail >=
this.high.get()) {
+ toTrim = this.counter.get() + avail - this.high.get();
}
long toEmit = avail - toSkip - toTrim;
@@ -100,17 +105,17 @@ public final class RangeGlobalStep<S> extends
FilterStep<S> implements Ranging,
@Override
public String toString() {
- return StringFactory.stepString(this, this.low, this.high);
+ return StringFactory.stepString(this, this.low.get(), this.high.get());
}
@Override
public long getLowRange() {
- return this.low;
+ return this.low.get();
}
@Override
public long getHighRange() {
- return this.high;
+ return this.high.get();
}
@Override
@@ -122,14 +127,14 @@ public final class RangeGlobalStep<S> extends
FilterStep<S> implements Ranging,
@Override
public int hashCode() {
- return super.hashCode() ^ Long.hashCode(this.low) ^
Long.hashCode(this.high);
+ return super.hashCode() ^ Long.hashCode(this.low.get()) ^
Long.hashCode(this.high.get());
}
@Override
public boolean equals(final Object other) {
if (super.equals(other)) {
final RangeGlobalStep typedOther = (RangeGlobalStep) other;
- return typedOther.low == this.low && typedOther.high == this.high;
+ return typedOther.low.get() == this.low.get() &&
typedOther.high.get() == this.high.get();
}
return false;
}
@@ -142,7 +147,7 @@ public final class RangeGlobalStep<S> extends FilterStep<S>
implements Ranging,
@Override
public MemoryComputeKey<TraverserSet<S>> getMemoryComputeKey() {
- return MemoryComputeKey.of(this.getId(), new
RangeBiOperator<>(this.high), false, true);
+ return MemoryComputeKey.of(this.getId(), new
RangeBiOperator<>(this.high.get()), false, true);
}
@Override
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
index cc746c8bb3..293eba24de 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
@@ -23,6 +23,7 @@ import
org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
import org.apache.tinkerpop.gremlin.process.traversal.step.Bypassing;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
import
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
@@ -41,15 +42,19 @@ import java.util.Set;
*/
public final class TailGlobalStep<S> extends AbstractStep<S, S> implements
Bypassing, Barrier<TraverserSet<S>> {
- private final long limit;
+ private final GValue<Long> limit;
private Deque<Traverser.Admin<S>> tail;
private long tailBulk = 0L;
private boolean bypass = false;
public TailGlobalStep(final Traversal.Admin traversal, final long limit) {
+ this(traversal, GValue.ofLong(null, limit));
+ }
+
+ public TailGlobalStep(final Traversal.Admin traversal, final GValue<Long>
limit) {
super(traversal);
this.limit = limit;
- this.tail = new ArrayDeque<>((int) limit);
+ this.tail = new ArrayDeque<>(limit.get().intValue());
}
public void setBypass(final boolean bypass) {
@@ -69,7 +74,7 @@ public final class TailGlobalStep<S> extends AbstractStep<S,
S> implements Bypas
// Pull the oldest traverser from the tail buffer.
final Traverser.Admin<S> oldest = this.tail.pop();
// Trim any excess from the oldest traverser.
- final long excess = this.tailBulk - this.limit;
+ final long excess = this.tailBulk - this.limit.get();
if (excess > 0) {
oldest.setBulk(oldest.bulk() - excess);
// Account for the loss of excess in the tail buffer
@@ -90,20 +95,20 @@ public final class TailGlobalStep<S> extends
AbstractStep<S, S> implements Bypas
@Override
public String toString() {
- return StringFactory.stepString(this, this.limit);
+ return StringFactory.stepString(this, this.limit.get());
}
@Override
public TailGlobalStep<S> clone() {
final TailGlobalStep<S> clone = (TailGlobalStep<S>) super.clone();
- clone.tail = new ArrayDeque<>((int) this.limit);
+ clone.tail = new ArrayDeque<>(this.limit.get().intValue());
clone.tailBulk = 0L;
return clone;
}
@Override
public int hashCode() {
- return super.hashCode() ^ Long.hashCode(this.limit);
+ return super.hashCode() ^ Long.hashCode(this.limit.get());
}
@Override
@@ -118,7 +123,7 @@ public final class TailGlobalStep<S> extends
AbstractStep<S, S> implements Bypas
while (!this.tail.isEmpty()) {
final Traverser.Admin<S> oldest = this.tail.getFirst();
final long bulk = oldest.bulk();
- if (this.tailBulk - bulk < limit)
+ if (this.tailBulk - bulk < limit.get())
break;
this.tail.pop();
this.tailBulk -= bulk;
@@ -129,7 +134,7 @@ public final class TailGlobalStep<S> extends
AbstractStep<S, S> implements Bypas
@Override
public MemoryComputeKey<TraverserSet<S>> getMemoryComputeKey() {
- return MemoryComputeKey.of(this.getId(), new
RangeGlobalStep.RangeBiOperator<>(this.limit), false, true);
+ return MemoryComputeKey.of(this.getId(), new
RangeGlobalStep.RangeBiOperator<>(this.limit.get()), false, true);
}
@Override
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
index 19b26af911..a1052be995 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
@@ -21,6 +21,7 @@ package
org.apache.tinkerpop.gremlin.process.traversal.step.map;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import
org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -39,12 +40,16 @@ import java.util.Set;
*/
public final class RangeLocalStep<S> extends ScalarMapStep<S, S> {
- private final long low;
- private final long high;
+ private final GValue<Long> low;
+ private final GValue<Long> high;
public RangeLocalStep(final Traversal.Admin traversal, final long low,
final long high) {
+ this(traversal, GValue.ofLong(null, low), GValue.ofLong(null, high));
+ }
+
+ public RangeLocalStep(final Traversal.Admin traversal, final GValue<Long>
low, final GValue<Long> high) {
super(traversal);
- if (low != -1 && high != -1 && low > high) {
+ if (low.get() != -1 && high.get() != -1 && low.get() > high.get()) {
throw new IllegalArgumentException("Not a legal range: [" + low +
", " + high + ']');
}
this.low = low;
@@ -52,18 +57,18 @@ public final class RangeLocalStep<S> extends
ScalarMapStep<S, S> {
}
public long getLowRange() {
- return this.low;
+ return this.low.get();
}
public long getHighRange() {
- return this.high;
+ return this.high.get();
}
@Override
protected S map(final Traverser.Admin<S> traverser) {
final S start = traverser.get();
- return applyRange(start, this.low, this.high);
+ return applyRange(start, this.low.get(), this.high.get());
}
/**
@@ -146,12 +151,12 @@ public final class RangeLocalStep<S> extends
ScalarMapStep<S, S> {
@Override
public String toString() {
- return StringFactory.stepString(this, this.low, this.high);
+ return StringFactory.stepString(this, this.low.get(), this.high.get());
}
@Override
public int hashCode() {
- return super.hashCode() ^ Long.hashCode(this.high) ^
Long.hashCode(this.low);
+ return super.hashCode() ^ Long.hashCode(this.high.get()) ^
Long.hashCode(this.low.get());
}
@Override
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
index 9f9770644f..2dbe084db8 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
@@ -22,6 +22,7 @@ package
org.apache.tinkerpop.gremlin.process.traversal.step.map;
import org.apache.tinkerpop.gremlin.process.traversal.Path;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
@@ -36,9 +37,13 @@ import java.util.Set;
*/
public final class TailLocalStep<S> extends ScalarMapStep<S, S> {
- private final long limit;
+ private final GValue<Long> limit;
public TailLocalStep(final Traversal.Admin traversal, final long limit) {
+ this(traversal, GValue.ofLong(null, limit));
+ }
+
+ public TailLocalStep(final Traversal.Admin traversal, final GValue<Long>
limit) {
super(traversal);
this.limit = limit;
}
@@ -55,19 +60,19 @@ public final class TailLocalStep<S> extends
ScalarMapStep<S, S> {
start instanceof Path ? ((Path) start).size() :
start instanceof Iterable ?
IteratorUtils.count((Iterable) start) :
IteratorUtils.count(IteratorUtils.asIterator(start));
- final long low = high - this.limit;
+ final long low = high - this.limit.get();
final S result = RangeLocalStep.applyRange(start, low, high);
return result;
}
@Override
public String toString() {
- return StringFactory.stepString(this, this.limit);
+ return StringFactory.stepString(this, this.limit.get());
}
@Override
public int hashCode() {
- return super.hashCode() ^ Long.hashCode(this.limit);
+ return super.hashCode() ^ Long.hashCode(this.limit.get());
}
@Override
diff --git
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
index ab5fbdcecb..003039560b 100644
---
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
+++
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
@@ -97,6 +97,18 @@ public class ArgumentVisitorTest {
{Integer.class, "x", GValue.of("x", 0L), createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0L)))},
{Integer.class, "x", 0, createAntlr(new
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0)))},
{Integer.class, "x", 0L, createAntlr(new
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0L)))},
+ {Long.class, "x", new VariableResolverException("x"),
createAntlr(VariableResolver.NoVariableResolver.instance())},
+ {Long.class, "0", 0L, createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
+ {Long.class, "0i", 0L, createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
+ {Long.class, "0L", 0L, createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
+ {Long.class, "x", GValue.ofLong("x", 0L), createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", (byte) 0)))},
+ {Long.class, "x", GValue.ofLong("x", 0L), createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", (short) 0)))},
+ {Long.class, "x", GValue.ofLong("x", 0L), createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0)))},
+ {Long.class, "x", GValue.ofLong("x", 0L), createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0L)))},
+ {Long.class, "x", 0L, createAntlr(new
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", (byte) 0)))},
+ {Long.class, "x", 0L, createAntlr(new
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", (short) 0)))},
+ {Long.class, "x", 0L, createAntlr(new
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0)))},
+ {Long.class, "x", 0L, createAntlr(new
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0L)))},
{Float.class, "x", new VariableResolverException("x"),
createAntlr(VariableResolver.NoVariableResolver.instance())},
{Float.class, "0.0d", 0.0, createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0)))},
{Float.class, "0d", 0.0, createAntlr(new
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0)))},
@@ -163,6 +175,11 @@ public class ArgumentVisitorTest {
final GremlinParser.IntegerArgumentContext ctx =
parser.integerArgument();
return
antlrToLanguage.argumentVisitor.visitIntegerArgument(ctx);
});
+ } else if (clazz.equals(Long.class)) {
+ assertParsing(() -> {
+ final GremlinParser.IntegerArgumentContext ctx =
parser.integerArgument();
+ return antlrToLanguage.argumentVisitor.parseLong(ctx);
+ });
} else if (clazz.equals(Float.class)) {
assertParsing(() -> {
final GremlinParser.FloatArgumentContext ctx =
parser.floatArgument();
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 ac6b67bd2f..006ffd72a4 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
@@ -340,19 +340,25 @@ const gremlins = {
g_V_orXoutEXknowsX__hasXlabel_softwareX_or_hasXage_gte_35XX_name:
[function({g}) { return g.V().or(__.outE("knows"), __.has(T.label,
"software").or().has("age", P.gte(35))).values("name") }],
g_V_asXaX_orXselectXaX_selectXaXX: [function({g}) { return
g.V().as("a").or(__.select("a"), __.select("a")) }],
g_VX1X_out_limitX2X: [function({g, vid1}) { return
g.V(vid1).out().limit(2) }],
+ g_VX1X_out_limitX2varX: [function({g, xx1, vid1}) { return
g.V(vid1).out().limit(xx1) }],
g_V_localXoutE_limitX1X_inVX_limitX3X: [function({g}) { return
g.V().local(__.outE().limit(1)).inV().limit(3) }],
g_VX1X_outXknowsX_outEXcreatedX_rangeX0_1X_inV: [function({g, vid1}) {
return g.V(vid1).out("knows").outE("created").range(0, 1).inV() }],
g_VX1X_outXknowsX_outXcreatedX_rangeX0_1X: [function({g, vid1}) { return
g.V(vid1).out("knows").out("created").range(0, 1) }],
g_VX1X_outXcreatedX_inXcreatedX_rangeX1_3X: [function({g, vid1}) { return
g.V(vid1).out("created").in_("created").range(1, 3) }],
+ g_VX1X_outXcreatedX_inXcreatedX_rangeX1var_3varX: [function({g, xx1, xx2,
vid1}) { return g.V(vid1).out("created").in_("created").range(xx1, xx2) }],
g_VX1X_outXcreatedX_inEXcreatedX_rangeX1_3X_outV: [function({g, vid1}) {
return g.V(vid1).out("created").inE("created").range(1, 3).outV() }],
g_V_repeatXbothX_timesX3X_rangeX5_11X: [function({g}) { return
g.V().repeat(__.both()).times(3).range(5, 11) }],
g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2X:
[function({g}) { return g.V().as("a").in_().as("b").in_().as("c").select("a",
"b", "c").by("name").limit(Scope.local, 2) }],
+ g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2varX:
[function({g, xx1}) { return
g.V().as("a").in_().as("b").in_().as("c").select("a", "b",
"c").by("name").limit(Scope.local, xx1) }],
g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_1X:
[function({g}) { return g.V().as("a").in_().as("b").in_().as("c").select("a",
"b", "c").by("name").limit(Scope.local, 1) }],
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_3X:
[function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a",
"b", "c").by("name").range(Scope.local, 1, 3) }],
+
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1var_3varX:
[function({g, xx1, xx2}) { return
g.V().as("a").out().as("b").out().as("c").select("a", "b",
"c").by("name").range(Scope.local, xx1, xx2) }],
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_2X:
[function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a",
"b", "c").by("name").range(Scope.local, 1, 2) }],
g_V_hasLabelXpersonX_order_byXageX_skipX1X_valuesXnameX: [function({g}) {
return g.V().hasLabel("person").order().by("age").skip(1).values("name") }],
+ g_V_hasLabelXpersonX_order_byXageX_skipX1varX_valuesXnameX: [function({g,
xx1}) { return
g.V().hasLabel("person").order().by("age").skip(xx1).values("name") }],
g_V_foldX_rangeXlocal_6_7X: [function({g}) { return
g.V().fold().range(Scope.local, 6, 7) }],
g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2X: [function({g}) {
return
g.V().outE().values("weight").fold().order(Scope.local).skip(Scope.local, 2)
}],
+ g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2varX: [function({g,
xx1}) { return
g.V().outE().values("weight").fold().order(Scope.local).skip(Scope.local, xx1)
}],
g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X: [function({g}) {
return g.V().hasLabel("person").order().by("age").values("name").skip(1) }],
g_VX1X_valuesXageX_rangeXlocal_20_30X: [function({g, vid1}) { return
g.V(vid1).values("age").range(Scope.local, 20, 30) }],
g_V_mapXin_hasIdX1XX_limitX2X_valuesXnameX: [function({g, vid1}) { return
g.V().map(__.in_().hasId(vid1)).limit(2).values("name") }],
@@ -370,6 +376,7 @@ const gremlins = {
g_V_both_asXaX_both_asXbX_simplePath_path_byXageX__fromXaX_toXbX:
[function({g}) { return
g.V().both().as("a").both().as("b").simplePath().path().by("age").from_("a").to("b")
}],
g_V_valuesXnameX_order_tailXglobal_2X: [function({g}) { return
g.V().values("name").order().tail(Scope.global, 2) }],
g_V_valuesXnameX_order_tailX2X: [function({g}) { return
g.V().values("name").order().tail(2) }],
+ g_V_valuesXnameX_order_tailX2varX: [function({g, xx1}) { return
g.V().values("name").order().tail(xx1) }],
g_V_valuesXnameX_order_tail: [function({g}) { return
g.V().values("name").order().tail() }],
g_V_valuesXnameX_order_tailX7X: [function({g}) { return
g.V().values("name").order().tail(7) }],
g_V_repeatXbothX_timesX3X_tailX7X: [function({g}) { return
g.V().repeat(__.both()).times(3).tail(7) }],
@@ -377,6 +384,7 @@ const gremlins = {
g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocal_1X:
[function({g}) { return
g.V().as("a").out().as("a").out().as("a").select("a").by(__.unfold().values("name").fold()).tail(Scope.local,
1) }],
g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocalX:
[function({g}) { return
g.V().as("a").out().as("a").out().as("a").select("a").by(__.unfold().values("name").fold()).tail(Scope.local)
}],
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2X:
[function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a",
"b", "c").by("name").tail(Scope.local, 2) }],
+ g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2varX:
[function({g, xx1}) { return
g.V().as("a").out().as("b").out().as("c").select("a", "b",
"c").by("name").tail(Scope.local, xx1) }],
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_1X:
[function({g}) { return g.V().as("a").out().as("b").out().as("c").select("a",
"b", "c").by("name").tail(Scope.local, 1) }],
g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_1X:
[function({g}) { return
g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,
"a").by(__.unfold().values("name").fold()).tail(Scope.local, 1) }],
g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocalX:
[function({g}) { return
g.V().as("a").out().as("a").out().as("a").select(Pop.mixed,
"a").by(__.unfold().values("name").fold()).tail(Scope.local) }],
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4
b/gremlin-language/src/main/antlr4/Gremlin.g4
index 8133e751ad..422166578e 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -588,8 +588,8 @@ traversalMethod_label
;
traversalMethod_limit
- : 'limit' LPAREN traversalScope COMMA integerLiteral RPAREN
#traversalMethod_limit_Scope_long
- | 'limit' LPAREN integerLiteral RPAREN #traversalMethod_limit_long
+ : 'limit' LPAREN traversalScope COMMA integerArgument RPAREN
#traversalMethod_limit_Scope_long
+ | 'limit' LPAREN integerArgument RPAREN #traversalMethod_limit_long
;
traversalMethod_local
@@ -720,8 +720,8 @@ traversalMethod_propertyMap
;
traversalMethod_range
- : 'range' LPAREN traversalScope COMMA integerLiteral COMMA integerLiteral
RPAREN #traversalMethod_range_Scope_long_long
- | 'range' LPAREN integerLiteral COMMA integerLiteral RPAREN
#traversalMethod_range_long_long
+ : 'range' LPAREN traversalScope COMMA integerArgument COMMA
integerArgument RPAREN #traversalMethod_range_Scope_long_long
+ | 'range' LPAREN integerArgument COMMA integerArgument RPAREN
#traversalMethod_range_long_long
;
traversalMethod_read
@@ -770,8 +770,8 @@ traversalMethod_simplePath
;
traversalMethod_skip
- : 'skip' LPAREN traversalScope COMMA integerLiteral RPAREN
#traversalMethod_skip_Scope_long
- | 'skip' LPAREN integerLiteral RPAREN #traversalMethod_skip_long
+ : 'skip' LPAREN traversalScope COMMA integerArgument RPAREN
#traversalMethod_skip_Scope_long
+ | 'skip' LPAREN integerArgument RPAREN #traversalMethod_skip_long
;
traversalMethod_store
@@ -790,8 +790,8 @@ traversalMethod_sum
traversalMethod_tail
: 'tail' LPAREN RPAREN #traversalMethod_tail_Empty
| 'tail' LPAREN traversalScope RPAREN #traversalMethod_tail_Scope
- | 'tail' LPAREN traversalScope COMMA integerLiteral RPAREN
#traversalMethod_tail_Scope_long
- | 'tail' LPAREN integerLiteral RPAREN #traversalMethod_tail_long
+ | 'tail' LPAREN traversalScope COMMA integerArgument RPAREN
#traversalMethod_tail_Scope_long
+ | 'tail' LPAREN integerArgument RPAREN #traversalMethod_tail_long
;
traversalMethod_fail
diff --git a/gremlin-python/src/main/python/radish/gremlin.py
b/gremlin-python/src/main/python/radish/gremlin.py
index 247f98b86f..eb81fb997c 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -322,19 +322,25 @@ world.gremlins = {
'g_V_orXoutEXknowsX__hasXlabel_softwareX_or_hasXage_gte_35XX_name':
[(lambda g:g.V().or_(__.out_e('knows'), __.has(T.label,
'software').or_().has('age', P.gte(35))).values('name'))],
'g_V_asXaX_orXselectXaX_selectXaXX': [(lambda
g:g.V().as_('a').or_(__.select('a'), __.select('a')))],
'g_VX1X_out_limitX2X': [(lambda g, vid1=None:g.V(vid1).out().limit(2))],
+ 'g_VX1X_out_limitX2varX': [(lambda g,
xx1=None,vid1=None:g.V(vid1).out().limit(xx1))],
'g_V_localXoutE_limitX1X_inVX_limitX3X': [(lambda
g:g.V().local(__.out_e().limit(1)).in_v().limit(3))],
'g_VX1X_outXknowsX_outEXcreatedX_rangeX0_1X_inV': [(lambda g,
vid1=None:g.V(vid1).out('knows').out_e('created').range_(0, 1).in_v())],
'g_VX1X_outXknowsX_outXcreatedX_rangeX0_1X': [(lambda g,
vid1=None:g.V(vid1).out('knows').out('created').range_(0, 1))],
'g_VX1X_outXcreatedX_inXcreatedX_rangeX1_3X': [(lambda g,
vid1=None:g.V(vid1).out('created').in_('created').range_(1, 3))],
+ 'g_VX1X_outXcreatedX_inXcreatedX_rangeX1var_3varX': [(lambda g,
xx1=None,xx2=None,vid1=None:g.V(vid1).out('created').in_('created').range_(xx1,
xx2))],
'g_VX1X_outXcreatedX_inEXcreatedX_rangeX1_3X_outV': [(lambda g,
vid1=None:g.V(vid1).out('created').in_e('created').range_(1, 3).out_v())],
'g_V_repeatXbothX_timesX3X_rangeX5_11X': [(lambda
g:g.V().repeat(__.both()).times(3).range_(5, 11))],
'g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2X':
[(lambda g:g.V().as_('a').in_().as_('b').in_().as_('c').select('a', 'b',
'c').by('name').limit(Scope.local, 2))],
+ 'g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2varX':
[(lambda g, xx1=None:g.V().as_('a').in_().as_('b').in_().as_('c').select('a',
'b', 'c').by('name').limit(Scope.local, xx1))],
'g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_1X':
[(lambda g:g.V().as_('a').in_().as_('b').in_().as_('c').select('a', 'b',
'c').by('name').limit(Scope.local, 1))],
'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_3X':
[(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a', 'b',
'c').by('name').range_(Scope.local, 1, 3))],
+
'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1var_3varX':
[(lambda g,
xx1=None,xx2=None:g.V().as_('a').out().as_('b').out().as_('c').select('a', 'b',
'c').by('name').range_(Scope.local, xx1, xx2))],
'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_2X':
[(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a', 'b',
'c').by('name').range_(Scope.local, 1, 2))],
'g_V_hasLabelXpersonX_order_byXageX_skipX1X_valuesXnameX': [(lambda
g:g.V().has_label('person').order().by('age').skip(1).values('name'))],
+ 'g_V_hasLabelXpersonX_order_byXageX_skipX1varX_valuesXnameX': [(lambda g,
xx1=None:g.V().has_label('person').order().by('age').skip(xx1).values('name'))],
'g_V_foldX_rangeXlocal_6_7X': [(lambda g:g.V().fold().range_(Scope.local,
6, 7))],
'g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2X': [(lambda
g:g.V().out_e().values('weight').fold().order(Scope.local).skip(Scope.local,
2))],
+ 'g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2varX': [(lambda g,
xx1=None:g.V().out_e().values('weight').fold().order(Scope.local).skip(Scope.local,
xx1))],
'g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X': [(lambda
g:g.V().has_label('person').order().by('age').values('name').skip(1))],
'g_VX1X_valuesXageX_rangeXlocal_20_30X': [(lambda g,
vid1=None:g.V(vid1).values('age').range_(Scope.local, 20, 30))],
'g_V_mapXin_hasIdX1XX_limitX2X_valuesXnameX': [(lambda g,
vid1=None:g.V().map(__.in_().has_id(vid1)).limit(2).values('name'))],
@@ -352,6 +358,7 @@ world.gremlins = {
'g_V_both_asXaX_both_asXbX_simplePath_path_byXageX__fromXaX_toXbX':
[(lambda
g:g.V().both().as_('a').both().as_('b').simple_path().path().by('age').from_('a').to('b'))],
'g_V_valuesXnameX_order_tailXglobal_2X': [(lambda
g:g.V().values('name').order().tail(Scope.global_, 2))],
'g_V_valuesXnameX_order_tailX2X': [(lambda
g:g.V().values('name').order().tail(2))],
+ 'g_V_valuesXnameX_order_tailX2varX': [(lambda g,
xx1=None:g.V().values('name').order().tail(xx1))],
'g_V_valuesXnameX_order_tail': [(lambda
g:g.V().values('name').order().tail())],
'g_V_valuesXnameX_order_tailX7X': [(lambda
g:g.V().values('name').order().tail(7))],
'g_V_repeatXbothX_timesX3X_tailX7X': [(lambda
g:g.V().repeat(__.both()).times(3).tail(7))],
@@ -359,6 +366,7 @@ world.gremlins = {
'g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocal_1X':
[(lambda
g:g.V().as_('a').out().as_('a').out().as_('a').select('a').by(__.unfold().values('name').fold()).tail(Scope.local,
1))],
'g_V_asXaX_out_asXaX_out_asXaX_selectXaX_byXunfold_valuesXnameX_foldX_tailXlocalX':
[(lambda
g:g.V().as_('a').out().as_('a').out().as_('a').select('a').by(__.unfold().values('name').fold()).tail(Scope.local))],
'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2X':
[(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a', 'b',
'c').by('name').tail(Scope.local, 2))],
+ 'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2varX':
[(lambda g, xx1=None:g.V().as_('a').out().as_('b').out().as_('c').select('a',
'b', 'c').by('name').tail(Scope.local, xx1))],
'g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_1X':
[(lambda g:g.V().as_('a').out().as_('b').out().as_('c').select('a', 'b',
'c').by('name').tail(Scope.local, 1))],
'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocal_1X':
[(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,
'a').by(__.unfold().values('name').fold()).tail(Scope.local, 1))],
'g_V_asXaX_out_asXaX_out_asXaX_selectXmixed_aX_byXunfold_valuesXnameX_foldX_tailXlocalX':
[(lambda g:g.V().as_('a').out().as_('a').out().as_('a').select(Pop.mixed,
'a').by(__.unfold().values('name').fold()).tail(Scope.local))],
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature
index d185d47f8e..cae49f7594 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature
@@ -33,6 +33,22 @@ Feature: Step - range()
| v[lop] |
And the result should have a count of 2
+ Scenario: g_VX1X_out_limitX2varX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter xx1 defined as "d[2].i"
+ And the traversal of
+ """
+ g.V(vid1).out().limit(xx1)
+ """
+ When iterated to list
+ Then the result should be of
+ | result |
+ | v[josh] |
+ | v[vadas] |
+ | v[lop] |
+ And the result should have a count of 2
+
Scenario: g_V_localXoutE_limitX1X_inVX_limitX3X
Given the modern graph
And the traversal of
@@ -91,6 +107,23 @@ Feature: Step - range()
| v[peter] |
And the result should have a count of 2
+ Scenario: g_VX1X_outXcreatedX_inXcreatedX_rangeX1var_3varX
+ Given the modern graph
+ And using the parameter vid1 defined as "v[marko].id"
+ And using the parameter xx1 defined as "d[1].i"
+ And using the parameter xx2 defined as "d[3].i"
+ And the traversal of
+ """
+ g.V(vid1).out("created").in("created").range(xx1, xx2)
+ """
+ When iterated to list
+ Then the result should be of
+ | result |
+ | v[marko] |
+ | v[josh] |
+ | v[peter] |
+ And the result should have a count of 2
+
Scenario: g_VX1X_outXcreatedX_inEXcreatedX_rangeX1_3X_outV
Given the modern graph
And using the parameter vid1 defined as "v[marko].id"
@@ -135,6 +168,19 @@ Feature: Step - range()
| m[{"a":"lop","b":"josh"}] |
| m[{"a":"ripple","b":"josh"}] |
+ Scenario:
g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_2varX
+ Given the modern graph
+ And using the parameter xx1 defined as "d[2].i"
+ And the traversal of
+ """
+
g.V().as("a").in().as("b").in().as("c").select("a","b","c").by("name").limit(Scope.local,
xx1)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | m[{"a":"lop","b":"josh"}] |
+ | m[{"a":"ripple","b":"josh"}] |
+
Scenario: g_V_asXaX_in_asXbX_in_asXcX_selectXa_b_cX_byXnameX_limitXlocal_1X
Given the modern graph
And the traversal of
@@ -159,6 +205,20 @@ Feature: Step - range()
| m[{"b":"josh","c":"lop"}] |
| m[{"b":"josh","c":"ripple"}] |
+ Scenario:
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1var_3varX
+ Given the modern graph
+ And using the parameter xx1 defined as "d[1].i"
+ And using the parameter xx2 defined as "d[3].i"
+ And the traversal of
+ """
+
g.V().as("a").out().as("b").out().as("c").select("a","b","c").by("name").range(Scope.local,
xx1, xx2)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | m[{"b":"josh","c":"lop"}] |
+ | m[{"b":"josh","c":"ripple"}] |
+
Scenario:
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_rangeXlocal_1_2X
Given the modern graph
And the traversal of
@@ -184,6 +244,20 @@ Feature: Step - range()
| josh |
| peter |
+ Scenario: g_V_hasLabelXpersonX_order_byXageX_skipX1varX_valuesXnameX
+ Given the modern graph
+ And using the parameter xx1 defined as "d[1].i"
+ And the traversal of
+ """
+ g.V().hasLabel("person").order().by("age").skip(xx1).values("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+ | josh |
+ | peter |
+
@GraphComputerVerificationReferenceOnly
Scenario: g_V_foldX_rangeXlocal_6_7X
Given the modern graph
@@ -205,6 +279,18 @@ Feature: Step - range()
| result |
| l[d[0.4].d,d[0.5].d,d[1.0].d,d[1.0].d] |
+ Scenario: g_V_outE_valuesXweightX_fold_orderXlocalX_skipXlocal_2varX
+ Given the modern graph
+ And using the parameter xx1 defined as "d[2].i"
+ And the traversal of
+ """
+
g.V().outE().values("weight").fold().order(Scope.local).skip(Scope.local, xx1)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | l[d[0.4].d,d[0.5].d,d[1.0].d,d[1.0].d] |
+
Scenario: g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X
Given the modern graph
And the traversal of
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Tail.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Tail.feature
index e8a2284c77..1fb3d215bd 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Tail.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Tail.feature
@@ -42,6 +42,19 @@ Feature: Step - tail()
| ripple |
| vadas |
+ Scenario: g_V_valuesXnameX_order_tailX2varX
+ Given the modern graph
+ And using the parameter xx1 defined as "d[2].i"
+ And the traversal of
+ """
+ g.V().values("name").order().tail(xx1)
+ """
+ When iterated to list
+ Then the result should be ordered
+ | result |
+ | ripple |
+ | vadas |
+
Scenario: g_V_valuesXnameX_order_tail
Given the modern graph
And the traversal of
@@ -127,6 +140,19 @@ Feature: Step - tail()
| m[{"b":"josh","c":"ripple"}] |
| m[{"b":"josh","c":"lop"}] |
+ Scenario:
g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_2varX
+ Given the modern graph
+ And using the parameter xx1 defined as "d[2].i"
+ And the traversal of
+ """
+
g.V().as("a").out().as("b").out().as("c").select("a","b","c").by("name").tail(Scope.local,
xx1)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | m[{"b":"josh","c":"ripple"}] |
+ | m[{"b":"josh","c":"lop"}] |
+
Scenario: g_V_asXaX_out_asXbX_out_asXcX_selectXa_b_cX_byXnameX_tailXlocal_1X
Given the modern graph
And the traversal of