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/06/06 19:26:00 UTC

(tinkerpop) branch type-predicate-poc created (now f9f18479fe)

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

xiazcy pushed a change to branch type-predicate-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


      at f9f18479fe asbool() & type predicate proposal drafts

This branch includes the following new commits:

     new f9f18479fe asbool() & type predicate proposal drafts

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(tinkerpop) 01/01: asbool() & type predicate proposal drafts

Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

xiazcy pushed a commit to branch type-predicate-poc
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit f9f18479fe9830b2ea0d86cd5c11eb4d22f4137d
Author: xiazcy <xi...@gmail.com>
AuthorDate: Fri Jun 6 12:25:51 2025 -0700

    asbool() & type predicate proposal drafts
---
 .../src/dev/future/proposal-asbool-step-7.asciidoc |  75 +++++++++++++++
 .../dev/future/proposal-type-predicate-8.asciidoc  | 105 +++++++++++++++++++++
 .../gremlin/process/traversal/Compare.java         |  40 ++++++++
 .../tinkerpop/gremlin/process/traversal/P.java     |  21 +++++
 .../gremlin/util/GremlinValueComparator.java       |  11 +++
 .../tinkerpop/gremlin/process/traversal/PTest.java |   3 +
 6 files changed, 255 insertions(+)

diff --git a/docs/src/dev/future/proposal-asbool-step-7.asciidoc b/docs/src/dev/future/proposal-asbool-step-7.asciidoc
new file mode 100644
index 0000000000..901fddd141
--- /dev/null
+++ b/docs/src/dev/future/proposal-asbool-step-7.asciidoc
@@ -0,0 +1,75 @@
+////
+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.
+////
+
+image::apache-tinkerpop-logo.png[width=500,link="https://tinkerpop.apache.org"]
+
+*x.y.z - Proposal 7*
+
+== asBool() Step
+
+=== Motivation
+
+Given the additions of the `asString()` and `asDate()` steps in the 3.7 line, this proposal seeks to bridge another gap in language functionality, which is boolean parsing.
+
+=== Definition
+
+The `asBool()` step will convert the incoming traverser into a Boolean value.
+
+Note that `null` value will be considered `false`.
+
+The incoming traverser can be of type:
+
+*Number* - All non-zero values are considered `true`, zero, `NaN` and `null` values are considered `false`, for example:
+[cols=",",options="header",]
+|===
+|Numerical Value |Boolean Value
+|1 |true
+|0 |false
+|3.14 |true
+|-1 |true
+|-0.0 |false
+|0.0 |false
+|NaN |false
+|null| false
+|===
+
+*String* - Strings will not be convertable into bool, except boolean strings:
+[cols=",",options="header",]
+|===
+|Sting Value |Boolean Value
+|"true" |true
+|"false" |false
+|"True" |true
+|"False" |false
+|"TRUE" |true
+|"FALSE" |false
+|"trUE" |true
+|"faLSe" |false
+|"null"|Parsing Exception
+|"1" |Parsing Exception
+|"hello" |Parsing Exception
+|===
+
+*All other types* - Throws parsing exception.
+
+=== Alternative semantics
+
+Depending on how we want `asBool()` to be used, a potential alternative is to make `asBool()` an eval function and follow the `Groovy Truth` definitions.
+
+* For strings, all non-empty strings are considered `true`, and empty strings are considered `false`. Note in this case, `"false"` will be considered `true`, which could be confusing.
+
+* For collection, all non-empty collections are considered `true`, and empty collections are considered `false`.
\ No newline at end of file
diff --git a/docs/src/dev/future/proposal-type-predicate-8.asciidoc b/docs/src/dev/future/proposal-type-predicate-8.asciidoc
new file mode 100644
index 0000000000..b9eb0771f3
--- /dev/null
+++ b/docs/src/dev/future/proposal-type-predicate-8.asciidoc
@@ -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.
+////
+
+image::apache-tinkerpop-logo.png[width=500,link="https://tinkerpop.apache.org"]
+
+*x.y.z - Proposal 7*
+
+== Type Predicate
+
+=== Motivation
+
+Following up on link:https://issues.apache.org/jira/browse/TINKERPOP-2234[TINKERPOP-2234], filtering of traversers based on types would be a very convenient addition to data manipulation in Gremlin. For example, when we
+perform union of traversals and only want vertices or edges, currently there is no simple way to assert the type and pass it through.
+
+=== Definitions
+
+For defining what types to assert, we'll be using a set of tokens. A proposed set of type tokens are listed below based on GraphBinary.
+
+* The `token` could be a defined set of `Type` enums, e.g. `Type.String`, `Type.Number`, `Type.Date`, `Type.Vertex`, `Type.Edge`, `Type.Property`.
+** Note that the `GremlinValueComparator` class contains a set of `Type` enums, which we could extract and promote to use.
+* In addition, could also recognize the `Number` type tokens used by the `asNumber()` step, i.e. `N.Int`, `N.Double`.
+
+The range of tokens are:
+[cols=",",options="header",]
+|===
+|Token |Gremlin Type Reference
+|N.Int |GraphBinary 4.0, GType
+|N.Long |GraphBinary 4.0, GType
+|N.Double |GraphBinary 4.0, GType
+|N.Float |GraphBinary 4.0, GType
+|N.BigDecimal |GraphBinary 4.0, GType
+|N.BigInteger |GraphBinary 4.0, GType
+|N.Byte |GraphBinary 4.0, GType
+|N.Short |GraphBinary 4.0, GType
+|Type.Number | Token for Java Number type
+|Type.String |GraphBinary 4.0, GType
+|Type.DateTime |GraphBinary 4.0, GType
+|Type.List |GraphBinary 4.0, GType
+|Type.Set |GraphBinary 4.0, GType
+|Type.Map |GraphBinary 4.0, GType
+|Type.UUID |GraphBinary, 4.0 GType
+|Type.Edge |GraphBinary 4.0
+|Type.Path |GraphBinary 4.0
+|Type.Property |GraphBinary 4.0
+|Type.Graph |GraphBinary 4.0
+|Type.Vertex |GraphBinary 4.0, GType
+|Type.VP |GraphBinary 4.0(VertexProperty)
+|Type.Direction |GraphBinary 4.0
+|Type.T |GraphBinary 4.0
+|Type.Binary |GraphBinary 4.0
+|Type.Boolean |GraphBinary 4.0
+|Type.Tree |GraphBinary 4.0
+|Type.Char |GraphBinary 4.0
+|Type.Duration |GraphBinary 4.0
+|Type.Marker |GraphBinary 4.0
+|Type.PDT(type)* |GraphBinary 4.0(CompositePDT & PrimitivePDT)
+|Type.Null |GraphBinary 4.0(Unspecified Null Object), GValue(UNKNOWN)
+|===
+
+*Providers are to register their custom types which can be string arguments to the token, for the Grammar to recognize.
+
+==== Addition of `P.of(token)`
+
+Given `P` is widely used by filter steps and has existing evaluation structure, we would also introduce a new predicate condition, which should be quite straight forward.
+
+* `P.of(token)`
+* `P.nof(token)` - negation "not of type"
+
+A special convenience for embedded use is to take Java class as overload for syntactic sugar.
+
+* `P.of(class)`
+* `P.nof(class)` - negation "not of type"
+
+[source]
+----
+// embedded - recognizes Java classes
+gremlin> g.V().is(P.of(Vertex)).fold()
+==> [v[1],v[2],[v3],[v4],[v5],[v6]]
+gremlin> g.inject(1.0,2,3,'hello',false).is(P.of(Number)).fold()
+==> [1.0,2,3]
+
+// remote - uses the token
+gremlin> g.V().is(P.of(Type.Vertex)).fold()
+==> [v[1],v[2],[v3],[v4],[v5],[v6]]
+gremlin> g.inject(1.0,2,3,'hello',false).is(P.of(Type.number)).fold()
+==> [1.0,2,3]
+
+gremlin> g.inject(1.0,2,3,'hello',false).is(P.nof(Type.number)).fold()
+==> ['hello',false]
+----
+
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Compare.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Compare.java
index 09387614f8..1f1be62777 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Compare.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Compare.java
@@ -51,6 +51,26 @@ public enum Compare implements PBiPredicate<Object, Object> {
         }
     },
 
+    /**
+     * Evaluates if the first object is equal to the second per Gremlin Comparison semantics.
+     *
+     * @since 3.8.0
+     */
+    of {
+        @Override
+        public boolean test(final Object first, final Object second) {
+            return GremlinValueComparator.COMPARABILITY.of(first, second);
+        }
+
+        /**
+         * The negative of {@code eq} is {@link #neq}.
+         */
+        @Override
+        public Compare negate() {
+            return nof;
+        }
+    },
+
     /**
      * Evaluates if the first object is not equal to the second per Gremlin Comparison semantics.
      *
@@ -71,6 +91,26 @@ public enum Compare implements PBiPredicate<Object, Object> {
         }
     },
 
+    /**
+     * Evaluates if the first object is not equal to the second per Gremlin Comparison semantics.
+     *
+     * @since 3.8.0
+     */
+    nof {
+        @Override
+        public boolean test(final Object first, final Object second) {
+            return !of.test(first, second);
+        }
+
+        /**
+         * The negative of {@code neq} is {@link #eq}
+         */
+        @Override
+        public Compare negate() {
+            return of;
+        }
+    },
+
     /**
      * Evaluates if the first object is greater than the second per Gremlin Comparison semantics.
      *
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 917a13891d..edd18f5265 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
@@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 
 import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
+import org.apache.tinkerpop.gremlin.util.GremlinValueComparator;
 
 import java.io.Serializable;
 import java.util.Arrays;
@@ -145,6 +146,26 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
         return new P(Compare.neq, value);
     }
 
+    /**
+     * Determines if values are of a type.
+     *
+     * @since 3.8.0-incubating
+     */
+    // restricting parameter type to Class for PoC
+    public static <V> P<V> of(final Class<?> value) {
+        return new P(Compare.of, value);
+    }
+
+    /**
+     * Determines if values are not of a type.
+     *
+     * @since 3.8.0-incubating
+     */
+    // restricting parameter type to Class for PoC
+    public static <V> P<V> nof(final Class<?> value) {
+        return new P(Compare.nof, value);
+    }
+
     /**
      * Determines if a value is less than another.
      *
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/GremlinValueComparator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/GremlinValueComparator.java
index f99c191b30..5593a11401 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/GremlinValueComparator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/GremlinValueComparator.java
@@ -80,6 +80,10 @@ public abstract class GremlinValueComparator implements Comparator<Object> {
         public boolean equals(final Object f, final Object s) {
             return compare(f, s) == 0;
         }
+
+        public boolean of(final Object f, final Object s) {
+            return ((Class<?>)s).isAssignableFrom(f.getClass());
+        }
     };
 
     /**
@@ -160,6 +164,11 @@ public abstract class GremlinValueComparator implements Comparator<Object> {
             }
         }
 
+        @Override
+        public boolean of(final Object f, final Object s) {
+            return ((Class<?>)s).isAssignableFrom(f.getClass());
+        }
+
         private boolean containersOfDifferentSize(final Object f, final Object s) {
             if (f instanceof Collection && s instanceof Collection)
                 if (((Collection) f).size() != (((Collection) s).size()))
@@ -377,4 +386,6 @@ public abstract class GremlinValueComparator implements Comparator<Object> {
      */
     public abstract boolean equals(final Object f, final Object s);
 
+    public abstract boolean of(final Object f, final Object s);
+
 }
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..c6689f76d2 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
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
+import org.apache.tinkerpop.gremlin.util.GremlinValueComparator;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -55,6 +56,8 @@ public class PTest {
         @Parameterized.Parameters(name = "{0}.test({1}) = {2}")
         public static Iterable<Object[]> data() {
             return new ArrayList<>(Arrays.asList(new Object[][]{
+                    {P.of(Number.class), 1, true},
+
                     {P.eq(0), 0, true},
                     {P.eq(0), -0, true},
                     {P.eq(0), +0, true},