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 8bee410b6362982bab7377c76bb99821b0667e25 Author: xiazcy <xia...@gmail.com> AuthorDate: Mon Jul 7 12:52:51 2025 -0400 minor adjustments to implementation and error messages, fix issues in GLVs --- .../language/translator/TranslateVisitor.java | 7 + .../tinkerpop/gremlin/process/traversal/N.java | 25 ++- .../process/traversal/step/map/AsNumberStep.java | 194 +++++++++++---------- .../traversal/step/map/AsNumberStepTest.java} | 41 +++-- .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 22 ++- gremlin-go/driver/cucumber/gremlin.go | 21 +++ gremlin-go/driver/graphBinary.go | 2 +- gremlin-go/driver/traversal.go | 36 ++-- .../gremlin-javascript/test/cucumber/gremlin.js | 3 +- .../test/unit/graphbinary/AnySerializer-test.js | 9 +- gremlin-python/build/generate.groovy | 2 +- .../gremlin_python/process/graph_traversal.py | 14 ++ .../python/gremlin_python/process/traversal.py | 10 ++ .../gremlin_python/structure/io/graphbinaryV1.py | 8 +- gremlin-python/src/main/python/radish/gremlin.py | 23 ++- .../tests/driver/test_driver_remote_connection.py | 2 +- .../gremlin/test/features/map/AsNumber.feature | 27 +-- 17 files changed, 284 insertions(+), 162 deletions(-) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java index 2dc4b5a49e..317dd098d5 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java @@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.language.grammar.GremlinBaseVisitor; import org.apache.tinkerpop.gremlin.language.grammar.GremlinParser; import org.apache.tinkerpop.gremlin.process.traversal.DT; import org.apache.tinkerpop.gremlin.process.traversal.Merge; +import org.apache.tinkerpop.gremlin.process.traversal.N; import org.apache.tinkerpop.gremlin.process.traversal.Operator; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.P; @@ -207,6 +208,12 @@ public class TranslateVisitor extends GremlinBaseVisitor<Void> { return null; } + @Override + public Void visitTraversalN(final GremlinParser.TraversalNContext ctx) { + appendExplicitNaming(ctx.getText(), N.class.getSimpleName()); + return null; + } + @Override public Void visitTraversalPredicate(final GremlinParser.TraversalPredicateContext ctx) { switch(ctx.getChildCount()) { diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java index d0bf66bfdc..67eda53a7d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java @@ -25,12 +25,21 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsNumberStep; * Used with {@link AsNumberStep} step. */ public enum N { - nbyte, - nshort, - nint, - nlong, - nfloat, - ndouble, - nbigInt, - nbigDecimal + nbyte("Byte"), + nshort("Short"), + nint("Integer"), + nlong("Long"), + nfloat("Float"), + ndouble("Double"), + nbigInt("BigInt"), + nbigDecimal("BigDecimal"),; + + private final String typeName; + + N(String name) {typeName = name;} + + @Override + public String toString() { + return typeName; + } } \ No newline at end of file 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 4c1bfe4e9f..1fe1a52051 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 @@ -36,97 +36,63 @@ import java.util.Map; import java.util.Set; /** - * Reference implementation for date concatenation step. - * - * @author Valentyn Kahamlyk + * Reference implementation for number parsing step. */ public final class AsNumberStep<S> extends ScalarMapStep<S, Number> { - private final N numberToken; - private final boolean auto; + private N numberToken; public AsNumberStep(final Traversal.Admin traversal) { super(traversal); - this.numberToken = N.nlong; - this.auto = true; + this.numberToken = null; } public AsNumberStep(final Traversal.Admin traversal, final N numberToken) { super(traversal); this.numberToken = numberToken; - this.auto = false; } - private static int getNumberBitsBasedOnValue(Number number) { - final Class<? extends Number> clazz = number.getClass(); - if (clazz.equals(BigInteger.class)) { - return 128; - } else if (clazz.equals(BigDecimal.class)) { - return 128; - } - boolean floatingPoint = (clazz.equals(Float.class) || clazz.equals(Double.class)); - if (!floatingPoint && (number.longValue() >= Byte.MIN_VALUE) && (number.longValue() <= Byte.MAX_VALUE)) { - return 8; - } else if (!floatingPoint && (number.longValue() >= Short.MIN_VALUE) && (number.longValue() <= Short.MAX_VALUE)) { - return 16; - } else if (!floatingPoint && (number.longValue() >= Integer.MIN_VALUE) && (number.longValue() <= Integer.MAX_VALUE)) { - return 32; - } else if (floatingPoint && (number.doubleValue() >= Float.MIN_VALUE) && (number.doubleValue() <= Float.MAX_VALUE)) { - return 32; - } else { - return 64; + @Override + protected Number map(Traverser.Admin<S> traverser) { + final Object object = traverser.get(); + if (object instanceof String) { + String numberText = (String) object; + Number number = parseNumber(numberText); + return numberToken == null ? autoNumber(number) : castNumber(number, numberToken); + } else if (object instanceof Number) { + Number number = (Number) object; + return numberToken == null ? autoNumber(number) : castNumber(number, numberToken); } + throw new IllegalArgumentException(String.format("Can't parse type %s as number.", object == null ? "null" : object.getClass().getSimpleName())); } - private static int getNumberTokenBits(N numberToken) { - if (numberToken == N.nbyte) { - return 8; - } else if (numberToken == N.nshort) { - return 16; - } else if (numberToken == N.nint) { - return 32; - } else if (numberToken == N.nlong) { - return 64; - } else if (numberToken == N.nfloat) { - return 32; - } else if (numberToken == N.ndouble) { - return 64; - } - return 128; + @Override + public Set<TraverserRequirement> getRequirements() { + return Collections.singleton(TraverserRequirement.OBJECT); } - private static Number castNumber(Number number, N numberToken) { - int sourceBits = getNumberBitsBasedOnValue(number); - int targetBits = getNumberTokenBits(numberToken); - if (sourceBits > targetBits) { - throw new ArithmeticException("Can not convert number type as would cause overflow."); - } - if (numberToken == N.nbyte) { - return number.byteValue(); - } else if (numberToken == N.nshort) { - return number.shortValue(); - } else if (numberToken == N.nint) { - return number.intValue(); - } else if (numberToken == N.nlong) { - return number.longValue(); - } else if (numberToken == N.nfloat) { - return number.floatValue(); - } else if (numberToken == N.ndouble) { - return number.doubleValue(); - } else if (numberToken == N.nbigInt) { - return BigInteger.valueOf(number.longValue()); - } else if (numberToken == N.nbigDecimal) { - return BigDecimal.valueOf(number.doubleValue()); - } - return number; + @Override + public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) { + super.setTraversal(parentTraversal); } - private static Number autoNumber(Number number) { - final Class<? extends Number> clazz = number.getClass(); - if (clazz.equals(Float.class)) { - return castNumber(number, N.ndouble); - } - return number; + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (numberToken != null ? numberToken.hashCode() : 0); + return result; + } + + @Override + public AsNumberStep<S> clone() { + final AsNumberStep<S> clone = (AsNumberStep<S>) super.clone(); + clone.numberToken = this.numberToken; + return clone; + } + + @Override + public String toString() { + return StringFactory.stepString(this); } public static Number parseNumber(final String value) { @@ -151,36 +117,80 @@ public final class AsNumberStep<S> extends ScalarMapStep<S, Number> { } return result; } catch (NumberFormatException nfe) { - throw new NumberFormatException(String.format("Can not parse number: '%s'", value)); + throw new NumberFormatException(String.format("Can't parse string '%s' as number.", value)); } } - @Override - protected Number map(Traverser.Admin<S> traverser) { - final Object object = traverser.get(); - if (object instanceof String) { - String numberText = (String) object; - Number number = parseNumber(numberText); - return auto ? autoNumber(number) : castNumber(number, numberToken); - } else if (object instanceof Number) { - Number number = (Number) object; - return auto ? autoNumber(number) : castNumber(number, numberToken); + private static Number autoNumber(Number number) { + final Class<? extends Number> clazz = number.getClass(); + if (clazz.equals(Float.class)) { + return castNumber(number, N.ndouble); } - throw new IllegalArgumentException(String.format("Can't parse '%s' as number.", object == null ? "null" : object.getClass().getSimpleName())); + return number; } - @Override - public Set<TraverserRequirement> getRequirements() { - return Collections.singleton(TraverserRequirement.OBJECT); + private static Number castNumber(Number number, N numberToken) { + int sourceBits = getNumberBitsBasedOnValue(number); + int targetBits = getNumberTokenBits(numberToken); + if (sourceBits > targetBits) { + throw new ArithmeticException(String.format("Can't convert number of type %s to %s due to overflow.", + number.getClass().getSimpleName(), numberToken.toString())); + } + if (numberToken == N.nbyte) { + return number.byteValue(); + } else if (numberToken == N.nshort) { + return number.shortValue(); + } else if (numberToken == N.nint) { + return number.intValue(); + } else if (numberToken == N.nlong) { + return number.longValue(); + } else if (numberToken == N.nfloat) { + return number.floatValue(); + } else if (numberToken == N.ndouble) { + return number.doubleValue(); + } else if (numberToken == N.nbigInt) { + return BigInteger.valueOf(number.longValue()); + } else if (numberToken == N.nbigDecimal) { + return BigDecimal.valueOf(number.doubleValue()); + } + return number; } - @Override - public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) { - super.setTraversal(parentTraversal); + private static int getNumberBitsBasedOnValue(Number number) { + final Class<? extends Number> clazz = number.getClass(); + if (clazz.equals(BigInteger.class)) { + return 128; + } else if (clazz.equals(BigDecimal.class)) { + return 128; + } + boolean floatingPoint = (clazz.equals(Float.class) || clazz.equals(Double.class)); + if (!floatingPoint && (number.longValue() >= Byte.MIN_VALUE) && (number.longValue() <= Byte.MAX_VALUE)) { + return 8; + } else if (!floatingPoint && (number.longValue() >= Short.MIN_VALUE) && (number.longValue() <= Short.MAX_VALUE)) { + return 16; + } else if (!floatingPoint && (number.longValue() >= Integer.MIN_VALUE) && (number.longValue() <= Integer.MAX_VALUE)) { + return 32; + } else if (floatingPoint && (number.doubleValue() >= Float.MIN_VALUE) && (number.doubleValue() <= Float.MAX_VALUE)) { + return 32; + } else { + return 64; + } } - @Override - public String toString() { - return StringFactory.stepString(this); + private static int getNumberTokenBits(N numberToken) { + if (numberToken == N.nbyte) { + return 8; + } else if (numberToken == N.nshort) { + return 16; + } else if (numberToken == N.nint) { + return 32; + } else if (numberToken == N.nlong) { + return 64; + } else if (numberToken == N.nfloat) { + return 32; + } else if (numberToken == N.ndouble) { + return 64; + } + return 128; } } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java similarity index 51% copy from gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java copy to gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java index d0bf66bfdc..a812aac827 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java @@ -16,21 +16,30 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.tinkerpop.gremlin.process.traversal; +package org.apache.tinkerpop.gremlin.process.traversal.step.map; -import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsNumberStep; +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; +import org.junit.Test; -/** - * Tokens that are used to denote different units of number. - * Used with {@link AsNumberStep} step. - */ -public enum N { - nbyte, - nshort, - nint, - nlong, - nfloat, - ndouble, - nbigInt, - nbigDecimal -} \ No newline at end of file +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +public class AsNumberStepTest extends StepTest { + + @Override + protected List<Traversal> getTraversals() { + return Collections.singletonList(__.asNumber()); + } + + @Test + public void testReturnTypes() { + assertEquals(1, __.__(1).asNumber().next()); + } + +} diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index 3cfccca976..25ba75311e 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -622,7 +622,27 @@ 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_injectX123X_asNumberXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(123).AsNumber()}}, + {"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_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_asNumberXN_nintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("5").AsNumber(N.Nint)}}, + {"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_VX1X_asNumberXN_nintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).AsNumber(N.Nint)}}, {"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 57534a17c3..8612cdbf5e 100644 --- a/gremlin-go/driver/cucumber/gremlin.go +++ b/gremlin-go/driver/cucumber/gremlin.go @@ -592,6 +592,27 @@ 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_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_asNumberXN_nintX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("5").AsNumber(gremlingo.N.Nint)}}, + "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_VX1X_asNumberXN_nintX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(nil).AsNumber(gremlingo.N.Nint)}}, "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-go/driver/graphBinary.go b/gremlin-go/driver/graphBinary.go index f89595c821..fd983ea80d 100644 --- a/gremlin-go/driver/graphBinary.go +++ b/gremlin-go/driver/graphBinary.go @@ -82,7 +82,7 @@ const ( bulkSetType dataType = 0x2a mergeType dataType = 0x2e dtType dataType = 0x2f - nType dataType = 0x30 + nType dataType = 0x30 metricsType dataType = 0x2c traversalMetricsType dataType = 0x2d durationType dataType = 0x81 diff --git a/gremlin-go/driver/traversal.go b/gremlin-go/driver/traversal.go index 96cf361c07..bd21fb6a06 100644 --- a/gremlin-go/driver/traversal.go +++ b/gremlin-go/driver/traversal.go @@ -330,7 +330,7 @@ type dts struct { Day dt } -// Merge is a set of operations for Vertex and Edge merging. +// DT is a set of operations for calculating date var DT = dts{ Second: "second", Minute: "minute", @@ -364,33 +364,33 @@ type n string type ns struct { // number type byte - NByte n + Nbyte n // number type short - NShort n + Nshort n // number type int - NInt n + Nint n // number type long - NLong n + Nlong n // number type float - NFloat n + Nfloat n // number type double - NDouble n + Ndouble n // number type bigInt - NBigInt n + NbigInt n // number type bigDecimal - NBigDecimal n + NbigDecimal n } -// Merge is a set of operations for Vertex and Edge merging. +// N is a set of operations for denoting number types during conversion. var N = ns{ - NByte: "nbyte", - NShort: "nshort", - NInt: "nint", - NLong: "nlong", - NFloat: "nfloat", - NDouble: "ndouble", - NBigInt: "nbigInt", - NBigDecimal: "nbigDecimal", + Nbyte: "nbyte", + Nshort: "nshort", + Nint: "nint", + Nlong: "nlong", + Nfloat: "nfloat", + Ndouble: "ndouble", + NbigInt: "nbigInt", + NbigDecimal: "nbigDecimal", } type operator string 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 2dc4eb664f..5f75840cd2 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 @@ -634,7 +634,7 @@ const gremlins = { 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) }, function({g}) { return g.inject("32768").asNumber(N.nshort) }], + 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) }], @@ -643,6 +643,7 @@ const gremlins = { 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_VX1X_asNumberXN_nintX: [function({g}) { return g.inject(null).asNumber(N.nint) }], 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-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js index ae7518f13a..b9399a6fff 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js @@ -176,6 +176,9 @@ describe('GraphBinary.AnySerializer', () => { { v: new t.EnumValue('Merge', 'onMatch'), b: [ DataType.MERGE,0x00, DataType.STRING,0x00, 0x00,0x00,0x00,0x07, ...from('onMatch') ] }, + { v: new t.EnumValue('N', 'nbyte'), + b: [ DataType.N,0x00, DataType.STRING,0x00, 0x00,0x00,0x00,0x05, ...from('nbyte') ] + }, { v: new t.EnumValue('Operator', 'addAll'), b: [ DataType.OPERATOR,0x00, DataType.STRING,0x00, 0x00,0x00,0x00,0x06, ...from('addAll') ] }, @@ -355,7 +358,7 @@ describe('GraphBinary.AnySerializer', () => { { err:/buffer is empty/, b:[] }, { err:/buffer is empty/, b:[] }, - { err:/unknown {type_code}/, b:[0x30] }, + { err:/unknown {type_code}/, b:[0x40] }, // tests an unassigned type code { err:/unknown {type_code}/, b:[0x8F] }, { err:/unknown {type_code}/, b:[0xFF] }, @@ -517,6 +520,10 @@ describe('GraphBinary.AnySerializer', () => { { v:null, b:[0x2e,0x01] }, { v:new t.EnumValue('Merge','onCreate'), b:[0x2e,0x00, 0x03,0x00, 0x00,0x00,0x00,0x08, ...from('onCreate')] }, + // N + { v:null, b:[0x30,0x01] }, + { v:new t.EnumValue('N','nbyte'), b:[0x30,0x00, 0x03,0x00, 0x00,0x00,0x00,0x05, ...from('nbyte')] }, + // OPERATOR { v:null, b:[0x19,0x01] }, { v:new t.EnumValue('Operator','addAll'), b:[0x19,0x00, 0x03,0x00, 0x00,0x00,0x00,0x06, ...from('addAll')] }, diff --git a/gremlin-python/build/generate.groovy b/gremlin-python/build/generate.groovy index 6da003cc54..45e204288e 100644 --- a/gremlin-python/build/generate.groovy +++ b/gremlin-python/build/generate.groovy @@ -63,7 +63,7 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer -> 'from gremlin_python.process.traversal import TraversalStrategy\n' + 'from gremlin_python.process.graph_traversal import __\n' + 'from gremlin_python.structure.graph import Graph\n' + - 'from gremlin_python.process.traversal import Barrier, Cardinality, CardinalityValue, P, TextP, Pop, Scope, Column, Order, Direction, DT, Merge, T, Pick, Operator, IO, WithOptions\n') + 'from gremlin_python.process.traversal import Barrier, Cardinality, CardinalityValue, P, TextP, Pop, Scope, Column, Order, Direction, DT, Merge, N, T, Pick, Operator, IO, WithOptions\n') // some traversals may require a static translation if the translator can't handle them for some reason def staticTranslate = [:] diff --git a/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py index f1f55f089c..ced9fc1890 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/graph_traversal.py @@ -318,6 +318,10 @@ class GraphTraversal(Traversal): self.bytecode.add_step("asDate", *args) return self + def as_number(self, *args): + self.bytecode.add_step("asNumber", *args) + return self + def as_string(self, *args): self.bytecode.add_step("asString", *args) return self @@ -1099,6 +1103,10 @@ class __(object, metaclass=MagicType): def as_date(cls, *args): return cls.graph_traversal(None, None, Bytecode()).as_date(*args) + @classmethod + def as_number(cls, *args): + return cls.graph_traversal(None, None, Bytecode()).as_number(*args) + @classmethod def as_string(cls, *args): return cls.graph_traversal(None, None, Bytecode()).as_string(*args) @@ -1871,6 +1879,10 @@ def as_date(*args): return __.as_date(*args) +def as_number(*args): + return __.as_number(*args) + + def as_string(*args): return __.as_string(*args) @@ -2415,6 +2427,8 @@ statics.add_static('as_', as_) statics.add_static('as_date', as_date) +statics.add_static('as_number', as_number) + statics.add_static('as_string', as_string) statics.add_static('barrier', barrier) diff --git a/gremlin-python/src/main/python/gremlin_python/process/traversal.py b/gremlin-python/src/main/python/gremlin_python/process/traversal.py index fb74433348..4f93bf97ad 100644 --- a/gremlin-python/src/main/python/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/python/gremlin_python/process/traversal.py @@ -208,6 +208,16 @@ statics.add_static('on_match', Merge.on_match) statics.add_static('in_v', Merge.in_v) statics.add_static('out_v', Merge.out_v) +N = Enum('N', ' nbyte nshort nint nlong nfloat ndouble nbigInt nbigDecimal') +statics.add_static('nbyte', N.nbyte) +statics.add_static('nshort', N.nshort) +statics.add_static('nint', N.nint) +statics.add_static('nlong', N.nlong) +statics.add_static('nfloat', N.nfloat) +statics.add_static('ndouble', N.ndouble) +statics.add_static('nbigInt', N.nbigInt) +statics.add_static('nbigDecimal', N.nbigDecimal) + Order = Enum('Order', ' asc desc shuffle') statics.add_static('shuffle', Order.shuffle) diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py index d74561bb8a..fa1e69352f 100644 --- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py +++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py @@ -33,7 +33,7 @@ from gremlin_python import statics from gremlin_python.statics import FloatType, BigDecimal, FunctionType, ShortType, IntType, LongType, BigIntType, \ TypeType, DictType, ListType, SetType, SingleByte, ByteBufferType, GremlinType, \ SingleChar -from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Cardinality, Column, Direction, DT, Merge, \ +from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Cardinality, Column, Direction, DT, Merge, N, \ Operator, Order, Pick, Pop, P, Scope, TextP, Traversal, Traverser, \ TraversalStrategy, T from gremlin_python.process.graph_traversal import GraphTraversal @@ -98,6 +98,7 @@ class DataType(Enum): traversalmetrics = 0x2d merge = 0x2e dt = 0x2f + n = 0x30 char = 0x80 duration = 0x81 inetaddress = 0x82 # todo @@ -977,6 +978,11 @@ class MergeIO(_EnumIO): python_type = Merge +class NIO(_EnumIO): + graphbinary_type = DataType.n + python_type = N + + class ScopeIO(_EnumIO): graphbinary_type = DataType.scope python_type = Scope diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index 5d4b19fa13..8c2134f592 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -33,7 +33,7 @@ from gremlin_python.process.strategies import * from gremlin_python.process.traversal import TraversalStrategy from gremlin_python.process.graph_traversal import __ from gremlin_python.structure.graph import Graph -from gremlin_python.process.traversal import Barrier, Cardinality, CardinalityValue, P, TextP, Pop, Scope, Column, Order, Direction, DT, Merge, T, Pick, Operator, IO, WithOptions +from gremlin_python.process.traversal import Barrier, Cardinality, CardinalityValue, P, TextP, Pop, Scope, Column, Order, Direction, DT, Merge, N, T, Pick, Operator, IO, WithOptions world.gremlins = { 'g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX': [(lambda g, xx1=None,xx2=None:g.V().branch(__.label().is_('person').count()).option(xx1, __.values('age')).option(xx2, __.values('lang')).option(xx2, __.values('name')))], @@ -595,6 +595,27 @@ 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_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_asNumberXN_nintX': [(lambda g:g.inject('5').as_number(N.nint))], + '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_VX1X_asNumberXN_nintX': [(lambda g:g.inject(None).as_number(N.nint))], '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-python/src/main/python/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py index eb6beee5c6..fe402a1091 100644 --- a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py +++ b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py @@ -25,7 +25,7 @@ from gremlin_python.statics import long from gremlin_python.process.traversal import Traverser from gremlin_python.process.traversal import TraversalStrategy from gremlin_python.process.traversal import Bindings -from gremlin_python.process.traversal import P, Order, T +from gremlin_python.process.traversal import P, Order, T, N from gremlin_python.process.graph_traversal import __ from gremlin_python.process.anonymous_traversal import traversal from gremlin_python.structure.graph import Vertex 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 7fef5997f1..868eb80274 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 @@ -158,7 +158,7 @@ Feature: Step - asNumber() g.inject(32768).asNumber(N.nshort) """ When iterated to list - Then the traversal will raise an error with message containing text of "Can not convert number type as would cause overflow." + Then the traversal will raise an error with message containing text of "Can't convert number of type Integer to Short due to overflow." @GraphComputerVerificationInjectionNotSupported Scenario: g_injectX300X_asNumberXN_nbyteX @@ -168,7 +168,7 @@ Feature: Step - asNumber() g.inject(300).asNumber(N.nbyte) """ When iterated to list - Then the traversal will raise an error with message containing text of "Can not convert number type as would cause overflow." + 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 @@ -202,17 +202,7 @@ Feature: Step - asNumber() g.inject("1,000").asNumber(N.nint) """ When iterated to list - Then the traversal will raise an error with message containing text of "Can not parse number: '1,000'" - - @GraphComputerVerificationInjectionNotSupported - Scenario: g_injectX32768X_asNumberXN_nshortX - Given the empty graph - And the traversal of - """ - g.inject("32768").asNumber(N.nshort) - """ - When iterated to list - Then the traversal will raise an error with message containing text of "Can not convert number type as would cause overflow." + 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 @@ -222,7 +212,7 @@ Feature: Step - asNumber() g.inject("test").asNumber() """ When iterated to list - Then the traversal will raise an error with message containing text of "Can not parse number: 'test'" + 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 @@ -232,7 +222,7 @@ Feature: Step - asNumber() g.inject([1, 2, 3, 4]).asNumber() """ When iterated to list - Then the traversal will raise an error with message containing text of "Can't parse 'ArrayList' as number." + 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 @@ -266,10 +256,7 @@ Feature: Step - asNumber() Given the empty graph And the traversal of """ - g.V(1).asNumber(N.nint) + g.inject(null).asNumber(N.nint) """ When iterated to list - Then the result should be unordered - | result | - | d[1].i | -# ==> Parsing Exception ("Type Vertex is not parsable to Type Integer") \ 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." \ No newline at end of file