Skip to content

Commit 3bd2bbe

Browse files
committed
Merge branch '3.8-dev'
2 parents 2c3f31f + e515cc5 commit 3bd2bbe

File tree

100 files changed

+4360
-1020
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+4360
-1020
lines changed

CHANGELOG.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ This release also includes changes from <<release-3-7-XXX, 3.7.XXX>>.
157157
* Deprecated `ProcessLimitedStandardSuite` and `ProcessLimitedComputerSuite` in favor of `ProcessEmbeddedStandardSuite` and `ProcessEmbeddedComputerSuite` respectively.
158158
* Deprecated `ProcessStandardSuite` and the `ProcessComputerSuite` in favor of Gherkin testing and the `ProcessEmbeddedStandardSuite` and `ProcessEmbeddedComputerSuite` for testing JVM-specific Gremlin behaviors.
159159
* Removed lambda oriented Gremlin testing from Gherkin test suite.
160+
* Implemented `P.typeOf()` predicate.
161+
* Added `GType` enum to denote types.
160162
* Removed `P.getOriginalValue()` in favor of `P.getValue()`.
161163
* Simplified comparability semantics from ternary boolean logic to binary logic.
162164
* Introduced `NotP` class for negation of `P`.

docs/src/dev/provider/gremlin-semantics.asciidoc

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,35 @@ for providers to decide how to handle this in their implementation. The referenc
337337
equivalent keys to appear in a map (e.g. `1` and `1.0` can both be keys in the same map), but when comparing maps we
338338
treat pairwise entries with semantically equivalent keys as the same.
339339
340+
==== Comparability of Types
341+
342+
The `P.typeOf()` predicate enables type-based filtering in TinkerPop using inheritance-aware comparison, where a value
343+
matches if it is the specified type or any of its subtypes.
344+
345+
===== GType Enums
346+
347+
Based on the support type space, we have defined a `GType` enum, which contains a set of enumerations that is used for
348+
type casting (`asNumber()`) and comparison (`P.typeOf()`) operations.
349+
350+
* **Numeric types**: `INT`, `LONG`, `DOUBLE`, `FLOAT`, `BYTE`, `SHORT`, `BIGDECIMAL`, `BIGINT`
351+
* **General types**: `STRING`, `BOOLEAN`, `CHAR`, `UUID`, `BINARY`
352+
* **Collection types**: `LIST`, `SET`, `MAP`
353+
* **Graph types**: `VERTEX`, `EDGE`, `PROPERTY`, `VPROPERTY`, `PATH`, `TREE`, `GRAPH`
354+
* **Temporal types**: `DATETIME`, `DURATION`
355+
* **Special types**: `NULL`, `NUMBER` (supertype for all numeric types)
356+
357+
===== GlobalTypeCache
358+
359+
Providers can register custom types outside the TinkerPop type space using the `GlobalTypeCache`, making them available
360+
for `P.typeOf(String)` filtering. Unregistered string inputs will throw an `IllegalArgumentException`.
361+
362+
The `registerDataType()` method registers the class's simple name by default, or accepts a custom string name. Providers
363+
should use PascalCase following Java conventions and prefix type names to avoid conflicts
364+
(e.g., `ProviderPrefix:SimpleTypeName`).
365+
366+
Do note that the type cache only enables type recognition for filtering. Custom types still require separate
367+
serialization support - clients without custom serializers cannot deserialize these types.
368+
340369
[[gremlin-semantics-orderability]]
341370
=== Orderability
342371
@@ -776,7 +805,7 @@ link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asDate-step[reference]
776805
777806
*Description:* converts the incoming traverser to the nearest parsable type if no argument is provided, or to the desired numerical type, based on the number token (`N`) provided.
778807
779-
*Syntax:* `asNumber()` | `asNumber(N numberToken)`
808+
*Syntax:* `asNumber()` | `asNumber(GType typeToken)`
780809
781810
[width="100%",options="header"]
782811
|=========================================================
@@ -786,7 +815,7 @@ link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asDate-step[reference]
786815
787816
*Arguments:*
788817
789-
* `numberToken` - The enum `N` to denote the desired type to parse/cast to.
818+
* `typeToken` - The enum `GType` to denote the desired type to parse/cast to.
790819
791820
If no type token is provided, the incoming number remains unchanged.
792821
@@ -795,6 +824,7 @@ If no type token is provided, the incoming number remains unchanged.
795824
* If any overflow occurs during narrowing of types, then an `ArithmeticException` will be thrown.
796825
* If the incoming string cannot be parsed into a valid number format, then a `NumberFormatException` will be thrown.
797826
* If the incoming traverser is a non-String/Number (including `null`) value then an `IllegalArgumentException` will be thrown.
827+
* If the supplied type token is not a number type, then an `IllegalArgumentException` will be thrown.
798828
799829
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java[source],
800830
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asNumber-step[reference]

docs/src/reference/gremlin-variants.asciidoc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,42 @@ java -cp target/run-examples-shaded.jar examples.BasicGremlin
13781378
java -cp target/run-examples-shaded.jar examples.ModernTraversals
13791379
----
13801380
1381+
[[gremlin-java-differences]]
1382+
=== Differences
1383+
1384+
Gremlin-Java provides additional syntactic sugar that leverages Java's type system for the `P.typeOf()` predicate,
1385+
which accepts Java `Class` objects directly, providing a more natural way to perform type checking:
1386+
1387+
[gremlin-groovy,modern]
1388+
----
1389+
// Java-specific syntax using Class objects
1390+
g.V().values("age").is(P.typeOf(Integer.class))
1391+
g.V().values("name").is(P.typeOf(String.class))
1392+
1393+
// Further simplification with Groovy sugar syntax
1394+
g.E().has("weight", P.typeOf(Double))
1395+
----
1396+
1397+
This is equivalent to using `GType` enums. Other Gremlin language variants must use the canonical `GType` enum approach:
1398+
1399+
[gremlin-groovy,modern]
1400+
----
1401+
// Canonical syntax available in all languages
1402+
g.V().values("age").is(P.typeOf(GType.INT))
1403+
g.V().values("name").is(P.typeOf(GType.STRING))
1404+
----
1405+
1406+
Any valid Java class accepted in the Console and with embedded Java is also accepted by `P.typeOf()`, as they are not
1407+
restricted by the grammar or serialization.
1408+
[gremlin-groovy,modern]
1409+
----
1410+
// Using java.awt.Color for example
1411+
gremlin> g.inject(java.awt.Color.red)
1412+
==>java.awt.Color[r=255,g=0,b=0]
1413+
gremlin> g.inject(java.awt.Color.red, "hi", 123).is(P.typeOf(java.awt.Color))
1414+
==>java.awt.Color[r=255,g=0,b=0]
1415+
----
1416+
13811417
[[gremlin-javascript]]
13821418
== Gremlin-JavaScript
13831419
IMPORTANT: 4.0.0-beta.1 Release - Gremlin-JavaScript is not available in this beta, please consider testing with

docs/src/reference/the-traversal.asciidoc

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
858858
=== AsNumber Step
859859
860860
The `asNumber()`-step (*map*) converts the incoming traverser to the nearest parsable type if no argument is provided,
861-
or to the desired numerical type, based on the number token (`N`) provided.
861+
or to the desired numerical type, based on the type token (`GType`) provided. If a type token entered isn't a numerical type, an `IllegalArgumentException` will be thrown.
862862
863863
Numerical input will pass through unless a type is specified by the number token. `ArithmeticException` will be thrown
864864
for any overflow during narrowing of types.
@@ -872,17 +872,13 @@ All other input types will result in `IllegalArgumentException`.
872872
[gremlin-groovy,modern]
873873
----
874874
g.inject(1234).asNumber() <1>
875-
g.inject(1.76).asNumber() <2>
876-
g.inject(1.76).asNumber(N.int_) <3>
877-
g.inject("1b").asNumber() <4>
878-
g.inject(33550336).asNumber(N.byte_) <5>
875+
g.inject(1.76d).asNumber() <2>
876+
g.inject(1.76d).asNumber(GType.INT) <3>
879877
----
880878
881879
<1> An int will be passed through.
882880
<2> A double will be passed through.
883881
<3> A double is converted into an int.
884-
<4> String containing any character other than numerical ones will result in `NumberFormatException`.
885-
<5> Narrowing of int to byte that overflows will throw `ArithmeticException`.
886882
887883
[NOTE, caption=Java]
888884
====
@@ -5481,12 +5477,8 @@ a comparatively slow script compilation, which makes parameterization essential
54815477
[[a-note-on-predicates]]
54825478
== A Note on Predicates
54835479
5484-
A `P` is a predicate of the form `Function<Object,Boolean>`. That is, given some object, return true or false. As of
5485-
the release of TinkerPop 3.4.0, Gremlin also supports simple text predicates, which only work on `String` values. The `TextP`
5486-
text predicates extend the `P` predicates, but are specialized in that they are of the form `Function<String,Boolean>`.
5487-
The provided predicates are outlined in the table below and are used in various steps such as <<has-step,`has()`>>-step,
5488-
<<where-step,`where()`>>-step, <<is-step,`is()`>>-step, etc. Two new additional `TextP` predicate members were added in the
5489-
TinkerPop 3.6.0 release that allow working with regular expressions. These are `TextP.regex` and `TextP.notRegex`
5480+
A `P` is a predicate of the form `Function<Object,Boolean>`. That is, given some object, return true or false. Gremlin
5481+
supports text predicates (`TextP`), which are specialized predicates that only work on String values and are of the form `Function<String,Boolean>`. Additionally, type predicate (`P.typeOf`) supports filtering traversers based on their runtime types. The provided predicates are outlined in the table below and are used in various steps such as <<has-step,`has()`>>-step, <<where-step,`where()`>>-step, <<is-step,`is()`>>-step, etc.
54905482
54915483
[width="100%",cols="3,15",options="header"]
54925484
|=========================================================
@@ -5502,6 +5494,8 @@ TinkerPop 3.6.0 release that allow working with regular expressions. These are `
55025494
| `P.between(number,number)` | Is the incoming number greater than or equal to the first provided number and less than the second?
55035495
| `P.within(objects...)` | Is the incoming object in the array of provided objects?
55045496
| `P.without(objects...)` | Is the incoming object not in the array of the provided objects?
5497+
| `P.typeOf(GType)` | Is the incoming object of the type indicated by the provided `GType` token?
5498+
| `P.typeOf(string)` | Is the incoming object of the type indicated by the provided `String`?
55055499
| `TextP.startingWith(string)` | Does the incoming `String` start with the provided `String`?
55065500
| `TextP.endingWith(string)` | Does the incoming `String` end with the provided `String`?
55075501
| `TextP.containing(string)` | Does the incoming `String` contain the provided `String`?
@@ -5559,6 +5553,69 @@ g.V().as('a').both().both().as('b').count()
55595553
g.V().as('a').both().both().as('b').where('a',neq('b')).count()
55605554
----
55615555
5556+
[[a-note-on-types]]
5557+
== A Note on Types
5558+
5559+
Gremlin steps typically operate over a handful of types that are mostly standard across graph systems. There are the
5560+
common numeric types like `Integer`, `Long`, `Double`, general types like `String`, and `Boolean`, container types like
5561+
`List`, `Set`, and `Map`, and structural types particular to graphs such as `Vertex`, `Edge`, and `Property`. During
5562+
traversal execution, it's common to encounter mixed data types, especially when extracting values from multiple
5563+
properties or when working with heterogeneous data that may have been stored inconsistently over time.
5564+
5565+
Gremlin identifies these types in the `GType` enumeration, offering a clear presentation of the standard data types one
5566+
might typically encounter with Gremlin. This enumeration is an important part of the Gremlin language in that it acts
5567+
as the argument to the `typeOf()` predicate used for filtering values based on their runtime data type.
5568+
5569+
[[gtype-enum]]
5570+
=== GType Enums
5571+
5572+
`GType` consists of the following enumerations:
5573+
5574+
* **Numeric types**: `INT`, `LONG`, `DOUBLE`, `FLOAT`, `BYTE`, `SHORT`, `BIGDECIMAL`, `BIGINT`
5575+
* **General types**: `STRING`, `BOOLEAN`, `CHAR`, `UUID`, `BINARY`
5576+
* **Collection types**: `LIST`, `SET`, `MAP`
5577+
* **Graph types**: `VERTEX`, `EDGE`, `PROPERTY`, `VPROPERTY`, `PATH`, `TREE`, `GRAPH`
5578+
* **Temporal types**: `DATETIME`, `DURATION`
5579+
* **Special types**: `NULL`, `NUMBER` (supertype for all numeric types)
5580+
5581+
As mentioned, the `typeOf()` predicate becomes particularly useful when dealing with mixed data scenarios. For example,
5582+
you would like to only return the integer values of a set of properties for further processing:
5583+
5584+
[gremlin-groovy,modern]
5585+
----
5586+
g.V().values('age','name').is(P.typeOf(GType.INT)).asNumber(GType.SHORT)
5587+
----
5588+
5589+
The `NUMBER` type allows for broader type-based filtering without needing to specify each individual numeric type:
5590+
5591+
[gremlin-groovy,modern]
5592+
----
5593+
g.union(V(), E()).values().is(P.typeOf(GType.NUMBER))
5594+
----
5595+
5596+
Type filtering is also valuable when working with traversals that return mixed graph elements. For example, when a
5597+
traversal might return both vertices and edges, you can add filter or condition based on the elements of interest:
5598+
5599+
[gremlin-groovy,modern]
5600+
----
5601+
g.V().outE().inV().path().unfold().is(P.typeOf(GType.EDGE))
5602+
g.V().outE().inV().path().unfold().choose(typeOf(VERTEX), values('name'), values('weight'))
5603+
----
5604+
5605+
[[global-type-cache]]
5606+
=== GlobalTypeCache
5607+
5608+
The `GlobalTypeCache` stores custom types registered by database providers as string-to-class mappings. These registered
5609+
type names can then be used with `P.typeOf()` for type filtering in the traversal. Consult your provider's documentation
5610+
for the correct type names when using provider-specific types.
5611+
5612+
By default, `GType` enumerations are registered using their simple class names and can be used as shown below.
5613+
5614+
[gremlin-groovy,modern]
5615+
----
5616+
gremlin> g.V().values('age','name').is(P.typeOf('Integer'))
5617+
----
5618+
55625619
[[a-note-on-maps]]
55635620
== A Note on Maps
55645621

0 commit comments

Comments
 (0)