This is an automated email from the ASF dual-hosted git repository. kenhuuu pushed a commit to branch TINKERPOP-2978 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit ff9e0d97294118659bc11079d2b1701ea9132ee3 Author: Ken Hu <[email protected]> AuthorDate: Sun Aug 27 14:36:38 2023 -0700 first run of all list function --- .../grammar/DefaultGremlinBaseVisitor.java | 5 + .../language/grammar/TraversalMethodVisitor.java | 8 ++ .../traversal/dsl/graph/GraphTraversal.java | 15 ++ .../gremlin/process/traversal/dsl/graph/__.java | 5 + .../process/traversal/step/filter/AllStep.java | 74 ++++++++++ .../traversal/translator/DotNetTranslator.java | 1 + .../process/traversal/util/BytecodeHelper.java | 2 + .../grammar/TraversalMethodVisitorTest.java | 5 + .../process/traversal/step/filter/AllStepTest.java | 57 ++++++++ .../Process/Traversal/GraphTraversal.cs | 9 ++ .../src/Gremlin.Net/Process/Traversal/__.cs | 8 ++ .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 12 ++ gremlin-go/driver/anonymousTraversal.go | 7 + gremlin-go/driver/cucumber/gremlin.go | 12 ++ gremlin-go/driver/graphTraversal.go | 6 + .../lib/process/graph-traversal.js | 11 ++ .../gremlin-javascript/test/cucumber/gremlin.js | 12 ++ gremlin-language/src/main/antlr4/Gremlin.g4 | 5 + .../gremlin_python/process/graph_traversal.py | 8 ++ gremlin-python/src/main/python/radish/gremlin.py | 12 ++ .../gremlin/test/features/filter/All.feature | 152 +++++++++++++++++++++ 21 files changed, 426 insertions(+) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java index ee160101c1..c065698b56 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java @@ -921,6 +921,11 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im */ @Override public T visitTraversalMethod_concat_String(final GremlinParser.TraversalMethod_concat_StringContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override + public T visitTraversalMethod_all_P(final GremlinParser.TraversalMethod_all_PContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ 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 68bf88ddb2..c0ba2f89a0 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 @@ -1741,6 +1741,14 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> return graphTraversal.concat(antlr.genericVisitor.parseStringVarargs(ctx.stringLiteralVarargs())); } + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_all_P(final GremlinParser.TraversalMethod_all_PContext ctx) { + return graphTraversal.all(antlr.traversalPredicateVisitor.visitTraversalPredicate(ctx.traversalPredicate())); + } + public GraphTraversal[] getNestedTraversalList(final GremlinParser.NestedTraversalListContext ctx) { return ctx.nestedTraversalExpr().nestedTraversal() .stream() 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 cefdf6993d..b16eba7973 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 @@ -56,6 +56,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.branch.LocalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.OptionalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.RepeatStep; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.UnionStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AllStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.CoinStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.ConnectiveStep; @@ -1996,6 +1997,19 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { return this.asAdmin().addStep(new IsStep<>(this.asAdmin(), predicate)); } + /** + * Filters <code>E</code> object values given the provided {@code predicate}. + * + * @param predicate the filter to apply + * @return the traversal with an appended {@link IsStep} + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#is-step" target="_blank">Reference Documentation - Is Step</a> + * @since 3.0.0-incubating + */ + public default <S2> GraphTraversal<S, E> all(final P<S2> predicate) { + this.asAdmin().getBytecode().addStep(Symbols.all, predicate); + return this.asAdmin().addStep(new AllStep<>(this.asAdmin(), predicate)); + } + /** * Filter the <code>E</code> object if it is not {@link P#eq} to the provided value. * @@ -3500,6 +3514,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { public static final String call = "call"; public static final String element = "element"; public static final String concat = "concat"; + public static final String all = "all"; public static final String timeLimit = "timeLimit"; public static final String simplePath = "simplePath"; 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 ab3aa9fa95..431ec6a51a 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 @@ -813,6 +813,11 @@ public class __ { return __.<A>start().is(value); } + /** + * @see GraphTraversal#all(P) + */ + public static <A> GraphTraversal<A, A> all(final P<A> predicate) { return __.<A>start().all(predicate); } + /** * @see GraphTraversal#not(Traversal) */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java new file mode 100644 index 0000000000..7aedf771e7 --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.step.filter; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +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; + +import java.util.EnumSet; +import java.util.Iterator; +import java.util.Set; + +public final class AllStep<S, S2> extends FilterStep<S> { + + private P<S2> predicate; + + public AllStep(final Traversal.Admin traversal, final P<S2> predicate) { + super(traversal); + this.predicate = predicate; + } + + @Override + protected boolean filter(final Traverser.Admin<S> traverser) { + final S item = traverser.get(); + + if (item instanceof Iterable || item instanceof Iterator || ((item != null) && item.getClass().isArray())) { + final Iterator<S2> iterator = IteratorUtils.asIterator(item); + while (iterator.hasNext()) { + if (!this.predicate.test(iterator.next())) { + return false; + } + } + return true; + } + + return false; + } + + @Override + public String toString() { + return StringFactory.stepString(this, this.predicate); + } + + @Override + public AllStep<S, S2> clone() { + final AllStep<S, S2> clone = (AllStep<S, S2>) super.clone(); + clone.predicate = this.predicate.clone(); + return clone; + } + + @Override + public Set<TraverserRequirement> getRequirements() { + return EnumSet.of(TraverserRequirement.OBJECT); + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java index 45e1154931..9e8a9f7fc0 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java @@ -510,6 +510,7 @@ public final class DotNetTranslator implements Translator.ScriptTranslator { private final static Map<String, String> FROM_CS_MAP = new HashMap<>(); static { + TO_CS_MAP.put(GraphTraversal.Symbols.all, "All<object>"); TO_CS_MAP.put(GraphTraversal.Symbols.branch, "Branch<object>"); TO_CS_MAP.put(GraphTraversal.Symbols.call, "Call<object>"); TO_CS_MAP.put(GraphTraversal.Symbols.cap, "Cap<object>"); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java index 85c7191642..8576dfa499 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java @@ -42,6 +42,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.branch.LocalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.OptionalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.RepeatStep; import org.apache.tinkerpop.gremlin.process.traversal.step.branch.UnionStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AllStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.CoinStep; import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalStep; @@ -198,6 +199,7 @@ public final class BytecodeHelper { put(GraphTraversal.Symbols.min, Arrays.asList(MinGlobalStep.class, MinGlobalStep.class)); put(GraphTraversal.Symbols.mean, Arrays.asList(MeanGlobalStep.class, MeanLocalStep.class)); put(GraphTraversal.Symbols.concat, Collections.singletonList(ConcatStep.class)); + put(GraphTraversal.Symbols.all, Collections.singletonList(AllStep.class)); put(GraphTraversal.Symbols.group, Arrays.asList(GroupStep.class, GroupSideEffectStep.class)); put(GraphTraversal.Symbols.groupCount, Arrays.asList(GroupCountStep.class, GroupCountSideEffectStep.class)); put(GraphTraversal.Symbols.tree, Arrays.asList(TreeStep.class, TreeSideEffectStep.class)); diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java index da2833ae91..a8bdd3a758 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitorTest.java @@ -116,6 +116,11 @@ public class TraversalMethodVisitorTest { compare(g.V().aggregate(Scope.local, "test"), eval("g.V().aggregate(Scope.local, 'test')")); } + @Test + public void shouldParseTraversalMethod_all_P() throws Exception { + compare(g.V().id().fold().all(gt(1)), eval("g.V().id().all(gt(1)")); + } + @Test public void shouldParseTraversalMethod_and() throws Exception { compare(g.V().and(outE("knows")), eval("g.V().and(outE('knows'))")); diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStepTest.java new file mode 100644 index 0000000000..c7e4801f00 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStepTest.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.step.filter; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.TextP; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class AllStepTest extends StepTest { + + @Override + protected List<Traversal> getTraversals() { return Collections.singletonList(__.all(P.gt(0))); } + + @Test + public void testReturnTypes() { + assertTrue(__.__(new int[]{}).all(P.gt(7)).hasNext()); + assertArrayEquals(new int[] {7, 10}, __.__(new int[]{5, 8, 10}, new int[] {7, 10}).all(P.gte(7)).next()); + + /** + * Test different incoming traverser types as feature tests only allow list + * -Should test array and other iterator types like Set + * -Should test that other types don't work + */ + + /** + * add test for like 10 incoming list traversers instead of just 2 max like now + */ + } +} diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs index f32dcae128..336abba76f 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs @@ -177,6 +177,15 @@ namespace Gremlin.Net.Process.Traversal return Wrap<TStart, TEnd>(this); } + /// <summary> + /// Adds the all step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<TStart, TEnd> All (P? predicate) + { + Bytecode.AddStep("all", predicate); + return Wrap<TStart, TEnd>(this); + } + /// <summary> /// Adds the and step to this <see cref="GraphTraversal{SType, EType}" />. /// </summary> diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs index 82b147cd75..04aae59f7d 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs @@ -115,6 +115,14 @@ namespace Gremlin.Net.Process.Traversal return new GraphTraversal<object, object>().Aggregate(sideEffectKey); } + /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the is step to that traversal. + /// </summary> + public static GraphTraversal<object, object> All(P? predicate) + { + return new GraphTraversal<object, object>().All(predicate); + } + /// <summary> /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the and step to that traversal. /// </summary> diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index 957a4fadab..41c3c6818b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -130,6 +130,18 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Union<object>(__.OutE().Count(),__.InE().Count(),__.OutE().Values<object>("weight").Sum<object>())}}, {"g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Local<object>(__.Union<object>(__.OutE().Count(),__.InE().Count(),__.OutE().Values<object>("weight").Sum<object>()))}}, {"g_VX1_2X_localXunionXcountXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"],p["vid2"]).Local<object>(__.Union<object>(__.Count()))}}, + {"g_V_valuesXageX_allXP_gtX32XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").All<object>(P.Gt(32))}}, + {"g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXP_gtX33XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Where(__.Is(P.Gt(33))).Fold().All<object>(P.Gt(33))}}, + {"g_V_valuesXageX_order_byXdescX_fold_allXP_gtX10XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().By(Order.Desc).Fold().All<object>(P.Gt(10))}}, + {"g_V_valuesXageX_order_byXdescX_fold_allXP_gtX30XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().By(Order.Desc).Fold().All<object>(P.Gt(30))}}, + {"g_V_injectXabc_bcdX_allXP_eqXbcdXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(p["xx1"]).All<object>(P.Eq("bcd"))}}, + {"g_V_injectXbcd_bcdX_allXP_eqXbcdXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(p["xx1"]).All<object>(P.Eq("bcd"))}}, + {"g_V_injectXnull_abcX_allXTextP_startingWithXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(p["xx1"]).All<object>(TextP.StartingWith("a"))}}, + {"g_V_injectX5_8_10_10_7X_allXP_gteX7XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(p["xx1"],p["xx2"]).All<object>(P.Gte(7))}}, + {"g_V_injectXnullX_allXP_eqXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(null).All<object>(P.Eq(null))}}, + {"g_V_injectX7X_allXP_eqX7XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(7).All<object>(P.Eq(7))}}, + {"g_V_injectXnull_nullX_allXP_eqXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(p["xx1"]).All<object>(P.Eq(null))}}, + {"g_V_injectX3_threeX_allXP_eqX3XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Inject(p["xx1"]).All<object>(P.Eq(3))}}, {"g_V_andXhasXage_gt_27X__outE_count_gte_2X_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().And(__.Has("age",P.Gt(27)),__.OutE().Count().Is(P.Gte(2))).Values<object>("name")}}, {"g_V_andXoutE__hasXlabel_personX_and_hasXage_gte_32XX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().And(__.OutE(),__.Has(T.Label,"person").And().Has("age",P.Gte(32))).Values<object>("name")}}, {"g_V_asXaX_outXknowsX_and_outXcreatedX_inXcreatedX_asXaX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("knows").And().Out("created").In("created").As("a").Values<object>("name")}}, diff --git a/gremlin-go/driver/anonymousTraversal.go b/gremlin-go/driver/anonymousTraversal.go index a6a03ecc17..38744eb500 100644 --- a/gremlin-go/driver/anonymousTraversal.go +++ b/gremlin-go/driver/anonymousTraversal.go @@ -55,6 +55,8 @@ type AnonymousTraversal interface { AddV(args ...interface{}) *GraphTraversal // Aggregate adds the aggregate step to the GraphTraversal. Aggregate(args ...interface{}) *GraphTraversal + // All adds the all step to the GraphTraversal. + All(args ...interface{}) *GraphTraversal // And adds the and step to the GraphTraversal. And(args ...interface{}) *GraphTraversal // As adds the as step to the GraphTraversal. @@ -307,6 +309,11 @@ func (anonymousTraversal *anonymousTraversal) Aggregate(args ...interface{}) *Gr return anonymousTraversal.graphTraversal().Aggregate(args...) } +// All adds the all step to the GraphTraversal. +func (anonymousTraversal *anonymousTraversal) All(args ...interface{}) *GraphTraversal { + return anonymousTraversal.graphTraversal().All(args...) +} + // And adds the and step to the GraphTraversal. func (anonymousTraversal *anonymousTraversal) And(args ...interface{}) *GraphTraversal { return anonymousTraversal.graphTraversal().And(args...) diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go index d0e9272013..ddfe40fa53 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -100,6 +100,18 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Union(gremlingo.T__.OutE().Count(), gremlingo.T__.InE().Count(), gremlingo.T__.OutE().Values("weight").Sum())}}, "g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Local(gremlingo.T__.Union(gremlingo.T__.OutE().Count(), gremlingo.T__.InE().Count(), gremlingo.T__.OutE().Values("weight").Sum()))}}, "g_VX1_2X_localXunionXcountXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"], p["vid2"]).Local(gremlingo.T__.Union(gremlingo.T__.Count()))}}, + "g_V_valuesXageX_allXP_gtX32XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").All(gremlingo.P.Gt(32))}}, + "g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXP_gtX33XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Where(gremlingo.T__.Is(gremlingo.P.Gt(33))).Fold().All(gremlingo.P.Gt(33))}}, + "g_V_valuesXageX_order_byXdescX_fold_allXP_gtX10XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().By(gremlingo.Order.Desc).Fold().All(gremlingo.P.Gt(10))}}, + "g_V_valuesXageX_order_byXdescX_fold_allXP_gtX30XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().By(gremlingo.Order.Desc).Fold().All(gremlingo.P.Gt(30))}}, + "g_V_injectXabc_bcdX_allXP_eqXbcdXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(p["xx1"]).All(gremlingo.P.Eq("bcd"))}}, + "g_V_injectXbcd_bcdX_allXP_eqXbcdXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(p["xx1"]).All(gremlingo.P.Eq("bcd"))}}, + "g_V_injectXnull_abcX_allXTextP_startingWithXaXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(p["xx1"]).All(gremlingo.TextP.StartingWith("a"))}}, + "g_V_injectX5_8_10_10_7X_allXP_gteX7XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(p["xx1"], p["xx2"]).All(gremlingo.P.Gte(7))}}, + "g_V_injectXnullX_allXP_eqXnullXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(nil).All(gremlingo.P.Eq(nil))}}, + "g_V_injectX7X_allXP_eqX7XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(7).All(gremlingo.P.Eq(7))}}, + "g_V_injectXnull_nullX_allXP_eqXnullXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(p["xx1"]).All(gremlingo.P.Eq(nil))}}, + "g_V_injectX3_threeX_allXP_eqX3XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Inject(p["xx1"]).All(gremlingo.P.Eq(3))}}, "g_V_andXhasXage_gt_27X__outE_count_gte_2X_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().And(gremlingo.T__.Has("age", gremlingo.P.Gt(27)), gremlingo.T__.OutE().Count().Is(gremlingo.P.Gte(2))).Values("name")}}, "g_V_andXoutE__hasXlabel_personX_and_hasXage_gte_32XX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().And(gremlingo.T__.OutE(), gremlingo.T__.Has(gremlingo.T.Label, "person").And().Has("age", gremlingo.P.Gte(32))).Values("name")}}, "g_V_asXaX_outXknowsX_and_outXcreatedX_inXcreatedX_asXaX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("a").Out("knows").And().Out("created").In("created").As("a").Values("name")}}, diff --git a/gremlin-go/driver/graphTraversal.go b/gremlin-go/driver/graphTraversal.go index 797774ec3e..5f143c5e41 100644 --- a/gremlin-go/driver/graphTraversal.go +++ b/gremlin-go/driver/graphTraversal.go @@ -82,6 +82,12 @@ func (g *GraphTraversal) Aggregate(args ...interface{}) *GraphTraversal { return g } +// All adds the all step to the GraphTraversal. +func (g *GraphTraversal) All(args ...interface{}) *GraphTraversal { + g.Bytecode.AddStep("all", args...) + return g +} + // And adds the and step to the GraphTraversal. func (g *GraphTraversal) And(args ...interface{}) *GraphTraversal { g.Bytecode.AddStep("and", args...) diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js index b14a9e578c..c93731210d 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js @@ -414,6 +414,16 @@ class GraphTraversal extends Traversal { return this; } + /** + * Graph traversal all method. + * @param {...Object} args + * @returns {GraphTraversal} + */ + all(...args) { + this.bytecode.addStep('all', args); + return this; + } + /** * Graph traversal and method. * @param {...Object} args @@ -1517,6 +1527,7 @@ const statics = { addE: (...args) => callOnEmptyTraversal('addE', args), addV: (...args) => callOnEmptyTraversal('addV', args), aggregate: (...args) => callOnEmptyTraversal('aggregate', args), + all: (...args) => callOnEmptyTraversal('all', args), and: (...args) => callOnEmptyTraversal('and', args), as: (...args) => callOnEmptyTraversal('as', args), barrier: (...args) => callOnEmptyTraversal('barrier', args), 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 7b55e7ba04..d99111d4af 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 @@ -120,6 +120,18 @@ const gremlins = { g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).union(__.outE().count(),__.inE().count(),__.outE().values("weight").sum()) }], g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).local(__.union(__.outE().count(),__.inE().count(),__.outE().values("weight").sum())) }], g_VX1_2X_localXunionXcountXX: [function({g, vid2, vid1}) { return g.V(vid1,vid2).local(__.union(__.count())) }], + g_V_valuesXageX_allXP_gtX32XX: [function({g}) { return g.V().values("age").all(P.gt(32)) }], + g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXP_gtX33XX: [function({g}) { return g.V().values("age").where(__.is(P.gt(33))).fold().all(P.gt(33)) }], + g_V_valuesXageX_order_byXdescX_fold_allXP_gtX10XX: [function({g}) { return g.V().values("age").order().by(Order.desc).fold().all(P.gt(10)) }], + g_V_valuesXageX_order_byXdescX_fold_allXP_gtX30XX: [function({g}) { return g.V().values("age").order().by(Order.desc).fold().all(P.gt(30)) }], + g_V_injectXabc_bcdX_allXP_eqXbcdXX: [function({g, xx1}) { return g.V().inject(xx1).all(P.eq("bcd")) }], + g_V_injectXbcd_bcdX_allXP_eqXbcdXX: [function({g, xx1}) { return g.V().inject(xx1).all(P.eq("bcd")) }], + g_V_injectXnull_abcX_allXTextP_startingWithXaXX: [function({g, xx1}) { return g.V().inject(xx1).all(TextP.startingWith("a")) }], + g_V_injectX5_8_10_10_7X_allXP_gteX7XX: [function({g, xx1, xx2}) { return g.V().inject(xx1,xx2).all(P.gte(7)) }], + g_V_injectXnullX_allXP_eqXnullXX: [function({g}) { return g.V().inject(null).all(P.eq(null)) }], + g_V_injectX7X_allXP_eqX7XX: [function({g}) { return g.V().inject(7).all(P.eq(7)) }], + g_V_injectXnull_nullX_allXP_eqXnullXX: [function({g, xx1}) { return g.V().inject(xx1).all(P.eq(null)) }], + g_V_injectX3_threeX_allXP_eqX3XX: [function({g, xx1}) { return g.V().inject(xx1).all(P.eq(3)) }], g_V_andXhasXage_gt_27X__outE_count_gte_2X_name: [function({g}) { return g.V().and(__.has("age",P.gt(27)),__.outE().count().is(P.gte(2))).values("name") }], g_V_andXoutE__hasXlabel_personX_and_hasXage_gte_32XX_name: [function({g}) { return g.V().and(__.outE(),__.has(T.label,"person").and().has("age",P.gte(32))).values("name") }], g_V_asXaX_outXknowsX_and_outXcreatedX_inXcreatedX_asXaX_name: [function({g}) { return g.V().as("a").out("knows").and().out("created").in_("created").as("a").values("name") }], diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index 703e7f41aa..7dece7bfa2 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -284,6 +284,7 @@ traversalMethod | traversalMethod_element | traversalMethod_call | traversalMethod_concat + | traversalMethod_all ; traversalMethod_V : 'V' LPAREN genericLiteralVarargs RPAREN @@ -809,6 +810,10 @@ traversalMethod_concat | 'concat' LPAREN stringLiteralVarargs RPAREN #traversalMethod_concat_String ; +traversalMethod_all + : 'all' LPAREN traversalPredicate RPAREN #traversalMethod_all_P + ; + /********************************************* ARGUMENT AND TERMINAL RULES **********************************************/ diff --git a/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py index 82a7926feb..51b3fe67f7 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py @@ -309,6 +309,10 @@ class GraphTraversal(Traversal): self.bytecode.add_step("aggregate", *args) return self + def all_(self, *args): + self.bytecode.add_step("all", *args) + return self + def and_(self, *args): self.bytecode.add_step("and", *args) return self @@ -975,6 +979,10 @@ class __(object, metaclass=MagicType): def aggregate(cls, *args): return cls.graph_traversal(None, None, Bytecode()).aggregate(*args) + @classmethod + def all_(cls, *args): + return cls.graph_traversal(None, None, Bytecode()).all_(*args) + @classmethod def and_(cls, *args): return cls.graph_traversal(None, None, Bytecode()).and_(*args) diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index 0284984cf8..26dc041671 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -101,6 +101,18 @@ world.gremlins = { 'g_VX1_2X_unionXoutE_count__inE_count__outE_weight_sumX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).union(__.outE().count(),__.inE().count(),__.outE().weight.sum_()))], 'g_VX1_2X_localXunionXoutE_count__inE_count__outE_weight_sumXX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).local(__.union(__.outE().count(),__.inE().count(),__.outE().weight.sum_())))], 'g_VX1_2X_localXunionXcountXX': [(lambda g, vid2=None,vid1=None:g.V(vid1,vid2).local(__.union(__.count())))], + 'g_V_valuesXageX_allXP_gtX32XX': [(lambda g:g.V().age.all_(P.gt(32)))], + 'g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXP_gtX33XX': [(lambda g:g.V().age.where(__.is_(P.gt(33))).fold().all_(P.gt(33)))], + 'g_V_valuesXageX_order_byXdescX_fold_allXP_gtX10XX': [(lambda g:g.V().age.order().by(Order.desc).fold().all_(P.gt(10)))], + 'g_V_valuesXageX_order_byXdescX_fold_allXP_gtX30XX': [(lambda g:g.V().age.order().by(Order.desc).fold().all_(P.gt(30)))], + 'g_V_injectXabc_bcdX_allXP_eqXbcdXX': [(lambda g, xx1=None:g.V().inject(xx1).all_(P.eq('bcd')))], + 'g_V_injectXbcd_bcdX_allXP_eqXbcdXX': [(lambda g, xx1=None:g.V().inject(xx1).all_(P.eq('bcd')))], + 'g_V_injectXnull_abcX_allXTextP_startingWithXaXX': [(lambda g, xx1=None:g.V().inject(xx1).all_(TextP.startingWith('a')))], + 'g_V_injectX5_8_10_10_7X_allXP_gteX7XX': [(lambda g, xx1=None,xx2=None:g.V().inject(xx1,xx2).all_(P.gte(7)))], + 'g_V_injectXnullX_allXP_eqXnullXX': [(lambda g:g.V().inject(None).all_(P.eq(None)))], + 'g_V_injectX7X_allXP_eqX7XX': [(lambda g:g.V().inject(7).all_(P.eq(7)))], + 'g_V_injectXnull_nullX_allXP_eqXnullXX': [(lambda g, xx1=None:g.V().inject(xx1).all_(P.eq(None)))], + 'g_V_injectX3_threeX_allXP_eqX3XX': [(lambda g, xx1=None:g.V().inject(xx1).all_(P.eq(3)))], 'g_V_andXhasXage_gt_27X__outE_count_gte_2X_name': [(lambda g:g.V().and_(__.has('age',P.gt(27)),__.outE().count().is_(P.gte(2))).name)], 'g_V_andXoutE__hasXlabel_personX_and_hasXage_gte_32XX_name': [(lambda g:g.V().and_(__.outE(),__.has(T.label,'person').and_().has('age',P.gte(32))).name)], 'g_V_asXaX_outXknowsX_and_outXcreatedX_inXcreatedX_asXaX_name': [(lambda g:g.V().as_('a').out('knows').and_().out('created').in_('created').as_('a').name)], diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/All.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/All.feature new file mode 100644 index 0000000000..ea1ffe3292 --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/All.feature @@ -0,0 +1,152 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassFilter @StepAll +Feature: Step - all() + + Scenario: g_V_valuesXageX_allXP_gtX32XX + Given the modern graph + And the traversal of + """ + g.V().values("age").all(P.gt(32)) + """ + When iterated to list + Then the result should be empty + + Scenario: g_V_valuesXageX_whereXisXP_gtX33XXX_fold_allXP_gtX33XX + Given the modern graph + And the traversal of + """ + g.V().values("age").where(__.is(P.gt(33))).fold().all(P.gt(33)) + """ + When iterated to list + Then the result should be unordered + | result | + | l[d[35].i] | + + Scenario: g_V_valuesXageX_order_byXdescX_fold_allXP_gtX10XX + Given the modern graph + And the traversal of + """ + g.V().values("age").order().by(desc).fold().all(P.gt(10)) + """ + When iterated to list + Then the result should be unordered + | result | + | l[d[35].i,d[32].i,d[29].i,d[27].i] | + + Scenario: g_V_valuesXageX_order_byXdescX_fold_allXP_gtX30XX + Given the modern graph + And the traversal of + """ + g.V().values("age").order().by(desc).fold().all(P.gt(30)) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectXabc_bcdX_allXP_eqXbcdXX + Given the empty graph + And using the parameter xx1 defined as "l[abc,bcd]" + And the traversal of + """ + g.V().inject(xx1).all(P.eq("bcd")) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectXbcd_bcdX_allXP_eqXbcdXX + Given the empty graph + And using the parameter xx1 defined as "l[bcd,bcd]" + And the traversal of + """ + g.V().inject(xx1).all(P.eq("bcd")) + """ + When iterated to list + Then the result should be unordered + | result | + | l[bcd,bcd] | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectXnull_abcX_allXTextP_startingWithXaXX + Given the empty graph + And using the parameter xx1 defined as "l[null,abc]" + And the traversal of + """ + g.V().inject(xx1).all(TextP.startingWith("a")) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectX5_8_10_10_7X_allXP_gteX7XX + Given the empty graph + And using the parameter xx1 defined as "l[d[5].i,d[8].i,d[10].i]" + And using the parameter xx2 defined as "l[d[10].i,d[7].i]" + And the traversal of + """ + g.V().inject(xx1,xx2).all(P.gte(7)) + """ + When iterated to list + Then the result should be unordered + | result | + | l[d[10].i,d[7].i] | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectXnullX_allXP_eqXnullXX + Given the empty graph + And the traversal of + """ + g.V().inject(null).all(P.eq(null)) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectX7X_allXP_eqX7XX + Given the empty graph + And the traversal of + """ + g.V().inject(7).all(P.eq(7)) + """ + When iterated to list + Then the result should be empty + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectXnull_nullX_allXP_eqXnullXX + Given the empty graph + And using the parameter xx1 defined as "l[null,null]" + And the traversal of + """ + g.V().inject(xx1).all(P.eq(null)) + """ + When iterated to list + Then the result should be unordered + | result | + | l[null,null] | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_V_injectX3_threeX_allXP_eqX3XX + Given the empty graph + And using the parameter xx1 defined as "l[d[3].i,three]" + And the traversal of + """ + g.V().inject(xx1).all(P.eq(3)) + """ + When iterated to list + Then the result should be empty \ No newline at end of file
