Skip to content

Commit

Permalink
Implement none()
Browse files Browse the repository at this point in the history
  • Loading branch information
ryn5 committed Dec 7, 2023
1 parent d39e28a commit de306e3
Show file tree
Hide file tree
Showing 20 changed files with 607 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,10 @@ protected void notImplemented(final ParseTree ctx) {
* {@inheritDoc}
*/
@Override public T visitTraversalMethod_min_Scope(final GremlinParser.TraversalMethod_min_ScopeContext ctx) { notImplemented(ctx); return null; }
/**
* {@inheritDoc}
*/
@Override public T visitTraversalMethod_none_P(final GremlinParser.TraversalMethod_none_PContext ctx) { notImplemented(ctx); return null; }
/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@
*/
package org.apache.tinkerpop.gremlin.language.grammar;

import org.apache.tinkerpop.gremlin.process.traversal.Merge;
import org.apache.tinkerpop.gremlin.process.traversal.Operator;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality;

import java.util.LinkedHashMap;
import java.util.Map;

import java.util.function.BiFunction;

import static org.apache.tinkerpop.gremlin.process.traversal.SackFunctions.Barrier.normSack;
Expand Down Expand Up @@ -1082,6 +1079,14 @@ public GraphTraversal visitTraversalMethod_min_Scope(final GremlinParser.Travers
return graphTraversal.min(antlr.argumentVisitor.parseScope(ctx.traversalScopeArgument()));
}

/**
* {@inheritDoc}
*/
@Override
public GraphTraversal visitTraversalMethod_none_P(final GremlinParser.TraversalMethod_none_PContext ctx) {
return graphTraversal.none(antlr.traversalPredicateVisitor.visitTraversalPredicate(ctx.traversalPredicate()));
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.IsStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.LambdaFilterStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NoneStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NotStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.OrStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.PathFilterStep;
Expand Down Expand Up @@ -171,6 +172,7 @@
import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AddPropertyStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateGlobalStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateLocalStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.FailStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupCountSideEffectStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupSideEffectStep;
Expand All @@ -182,7 +184,6 @@
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SackValueStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectCapStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateLocalStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.TraversalSideEffectStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.TreeSideEffectStep;
Expand Down Expand Up @@ -2829,6 +2830,19 @@ public default <S2> GraphTraversal<S, E> any(final P<S2> predicate) {
return this.asAdmin().addStep(new AnyStep<>(this.asAdmin(), predicate));
}

/**
* Filters <code>E</code> lists given the provided {@code predicate}.
*
* @param predicate the filter to apply
* @return the traversal with an appended {@link NoneStep}
* @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#none-step" target="_blank">Reference Documentation - None Step</a>
* @since 4.0.0
*/
public default <S2> GraphTraversal<S, E> none(final P<S2> predicate) {
this.asAdmin().getBytecode().addStep(Symbols.none, predicate);
return this.asAdmin().addStep(new NoneStep<>(this.asAdmin(), predicate));
}

///////////////////// SIDE-EFFECT STEPS /////////////////////

/**
Expand Down Expand Up @@ -4078,6 +4092,7 @@ private Symbols() {
public static final String dateDiff = "dateDiff";
public static final String all = "all";
public static final String any = "any";
public static final String none = "none";
public static final String merge = "merge";
public static final String product = "product";
public static final String combine = "combine";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,11 @@ public static <A> GraphTraversal<A, A> drop() {
*/
public static <A> GraphTraversal<A, A> any(final P<A> predicate) { return __.<A>start().any(predicate); }

/**
* @see GraphTraversal#none(P)
*/
public static <A> GraphTraversal<A, A> none(final P<A> predicate) { return __.<A>start().none(predicate); }

///////////////////// SIDE-EFFECT STEPS /////////////////////

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* 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.GremlinTypeErrorException;
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 NoneStep<S, S2> extends FilterStep<S> {

private P<S2> predicate;

public NoneStep(final Traversal.Admin traversal, final P<S2> predicate) {
super(traversal);

if (null == predicate) {
throw new IllegalArgumentException("Input predicate to none step can't be null.");
}

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())) {
GremlinTypeErrorException typeError = null;
final Iterator<S2> iterator = IteratorUtils.asIterator(item);
while (iterator.hasNext()) {
try {
if (this.predicate.test(iterator.next())) {
return false;
}
} catch (GremlinTypeErrorException gtee) {
// hold onto it until the end in case any other element evaluates to TRUE
typeError = gtee;
}
}
if (typeError != null) throw typeError;
return true;
}

return false;
}

@Override
public String toString() {
return StringFactory.stepString(this, this.predicate);
}

@Override
public NoneStep<S, S2> clone() {
final NoneStep<S, S2> clone = (NoneStep<S, S2>) super.clone();
clone.predicate = this.predicate.clone();
return clone;
}

@Override
public Set<TraverserRequirement> getRequirements() {
return EnumSet.of(TraverserRequirement.OBJECT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.IsStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.LambdaFilterStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NoneStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.NotStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.OrStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.filter.PathFilterStep;
Expand Down Expand Up @@ -248,6 +249,7 @@ public final class BytecodeHelper {
put(GraphTraversal.Symbols.dateDiff, Collections.singletonList(DateDiffStep.class));
put(GraphTraversal.Symbols.all, Collections.singletonList(AllStep.class));
put(GraphTraversal.Symbols.any, Collections.singletonList(AnyStep.class));
put(GraphTraversal.Symbols.none, Collections.singletonList(NoneStep.class));
put(GraphTraversal.Symbols.combine, Collections.singletonList(CombineStep.class));
put(GraphTraversal.Symbols.difference, Collections.singletonList(DifferenceStep.class));
put(GraphTraversal.Symbols.disjunct, Collections.singletonList(DisjunctStep.class));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* 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.HashSet;
import java.util.List;
import java.util.Set;

import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.any;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

public class NoneStepTest extends StepTest {

@Override
protected List<Traversal> getTraversals() { return Collections.singletonList(__.none(P.gt(0))); }

@Test
public void testReturnTypes() {
assertTrue(__.__(new int[]{}).none(P.gt(7)).hasNext());
assertArrayEquals(new int[] {5, 6}, __.__(new int[] {5, 8, 10}, new int[] {5, 6}).not(any(P.gte(7))).next());
assertArrayEquals(new long[] {5L, 6L}, __.__(new long[] {5L, 8L, 10L}, new long[] {5L, 6L}).none(P.gte(7)).next());
assertArrayEquals(new Long[] {5L, 6L}, __.__(1).constant(new Long[] {5L, 6L}).none(P.gte(7)).next());
assertArrayEquals(new double[] {5.1, 6.5}, __.__(new double[] {5.5, 8.0, 10.1}, new double[] {5.1, 6.5}).none(P.gte(7.0)).next(), 0.01);
}

@Test
public void testNullParameter() {
final Throwable thrown = assertThrows(IllegalArgumentException.class, () -> __.__(new int[]{1}).none(null).hasNext());
assertEquals("Input predicate to none step can't be null.", thrown.getMessage());
}

@Test
public void testSetTraverser() {
final Set<Integer> numbers = new HashSet<>();
numbers.add(5);
numbers.add(6);

assertTrue(__.__(numbers).none(P.gt(7)).hasNext());
}

@Test
public void testListIteratorTraverser() {
final List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(11);

assertTrue(__.__(numbers.iterator()).none(P.lt(10)).hasNext());
}

@Test
public void testCornerCases() {
final List validOne = new ArrayList() {{ add(20); }};
final List validTwo = new ArrayList() {{ add(21); add(25);}};
final List validThree = new ArrayList() {{ add(51); add(57); add(71); }};
final List containsNull = new ArrayList() {{ add(50); add(null); add(60); }};
final List containsNull2 = new ArrayList() {{ add(1); add(null); add(2); }};
final List empty = new ArrayList();
final List incorrectType = new ArrayList() {{ add(100); add("25"); }};
final List valueTooSmall = new ArrayList() {{ add(101); add(1); add(10);}};

final List bcd = new ArrayList() {{ add(null); add("bcd"); }};
final List bcdnull = new ArrayList() {{ add("bcd"); }};
final List abc = new ArrayList() {{ add("abc"); }};
final List abcnull = new ArrayList() {{ add("abc"); add(null); }};

assertEquals(4L, __.__(validOne, null, containsNull, empty, incorrectType, valueTooSmall, validTwo, validThree)
.none(P.lte(3)).count().next().longValue());
assertEquals(1L, __.__(bcd).none(TextP.startingWith("a")).count().next().longValue()); // e 0 a 0
assertEquals(1L, __.__(bcdnull).none(TextP.startingWith("a")).count().next().longValue()); // actual 1
assertEquals(0L, __.__(abc).none(TextP.startingWith("a")).count().next().longValue()); // actual 0
assertEquals(0L, __.__(abcnull).none(TextP.startingWith("a")).count().next().longValue()); // actual 0

assertEquals(1L, __.__(bcd).all(TextP.startingWith("a")).count().next().longValue()); // actual 0
assertEquals(1L, __.__(bcdnull).all(TextP.startingWith("a")).count().next().longValue()); // actual 1
assertEquals(0L, __.__(abcnull).all(TextP.startingWith("a")).count().next().longValue()); // actual 0
}
}
Loading

0 comments on commit de306e3

Please sign in to comment.