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

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

commit 01c2d78ec1939750e5c2a7fc711217a2f1a823f6
Author: xiazcy <xia...@gmail.com>
AuthorDate: Mon Jul 7 17:55:22 2025 -0400

    Minor tweak for string parsing and updated relevant docs
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/reference/the-traversal.asciidoc          | 31 ++++++++++++++
 docs/src/upgrade/release-3.8.x.asciidoc            | 47 ++++++++++++++++++++++
 .../process/traversal/step/map/AsNumberStep.java   |  6 +--
 .../traversal/step/map/AsNumberStepTest.java       | 39 ++++++++++++++++++
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  2 +-
 gremlin-go/driver/cucumber/gremlin.go              |  2 +-
 .../gremlin-javascript/test/cucumber/gremlin.js    |  2 +-
 gremlin-python/src/main/python/radish/gremlin.py   |  2 +-
 .../gremlin/test/features/map/AsNumber.feature     |  8 ++--
 10 files changed, 127 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 36d0d90344..040f96ca9b 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -75,6 +75,7 @@ This release also includes changes from <<release-3-7-XXX, 
3.7.XXX>>.
 * Moved all lambda oriented Gremlin tests to `LambdaStepTest` in the Java test 
suite.
 * Removed the `@RemoteOnly` testing tag in Gherkin as lambda tests have all 
been moved to the Java test suite.
 * Updated gremlin-javascript to use GraphBinary as default instead of 
GraphSONv3
+* Added the `asNumber()` steps to perform number conversion.
 * Renamed many types in the grammar for consistent use of terms "Literal", 
"Argument", and "Varargs"
 
 == TinkerPop 3.7.0 (Gremfir Master of the Pan Flute)
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index eaf36d2b96..e39425881c 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -829,6 +829,37 @@ g.inject(datetime("2023-08-24T00:00:00Z")).asDate() <3>
 
 
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asDate()++[`asDate()`]
 
+[[asNumber-step]]
+=== AsNumber Step
+
+The `asNumber()`-step (*map*) 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.
+
+Numerical input will pass through unless a type is specified by the number 
token, with the exception that any float number will be converted into double. 
`ArithmeticException` will be thrown for any overflow during narrowing of types.
+
+String input will be parsed. By default, the smalled unit of number to be 
parsed into is `int` if no number token is provided. `NumberFormatException` 
will be thrown for any unparsable strings.
+
+All other input types will result in `IllegalArgumentException`.
+
+[gremlin-groovy,modern]
+----
+g.inject(1).asNumber() <1>
+g.inject(1.76).asNumber() <2>
+g.inject(1.76).asNumber(N.nint) <3>
+g.inject("1b").asNumber() <4>
+g.inject(33550336).asNumber(N.nbyte) <5>
+----
+
+<1> An int will be passed through.
+<2> A double will be passed through.
+<3> A double is converted into an in.
+<4> String containing any character other than numerical ones will result in 
`NumberFormatException`.
+<5> Narrowing of int to byte that overflows will throw `ArithmeticException`.
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asNumber()++[`asNumber()`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asNumber(org.apache.tinkerpop.gremlin.process.traversal.N)++[`asNumber(N)`]
+
 [[barrier-step]]
 === Barrier Step
 
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc 
b/docs/src/upgrade/release-3.8.x.asciidoc
index c1de647afc..50dea6654b 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -30,6 +30,53 @@ complete list of all the modifications that are part of this 
release.
 
 === Upgrading for Users
 
+==== Number Conversion Step
+
+We have introduced a number conversion step, `asNumber()`, which 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.
+
+Numerical input will pass through unless a type is specified by the number 
token, with the exception that any float number will be converted into double. 
`ArithmeticException` will be thrown for any overflow during narrowing of types:
+
+[source,text]
+----
+gremlin> g.inject(5).asNumber()
+==> 5    // parses to int
+gremlin> g.inject(5.0).asNumber()
+==> 5    // parses to double
+gremlin> g.inject(5.123f).asNumber()
+==> 5.123  // will cast float to double
+// Narrowing of types may result in ArithmeticException due to overflow
+gremlin> g.inject(12).asNumber(N.byte)
+==> 12
+gremlin> g.inject(128).asNumber(N.byte)
+==> ArithmeticException
+gremlin> g.inject(300).asNumber(N.byte)
+==> ArithmeticException
+----
+
+String input will be parsed. By default, the smalled unit of number to be 
parsed into is `int` if no number token is provided. `NumberFormatException` 
will be thrown for any unparsable strings:
+
+[source,text]
+----
+gremlin> g.inject("5").asNumber()
+==> 5
+gremlin> g.inject("5.7").asNumber(N.int)
+==> 5
+gremlin> g.inject("1,000").asNumber(N.nint)
+==> NumberFormatException
+gremlin> g.inject("128").asNumber(N.nbyte)
+==> ArithmeticException
+----
+
+All other input types will result in `IllegalArgumentException`:
+[source,text]
+----
+gremlin> g.inject([1, 2, 3, 4]).asNumber()
+==> IllegalArgumentException
+----
+
+See: 
link:https://tinkerpop.apache.org/docs/3.8.0/reference/#asNumber-step[asNumber()-step]
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-3166[TINKERPOP-3166]
+
 ==== Auto promotion of number types
 
 Previously, operations like sum or sack that involved mathematical 
calculations did not automatically promote the result
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
index 1fe1a52051..1fb093be11 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
@@ -106,11 +106,7 @@ public final class AsNumberStep<S> extends 
ScalarMapStep<S, Number> {
                 return result;
             }
             BigInteger result = new BigInteger(value.trim());
-            if (result.bitLength() <= 7) {
-                return result.byteValue();
-            } else if (result.bitLength() <= 15) {
-                return result.shortValue();
-            } else if (result.bitLength() <= 31) {
+            if (result.bitLength() <= 31) { // default to int if not 
specified, smaller sizes need to be intentionally set
                 return result.intValue();
             } else if (result.bitLength() <= 63) {
                 return result.longValue();
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
index a812aac827..396d4bd8e4 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
+import org.apache.tinkerpop.gremlin.process.traversal.N;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
@@ -26,6 +27,7 @@ import org.junit.Test;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.UUID;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -40,6 +42,43 @@ public class AsNumberStepTest extends StepTest {
     @Test
     public void testReturnTypes() {
         assertEquals(1, __.__(1).asNumber().next());
+        assertEquals((byte) 1, __.__(1).asNumber(N.nbyte).next());
+        assertEquals(1, __.__(1.8).asNumber(N.nint).next());
+        assertEquals(1, __.__(1L).asNumber(N.nint).next());
+        assertEquals(1L, __.__(1L).asNumber().next());
+        assertEquals(1, __.__("1").asNumber(N.nint).next());
+        assertEquals(1, __.__("1").asNumber().next());
+        assertEquals((byte) 1, __.__("1").asNumber(N.nbyte).next());
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowExceptionWhenInvalidStringInput() {
+        __.__("This String is not a number").asNumber().next();
+    }
+
+    @Test(expected = NumberFormatException.class)
+    public void shouldThrowParseExceptionWithInvalidNumberStringInput() {
+        __.__("128abc").asNumber().next();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldThrowExceptionWhenArrayInput() {
+        __.__(Arrays.asList(1, 2)).asNumber().next();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldThrowExceptionWhenUUIDInput() {
+        __.__(UUID.randomUUID()).asNumber().next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenParsedNumberOverflows() {
+        __.__("128").asNumber(N.nbyte).next();
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void shouldThrowOverflowExceptionWhenCastNumberOverflows() {
+        __.__(128).asNumber(N.nbyte).next();
     }
 
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 25ba75311e..e624af80f5 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -636,7 +636,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_injectX32768X_asNumberXN_nshortX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(32768).AsNumber(N.Nshort)}}, 
                {"g_injectX300X_asNumberXN_nbyteX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(300).AsNumber(N.Nbyte)}}, 
                {"g_injectX5X_asNumberXX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.Inject<object>("5").AsNumber()}}, 
-               {"g_injectX5X_asNumberXN_nintX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>("5").AsNumber(N.Nint)}}, 
+               {"g_injectX5X_asNumberXN_byteX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>("5").AsNumber(N.Nbyte)}}, 
                {"g_injectX1_000X_asNumberXN_nintX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>("1,000").AsNumber(N.Nint)}}, 
                {"g_injectXtestX_asNumberXX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>("test").AsNumber()}}, 
                {"g_injectX_1__2__3__4_X_asNumberXX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(new List<object> { 1, 2, 3, 4 }).AsNumber()}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index 8612cdbf5e..be4614c490 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -606,7 +606,7 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_injectX32768X_asNumberXN_nshortX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.Inject(32768).AsNumber(gremlingo.N.Nshort)}}, 
     "g_injectX300X_asNumberXN_nbyteX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.Inject(300).AsNumber(gremlingo.N.Nbyte)}}, 
     "g_injectX5X_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject("5").AsNumber()}}, 
-    "g_injectX5X_asNumberXN_nintX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject("5").AsNumber(gremlingo.N.Nint)}}, 
+    "g_injectX5X_asNumberXN_byteX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject("5").AsNumber(gremlingo.N.Nbyte)}}, 
     "g_injectX1_000X_asNumberXN_nintX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.Inject("1,000").AsNumber(gremlingo.N.Nint)}}, 
     "g_injectXtestX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject("test").AsNumber()}}, 
     "g_injectX_1__2__3__4_X_asNumberXX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 2, 3, 
4}).AsNumber()}}, 
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 5f75840cd2..eaf50c7474 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
@@ -637,7 +637,7 @@ const gremlins = {
     g_injectX32768X_asNumberXN_nshortX: [function({g}) { return 
g.inject(32768).asNumber(N.nshort) }], 
     g_injectX300X_asNumberXN_nbyteX: [function({g}) { return 
g.inject(300).asNumber(N.nbyte) }], 
     g_injectX5X_asNumberXX: [function({g}) { return g.inject("5").asNumber() 
}], 
-    g_injectX5X_asNumberXN_nintX: [function({g}) { return 
g.inject("5").asNumber(N.nint) }], 
+    g_injectX5X_asNumberXN_byteX: [function({g}) { return 
g.inject("5").asNumber(N.nbyte) }], 
     g_injectX1_000X_asNumberXN_nintX: [function({g}) { return 
g.inject("1,000").asNumber(N.nint) }], 
     g_injectXtestX_asNumberXX: [function({g}) { return 
g.inject("test").asNumber() }], 
     g_injectX_1__2__3__4_X_asNumberXX: [function({g}) { return g.inject([1, 2, 
3, 4]).asNumber() }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index 8c2134f592..89731ece25 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -609,7 +609,7 @@ world.gremlins = {
     'g_injectX32768X_asNumberXN_nshortX': [(lambda 
g:g.inject(32768).as_number(N.nshort))], 
     'g_injectX300X_asNumberXN_nbyteX': [(lambda 
g:g.inject(300).as_number(N.nbyte))], 
     'g_injectX5X_asNumberXX': [(lambda g:g.inject('5').as_number())], 
-    'g_injectX5X_asNumberXN_nintX': [(lambda 
g:g.inject('5').as_number(N.nint))], 
+    'g_injectX5X_asNumberXN_byteX': [(lambda 
g:g.inject('5').as_number(N.nbyte))], 
     'g_injectX1_000X_asNumberXN_nintX': [(lambda 
g:g.inject('1,000').as_number(N.nint))], 
     'g_injectXtestX_asNumberXX': [(lambda g:g.inject('test').as_number())], 
     'g_injectX_1__2__3__4_X_asNumberXX': [(lambda g:g.inject([1, 2, 3, 
4]).as_number())], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
index 868eb80274..2a5972a067 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
@@ -180,19 +180,19 @@ Feature: Step - asNumber()
     When iterated to list
     Then the result should be unordered
       | result |
-      | d[5].b |
+      | d[5].i |
 
   @GraphComputerVerificationInjectionNotSupported
-  Scenario: g_injectX5X_asNumberXN_nintX
+  Scenario: g_injectX5X_asNumberXN_byteX
     Given the empty graph
     And the traversal of
       """
-      g.inject("5").asNumber(N.nint)
+      g.inject("5").asNumber(N.nbyte)
       """
     When iterated to list
     Then the result should be unordered
       | result |
-      | d[5].i |
+      | d[5].b |
 
   @GraphComputerVerificationInjectionNotSupported
   Scenario: g_injectX1_000X_asNumberXN_nintX

Reply via email to