You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by xi...@apache.org on 2025/10/28 23:09:25 UTC

(tinkerpop) branch 3.7-dev updated: CTR deprecate has(key, traversal)

This is an automated email from the ASF dual-hosted git repository.

xiazcy 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 7eaecf4264 CTR deprecate has(key, traversal)
7eaecf4264 is described below

commit 7eaecf42640629934c20f68eebcbe5c2c3e23ad4
Author: xiazcy <xi...@gmail.com>
AuthorDate: Tue Oct 28 16:09:17 2025 -0700

    CTR deprecate has(key, traversal)
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/reference/the-traversal.asciidoc          | 17 ++++++-------
 docs/src/upgrade/release-3.7.x.asciidoc            | 29 ++++++++++++++++++++++
 .../traversal/dsl/graph/GraphTraversal.java        |  4 +++
 .../gremlin/process/traversal/dsl/graph/__.java    |  4 +++
 .../Process/Traversal/GraphTraversal.cs            |  2 ++
 .../src/Gremlin.Net/Process/Traversal/__.cs        |  2 ++
 7 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 0e50ed6929..af6ba38b9b 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -27,6 +27,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Added getter for `parameterItems` and `valueTraversal` on `DifferenceStep`.
 * Added properties to `Element` objects found in a `Path` for GraphSON v2 and v3 and GraphBinary.
 * Fixed edge properties for GraphBinary which were not deserializing properly.
+* Deprecated `has(key, traversal)` and `has(T, traversal)` options for `has()` step.
 * Improved GLV examples reliability and documentation with step-by-step instructions.
 * Added root-level GLV examples in `glv-examples/` directory that use published driver versions for easy out-of-the-box usage, separate from module-level examples that use local development code.
 * Bump netty to 4.1.125.Final
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 5be99761e8..f8c7a47930 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -1901,15 +1901,14 @@ the key,value pairs for those vertices.
 <9> Property key is always stored as `String` and therefore an equality check with `null` will produce no result.
 <10> An example of `has()` where the argument is a `Traversal` and does not quite behave the way most expect.
 
-Item 10 in the above set of examples bears some discussion. The behavior is not such that the result of the `Traversal`
-is used as the comparing value for `has()`, but the current `Traverser`, which in this case is the vertex `label`, is
-given to the `Traversal` to behave as a filter itself. In other words, if the `Traversal` (i.e. `is('person')`) returns
-a value then the `has()` is effectively `true`. A common mistake is to try to use `select()` in this context where one
-would do `has('name', select('n'))` to try to inject the value of "n" into the step to get `has('name', <value-of-n>)`,
-but this would instead simply produce an always `true` filter for `has()`.
-
-TinkerPop does not support a regular expression predicate, although specific graph databases that leverage TinkerPop
-may provide a partial match extension.
+Item 10 in the above set of examples is deprecated as of 3.7.5, and bears some discussion. The behavior is not such that
+the result of the `Traversal` is used as the comparing value for `has()`, but the current `Traverser`, which in this case
+is the vertex `label`, is given to the `Traversal` to behave as a filter itself. In other words, if the `Traversal`
+(i.e. `is('person')`) returns a value then the `has()` is effectively `true`. A common mistake is to try to use
+`select()` in this context where one would do `has('name', select('n'))` to try to inject the value of "n" into the step
+to get `has('name', <value-of-n>)`, but this would instead simply produce an always `true` filter for `has()`. Due to
+this confusing expectation, this option is on the deprecation path for 3.7.5, and will be removed in next major version.
+The recommendation is to consider using `where()` for complex filtering or `has(key, predicate)` for value comparisons.
 
 *Additional References*
 
diff --git a/docs/src/upgrade/release-3.7.x.asciidoc b/docs/src/upgrade/release-3.7.x.asciidoc
index 09d40562ac..3423b21837 100644
--- a/docs/src/upgrade/release-3.7.x.asciidoc
+++ b/docs/src/upgrade/release-3.7.x.asciidoc
@@ -30,6 +30,35 @@ complete list of all the modifications that are part of this release.
 
 === Upgrading for Users
 
+==== Deprecated has(key, traversal)
+
+The `has(key, traversal)` API is deprecated as of 3.7.5, due to its confusing behavior that differed from other
+`has()` variants, and a common misunderstanding of the API. Unlike `has(key, value)`, which performs equality comparison,
+`has(key, traversal)` only checked if the traversal produced any result. This leads to inconsistency in the semantics,
+and this API be removed in the next major version. The recommendation is to consider using `where()` for complex
+filtering or `has(key, predicate)` for value comparisons.
+
+[source,text]
+----
+// 3.7.4 - this condition is meaningless but yields result because count() is productive
+gremlin> g.V().has("age", __.count())
+==>v[1]
+==>v[2]
+==>v[3]
+==>v[4]
+==>v[5]
+==>v[6]
+// 3.7.4 - simple example
+gremlin> g.V().has("age", __.is(P.gt(30)))
+==>v[4]
+==>v[6]
+// 3.7.5+ - for proper use cases consider using predicate or where() for filtering
+gremlin> g.V().has("age", P.gt(30))
+==>v[4]
+==>v[6]
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1463[TINKERPOP-1463]
 
 === Upgrading for Providers
 
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 c97a172b6d..d7163ecfa0 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
@@ -2254,6 +2254,8 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @return the traversal with an appended {@link HasStep}
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
      * @since 3.1.0-incubating
+     * @deprecated As of release 3.7.5, not replaced. Consider {@code where()} for complex filtering or
+     * {@code has(T, predicate)} for value comparisons.
      */
     public default GraphTraversal<S, E> has(final T accessor, final Traversal<?, ?> propertyTraversal) {
         if (null == accessor)
@@ -2288,6 +2290,8 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @return the traversal with an appended {@link HasStep}
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
      * @since 3.0.0-incubating
+     * @deprecated As of release 3.7.5, not replaced. Consider {@code where()} for complex filtering or
+     * {@code has(key, predicate)} for value comparisons.
      */
     public default GraphTraversal<S, E> has(final String propertyKey, final Traversal<?, ?> propertyTraversal) {
         // the translation here of null to has(String, Object) is likely what was intended. a null Traversal doesn't
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 270317772c..cb9a9bf251 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
@@ -943,6 +943,8 @@ public class __ {
 
     /**
      * @see GraphTraversal#has(T, Traversal)
+     * @deprecated As of release 3.7.5, not replaced. Consider {@code where()} for complex filtering or
+     * {@code has(T, predicate)} for value comparisons.
      */
     public static <A> GraphTraversal<A, A> has(final T accessor, final Traversal<?, ?> propertyTraversal) {
         return __.<A>start().has(accessor, propertyTraversal);
@@ -950,6 +952,8 @@ public class __ {
 
     /**
      * @see GraphTraversal#has(String, Traversal)
+     * @deprecated As of release 3.7.5, not replaced. Consider {@code where()} for complex filtering or
+     * {@code has(key, predicate)} for value comparisons.
      */
     public static <A> GraphTraversal<A, A> has(final String propertyKey, final Traversal<?, ?> propertyTraversal) {
         return __.<A>start().has(propertyKey, propertyTraversal);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index 8050f0ad56..9dbda4d2be 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -973,6 +973,7 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Adds the has step to this <see cref="GraphTraversal{SType, EType}" />.
         /// </summary>
+        [Obsolete("Deprecated as of 3.7.5. Not replaced. Consider Where() for complex filtering or Has(key, predicate) for value comparisons", false)]
         public GraphTraversal<TStart, TEnd> Has (string? propertyKey, ITraversal propertyTraversal)
         {
             Bytecode.AddStep("has", propertyKey, propertyTraversal);
@@ -1000,6 +1001,7 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Adds the has step to this <see cref="GraphTraversal{SType, EType}" />.
         /// </summary>
+        [Obsolete("Deprecated as of 3.7.5. Not replaced. Consider Where() for complex filtering or Has(T, predicate) for value comparisons", false)]
         public GraphTraversal<TStart, TEnd> Has (T accessor, ITraversal propertyTraversal)
         {
             Bytecode.AddStep("has", accessor, propertyTraversal);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
index 2ae4603cd1..4c81c5bd38 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
@@ -675,6 +675,7 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the has step to that traversal.
         /// </summary>
+        [Obsolete("Deprecated as of 3.7.5. Not replaced. Consider Where() for complex filtering or Has(key, predicate) for value comparisons", false)]
         public static GraphTraversal<object, object> Has(string? propertyKey, ITraversal propertyTraversal)
         {
             return new GraphTraversal<object, object>().Has(propertyKey, propertyTraversal);            
@@ -699,6 +700,7 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the has step to that traversal.
         /// </summary>
+        [Obsolete("Deprecated as of 3.7.5. Not replaced. Consider Where() for complex filtering or Has(key, predicate) for value comparisons", false)]
         public static GraphTraversal<object, object> Has(T accessor, ITraversal propertyTraversal)
         {
             return new GraphTraversal<object, object>().Has(accessor, propertyTraversal);