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 edd6f8161ae6b3e1ab82829b71365cc3ba6bd976 Author: xiazcy <[email protected]> AuthorDate: Fri Jul 18 10:21:25 2025 -0700 feature test & docs update --- CHANGELOG.asciidoc | 2 +- docs/src/dev/provider/gremlin-semantics.asciidoc | 27 ++++++++ docs/src/reference/the-traversal.asciidoc | 2 +- docs/src/upgrade/release-3.8.x.asciidoc | 38 ++++++++---- .../process/traversal/step/map/AsNumberStep.java | 4 +- .../tinkerpop/gremlin/util/NumberHelper.java | 5 +- .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 27 ++++---- gremlin-go/driver/cucumber/gremlin.go | 27 ++++---- .../gremlin-javascript/test/cucumber/gremlin.js | 27 ++++---- gremlin-python/src/main/python/radish/gremlin.py | 27 ++++---- .../gremlin/test/features/map/AsNumber.feature | 71 +++++++++++++++++----- 11 files changed, 178 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 244b92f88c..c969413f17 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -76,7 +76,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. +* Added the `asNumber()` step 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/dev/provider/gremlin-semantics.asciidoc b/docs/src/dev/provider/gremlin-semantics.asciidoc index a499a015fe..26aebcd241 100644 --- a/docs/src/dev/provider/gremlin-semantics.asciidoc +++ b/docs/src/dev/provider/gremlin-semantics.asciidoc @@ -801,6 +801,33 @@ Incoming date remains unchanged. See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java[source], link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asDate-step[reference] +[[asNumber-step]] +=== asNumber() + +*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. + +*Syntax:* `asNumber()` | `asNumber(N numberToken)` + +[width="100%",options="header"] +|========================================================= +|Start Step |Mid Step |Modulated |Domain |Range +|N |Y |N |`Number`/`String` |`Number` +|========================================================= + +*Arguments:* + +* `numberToken` - The enum `N` to denote the desired type to parse/cast to. + +If no type token is provided, the incoming number remains unchanged. + +*Exceptions* +* If any overflow occurs during narrowing of types, then an `ArithmeticException` will be thrown. +* If the incoming string cannot be parsed into a valid number format, then a `NumberFormatException` will be thrown. +* If the incoming traverser is a non-String/Number (including `null`) value then an `IllegalArgumentException` will be thrown. + +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], +link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asNumber-step[reference] + [[barrier-step]] === barrier() diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc index 39dd9f9c39..73cee7c549 100644 --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@ -832,7 +832,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre [[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. +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. diff --git a/docs/src/upgrade/release-3.8.x.asciidoc b/docs/src/upgrade/release-3.8.x.asciidoc index 2c49bd6410..2e04c587b2 100644 --- a/docs/src/upgrade/release-3.8.x.asciidoc +++ b/docs/src/upgrade/release-3.8.x.asciidoc @@ -32,25 +32,41 @@ complete list of all the modifications that are part of this release. ==== 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. +We have been iterative introducing new language features into Gremlin, with the last major set of string, list and date manipulation +steps introduced in the 3.7 line. In 3.8.0, we are now introducing a number conversion step, `asNumber()`, to bridge +a gap in casting functionalities. -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: +The new `asNumber()` serves as an umbrella step that parses strings and casts numbers into desired types. For the convenience of remote traversals in GLVs, these number types are denoted by a set of number tokens (`N`). + +This new step will allow users to normalize their data by converting string numbers and mixed numeric types to consistent format, making it easier to perform downstream mathematical operations. As an example: + +[source,text] +---- +// sum() step can only take numbers +gremlin> g.inject(1.0, 2l, 3, "4", "0x5").sum() +class java.lang.String cannot be cast to class java.lang.Number + +// use asNumber() to avoid casting exceptions +gremlin> g.inject(1.0, 2l, 3, "4", "0x5").asNumber().sum() +==>15.0 + +// given sum() step returned a double, one can use asNumber() to further cast the result into desired type +gremlin> g.inject(1.0, 2l, 3, "4", "0x5").asNumber().sum().asNumber(N.nint) +==>15 +---- + +Semantically, the `asNumber()` step will convert 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. `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(5.0).asNumber(N.nint) +==> 5 // casts double to int 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: 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 59e88ef604..29ea0007e7 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 @@ -47,7 +47,7 @@ public class AsNumberStep<S> extends ScalarMapStep<S, Number> { } @Override - protected Number map(Traverser.Admin<S> traverser) { + protected Number map(final Traverser.Admin<S> traverser) { final Object object = traverser.get(); if (object instanceof String) { String numberText = (String) object; @@ -89,7 +89,7 @@ public class AsNumberStep<S> extends ScalarMapStep<S, Number> { return StringFactory.stepString(this); } - public static Number parseNumber(final String value) { + private static Number parseNumber(final String value) { if (NumberUtils.isCreatable(value.trim())) { return NumberUtils.createNumber(value.trim()); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java index b31499a4ad..b9e6f8b7c5 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/NumberHelper.java @@ -786,11 +786,12 @@ public final class NumberHelper { a.getClass().getSimpleName(), numberToken)); } - private static Long getLong(Number num, N numberToken) { + private static Long getLong(final Number num, final N numberToken) { // Explicitly throw when converting floating point infinity and NaN to whole numbers if (Double.isNaN(num.doubleValue())) { throw new ArithmeticException(String.format("Can't convert NaN to %s.", numberToken)); - } else if (Double.isInfinite(num.doubleValue())) { + } + if (Double.isInfinite(num.doubleValue())) { throw new ArithmeticException(String.format("Can't convert floating point infinity to %s.", numberToken)); } try { diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index 7e7afe35f6..466499259a 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -622,27 +622,30 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_injectX1_2X_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).AsDate()}}, {"g_injectXnullX_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).AsDate()}}, {"g_injectXinvalidstrX_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("This String is not an ISO 8601 Date").AsDate()}}, - {"g_injectX5bX_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>((byte) 5).AsNumber()}}, - {"g_injectX5sX_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>((short) 5).AsNumber()}}, - {"g_injectX5iX_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5).AsNumber()}}, - {"g_injectX5lX_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5l).AsNumber()}}, - {"g_injectX5nX_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new BigInteger(5)).AsNumber()}}, - {"g_injectX5_0X_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5.0).AsNumber()}}, - {"g_injectX5_75fX_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5.75f).AsNumber()}}, + {"g_injectX5bX_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>((byte) 5).AsNumber()}}, + {"g_injectX5sX_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>((short) 5).AsNumber()}}, + {"g_injectX5iX_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5).AsNumber()}}, + {"g_injectX5lX_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5l).AsNumber()}}, + {"g_injectX5nX_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new BigInteger(5)).AsNumber()}}, + {"g_injectX5_0X_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5.0).AsNumber()}}, + {"g_injectX5_75fX_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5.75f).AsNumber()}}, {"g_injectX5_43X_asNumberXN_nintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5.43).AsNumber(N.Nint)}}, {"g_injectX5_67X_asNumberXN_nintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5.67).AsNumber(N.Nint)}}, {"g_injectX5X_asNumberXN_nlongX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(5).AsNumber(N.Nlong)}}, {"g_injectX12X_asNumberXN_nbyteX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(12).AsNumber(N.Nbyte)}}, {"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_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("5").AsNumber()}}, {"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()}}, - {"g_injectX_1__2__3__4_X_unfoldXX_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { 1, 2, 3, 4 }).Unfold<object>().AsNumber()}}, - {"g_injectX_1__2__3__4_X_unfoldXX_asNumberXX_foldXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { 1, 2, 3, 4 }).Unfold<object>().AsNumber().Fold()}}, + {"g_injectXtestX_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("test").AsNumber()}}, + {"g_injectX_1_2_3_4X_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { 1, 2, 3, 4 }).AsNumber()}}, + {"g_injectX1_2_3_4X_unfold_asNumber", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { 1, 2, 3, 4 }).Unfold<object>().AsNumber()}}, + {"g_injectX_1__2__3__4_X_asNumberXX_foldXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("1", 2, "3", 4).AsNumber().Fold()}}, + {"g_injectX1_2_3_4_0x5X_asNumber_sum_asNumberXnbyteX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"], p["xx2"], p["xx3"], "4", "0x5").AsNumber().Sum<object>().AsNumber(N.Nbyte)}}, {"g_VX1X_asNumberXN_nintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).AsNumber(N.Nint)}}, + {"g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXnintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").Out("knows").As("b").Math("a + b").By("age").AsNumber(N.Nint)}}, + {"g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXnlongX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.WithSideEffect("x", p["xx1"]).V().Values<object>("age").Math("_ + x").AsNumber(N.Nlong)}}, {"g_injectX1_2X_asString", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"], p["xx2"]).AsString()}}, {"g_injectX1_2X_asStringXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"], p["xx2"]).AsString<object>(Scope.Local)}}, {"g_injectXlist_1_2X_asStringXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).AsString<object>(Scope.Local)}}, diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go index 3af86f0165..9beb85fe5f 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -592,27 +592,30 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[ "g_injectX1_2X_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).AsDate()}}, "g_injectXnullX_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil).AsDate()}}, "g_injectXinvalidstrX_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("This String is not an ISO 8601 Date").AsDate()}}, - "g_injectX5bX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, - "g_injectX5sX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, - "g_injectX5iX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, - "g_injectX5lX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, - "g_injectX5nX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, - "g_injectX5_0X_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5.0).AsNumber()}}, - "g_injectX5_75fX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5.75).AsNumber()}}, + "g_injectX5bX_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, + "g_injectX5sX_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, + "g_injectX5iX_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, + "g_injectX5lX_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, + "g_injectX5nX_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber()}}, + "g_injectX5_0X_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5.0).AsNumber()}}, + "g_injectX5_75fX_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5.75).AsNumber()}}, "g_injectX5_43X_asNumberXN_nintX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5.43).AsNumber(gremlingo.N.Nint)}}, "g_injectX5_67X_asNumberXN_nintX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5.67).AsNumber(gremlingo.N.Nint)}}, "g_injectX5X_asNumberXN_nlongX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(5).AsNumber(gremlingo.N.Nlong)}}, "g_injectX12X_asNumberXN_nbyteX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(12).AsNumber(gremlingo.N.Nbyte)}}, "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_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("5").AsNumber()}}, "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()}}, - "g_injectX_1__2__3__4_X_unfoldXX_asNumberXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 2, 3, 4}).Unfold().AsNumber()}}, - "g_injectX_1__2__3__4_X_unfoldXX_asNumberXX_foldXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 2, 3, 4}).Unfold().AsNumber().Fold()}}, + "g_injectXtestX_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("test").AsNumber()}}, + "g_injectX_1_2_3_4X_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 2, 3, 4}).AsNumber()}}, + "g_injectX1_2_3_4X_unfold_asNumber": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 2, 3, 4}).Unfold().AsNumber()}}, + "g_injectX_1__2__3__4_X_asNumberXX_foldXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("1", 2, "3", 4).AsNumber().Fold()}}, + "g_injectX1_2_3_4_0x5X_asNumber_sum_asNumberXnbyteX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], p["xx2"], p["xx3"], "4", "0x5").AsNumber().Sum().AsNumber(gremlingo.N.Nbyte)}}, "g_VX1X_asNumberXN_nintX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil).AsNumber(gremlingo.N.Nint)}}, + "g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXnintX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("a").Out("knows").As("b").Math("a + b").By("age").AsNumber(gremlingo.N.Nint)}}, + "g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXnlongX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.WithSideEffect("x", p["xx1"]).V().Values("age").Math("_ + x").AsNumber(gremlingo.N.Nlong)}}, "g_injectX1_2X_asString": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], p["xx2"]).AsString()}}, "g_injectX1_2X_asStringXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], p["xx2"]).AsString(gremlingo.Scope.Local)}}, "g_injectXlist_1_2X_asStringXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).AsString(gremlingo.Scope.Local)}}, 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 4f021edbc1..9ad1b33b8e 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 @@ -623,27 +623,30 @@ const gremlins = { g_injectX1_2X_asDate: [function({g, xx1}) { return g.inject(xx1).asDate() }], g_injectXnullX_asDate: [function({g}) { return g.inject(null).asDate() }], g_injectXinvalidstrX_asDate: [function({g}) { return g.inject("This String is not an ISO 8601 Date").asDate() }], - g_injectX5bX_asNumberXX: [function({g}) { return g.inject(5).asNumber() }], - g_injectX5sX_asNumberXX: [function({g}) { return g.inject(5).asNumber() }], - g_injectX5iX_asNumberXX: [function({g}) { return g.inject(5).asNumber() }], - g_injectX5lX_asNumberXX: [function({g}) { return g.inject(5).asNumber() }], - g_injectX5nX_asNumberXX: [function({g}) { return g.inject(5).asNumber() }], - g_injectX5_0X_asNumberXX: [function({g}) { return g.inject(5.0).asNumber() }], - g_injectX5_75fX_asNumberXX: [function({g}) { return g.inject(5.75).asNumber() }], + g_injectX5bX_asNumber: [function({g}) { return g.inject(5).asNumber() }], + g_injectX5sX_asNumber: [function({g}) { return g.inject(5).asNumber() }], + g_injectX5iX_asNumber: [function({g}) { return g.inject(5).asNumber() }], + g_injectX5lX_asNumber: [function({g}) { return g.inject(5).asNumber() }], + g_injectX5nX_asNumber: [function({g}) { return g.inject(5).asNumber() }], + g_injectX5_0X_asNumber: [function({g}) { return g.inject(5.0).asNumber() }], + g_injectX5_75fX_asNumber: [function({g}) { return g.inject(5.75).asNumber() }], g_injectX5_43X_asNumberXN_nintX: [function({g}) { return g.inject(5.43).asNumber(N.nint) }], g_injectX5_67X_asNumberXN_nintX: [function({g}) { return g.inject(5.67).asNumber(N.nint) }], g_injectX5X_asNumberXN_nlongX: [function({g}) { return g.inject(5).asNumber(N.nlong) }], g_injectX12X_asNumberXN_nbyteX: [function({g}) { return g.inject(12).asNumber(N.nbyte) }], 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_asNumber: [function({g}) { return g.inject("5").asNumber() }], 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() }], - g_injectX_1__2__3__4_X_unfoldXX_asNumberXX: [function({g}) { return g.inject([1, 2, 3, 4]).unfold().asNumber() }], - g_injectX_1__2__3__4_X_unfoldXX_asNumberXX_foldXX: [function({g}) { return g.inject([1, 2, 3, 4]).unfold().asNumber().fold() }], + g_injectXtestX_asNumber: [function({g}) { return g.inject("test").asNumber() }], + g_injectX_1_2_3_4X_asNumber: [function({g}) { return g.inject([1, 2, 3, 4]).asNumber() }], + g_injectX1_2_3_4X_unfold_asNumber: [function({g}) { return g.inject([1, 2, 3, 4]).unfold().asNumber() }], + g_injectX_1__2__3__4_X_asNumberXX_foldXX: [function({g}) { return g.inject("1", 2, "3", 4).asNumber().fold() }], + g_injectX1_2_3_4_0x5X_asNumber_sum_asNumberXnbyteX: [function({g, xx1, xx3, xx2}) { return g.inject(xx1, xx2, xx3, "4", "0x5").asNumber().sum().asNumber(N.nbyte) }], g_VX1X_asNumberXN_nintX: [function({g}) { return g.inject(null).asNumber(N.nint) }], + g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXnintX: [function({g}) { return g.V().as("a").out("knows").as("b").math("a + b").by("age").asNumber(N.nint) }], + g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXnlongX: [function({g, xx1}) { return g.withSideEffect("x", xx1).V().values("age").math("_ + x").asNumber(N.nlong) }], g_injectX1_2X_asString: [function({g, xx1, xx2}) { return g.inject(xx1, xx2).asString() }], g_injectX1_2X_asStringXlocalX: [function({g, xx1, xx2}) { return g.inject(xx1, xx2).asString(Scope.local) }], g_injectXlist_1_2X_asStringXlocalX: [function({g, xx1}) { return g.inject(xx1).asString(Scope.local) }], diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index ab2c6daeb7..f33c343d58 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -595,27 +595,30 @@ world.gremlins = { 'g_injectX1_2X_asDate': [(lambda g, xx1=None:g.inject(xx1).as_date())], 'g_injectXnullX_asDate': [(lambda g:g.inject(None).as_date())], 'g_injectXinvalidstrX_asDate': [(lambda g:g.inject('This String is not an ISO 8601 Date').as_date())], - 'g_injectX5bX_asNumberXX': [(lambda g:g.inject(5).as_number())], - 'g_injectX5sX_asNumberXX': [(lambda g:g.inject(5).as_number())], - 'g_injectX5iX_asNumberXX': [(lambda g:g.inject(5).as_number())], - 'g_injectX5lX_asNumberXX': [(lambda g:g.inject(long(5)).as_number())], - 'g_injectX5nX_asNumberXX': [(lambda g:g.inject(bigint(5)).as_number())], - 'g_injectX5_0X_asNumberXX': [(lambda g:g.inject(5.0).as_number())], - 'g_injectX5_75fX_asNumberXX': [(lambda g:g.inject(5.75).as_number())], + 'g_injectX5bX_asNumber': [(lambda g:g.inject(5).as_number())], + 'g_injectX5sX_asNumber': [(lambda g:g.inject(5).as_number())], + 'g_injectX5iX_asNumber': [(lambda g:g.inject(5).as_number())], + 'g_injectX5lX_asNumber': [(lambda g:g.inject(long(5)).as_number())], + 'g_injectX5nX_asNumber': [(lambda g:g.inject(bigint(5)).as_number())], + 'g_injectX5_0X_asNumber': [(lambda g:g.inject(5.0).as_number())], + 'g_injectX5_75fX_asNumber': [(lambda g:g.inject(5.75).as_number())], 'g_injectX5_43X_asNumberXN_nintX': [(lambda g:g.inject(5.43).as_number(N.nint))], 'g_injectX5_67X_asNumberXN_nintX': [(lambda g:g.inject(5.67).as_number(N.nint))], 'g_injectX5X_asNumberXN_nlongX': [(lambda g:g.inject(5).as_number(N.nlong))], 'g_injectX12X_asNumberXN_nbyteX': [(lambda g:g.inject(12).as_number(N.nbyte))], '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_asNumber': [(lambda g:g.inject('5').as_number())], '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())], - 'g_injectX_1__2__3__4_X_unfoldXX_asNumberXX': [(lambda g:g.inject([1, 2, 3, 4]).unfold().as_number())], - 'g_injectX_1__2__3__4_X_unfoldXX_asNumberXX_foldXX': [(lambda g:g.inject([1, 2, 3, 4]).unfold().as_number().fold())], + 'g_injectXtestX_asNumber': [(lambda g:g.inject('test').as_number())], + 'g_injectX_1_2_3_4X_asNumber': [(lambda g:g.inject([1, 2, 3, 4]).as_number())], + 'g_injectX1_2_3_4X_unfold_asNumber': [(lambda g:g.inject([1, 2, 3, 4]).unfold().as_number())], + 'g_injectX_1__2__3__4_X_asNumberXX_foldXX': [(lambda g:g.inject('1', 2, '3', 4).as_number().fold())], + 'g_injectX1_2_3_4_0x5X_asNumber_sum_asNumberXnbyteX': [(lambda g, xx1=None,xx3=None,xx2=None:g.inject(xx1, xx2, xx3, '4', '0x5').as_number().sum_().as_number(N.nbyte))], 'g_VX1X_asNumberXN_nintX': [(lambda g:g.inject(None).as_number(N.nint))], + 'g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXnintX': [(lambda g:g.V().as_('a').out('knows').as_('b').math('a + b').by('age').as_number(N.nint))], + 'g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXnlongX': [(lambda g, xx1=None:g.with_side_effect('x', xx1).V().values('age').math('_ + x').as_number(N.nlong))], 'g_injectX1_2X_asString': [(lambda g, xx1=None,xx2=None:g.inject(xx1, xx2).as_string())], 'g_injectX1_2X_asStringXlocalX': [(lambda g, xx1=None,xx2=None:g.inject(xx1, xx2).as_string(Scope.local))], 'g_injectXlist_1_2X_asStringXlocalX': [(lambda g, xx1=None:g.inject(xx1).as_string(Scope.local))], 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 70c2154841..cb36ba87b6 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 @@ -19,7 +19,7 @@ Feature: Step - asNumber() @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5bX_asNumberXX + Scenario: g_injectX5bX_asNumber Given the empty graph And the traversal of """ @@ -31,7 +31,7 @@ Feature: Step - asNumber() | d[5].b | @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5sX_asNumberXX + Scenario: g_injectX5sX_asNumber Given the empty graph And the traversal of """ @@ -43,7 +43,7 @@ Feature: Step - asNumber() | d[5].s | @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5iX_asNumberXX + Scenario: g_injectX5iX_asNumber Given the empty graph And the traversal of """ @@ -55,7 +55,7 @@ Feature: Step - asNumber() | d[5].i | @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5lX_asNumberXX + Scenario: g_injectX5lX_asNumber Given the empty graph And the traversal of """ @@ -67,7 +67,7 @@ Feature: Step - asNumber() | d[5].l | @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5nX_asNumberXX + Scenario: g_injectX5nX_asNumber Given the empty graph And the traversal of """ @@ -79,7 +79,7 @@ Feature: Step - asNumber() | d[5].n | @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5_0X_asNumberXX + Scenario: g_injectX5_0X_asNumber Given the empty graph And the traversal of """ @@ -91,7 +91,7 @@ Feature: Step - asNumber() | d[5].d | @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5_75fX_asNumberXX + Scenario: g_injectX5_75fX_asNumber Given the empty graph And the traversal of """ @@ -171,7 +171,7 @@ Feature: Step - asNumber() Then the traversal will raise an error with message containing text of "Can't convert number of type Integer to Byte due to overflow." @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX5X_asNumberXX + Scenario: g_injectX5X_asNumber Given the empty graph And the traversal of """ @@ -205,7 +205,7 @@ Feature: Step - asNumber() Then the traversal will raise an error with message containing text of "Can't parse string '1,000' as number." @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectXtestX_asNumberXX + Scenario: g_injectXtestX_asNumber Given the empty graph And the traversal of """ @@ -215,7 +215,7 @@ Feature: Step - asNumber() Then the traversal will raise an error with message containing text of "Can't parse string 'test' as number." @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX_1__2__3__4_X_asNumberXX + Scenario: g_injectX_1_2_3_4X_asNumber Given the empty graph And the traversal of """ @@ -225,7 +225,7 @@ Feature: Step - asNumber() Then the traversal will raise an error with message containing text of "Can't parse type ArrayList as number." @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX_1__2__3__4_X_unfoldXX_asNumberXX + Scenario: g_injectX1_2_3_4X_unfold_asNumber Given the empty graph And the traversal of """ @@ -240,17 +240,32 @@ Feature: Step - asNumber() | d[4].i | @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX_1__2__3__4_X_unfoldXX_asNumberXX_foldXX + Scenario: g_injectX_1__2__3__4_X_asNumberXX_foldXX Given the empty graph And the traversal of """ - g.inject([1, 2, 3, 4]).unfold().asNumber().fold() + g.inject("1", 2, "3", 4).asNumber().fold() """ When iterated to list Then the result should be unordered | result | | l[d[1].i,d[2].i,d[3].i,d[4].i] | + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX1_2_3_4_0x5X_asNumber_sum_asNumberXnbyteX + Given the empty graph + And using the parameter xx1 defined as "d[1.0].d" + And using the parameter xx2 defined as "d[2].i" + And using the parameter xx3 defined as "d[3].l" + And the traversal of + """ + g.inject(xx1, xx2, xx3, "4", "0x5").asNumber().sum().asNumber(N.nbyte) + """ + When iterated to list + Then the result should be unordered + | result | + | d[15].b | + @GraphComputerVerificationInjectionNotSupported Scenario: g_VX1X_asNumberXN_nintX Given the empty graph @@ -259,4 +274,32 @@ Feature: Step - asNumber() g.inject(null).asNumber(N.nint) """ When iterated to list - Then the traversal will raise an error with message containing text of "Can't parse type null as number." \ No newline at end of file + Then the traversal will raise an error with message containing text of "Can't parse type null as number." + + @GraphComputerVerificationReferenceOnly + Scenario: g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXnintX + Given the modern graph + And the traversal of + """ + g.V().as("a").out("knows").as("b").math("a + b").by("age").asNumber(N.nint) + """ + When iterated to list + Then the result should be unordered + | result | + | d[56].i | + | d[61].i | + + Scenario: g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXnlongX + Given the modern graph + And using the parameter xx1 defined as "d[100].i" + And the traversal of + """ + g.withSideEffect("x", xx1).V().values("age").math("_ + x").asNumber(N.nlong) + """ + When iterated to list + Then the result should be unordered + | result | + | d[129].l | + | d[127].l | + | d[132].l | + | d[135].l |
