This is an automated email from the ASF dual-hosted git repository.
Cole-Greer pushed a commit to branch 3.7-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.7-dev by this push:
new 7e1820c51b TINKERPOP-3270 `where(P)` throws a descriptive error for
non-String scope keys (#3559)
7e1820c51b is described below
commit 7e1820c51b4dcf5748662db9f9744ce36a664595
Author: Guian Gumpac <[email protected]>
AuthorDate: Thu Jul 23 17:23:40 2026 -0700
TINKERPOP-3270 `where(P)` throws a descriptive error for non-String scope
keys (#3559)
Assisted-by: Kiro: Claude Opus 4.8
---
CHANGELOG.asciidoc | 2 +-
.../traversal/step/filter/WherePredicateStep.java | 10 ++++-
.../process/traversal/step/filter/WhereTest.java | 45 ++++++++++++++++++++++
3 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 605013b87e..8abe3b199a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
=== TinkerPop 3.7.7 (Release Date: NOT OFFICIALLY RELEASED YET)
* Fixed `subgraph()` to throw a descriptive error identifying the required
`Edge` input instead of an internal `ClassCastException` when the traversal
produces a non-edge value.
+* Fixed `where(P)` to throw a descriptive error identifying the required
String scope key (and suggesting `is(P)` for value comparisons) instead of an
internal `ClassCastException` when given a non-String predicate value.
* Fixed `PeerPressure.property_name` in `gremlin-python` incorrectly mapping
to the `pageRank` property name token.
* Added `NextN(n)` to `Traversal` in `gremlin-go` for batched result
iteration, providing API parity with `next(n)` in the Java, Python, and .NET
GLVs.
* Added `next(n)` to `Traversal` in `gremlin-javascript` for batched result
iteration, providing API parity with `next(n)` in the Java, Python, and .NET
GLVs.
@@ -36,7 +37,6 @@
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Removed the Mono dependency from the `gremlin-dotnet` build/release process,
using `dotnet pack`/`dotnet nuget push` instead of `mono nuget.exe`.
* Expanded `gremlin-python` CI matrix to test against Python 3.9, 3.10, 3.11,
3.12, and 3.13.
* Add Node 26 support for `gremlin-javascript` and `gremlint`.
-* Corrected numerous inaccuracies in the reference documentation, including
wrong default values (connection pool sizes, buffer sizes, ports, timeouts),
stale serializer class names, removed options documented as available, and
broken code examples across the JVM, Python, `.NET`, Go, and JavaScript drivers.
* Fixed a panic in `gremlin-go` `PartitionStrategy` when `ReadPartitions` was
left unset.
* Fixed `gremlin-python` `ProductiveByStrategy` to pass through the
`productiveKeys` argument, which was previously accepted but never serialized
to the server.
* Deprecated `ProductiveByStrategy` which was introduced as a temporary way to
mimic pre-3.5.0 null processing behavior.
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
index 77c3f4abc9..55fd568ba6 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
@@ -101,8 +101,14 @@ public final class WherePredicateStep<S> extends
FilterStep<S> implements Scopin
}
public String getSelectKey(final P<Object> predicate) {
- return (String) (predicate.getValue() instanceof Collection ?
((Collection) predicate.getValue()).iterator().next()
- : predicate.getValue()); // hack for within("x"))
+ final Object selectKey = predicate.getValue() instanceof Collection
+ ? ((Collection) predicate.getValue()).iterator().next()
+ : predicate.getValue(); // hack for within("x")
+ if (!(selectKey instanceof String))
+ throw new IllegalArgumentException(String.format(
+ "where(P) requires a String scope key but encountered %s;
use is(P) to compare values",
+ null == selectKey ? "null" :
selectKey.getClass().getSimpleName()));
+ return (String) selectKey;
}
public void removeStartKey() {
diff --git
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
index e63ed52904..b7bd8ce971 100644
---
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
+++
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
@@ -24,6 +24,7 @@ import
org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Path;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.junit.Test;
@@ -52,10 +53,12 @@ import static
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.or;
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -127,6 +130,12 @@ public abstract class WhereTest extends
AbstractGremlinProcessTest {
public abstract Traversal<Vertex, String>
get_g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name(final Object v3Id);
+ // where(P) with a non-String scope key (invalid usage - value comparisons
require is(P))
+
+ public abstract Traversal<Vertex, Integer>
get_g_V_valuesXageX_whereXgtX5XX();
+
+ public abstract Traversal<Vertex, Vertex>
get_g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX();
+
@Test
@LoadGraphWith(MODERN)
public void
g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_eqXbXX() {
@@ -418,6 +427,28 @@ public abstract class WhereTest extends
AbstractGremlinProcessTest {
assertThat(traversal.hasNext(), is(false));
}
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_valuesXageX_whereXgtX5XX() {
+ try {
+ get_g_V_valuesXageX_whereXgtX5XX();
+ fail("where(P) with a non-String predicate value should throw an
IllegalArgumentException at construction");
+ } catch (IllegalArgumentException iae) {
+ assertThat(iae.getMessage(), containsString("use is(P)"));
+ }
+ }
+
+ @Test
+ @LoadGraphWith(MODERN)
+ public void g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX() {
+ try {
+ get_g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX();
+ fail("where(P) with a non-String predicate value should throw an
IllegalArgumentException at construction");
+ } catch (IllegalArgumentException iae) {
+ assertThat(iae.getMessage(), containsString("use is(P)"));
+ }
+ }
+
public static class Traversals extends WhereTest {
@@ -552,5 +583,19 @@ public abstract class WhereTest extends
AbstractGremlinProcessTest {
public Traversal<Vertex, String>
get_g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name(final Object v3Id) {
return g.V(v3Id).as("a").in().out().as("b").where("a",
eq("b")).by("age").values("name");
}
+
+ @Override
+ public Traversal<Vertex, Integer> get_g_V_valuesXageX_whereXgtX5XX() {
+ // gt(5) yields a P whose value is an Integer rather than a String
scope key; the cast mimics the
+ // erased P<String> that reaches where(P) via raw types, bytecode,
or deserialization
+ final P<String> nonStringKeyPredicate = (P) gt(5);
+ return g.V().<Integer>values("age").where(nonStringKeyPredicate);
+ }
+
+ @Override
+ public Traversal<Vertex, Vertex>
get_g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX() {
+ final P<String> nonStringKeyPredicate = (P) gt(5);
+ return
g.V().hasLabel("person").where(__.values("age").where(nonStringKeyPredicate));
+ }
}
}
\ No newline at end of file