This is an automated email from the ASF dual-hosted git repository.
colegreer pushed a commit to branch GValueManager3.8
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/GValueManager3.8 by this push:
new 7d1193ffaa Add contracts for predicates
7d1193ffaa is described below
commit 7d1193ffaaa00e4930f44341ac88d272f2141ac8
Author: Cole-Greer <[email protected]>
AuthorDate: Fri May 23 09:53:43 2025 -0700
Add contracts for predicates
---
.../gremlin/process/traversal/GValueManager.java | 209 +++++++++++++--------
.../tinkerpop/gremlin/process/traversal/P.java | 69 +++----
.../tinkerpop/gremlin/process/traversal/TextP.java | 82 ++++++++
.../traversal/dsl/graph/GraphTraversal.java | 33 +++-
.../gremlin/process/traversal/step/GValue.java | 3 +
.../process/traversal/step/HasContainerHolder.java | 10 +-
.../process/traversal/step/filter/IsStep.java | 5 +-
.../PredicateContract.java} | 23 +--
.../process/traversal/util/ConnectiveP.java | 7 +-
.../process/traversal/util/TraversalHelper.java | 12 +-
.../tinkerpop/gremlin/process/traversal/PTest.java | 102 +++++++++-
.../strategy/optimization/CountStrategyTest.java | 5 +-
.../gremlin-javascript/test/cucumber/gremlin.js | 4 +-
13 files changed, 416 insertions(+), 148 deletions(-)
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
index e34d342eb2..27e1378e27 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
@@ -18,6 +18,7 @@
*/
package org.apache.tinkerpop.gremlin.process.traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.AddEdgeContract;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.AddVertexContract;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.CallContract;
@@ -26,12 +27,16 @@ import
org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.EdgeLabelContract;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.AddPropertyContract;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.MergeElementContract;
+import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.PredicateContract;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.RangeContract;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.StepContract;
import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.TailContract;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import java.io.Serializable;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -49,16 +54,14 @@ public final class GValueManager implements Serializable,
Cloneable {
private boolean locked = false;
private final Map<String, GValue> gValueRegistry = new IdentityHashMap();
private final Map<Step, StepContract> stepRegistry = new IdentityHashMap();
- private final Map<Step, P> predicateRegistry = new IdentityHashMap();
public GValueManager() {
- this(Collections.EMPTY_MAP, Collections.EMPTY_MAP,
Collections.EMPTY_MAP);
+ this(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
}
- private GValueManager(Map<String, GValue> gValueRegistry, Map<Step,
StepContract> stepRegistry, Map<Step, P> predicateRegistry) {
+ private GValueManager(Map<String, GValue> gValueRegistry, Map<Step,
StepContract> stepRegistry) {
this.gValueRegistry.putAll(gValueRegistry);
this.stepRegistry.putAll(stepRegistry);
- this.predicateRegistry.putAll(predicateRegistry);
}
/**
@@ -69,14 +72,6 @@ public final class GValueManager implements Serializable,
Cloneable {
stepRegistry.put(step, contract);
}
- /**
- * Register a step with any {@link P} containing a {@link GValue}.
- */
- public void register(final Step step, final P predicate) {
- if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
- predicateRegistry.put(step, predicate);
- }
-
/**
* Locks the current state of the manager, ensuring that no further
modifications can be made.
* <p/>
@@ -92,36 +87,26 @@ public final class GValueManager implements Serializable,
Cloneable {
// can only lock once so if already locked, just return.
if (locked) return;
- for (Map.Entry<Step, StepContract> entry : stepRegistry.entrySet()) {
- final StepContract contract = entry.getValue();
- if (contract instanceof RangeContract) {
- extractGValue((RangeContract<GValue<Long>>) contract);
- } else if (contract instanceof TailContract) {
- extractGValue((TailContract<GValue<Long>>) contract);
- } else if (contract instanceof MergeElementContract) {
- extractGValue((MergeElementContract<GValue<Map<?, ?>>> )
contract);
- } else if (contract instanceof ElementIdsContract) {
- extractGValue((ElementIdsContract<GValue>) contract);
- } else if (contract instanceof AddVertexContract) {
- extractGValue((AddVertexContract<GValue<String>, ?,
GValue<?>>) contract);
- } else if (contract instanceof AddEdgeContract) {
- extractGValue((AddEdgeContract<GValue<String>, GValue<Vertex>,
?, GValue<?>>) contract);
- } else if (contract instanceof AddPropertyContract) {
- extractGValue((AddPropertyContract<?, GValue<?>>) contract);
- } else if (contract instanceof EdgeLabelContract) {
- extractGValue((EdgeLabelContract<GValue<String>>) contract);
- } else if (contract instanceof CallContract) {
- extractGValue((CallContract<GValue<Map<?, ?>>>) contract);
- } else {
- throw new IllegalArgumentException("Unsupported StepContract
type: " + contract.getClass().getName());
- }
+ for (StepContract contract : stepRegistry.values()) {
+ registerGValues(extractGValues(contract));
}
- for (Map.Entry<Step, P> entry : predicateRegistry.entrySet()) {
- extractPredicateGValues(entry.getValue());
+ locked = true;
+ }
+
+ private void registerGValues(Collection<GValue<?>> gValues) {
+ for (GValue<?> gValue : gValues) {
+ if (gValue.getName() != null) {
+ gValueRegistry.put(gValue.getName(), gValue);
+ }
}
+ }
- locked = true;
+ private void removeGValues(Collection<GValue<?>> gValues) {
+ for (GValue<?> gValue : gValues) {
+ gValueRegistry.remove(gValue.getName(), gValue);
+ // TODO:: cascade to other steps
+ }
}
/**
@@ -136,7 +121,6 @@ public final class GValueManager implements Serializable,
Cloneable {
//TODO deal with conflicts
gValueRegistry.putAll(other.gValueRegistry);
stepRegistry.putAll(other.stepRegistry);
- predicateRegistry.putAll(other.predicateRegistry);
}
/**
@@ -149,10 +133,6 @@ public final class GValueManager implements Serializable,
Cloneable {
if (stepRegistry.containsKey(sourceStep)) {
stepRegistry.put(targetStep, stepRegistry.get(sourceStep));
}
-
- if (predicateRegistry.containsKey(sourceStep)) {
- predicateRegistry.put(targetStep,
predicateRegistry.get(sourceStep));
- }
}
/**
@@ -173,7 +153,7 @@ public final class GValueManager implements Serializable,
Cloneable {
* {@code false} otherwise
*/
public <S> boolean isParameterized(final Step step) {
- return this.stepRegistry.containsKey(step) ||
this.predicateRegistry.containsKey(step);
+ return this.stepRegistry.containsKey(step);
}
/**
@@ -189,7 +169,7 @@ public final class GValueManager implements Serializable,
Cloneable {
* Determines whether the GValueManager contains any registered GValues,
steps, or predicates.
*/
public boolean isEmpty() {
- return gValueRegistry.isEmpty() && stepRegistry.isEmpty() &&
predicateRegistry.isEmpty();
+ return gValueRegistry.isEmpty() && stepRegistry.isEmpty();
}
/**
@@ -198,7 +178,6 @@ public final class GValueManager implements Serializable,
Cloneable {
public void reset() {
stepRegistry.clear();
gValueRegistry.clear();
- predicateRegistry.clear();
}
/**
@@ -210,16 +189,42 @@ public final class GValueManager implements Serializable,
Cloneable {
*/
public void remove(final Step step) {
if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
- stepRegistry.remove(step);
- predicateRegistry.remove(step);
+ StepContract removedContract = stepRegistry.remove(step);
+
+ if (removedContract != null) {
+ removeGValues(extractGValues(removedContract));
+ }
}
- private void extractPredicateGValues(final P predicate) {
- if (predicate.getValue() instanceof GValue) {
- GValue<?> gValue = (GValue<?>) predicate.getValue();
- if (gValue.isVariable()) {
- gValueRegistry.put(gValue.getName(), gValue);
- }
+ private Collection<GValue<?>> extractPredicateGValues(final P predicate) {
+ return predicate.getGValueRegistry().getGValues();
+ }
+
+ private Collection<GValue<?>> extractGValues(final StepContract contract) {
+ if (contract instanceof RangeContract) {
+ return extractGValue((RangeContract<GValue<Long>>) contract);
+ } else if (contract instanceof TailContract) {
+ return extractGValue((TailContract<GValue<Long>>) contract);
+ } else if (contract instanceof MergeElementContract) {
+ return extractGValue((MergeElementContract<GValue<Map<?, ?>>> )
contract);
+ } else if (contract instanceof ElementIdsContract) {
+ return extractGValue((ElementIdsContract<GValue<?>>) contract);
+ } else if (contract instanceof AddVertexContract) {
+ return extractGValue((AddVertexContract<GValue<String>, ?,
GValue<?>>) contract);
+ } else if (contract instanceof AddEdgeContract) {
+ return extractGValue((AddEdgeContract<GValue<String>,
GValue<Vertex>, ?, GValue<?>>) contract);
+ } else if (contract instanceof AddPropertyContract) {
+ return extractGValue((AddPropertyContract<?, GValue<?>>) contract);
+ } else if (contract instanceof EdgeLabelContract) {
+ return extractGValue((EdgeLabelContract<GValue<String>>) contract);
+ } else if (contract instanceof CallContract) {
+ return extractGValue((CallContract<GValue<Map<?, ?>>>) contract);
+ } else if (contract instanceof PredicateContract) {
+ return extractGValue((PredicateContract) contract);
+ } else if (contract instanceof HasContainerHolder) {
+ return extractGValue((HasContainerHolder) contract);
+ } else {
+ throw new IllegalArgumentException("Unsupported StepContract type:
" + contract.getClass().getName());
}
}
@@ -227,122 +232,164 @@ public final class GValueManager implements
Serializable, Cloneable {
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final RangeContract<GValue<Long>> contract) {
+ private Collection<GValue<?>> extractGValue(final
RangeContract<GValue<Long>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
if (contract.getHighRange().isVariable()) {
- gValueRegistry.put(contract.getHighRange().getName(),
contract.getHighRange());
+ results.add(contract.getHighRange());
}
if (contract.getLowRange().isVariable()) {
- gValueRegistry.put(contract.getLowRange().getName(),
contract.getLowRange());
+ results.add(contract.getLowRange());
}
+ return results;
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final TailContract<GValue<Long>> contract) {
+ private Collection<GValue<?>> extractGValue(final
TailContract<GValue<Long>> contract) {
if (contract.getLimit().getName() != null) {
- gValueRegistry.put(contract.getLimit().getName(),
contract.getLimit());
+ return Collections.singletonList(contract.getLimit());
}
+ return Collections.emptyList();
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final MergeElementContract<GValue<Map<?,?>>>
contract) {
+ private Collection<GValue<?>> extractGValue(final
MergeElementContract<GValue<Map<?,?>>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
if (contract.getMergeMap() != null) {
- gValueRegistry.put(contract.getMergeMap().getName(),
contract.getMergeMap());
+ results.add(contract.getMergeMap());
}
if (contract.getOnCreateMap() != null) {
- gValueRegistry.put(contract.getOnCreateMap().getName(),
contract.getOnCreateMap());
+ results.add(contract.getOnCreateMap());
}
if (contract.getOnMatchMap() != null) {
- gValueRegistry.put(contract.getOnMatchMap().getName(),
contract.getOnMatchMap());
+ results.add(contract.getOnMatchMap());
}
+ return results;
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final ElementIdsContract<GValue> contract) {
+ private Collection<GValue<?>> extractGValue(final
ElementIdsContract<GValue<?>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
for (GValue gValue: contract.getIds()) {
if (gValue.isVariable()) {
- gValueRegistry.put(gValue.getName(), gValue);
+ results.add(gValue);
}
}
+ return results;
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final AddVertexContract<GValue<String>, ?,
GValue<?>> contract) {
+ private Collection<GValue<?>> extractGValue(final
AddVertexContract<GValue<String>, ?, GValue<?>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
if (contract.getLabel() != null) {
- gValueRegistry.put(contract.getLabel().getName(),
contract.getLabel());
+ results.add(contract.getLabel());
}
for (GValue<?> value : contract.getProperties().values()) {
- gValueRegistry.put(value.getName(), value);
+ results.add(value);
}
+ return results;
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final AddEdgeContract<GValue<String>,
GValue<Vertex>, ?, GValue<?>> contract) {
+ private Collection<GValue<?>> extractGValue(final
AddEdgeContract<GValue<String>, GValue<Vertex>, ?, GValue<?>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
if (contract.getLabel() != null) {
- gValueRegistry.put(contract.getLabel().getName(),
contract.getLabel());
+ results.add(contract.getLabel());
}
if (contract.getFrom() != null) {
- gValueRegistry.put(contract.getFrom().getName(),
contract.getFrom());
+ results.add(contract.getFrom());
}
if (contract.getTo() != null) {
- gValueRegistry.put(contract.getTo().getName(), contract.getTo());
+ results.add(contract.getTo());
}
if (contract.getProperties() != null) {
for (GValue<?> value : contract.getProperties().values()) {
- gValueRegistry.put(value.getName(), value);
+ results.add(value);
}
}
+ return results;
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final AddPropertyContract<?, GValue<?>>
contract) {
- gValueRegistry.put(contract.getValue().getName(), contract.getValue());
+ private Collection<GValue<?>> extractGValue(final AddPropertyContract<?,
GValue<?>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
+ results.add(contract.getValue());
for (GValue<?> value : contract.getProperties().values()) {
- gValueRegistry.put(value.getName(), value);
+ results.add(value);
}
+ return results;
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final EdgeLabelContract<GValue<String>>
contract) {
+ private Collection<GValue<?>> extractGValue(final
EdgeLabelContract<GValue<String>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
for (GValue gValue: contract.getEdgeLabels()) {
if (gValue.getName() != null) {
- gValueRegistry.put(gValue.getName(), gValue);
+ results.add(gValue);
}
}
+ return results;
}
/**
* Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
* manager.
*/
- private void extractGValue(final CallContract<GValue<Map<?,?>>> contract) {
+ private Collection<GValue<?>> extractGValue(final
CallContract<GValue<Map<?,?>>> contract) {
+ Collection<GValue<?>> results = new ArrayList();
if (contract.getStaticParams().getName() != null) {
- gValueRegistry.put(contract.getStaticParams().getName(),
contract.getStaticParams());
+ results.add(contract.getStaticParams());
+ }
+ return results;
+ }
+
+ /**
+ * Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
+ * manager.
+ */
+ private Collection<GValue<?>> extractGValue(final PredicateContract
contract) {
+ if (contract.getPredicate() != null) {
+ return contract.getPredicate().getGValueRegistry().getGValues();
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Extract {@link GValue} instances from contracts to the registry after
{@link #lock()} has been called on the
+ * manager.
+ */
+ private Collection<GValue<?>> extractGValue(final HasContainerHolder
contract) {
+ Collection<GValue<?>> results = new ArrayList();
+ for (P<?> predicate : contract.getPredicates()) {
+ if (predicate != null) {
+ results.addAll(predicate.getGValueRegistry().getGValues());
+ }
}
+ return results;
}
@Override
public GValueManager clone() {
- return new GValueManager(gValueRegistry, stepRegistry,
predicateRegistry);
+ return new GValueManager(gValueRegistry, stepRegistry);
}
}
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 24d7d538cd..6dee62840d 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -43,23 +43,27 @@ public class P<V> implements Predicate<V>, Serializable,
Cloneable {
protected V value;
protected V originalValue;
- public boolean parameterized;
public GValueRegistry gValueRegistry;
public P(final PBiPredicate<V, V> biPredicate, V value) {
- parameterized = value instanceof GValue || (value instanceof List &&
((List) value).stream().anyMatch(v -> v instanceof GValue));
- if (parameterized) {
- if (value instanceof GValue) {
- gValueRegistry = new GValueRegistry(this, (GValue<V>) value);
- value = ((GValue<V>) value).get();
- } else {
- gValueRegistry = new GValueRegistry(this,
GValue.ensureGValues(((List) value).toArray()));
- }
+ if (value instanceof GValue) {
+ gValueRegistry = new GValueRegistry(this, (GValue<V>) value);
+ this.value = ((GValue<V>) value).get();
+ } else if (value instanceof List && ((List) value).stream().anyMatch(v
-> v instanceof GValue)) {
+ gValueRegistry = new GValueRegistry(this,
GValue.ensureGValues(((List) value).toArray()));
+ this.value = (V)
Arrays.asList(GValue.resolveToValues(GValue.ensureGValues(((List)
value).toArray())));
} else {
gValueRegistry = new GValueRegistry();
+ this.value = value;
}
- this.value = value;
- this.originalValue = value;
+ this.originalValue = this.value;
+ this.biPredicate = biPredicate;
+ }
+
+ public P(final PBiPredicate<V, V> biPredicate, GValue<V> value) {
+ gValueRegistry = new GValueRegistry(this, value);
+ this.value = value.get();
+ this.originalValue = value.get();
this.biPredicate = biPredicate;
}
@@ -93,12 +97,7 @@ public class P<V> implements Predicate<V>, Serializable,
Cloneable {
@Override
public boolean test(final V testValue) {
- // this might be a bunch of GValue that need to be resolved. zomg
- if (this.value instanceof List) {
- return this.biPredicate.test(testValue, (V) ((List)
this.value).stream().map(GValue::valueOf).collect(Collectors.toList()));
- } else {
- return this.biPredicate.test(testValue, (V)
GValue.valueOf(this.value));
- }
+ return this.biPredicate.test(testValue, this.value);
}
@Override
@@ -300,34 +299,40 @@ public class P<V> implements Predicate<V>, Serializable,
Cloneable {
}
public boolean isParameterized() {
- return parameterized;
+ return !gValueRegistry.isEmpty();
+ }
+
+ public GValueRegistry getGValueRegistry() {
+ return gValueRegistry;
}
- protected class GValueRegistry implements Serializable {
- private Map<P, GValue> GValueRegistry = new IdentityHashMap<>();
+ protected class GValueRegistry<T> implements Serializable {
+ private Map<P, GValue<T>> gValueRegistry = new IdentityHashMap<>();
- public GValueRegistry() {};
+ public GValueRegistry() {}
- public GValueRegistry(P predicate, GValue gValue) {
- GValueRegistry.put(predicate, gValue);
+ public GValueRegistry(P predicate, GValue<T> gValue) {
+ gValueRegistry.put(predicate, gValue);
}
- public GValueRegistry(P predicate, GValue[] gValues) {
- for (GValue gValue : gValues) {
+ public GValueRegistry(P predicate, GValue<T>[] gValues) {
+ for (GValue<T> gValue : gValues) {
if (gValue.isVariable()) {
- GValueRegistry.put(predicate, gValue);
+ gValueRegistry.put(predicate, gValue);
}
}
}
- public GValueRegistry(GValueRegistry... registries) {
- for (final GValueRegistry registry : registries) {
- this.merge(registry);
- }
+ public void addAll(final GValueRegistry other) {
+ this.gValueRegistry.putAll(other.gValueRegistry);
+ }
+
+ public boolean isEmpty(){
+ return this.gValueRegistry.isEmpty();
}
- public void merge(final GValueRegistry other) {
- this.GValueRegistry.putAll(other.GValueRegistry);
+ public Collection<GValue<T>> getGValues() {
+ return gValueRegistry.values();
}
}
}
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
index 2e599c3e77..97e42f0b7d 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
@@ -18,6 +18,8 @@
*/
package org.apache.tinkerpop.gremlin.process.traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+
/**
* Predefined {@code Predicate} values that can be used as {@code String}
filters.
*
@@ -29,6 +31,10 @@ public class TextP extends P<String> {
super(biPredicate, value);
}
+ public TextP(final PBiPredicate<String, String> biPredicate, final
GValue<String> value) {
+ super(biPredicate, value);
+ }
+
@Override
public boolean equals(final Object other) {
return other instanceof TextP && super.equals(other);
@@ -59,6 +65,15 @@ public class TextP extends P<String> {
return new TextP(Text.startingWith, value);
}
+ /**
+ * Determines if String does start with the given value.
+ *
+ * @since 3.8.0
+ */
+ public static TextP startingWith(final GValue<String> value) {
+ return new TextP(Text.startingWith, value);
+ }
+
/**
* Determines if String does not start with the given value.
*
@@ -68,6 +83,15 @@ public class TextP extends P<String> {
return new TextP(Text.notStartingWith, value);
}
+ /**
+ * Determines if String does not start with the given value.
+ *
+ * @since 3.8.0
+ */
+ public static TextP notStartingWith(final GValue<String> value) {
+ return new TextP(Text.notStartingWith, value);
+ }
+
/**
* Determines if String does start with the given value.
*
@@ -77,6 +101,15 @@ public class TextP extends P<String> {
return new TextP(Text.endingWith, value);
}
+ /**
+ * Determines if String does start with the given value.
+ *
+ * @since 3.8.0
+ */
+ public static TextP endingWith(final GValue<String> value) {
+ return new TextP(Text.endingWith, value);
+ }
+
/**
* Determines if String does not start with the given value.
*
@@ -86,6 +119,15 @@ public class TextP extends P<String> {
return new TextP(Text.notEndingWith, value);
}
+ /**
+ * Determines if String does not start with the given value.
+ *
+ * @since 3.8.0
+ */
+ public static TextP notEndingWith(final GValue<String> value) {
+ return new TextP(Text.notEndingWith, value);
+ }
+
/**
* Determines if String does contain the given value.
*
@@ -95,6 +137,15 @@ public class TextP extends P<String> {
return new TextP(Text.containing, value);
}
+ /**
+ * Determines if String does contain the given value.
+ *
+ * @since 3.8.0
+ */
+ public static TextP containing(final GValue<String> value) {
+ return new TextP(Text.containing, value);
+ }
+
/**
* Determines if String does not contain the given value.
*
@@ -103,6 +154,15 @@ public class TextP extends P<String> {
public static TextP notContaining(final String value) {
return new TextP(Text.notContaining, value);
}
+
+ /**
+ * Determines if String does not contain the given value.
+ *
+ * @since 3.8.0
+ */
+ public static TextP notContaining(final GValue<String> value) {
+ return new TextP(Text.notContaining, value);
+ }
/**
* Determines if String has a match with the given regex pattern. The
TinkerPop reference implementation uses
@@ -116,6 +176,18 @@ public class TextP extends P<String> {
return new TextP(new Text.RegexPredicate(value, false), value);
}
+ /**
+ * Determines if String has a match with the given regex pattern. The
TinkerPop reference implementation uses
+ * Java syntax for regex. The string is considered a match to the pattern
if any substring matches the pattern. It
+ * is therefore important to use the appropriate boundary matchers (e.g.
`$` for end of a line) to ensure a proper
+ * match.
+ *
+ * @since 3.8.0
+ */
+ public static TextP regex(final GValue<String> value) {
+ return new TextP(new Text.RegexPredicate(value.get(), false), value);
+ }
+
/**
* Determines if String has no match with the given regex pattern and the
reference implementation treats it as a
* simple negation of the evaluation of the pattern match of {@link
#regex(String)}.
@@ -125,4 +197,14 @@ public class TextP extends P<String> {
public static TextP notRegex(final String value) {
return new TextP(new Text.RegexPredicate(value, true), value);
}
+
+ /**
+ * Determines if String has no match with the given regex pattern and the
reference implementation treats it as a
+ * simple negation of the evaluation of the pattern match of {@link
#regex(String)}.
+ *
+ * @since 3.8.0
+ */
+ public static TextP notRegex(final GValue<String> value) {
+ return new TextP(new Text.RegexPredicate(value.get(), true), value);
+ }
}
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 f94bf9d70b..47da16bda3 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
@@ -2449,6 +2449,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
* @since 3.0.0-incubating
*/
public default GraphTraversal<S, E> filter(final Predicate<Traverser<E>>
predicate) {
+ if (predicate != null && predicate instanceof P && ((P<Traverser<E>>)
predicate).isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by filter()");
+ }
this.asAdmin().getBytecode().addStep(Symbols.filter, predicate);
return this.asAdmin().addStep(new LambdaFilterStep<>(this.asAdmin(),
predicate));
}
@@ -2559,6 +2562,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
* @since 3.0.0-incubating
*/
public default GraphTraversal<S, E> where(final String startKey, final
P<String> predicate) {
+ if (predicate != null && predicate.isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by where()");
+ }
this.asAdmin().getBytecode().addStep(Symbols.where, startKey,
predicate);
return this.asAdmin().addStep(new WherePredicateStep<>(this.asAdmin(),
Optional.ofNullable(startKey), predicate));
}
@@ -2574,6 +2580,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
* @since 3.0.0-incubating
*/
public default GraphTraversal<S, E> where(final P<String> predicate) {
+ if (predicate != null && predicate.isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by where()");
+ }
this.asAdmin().getBytecode().addStep(Symbols.where, predicate);
return this.asAdmin().addStep(new WherePredicateStep<>(this.asAdmin(),
Optional.empty(), predicate));
}
@@ -3006,6 +3015,8 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
// if calling hasKey(null), the likely use the caller is going for is
not a "no predicate" but a eq(null)
if (null == predicate) {
return hasKey((String) null);
+ } else if (predicate.isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by hasKey()");
} else {
this.asAdmin().getBytecode().addStep(Symbols.hasKey, predicate);
return TraversalHelper.addHasContainer(this.asAdmin(), new
HasContainer(T.key.getAccessor(), predicate));
@@ -3080,7 +3091,7 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
final IsStep<E> step = new IsStep<>(this.asAdmin(), predicate);
if (predicate.isParameterized()) {
- this.asAdmin().getGValueManager().register(step, predicate);
+ this.asAdmin().getGValueManager().register(step, step);
}
return this.asAdmin().addStep(step);
@@ -3100,7 +3111,7 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
final IsStep<E> step = new IsStep<>(this.asAdmin(), predicate);
if (predicate.isParameterized()) {
- this.asAdmin().getGValueManager().register(step, predicate);
+ this.asAdmin().getGValueManager().register(step, step);
}
return this.asAdmin().addStep(step);
@@ -3515,6 +3526,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
* @since 3.7.1
*/
public default <S2> GraphTraversal<S, E> all(final P<S2> predicate) {
+ if (predicate != null && predicate.isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by all()"); //TODO:: should this be supported?
+ }
this.asAdmin().getBytecode().addStep(Symbols.all, predicate);
return this.asAdmin().addStep(new AllStep<>(this.asAdmin(),
predicate));
}
@@ -3528,6 +3542,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
* @since 3.7.1
*/
public default <S2> GraphTraversal<S, E> any(final P<S2> predicate) {
+ if (predicate != null && predicate.isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by any()"); //TODO:: should this be supported?
+ }
this.asAdmin().getBytecode().addStep(Symbols.any, predicate);
return this.asAdmin().addStep(new AnyStep<>(this.asAdmin(),
predicate));
}
@@ -4045,6 +4062,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
*/
public default <E2> GraphTraversal<S, E2> choose(final Predicate<E>
choosePredicate,
final Traversal<?, E2>
trueChoice, final Traversal<?, E2> falseChoice) {
+ if (choosePredicate instanceof P && ((P<E>)
choosePredicate).isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by choose()");
+ }
this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate,
trueChoice, falseChoice);
return this.asAdmin().addStep(new ChooseStep<E, E2,
Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.filter(new
PredicateTraverser<>(choosePredicate)), (Traversal.Admin<E, E2>) trueChoice,
(Traversal.Admin<E, E2>) falseChoice));
}
@@ -4061,6 +4081,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
*/
public default <E2> GraphTraversal<S, E2> choose(final Predicate<E>
choosePredicate,
final Traversal<?, E2>
trueChoice) {
+ if (choosePredicate instanceof P && ((P<E>)
choosePredicate).isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by choose()");
+ }
this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate,
trueChoice);
return this.asAdmin().addStep(new ChooseStep<E, E2,
Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.filter(new
PredicateTraverser<>(choosePredicate)), (Traversal.Admin<E, E2>) trueChoice,
(Traversal.Admin<E, E2>) __.identity()));
}
@@ -4154,6 +4177,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
* @since 3.0.0-incubating
*/
public default GraphTraversal<S, E> emit(final Predicate<Traverser<E>>
emitPredicate) {
+ if (emitPredicate != null && emitPredicate instanceof P &&
((P<Traverser<E>>) emitPredicate).isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by emit()");
+ }
this.asAdmin().getBytecode().addStep(Symbols.emit, emitPredicate);
return RepeatStep.addEmitToTraversal(this, (Traversal.Admin<E, ?>)
__.filter(emitPredicate));
}
@@ -4192,6 +4218,9 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
* @since 3.0.0-incubating
*/
public default GraphTraversal<S, E> until(final Predicate<Traverser<E>>
untilPredicate) {
+ if (untilPredicate != null && untilPredicate instanceof P &&
((P<Traverser<E>>) untilPredicate).isParameterized()) {
+ throw new IllegalArgumentException("Parameterized predicates are
not supported by until()");
+ }
this.asAdmin().getBytecode().addStep(Symbols.until, untilPredicate);
return RepeatStep.addUntilToTraversal(this, (Traversal.Admin<E, ?>)
__.filter(untilPredicate));
}
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
index a65f4e8812..dbc78a6cc0 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -51,6 +51,9 @@ public class GValue<V> implements Serializable {
if (name != null && name.startsWith("_")) {
throw new IllegalArgumentException(String.format("Invalid GValue
name [%s]. Should not start with _.", name));
}
+ if (value instanceof GValue) {
+ throw new IllegalArgumentException("GValues cannot be nested");
+ }
this.name = name;
this.type = type;
this.value = value;
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
index 67c3d1e7e4..b4b08eac9e 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
@@ -18,14 +18,18 @@
*/
package org.apache.tinkerpop.gremlin.process.traversal.step;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.StepContract;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
+import java.util.Collection;
import java.util.List;
+import java.util.stream.Collectors;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
-public interface HasContainerHolder {
+public interface HasContainerHolder extends StepContract {
public List<HasContainer> getHasContainers();
@@ -34,4 +38,8 @@ public interface HasContainerHolder {
public default void removeHasContainer(final HasContainer hasContainer) {
throw new UnsupportedOperationException("The holder does not support
container removal: " + this.getClass().getCanonicalName());
}
+
+ public default Collection<P<?>> getPredicates() {
+ return getHasContainers().stream().map(p ->
p.getPredicate()).collect(Collectors.toList());
+ }
}
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
index a2889864a8..c27bc51248 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
@@ -21,6 +21,7 @@ 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.step.stepContract.PredicateContract;
import
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -31,7 +32,7 @@ import java.util.Set;
* @author Daniel Kuppitz (http://gremlin.guru)
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
-public final class IsStep<S> extends FilterStep<S> {
+public final class IsStep<S> extends FilterStep<S> implements
PredicateContract {
private P<S> predicate;
@@ -50,7 +51,7 @@ public final class IsStep<S> extends FilterStep<S> {
return StringFactory.stepString(this, this.predicate);
}
-
+ @Override
public P<S> getPredicate() {
return this.predicate;
}
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/stepContract/PredicateContract.java
similarity index 57%
copy from
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
copy to
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/stepContract/PredicateContract.java
index 67c3d1e7e4..b940816591 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/stepContract/PredicateContract.java
@@ -16,22 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.tinkerpop.gremlin.process.traversal.step;
+package org.apache.tinkerpop.gremlin.process.traversal.step.stepContract;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
-
-import java.util.List;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * Defines the contract for steps containing a single {@link P}.
*/
-public interface HasContainerHolder {
-
- public List<HasContainer> getHasContainers();
-
- public void addHasContainer(final HasContainer hasContainer);
+public interface PredicateContract extends StepContract {
- public default void removeHasContainer(final HasContainer hasContainer) {
- throw new UnsupportedOperationException("The holder does not support
container removal: " + this.getClass().getCanonicalName());
- }
+ /**
+ * Retrieves the step's predicate.
+ *
+ * @return the predicate associated with the step
+ */
+ public P<?> getPredicate();
}
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
index 9520a58263..010ee2d1fa 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
@@ -34,12 +34,11 @@ public abstract class ConnectiveP<V> extends P<V> {
protected List<P<V>> predicates = new ArrayList<>();
public ConnectiveP(final List<P<V>> predicates) {
- super(null, null);
+ super(null, (V) null);
for (P<V> p : predicates) {
- if (p.parameterized) {
- this.parameterized = true;
- this.gValueRegistry.merge(p.gValueRegistry);
+ if (p.isParameterized()) {
+ this.gValueRegistry.addAll(p.gValueRegistry);
}
}
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index a981e1a1ce..c881cca44b 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -791,8 +791,16 @@ public final class TraversalHelper {
public static <T extends Traversal.Admin<?, ?>> T addHasContainer(final T
traversal, final HasContainer hasContainer) {
if (traversal.getEndStep() instanceof HasContainerHolder) {
((HasContainerHolder)
traversal.getEndStep()).addHasContainer(hasContainer);
+ if (hasContainer.getPredicate().isParameterized()) {
+ traversal.getGValueManager().register(traversal.getEndStep(),
(HasContainerHolder) traversal.getEndStep());
+ }
return traversal;
- } else
- return (T) traversal.addStep(new HasStep<>(traversal,
hasContainer));
+ } else {
+ HasStep<?> step = new HasStep<>(traversal, hasContainer);
+ if (hasContainer.getPredicate().isParameterized()) {
+ traversal.getGValueManager().register(step, step);
+ }
+ return (T) traversal.addStep(step);
+ }
}
}
diff --git
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
index 15855e0108..322133d52b 100644
---
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
+++
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
@@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
import org.junit.Before;
@@ -66,6 +67,12 @@ public class PTest {
{P.eq(Double.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY,
false},
{P.eq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY,
false},
{P.eq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY,
false},
+ {P.eq(GValue.of("x",0)), 0, true},
+ {P.eq(GValue.of("x",-0)), +0, true},
+ {P.eq(GValue.of("x",0)), 1, false},
+ {P.eq(GValue.of("x",0)), null, false},
+ {P.eq(GValue.of("x",null)), null, true},
+ {P.eq(GValue.of("x",null)), 0, false},
{P.neq(0), 0, false},
{P.neq(0), -0, false},
{P.neq(0), +0, false},
@@ -77,31 +84,63 @@ public class PTest {
{P.neq(Double.POSITIVE_INFINITY),
Double.NEGATIVE_INFINITY, true},
{P.neq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY,
true},
{P.neq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY,
true},
+ {P.neq(GValue.of("x",0)), 0, false},
+ {P.neq(GValue.of("x",-0)), +0, false},
+ {P.neq(GValue.of("x",0)), 1, true},
+ {P.neq(GValue.of("x",0)), null, true},
+ {P.neq(GValue.of("x",null)), null, false},
+ {P.neq(GValue.of("x",null)), 0, true},
{P.gt(0), -1, false},
{P.gt(0), 0, false},
{P.gt(0), 1, true},
+ {P.gt(GValue.of("x",0)), -1, false},
+ {P.gt(GValue.of("x",0)), 0, false},
+ {P.gt(GValue.of("x",0)), 1, true},
{P.lt(0), -1, true},
{P.lt(0), 0, false},
{P.lt(0), 1, false},
+ {P.lt(GValue.of("x",0)), -1, true},
+ {P.lt(GValue.of("x",0)), 0, false},
+ {P.lt(GValue.of("x",0)), 1, false},
{P.gte(0), -1, false},
{P.gte(0), 0, true},
{P.gte(0), 1, true},
+ {P.gte(GValue.of("x",0)), -1, false},
+ {P.gte(GValue.of("x",0)), 0, true},
+ {P.gte(GValue.of("x",0)), 1, true},
{P.lte(0), -1, true},
{P.lte(0), 0, true},
{P.lte(0), 1, false},
+ {P.lte(GValue.of("x",0)), -1, true},
+ {P.lte(GValue.of("x",0)), 0, true},
+ {P.lte(GValue.of("x",0)), 1, false},
{P.between(1, 10), 0, false},
{P.between(1, 10), 1, true},
{P.between(1, 10), 9, true},
{P.between(1, 10), 10, false},
+ {P.between(GValue.of("x",1), GValue.of("y",10)), 0, false},
+ {P.between(GValue.of("x",1), GValue.of("y",10)), 1, true},
+ {P.between(GValue.of("x",1), 10), 9, true},
+ {P.between(1, GValue.of("y",10)), 10, false},
{P.inside(1, 10), 0, false},
{P.inside(1, 10), 1, false},
{P.inside(1, 10), 9, true},
{P.inside(1, 10), 10, false},
+ {P.inside(GValue.of("x",1), GValue.of("y",10)), 0, false},
+ {P.inside(GValue.of("x",1), GValue.of("y",10)), 1, false},
+ {P.inside(1, GValue.of("y",10)), 9, true},
+ {P.inside(GValue.of("x",1), 10), 10, false},
{P.outside(1, 10), 0, true},
{P.outside(1, 10), 1, false},
{P.outside(1, 10), 9, false},
{P.outside(1, 10), 10, false},
{P.outside(1, Double.NaN), 0, true},
+ {P.outside(GValue.of("x",1), GValue.of("y",10)), 0, true},
+ {P.outside(GValue.of("x",1), GValue.of("y",10)), 1, false},
+ {P.outside(1, GValue.of("y",10)), 9, false},
+ {P.outside(GValue.of("x",1), 10), 10, false},
+ {P.outside(GValue.of("x",1), GValue.of("y",Double.NaN)),
0, true},
+
{P.within(), 0, false},
{P.within((Object) null), 0, false},
{P.within((Object) null), null, true},
@@ -119,6 +158,16 @@ public class PTest {
{P.within(Arrays.asList(1, 2, 3)), 0, false},
{P.within(Arrays.asList(1, 2, 3)), 1, true},
{P.within(Arrays.asList(1, 2, 3)), 10, false},
+ {P.within(GValue.of("x", null)), 0, false},
+ {P.within(GValue.of("x", null)), null, true},
+ {P.within(GValue.of("x", (Collection) null)), 0, false},
+ {P.within(GValue.of("x", (Collection) null)), null, true},
+ {P.within(GValue.of("x", null), GValue.of("y", 2),
GValue.of("z", 3)), 0, false},
+ {P.within(GValue.of("x", null), GValue.of("y", 2),
GValue.of("z", 3)), null, true},
+ {P.within(GValue.of("x", null), GValue.of("y", 2),
GValue.of("z", 3)), 2, true},
+ {P.within(GValue.of("x", 1), GValue.of("y", 2),
GValue.of("z", 3)), 0, false},
+ {P.within(GValue.of("x", 1), GValue.of("y", 2),
GValue.of("z", 3)), 1, true},
+ {P.within(GValue.of("x", 1), GValue.of("y", 2),
GValue.of("z", 3)), 10, false},
{P.without(), 0, true},
{P.without((Object) null), 0, true},
{P.without((Object) null), null, false},
@@ -136,11 +185,32 @@ public class PTest {
{P.without(Arrays.asList(1, 2, 3)), 0, true},
{P.without(Arrays.asList(1, 2, 3)), 1, false},
{P.without(Arrays.asList(1, 2, 3)), 10, true},
+ {P.without(GValue.of("x", null)), 0, true},
+ {P.without(GValue.of("x", null)), null, false},
+ {P.without(GValue.of("x", (Collection) null)), 0, true},
+ {P.without(GValue.of("x", (Collection) null)), null,
false},
+ {P.without(GValue.of("x", null), GValue.of("y", 2),
GValue.of("z", 3)), 0, true},
+ {P.without(GValue.of("x", null), GValue.of("y", 2),
GValue.of("z", 3)), null, false},
+ {P.without(GValue.of("x", null), GValue.of("y", 2),
GValue.of("z", 3)), 2, false},
+ {P.without(GValue.of("x", 1), GValue.of("y", 2),
GValue.of("z", 3)), 0, true},
+ {P.without(GValue.of("x", 1), GValue.of("y", 2),
GValue.of("z", 3)), 1, false},
+ {P.without(GValue.of("x", 1), GValue.of("y", 2),
GValue.of("z", 3)), 10, true},
+ {P.without(Arrays.asList(GValue.of("x", null),
GValue.of("y", 2), GValue.of("z", 3))), null, false},
+ {P.without(Arrays.asList(GValue.of("x", null),
GValue.of("y", 2), GValue.of("z", 3))), 1, true},
+ {P.without(Arrays.asList(GValue.of("x", null),
GValue.of("y", 2), GValue.of("z", 3))), 2, false},
+ {P.without(Arrays.asList(GValue.of("x", 1), GValue.of("y",
2), GValue.of("z", 3))), 0, true},
+ {P.without(Arrays.asList(GValue.of("x", 1), GValue.of("y",
2), GValue.of("z", 3))), 1, false},
+ {P.without(Arrays.asList(GValue.of("x", 1), GValue.of("y",
2), GValue.of("z", 3))), 10, true},
{P.between("m", "n").and(P.neq("marko")), "marko", false},
{P.between("m", "n").and(P.neq("marko")), "matthias",
true},
{P.between("m", "n").or(P.eq("daniel")), "marko", true},
{P.between("m", "n").or(P.eq("daniel")), "daniel", true},
{P.between("m", "n").or(P.eq("daniel")), "stephen", false},
+ {P.between(GValue.of("x", "m"), GValue.of("y",
"n")).and(P.neq(GValue.of("z", "marko"))), "marko", false},
+ {P.between(GValue.of("x", "m"), GValue.of("y",
"n")).and(P.neq(GValue.of("z", "marko"))), "matthias", true},
+ {P.between(GValue.of("x", "m"), GValue.of("y",
"n")).or(P.eq(GValue.of("z", "daniel"))), "marko", true},
+ {P.between(GValue.of("x", "m"), GValue.of("y",
"n")).or(P.eq(GValue.of("z", "daniel"))), "daniel", true},
+ {P.between(GValue.of("x", "m"), GValue.of("y",
"n")).or(P.eq(GValue.of("z", "daniel"))), "stephen", false},
{P.within().and(P.within()), 0, false},
{P.within().and(P.without()), 0, false},
{P.without().and(P.without()), 0, true},
@@ -151,10 +221,16 @@ public class PTest {
// text predicates
{TextP.containing("ark"), "marko", true},
{TextP.containing("ark"), "josh", false},
+ {TextP.containing(GValue.ofString("x", "ark")), "marko",
true},
+ {TextP.containing(GValue.ofString("x", "ark")), "josh",
false},
{TextP.startingWith("jo"), "marko", false},
{TextP.startingWith("jo"), "josh", true},
+ {TextP.startingWith(GValue.ofString("x", "jo")), "marko",
false},
+ {TextP.startingWith(GValue.ofString("x", "jo")), "josh",
true},
{TextP.endingWith("ter"), "marko", false},
{TextP.endingWith("ter"), "peter", true},
+ {TextP.endingWith(GValue.ofString("x", "ter")), "marko",
false},
+ {TextP.endingWith(GValue.ofString("x", "ter")), "peter",
true},
{TextP.containing("o"), "marko", true},
{TextP.containing("o"), "josh", true},
{TextP.containing("o").and(P.gte("j")), "marko", true},
@@ -163,20 +239,30 @@ public class PTest {
{TextP.containing("o").and(P.gte("j")).and(TextP.endingWith("ko")), "josh",
false},
{TextP.containing("o").and(P.gte("j").and(TextP.endingWith("ko"))), "marko",
true},
{TextP.containing("o").and(P.gte("j").and(TextP.endingWith("ko"))), "josh",
false},
+ {TextP.containing(GValue.ofString("x", "o")), "marko",
true},
+ {TextP.containing(GValue.ofString("x", "o")), "josh",
true},
+ {TextP.containing(GValue.ofString("x",
"o")).and(P.gte(GValue.ofString("y", "j"))), "marko", true},
+ {TextP.containing(GValue.ofString("x",
"o")).and(P.gte(GValue.ofString("y", "j"))), "josh", true},
+ {TextP.containing(GValue.ofString("x",
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")),
"marko", true},
+ {TextP.containing(GValue.ofString("x",
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")),
"josh", false},
+ {TextP.containing(GValue.ofString("x",
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")),
"marko", true},
+ {TextP.containing(GValue.ofString("x",
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")),
"josh", false},
// type errors
{P.outside(Double.NaN, Double.NaN), 0,
GremlinTypeErrorException.class},
{P.inside(-1, Double.NaN), 0,
GremlinTypeErrorException.class},
{P.inside(Double.NaN, 1), 0,
GremlinTypeErrorException.class},
- {TextP.containing(null), "abc",
GremlinTypeErrorException.class},
+ {TextP.containing((String) null), "abc",
GremlinTypeErrorException.class},
{TextP.containing("abc"), null,
GremlinTypeErrorException.class},
- {TextP.containing(null), null,
GremlinTypeErrorException.class},
- {TextP.startingWith(null), "abc",
GremlinTypeErrorException.class},
+ {TextP.containing((String) null), null,
GremlinTypeErrorException.class},
+ {TextP.startingWith((String) null), "abc",
GremlinTypeErrorException.class},
{TextP.startingWith("abc"), null,
GremlinTypeErrorException.class},
- {TextP.startingWith(null), null,
GremlinTypeErrorException.class},
- {TextP.endingWith(null), "abc",
GremlinTypeErrorException.class},
+ {TextP.startingWith((String) null), null,
GremlinTypeErrorException.class},
+ {TextP.endingWith((String) null), "abc",
GremlinTypeErrorException.class},
{TextP.endingWith("abc"), null,
GremlinTypeErrorException.class},
- {TextP.endingWith(null), null,
GremlinTypeErrorException.class},
+ {TextP.endingWith((String) null), null,
GremlinTypeErrorException.class},
+
+ // regex
{TextP.regex("D"), "Dallas Fort Worth", true},
{TextP.regex("d"), "Dallas Fort Worth", false},
{TextP.regex("^D"), "Dallas Fort Worth", true},
@@ -196,6 +282,10 @@ public class PTest {
{TextP.regex("(?i)abc"), "123-ABC-456", true},
{TextP.regex("(?i)[a-b]{3}-[1-9]{3}-[a-z]{3}"),
"123-ABC-456", false},
{TextP.regex("Tinker.*\\u00A9"), "Apache TinkerPop©",
true},
+ {TextP.regex(GValue.ofString("x",
"(?i)[a-b]{3}-[1-9]{3}-[a-z]{3}")), "123-ABC-456", false},
+ {TextP.regex(GValue.ofString("x", "Tinker.*\\u00A9")),
"Apache TinkerPop©", true},
+ {TextP.notRegex(GValue.ofString("x",
"(?i)[a-b]{3}-[1-9]{3}-[a-z]{3}")), "123-ABC-456", true},
+ {TextP.notRegex(GValue.ofString("x", "Tinker.*\\u00A9")),
"Apache TinkerPop©", false},
}));
}
diff --git
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
index ff5f800e80..163a390e1d 100644
---
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
+++
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
@@ -223,9 +223,8 @@ public class CountStrategyTest {
{__.out().count().is(gte(GValue.ofInteger("x", 2)))},
{__.out().count().is(inside(GValue.ofInteger("x", 2),
GValue.ofInteger("y", 4)))},
{__.out().count().is(outside(GValue.ofInteger("x", 2),
GValue.ofInteger("y", 4)))},
- // TODO: within/out() are broken for GValue - not
initializing properly in the P constructor to preserve the GValue and missing
the chance to mark as parameterized
-// {__.out().count().is(within(GValue.ofInteger("x", 2),
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
-// {__.out().count().is(without(GValue.ofInteger("x", 2),
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
+ {__.out().count().is(within(GValue.ofInteger("x", 2),
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
+ {__.out().count().is(without(GValue.ofInteger("x", 2),
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
{__.map(__.count().is(GValue.of("x", 0)))},
{__.flatMap(__.count().is(GValue.of("x", 0)))},
{__.flatMap(__.count().is(GValue.of("x", 0))).as("a")},
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 ec23244172..198a4cbd72 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
@@ -467,7 +467,7 @@ const gremlins = {
g_withoutStrategiesXMatchPredicateStrategyX_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXa_b_cX:
[function({g}) { return
g.withoutStrategies(MatchPredicateStrategy).V().match(__.as("a").out("created").has("name",
"lop").as("b"), __.as("b").in_("created").has("age",
29).as("c")).where(__.as("c").repeat(__.out()).times(2)).select("a", "b", "c")
}],
g_withStrategiesXMessagePassingReductionStrategyX_V: [function({g}) {
return g.withStrategies(new MessagePassingReductionStrategy()).V() }],
g_withoutStrategiesXMessagePassingReductionStrategyX_V: [function({g}) {
return g.withoutStrategies(MessagePassingReductionStrategy).V() }],
- g_V_coworker: [function({g, xx1}) { return
g.V().hasLabel("person").filter(__.outE("created")).aggregate("p").as("p1").values("name").as("p1n").select("p").unfold().where(P.neq("p1")).as("p2").values("name").as("p2n").select("p2").out("created").choose(__.in_("created").where(P.eq("p1")),
__.values("name"),
__.constant(xx1)).group().by(__.select("p1n")).by(__.group().by(__.select("p2n")).by(__.unfold().fold().project("numCoCreated",
"coCreated").by(__.count(Scope.local)).by())).unfol [...]
+ g_V_coworker: [function({g}) { return
g.V().hasLabel("person").filter(__.outE("created")).aggregate("p").as("p1").values("name").as("p1n").select("p").unfold().where(P.neq("p1")).as("p2").values("name").as("p2n").select("p2").out("created").choose(__.in_("created").where(P.eq("p1")),
__.values("name"),
__.constant([])).group().by(__.select("p1n")).by(__.group().by(__.select("p2n")).by(__.unfold().fold().project("numCoCreated",
"coCreated").by(__.count(Scope.local)).by())).unfold() }],
g_V_coworker_with_midV: [function({g}) { return
g.V().hasLabel("person").filter(__.outE("created")).as("p1").V().hasLabel("person").where(P.neq("p1")).filter(__.outE("created")).as("p2").map(__.out("created").where(__.in_("created").as("p1")).values("name").fold()).group().by(__.select("p1").by("name")).by(__.group().by(__.select("p2").by("name")).by(__.project("numCoCreated",
"coCreated").by(__.count(Scope.local)).by())).unfold() }],
g_withStrategiesXOptionsStrategyX_V: [function({g}) { return
g.withStrategies(new OptionsStrategy()).V() }],
g_withStrategiesXOptionsStrategyXmyVar_myValueXX_V: [function({g}) {
return g.withStrategies(new OptionsStrategy({myVar: "myValue"})).V() }],
@@ -1679,7 +1679,7 @@ const gremlins = {
g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack:
[function({g, vid1}) { return g.withSack(1.0,
Operator.sum).V(vid1).local(__.out("knows").barrier(Barrier.normSack)).in_("knows").barrier().sack()
}],
g_V_sackXassignX_byXageX_sack: [function({g}) { return
g.V().sack(Operator.assign).by("age").sack() }],
g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack:
[function({g}) { return
g.withSack(10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
[...]
- g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack: [function({g, xx1}) {
return g.withSack(2).V().sack(Operator.div).by(__.constant(xx1)).sack() }],
+ g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack: [function({g}) { return
g.withSack(2).V().sack(Operator.div).by(__.constant(4.0)).sack() }],
g_V_sackXassignX_byXageX_byXnameX_sack: [function({g}) { return
g.V().sack(Operator.assign).by("age").by("name").sack() }],
g_V_sideEffectXidentityX: [function({g}) { return
g.V().sideEffect(__.identity()) }],
g_V_sideEffectXidentity_valuesXnameXX: [function({g}) { return
g.V().sideEffect(__.identity().values("name")) }],