This is an automated email from the ASF dual-hosted git repository. colegreer pushed a commit to branch gvalue-range in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 6325b6adc529cee048fc1174956a78f0b2f80595 Author: Cole-Greer <[email protected]> AuthorDate: Wed Jan 15 15:32:54 2025 -0800 WIP add GValue to range(), limit(), skip(), and tail() steps --- .../gremlin/language/grammar/ArgumentVisitor.java | 26 +++++ .../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 ++- gremlin-language/src/main/antlr4/Gremlin.g4 | 16 +-- 9 files changed, 340 insertions(+), 57 deletions(-) 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..cd19752309 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,31 @@ public class ArgumentVisitor extends DefaultGremlinBaseVisitor<Object> { } } + /** + * Alternative to visitIntegerArgument which promotes types to either Long or GValue<Long> + */ + 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..05632f25d6 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(long, long) + */ + 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, long, long) + */ + 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(long) + */ + 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, long) + */ + 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(long) + */ + 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, long) + */ + 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(long) + */ + 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, long) + */ + 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-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
