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 e4ec14140cd978fd903c4317b24951521258fdea Author: Peter Tribe <[email protected]> AuthorDate: Thu Jun 12 18:42:11 2025 -0600 asNumber implementations --- .../tinkerpop/gremlin/jsr223/CoreImports.java | 3 + .../grammar/DefaultGremlinBaseVisitor.java | 12 + .../language/grammar/TraversalMethodVisitor.java | 17 ++ .../tinkerpop/gremlin/process/traversal/N.java | 36 +++ .../traversal/dsl/graph/GraphTraversal.java | 27 ++ .../gremlin/process/traversal/dsl/graph/__.java | 15 ++ .../process/traversal/step/map/AsNumberStep.java | 186 ++++++++++++++ .../process/traversal/util/BytecodeHelper.java | 2 + .../gremlin/structure/io/binary/DataType.java | 1 + .../io/binary/TypeSerializerRegistry.java | 2 + .../structure/io/binary/types/EnumSerializer.java | 2 + .../structure/io/graphson/GraphSONModule.java | 7 + .../gremlin/structure/io/gryo/GryoVersion.java | 2 + .../Process/Traversal/GraphTraversal.cs | 9 + .../src/Gremlin.Net/Process/Traversal/N.cs | 74 ++++++ .../src/Gremlin.Net/Process/Traversal/__.cs | 8 + .../Structure/IO/GraphBinary/DataType.cs | 1 + .../IO/GraphBinary/TypeSerializerRegistry.cs | 2 + .../IO/GraphBinary/Types/EnumSerializer.cs | 6 + .../Structure/IO/GraphSON/GraphSONReader.cs | 1 + .../Structure/IO/GraphSON/NDeserializer.cs | 38 +++ .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 1 + .../Structure/IO/GraphBinary/GraphBinaryTests.cs | 15 ++ .../Structure/IO/GraphSON/GraphSONReaderTests.cs | 12 + .../Structure/IO/GraphSON/GraphSONWriterTests.cs | 11 + gremlin-go/driver/anonymousTraversal.go | 5 + gremlin-go/driver/graphBinary.go | 3 + gremlin-go/driver/graphTraversal.go | 6 + gremlin-go/driver/serializer.go | 2 + gremlin-go/driver/traversal.go | 34 +++ gremlin-javascript/build/generate.groovy | 1 + .../lib/process/graph-traversal.js | 10 + .../gremlin-javascript/lib/process/traversal.js | 1 + .../lib/structure/io/binary/internals/DataType.js | 1 + .../io/binary/internals/EnumSerializer.js | 1 + .../gremlin-javascript/test/cucumber/gremlin.js | 21 ++ gremlin-language/src/main/antlr4/Gremlin.g4 | 38 +++ .../gremlin/test/features/map/AsNumber.feature | 275 +++++++++++++++++++++ 38 files changed, 888 insertions(+) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java index a4d77b0fd2..82e3ed78c4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java @@ -60,6 +60,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Bindings; import org.apache.tinkerpop.gremlin.process.traversal.DT; import org.apache.tinkerpop.gremlin.process.traversal.IO; 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; @@ -204,6 +205,7 @@ public final class CoreImports { CLASS_IMPORTS.add(Direction.class); CLASS_IMPORTS.add(DT.class); CLASS_IMPORTS.add(Merge.class); + CLASS_IMPORTS.add(N.class); CLASS_IMPORTS.add(Operator.class); CLASS_IMPORTS.add(Order.class); CLASS_IMPORTS.add(Pop.class); @@ -363,6 +365,7 @@ public final class CoreImports { Collections.addAll(ENUM_IMPORTS, Direction.values()); Collections.addAll(ENUM_IMPORTS, DT.values()); Collections.addAll(ENUM_IMPORTS, Merge.values()); + Collections.addAll(ENUM_IMPORTS, N.values()); Collections.addAll(ENUM_IMPORTS, Operator.values()); Collections.addAll(ENUM_IMPORTS, Order.values()); Collections.addAll(ENUM_IMPORTS, Pop.values()); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java index cf3946e550..e37503226b 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java @@ -1067,6 +1067,14 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im * {@inheritDoc} */ @Override public T visitTraversalMethod_dateDiff_Date(final GremlinParser.TraversalMethod_dateDiff_DateContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_asNumber_Empty(final GremlinParser.TraversalMethod_asNumber_EmptyContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalMethod_asNumber_traversalN(final GremlinParser.TraversalMethod_asNumber_traversalNContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ @@ -1107,6 +1115,10 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im * {@inheritDoc} */ @Override public T visitTraversalDT(GremlinParser.TraversalDTContext ctx) { notImplemented(ctx); return null; } + /** + * {@inheritDoc} + */ + @Override public T visitTraversalN(GremlinParser.TraversalNContext ctx) { notImplemented(ctx); return null; } /** * {@inheritDoc} */ diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java index 6a45f660ff..ccc24cea14 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java @@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.language.grammar; 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.Pop; @@ -2102,6 +2103,22 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal> return graphTraversal.dateDiff(antlr.genericVisitor.parseDate(ctx.dateLiteral())); } + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_asNumber_Empty(final GremlinParser.TraversalMethod_asNumber_EmptyContext ctx) { + return graphTraversal.asNumber(); + } + + /** + * {@inheritDoc} + */ + @Override + public GraphTraversal visitTraversalMethod_asNumber_traversalN(final GremlinParser.TraversalMethod_asNumber_traversalNContext ctx) { + return graphTraversal.asNumber( + TraversalEnumParser.parseTraversalEnumFromContext(N.class, ctx.traversalN())); + } public GraphTraversal[] getNestedTraversalList(final GremlinParser.NestedTraversalListContext ctx) { return ctx.nestedTraversalExpr().nestedTraversal() 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 new file mode 100644 index 0000000000..d0bf66bfdc --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/N.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal; + +import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsNumberStep; + +/** + * 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 diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java index 32b830c252..e1daab30d2 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java @@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.Shortest import org.apache.tinkerpop.gremlin.process.traversal.DT; import org.apache.tinkerpop.gremlin.process.traversal.Failure; import org.apache.tinkerpop.gremlin.process.traversal.Merge; +import org.apache.tinkerpop.gremlin.process.traversal.N; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Path; @@ -83,6 +84,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStartStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsDateStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsNumberStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsStringGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsStringLocalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.CallStep; @@ -1903,6 +1905,30 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { return this.asAdmin().addStep(new DateDiffStep<>(this.asAdmin(), dateTraversal)); } + /** + * Parse value of the incoming traverser as an ISO-8601 {@link Number}. + * + * @return the traversal with an appended {@link AsNumberStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#AsNumberStep-step" target="_blank">Reference Documentation - AsNumberStep Step</a> + * @since 3.7.1 + */ + public default GraphTraversal<S, Number> asNumber() { + this.asAdmin().getBytecode().addStep(Symbols.asNumber); + return this.asAdmin().addStep(new AsNumberStep<>(this.asAdmin())); + } + + /** + * Parse value of the incoming traverser as an ISO-8601 {@link Number}. + * + * @return the traversal with an appended {@link AsNumberStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#AsNumberStep-step" target="_blank">Reference Documentation - AsNumberStep Step</a> + * @since 3.7.1 + */ + public default GraphTraversal<S, Number> asNumber(final N numberToken) { + this.asAdmin().getBytecode().addStep(Symbols.asNumber, numberToken); + return this.asAdmin().addStep(new AsNumberStep<>(this.asAdmin(), numberToken)); + } + /** * Calculates the difference between the list traverser and list argument. * @@ -4122,6 +4148,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { public static final String asDate = "asDate"; public static final String dateAdd = "dateAdd"; public static final String dateDiff = "dateDiff"; + public static final String asNumber = "asNumber"; public static final String all = "all"; public static final String any = "any"; public static final String merge = "merge"; diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java index e1edcfc5f4..e3250f3095 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.dsl.graph; import org.apache.tinkerpop.gremlin.process.traversal.DT; +import org.apache.tinkerpop.gremlin.process.traversal.N; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.Pop; @@ -809,6 +810,20 @@ public class __ { return __.<A>start().dateDiff(dateTraversal); } + /** + * @see GraphTraversal#asNumber() + */ + public static <A> GraphTraversal<A, Number> asNumber() { + return __.<A>start().asNumber(); + } + + /** + * @see GraphTraversal#asNumber(N) + */ + public static <A> GraphTraversal<A, Number> asNumber(final N numberToken) { + return __.<A>start().asNumber(numberToken); + } + /** * @see GraphTraversal#difference(Object) */ 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 new file mode 100644 index 0000000000..4c1bfe4e9f --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.process.traversal.step.map; + +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.tinkerpop.gremlin.process.traversal.N; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; +import org.apache.tinkerpop.gremlin.structure.util.StringFactory; +import org.apache.tinkerpop.gremlin.util.NumberHelper; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Reference implementation for date concatenation step. + * + * @author Valentyn Kahamlyk + */ +public final class AsNumberStep<S> extends ScalarMapStep<S, Number> { + + private final N numberToken; + private final boolean auto; + + public AsNumberStep(final Traversal.Admin traversal) { + super(traversal); + this.numberToken = N.nlong; + this.auto = true; + } + + 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; + } + } + + 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; + } + + 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; + } + + 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; + } + + public static Number parseNumber(final String value) { + try { + boolean isFloatingPoint = value.contains(".") || value.contains("e") || value.contains("E"); + if (isFloatingPoint) { + BigDecimal result = new BigDecimal(value.trim()); + if (BigDecimal.valueOf(result.doubleValue()).compareTo(result) == 0) { + return result.doubleValue(); + } + 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) { + return result.intValue(); + } else if (result.bitLength() <= 63) { + return result.longValue(); + } + return result; + } catch (NumberFormatException nfe) { + throw new NumberFormatException(String.format("Can not parse number: '%s'", 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); + } + throw new IllegalArgumentException(String.format("Can't parse '%s' as number.", object == null ? "null" : object.getClass().getSimpleName())); + } + + @Override + public Set<TraverserRequirement> getRequirements() { + return Collections.singleton(TraverserRequirement.OBJECT); + } + + @Override + public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) { + super.setTraversal(parentTraversal); + } + + @Override + public String toString() { + return StringFactory.stepString(this); + } +} diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java index 9a508be6d5..e9e2ac90da 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/BytecodeHelper.java @@ -65,6 +65,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTraversal import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsDateStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsNumberStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsStringGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.AsStringLocalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.CallStep; @@ -247,6 +248,7 @@ public final class BytecodeHelper { put(GraphTraversal.Symbols.asDate, Collections.singletonList(AsDateStep.class)); put(GraphTraversal.Symbols.dateAdd, Collections.singletonList(DateAddStep.class)); put(GraphTraversal.Symbols.dateDiff, Collections.singletonList(DateDiffStep.class)); + put(GraphTraversal.Symbols.asNumber, Collections.singletonList(AsNumberStep.class)); put(GraphTraversal.Symbols.all, Collections.singletonList(AllStep.class)); put(GraphTraversal.Symbols.any, Collections.singletonList(AnyStep.class)); put(GraphTraversal.Symbols.combine, Collections.singletonList(CombineStep.class)); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java index e3fd09f16a..c0738a3496 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/DataType.java @@ -72,6 +72,7 @@ public enum DataType { TRAVERSALMETRICS(0x2D), MERGE(0x2E), DT(0x2F), + N(0x30), CHAR(0X80), DURATION(0X81), diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java index 9958179318..4b48d8d211 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java @@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.structure.io.binary; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; 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; @@ -166,6 +167,7 @@ public class TypeSerializerRegistry { new RegistryEntry<>(Direction.class, EnumSerializer.DirectionSerializer), new RegistryEntry<>(DT.class, EnumSerializer.DTSerializer), new RegistryEntry<>(Merge.class, EnumSerializer.MergeSerializer), + new RegistryEntry<>(N.class, EnumSerializer.NSerializer), new RegistryEntry<>(Operator.class, EnumSerializer.OperatorSerializer), new RegistryEntry<>(Order.class, EnumSerializer.OrderSerializer), new RegistryEntry<>(Pick.class, EnumSerializer.PickSerializer), diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java index dcd1469460..730ffab1c9 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java @@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.structure.io.binary.types; 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.Pick; @@ -51,6 +52,7 @@ public class EnumSerializer<E extends Enum> extends SimpleTypeSerializer<E> { public static final EnumSerializer<Direction> DirectionSerializer = new EnumSerializer<>(DataType.DIRECTION, Direction::valueOf); public static final EnumSerializer<DT> DTSerializer = new EnumSerializer<>(DataType.DT, DT::valueOf); public static final EnumSerializer<Merge> MergeSerializer = new EnumSerializer<>(DataType.MERGE, Merge::valueOf); + public static final EnumSerializer<N> NSerializer = new EnumSerializer<>(DataType.N, N::valueOf); public static final EnumSerializer<Operator> OperatorSerializer = new EnumSerializer<>(DataType.OPERATOR, Operator::valueOf); public static final EnumSerializer<Order> OrderSerializer = new EnumSerializer<>(DataType.ORDER, Order::valueOf); public static final EnumSerializer<Pick> PickSerializer = new EnumSerializer<>(DataType.PICK, Pick::valueOf); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java index 23cd17cfac..1869f3d3b1 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java @@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verifica import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; 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; @@ -185,6 +186,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Direction.class, DT.class, Merge.class, + N.class, Operator.class, Order.class, Pop.class, @@ -277,6 +279,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Direction.class, DT.class, Merge.class, + N.class, Operator.class, Order.class, Pop.class, @@ -324,6 +327,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Direction.values(), DT.values(), Merge.values(), + N.values(), Operator.values(), Order.values(), Pop.values(), @@ -445,6 +449,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Direction.class, DT.class, Merge.class, + N.class, Operator.class, Order.class, Pop.class, @@ -531,6 +536,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Direction.class, DT.class, Merge.class, + N.class, Operator.class, Order.class, Pop.class, @@ -570,6 +576,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule { Direction.values(), DT.values(), Merge.values(), + N.values(), Operator.values(), Order.values(), Pop.values(), diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java index f4eb044b0b..65b0f7164c 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java @@ -342,6 +342,7 @@ public enum GryoVersion { add(GryoTypeReg.of(Pick.class, 137)); add(GryoTypeReg.of(DT.class, 198)); add(GryoTypeReg.of(Merge.class, 196)); + add(GryoTypeReg.of(DT.class, 199)); add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer())); add(GryoTypeReg.of(MultiComparator.class, 165)); @@ -550,6 +551,7 @@ public enum GryoVersion { add(GryoTypeReg.of(Pick.class, 137)); add(GryoTypeReg.of(DT.class, 198)); add(GryoTypeReg.of(Merge.class, 196)); + add(GryoTypeReg.of(DT.class, 199)); add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer())); add(GryoTypeReg.of(MultiComparator.class, 165)); diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs index 8adff6b819..07825fe7c7 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs @@ -670,6 +670,15 @@ namespace Gremlin.Net.Process.Traversal return Wrap<TStart, long>(this); } + /// <summary> + /// Adds the asNumber step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<TStart, object> AsNumber(N numberToken) + { + Bytecode.AddStep("asNumber", numberToken); + return Wrap<TStart, object>(this); + } + /// <summary> /// Adds the dedup step to this <see cref="GraphTraversal{SType, EType}" />. /// </summary> diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/N.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/N.cs new file mode 100644 index 0000000000..8996957b30 --- /dev/null +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/N.cs @@ -0,0 +1,74 @@ +#region License + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#endregion + +using System; +using System.Collections.Generic; + +namespace Gremlin.Net.Process.Traversal +{ +#pragma warning disable 1591 + + public class N : EnumWrapper, IFunction + { + private N(string enumValue) + : base("N", enumValue) + { + } + + public static N NByte => new N("nbyte"); + public static N NShort => new N("nshort"); + public static N NInt => new N("nint"); + public static N NLong => new N("nlong"); + public static N NFloat => new N("nfloat"); + public static N NDouble => new N("ndouble"); + public static N NBigInt => new N("nbigInt"); + public static N NBigDecimal => new N("nbigDecimal"); + + private static readonly Dictionary<string, N> Properties = new() + { + { "nbyte", NByte }, + { "nshort", NShort }, + { "nint", NInt }, + { "nlong", NLong }, + { "nfloat", NFloat }, + { "ndouble", NDouble }, + { "nbigInt", NBigInt }, + { "nbigDecimal", NBigDecimal }, + }; + + /// <summary> + /// Gets the Merge enumeration by value. + /// </summary> + public static N GetByValue(string value) + { + if (!Properties.TryGetValue(value, out var property)) + { + throw new ArgumentException($"No matching N for value '{value}'"); + } + return property; + } + } + + +#pragma warning restore 1591 +} \ No newline at end of file diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs index 1e1995caad..d21cba4911 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs @@ -442,6 +442,14 @@ namespace Gremlin.Net.Process.Traversal return new GraphTraversal<object, long>().DateDiff(dateTraversal); } + /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the dateAdd step to that traversal. + /// </summary> + public static GraphTraversal<object, object> AsNumber(N numberToken) + { + return new GraphTraversal<object, object>().AsNumber(numberToken); + } + /// <summary> /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the dedup step to that traversal. /// </summary> diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs index 161db1b1af..9cae6ddfe2 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs @@ -57,6 +57,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary public static readonly DataType Direction = new DataType(0x18); public static readonly DataType DT = new DataType(0x2F); public static readonly DataType Merge = new DataType(0x2E); + public static readonly DataType N = new DataType(0x30); public static readonly DataType Operator = new DataType(0x19); public static readonly DataType Order = new DataType(0x1A); public static readonly DataType Pick = new DataType(0x1B); diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs index 89a6c97e56..74e00001e0 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs @@ -64,6 +64,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary {typeof(Direction), EnumSerializers.DirectionSerializer}, {typeof(DT), EnumSerializers.DTSerializer}, {typeof(Merge), EnumSerializers.MergeSerializer}, + {typeof(N), EnumSerializers.NSerializer}, {typeof(Operator), EnumSerializers.OperatorSerializer}, {typeof(Order), EnumSerializers.OrderSerializer}, {typeof(Pick), EnumSerializers.PickSerializer}, @@ -113,6 +114,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary {DataType.Direction, EnumSerializers.DirectionSerializer}, {DataType.DT, EnumSerializers.DTSerializer}, {DataType.Merge, EnumSerializers.MergeSerializer}, + {DataType.N, EnumSerializers.NSerializer}, {DataType.Operator, EnumSerializers.OperatorSerializer}, {DataType.Order, EnumSerializers.OrderSerializer}, {DataType.Pick, EnumSerializers.PickSerializer}, diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs index a3ea2f8535..d50232c6d6 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/EnumSerializer.cs @@ -71,6 +71,12 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types public static readonly EnumSerializer<Merge> MergeSerializer = new EnumSerializer<Merge>(DataType.Merge, Merge.GetByValue); + /// <summary> + /// A serializer for <see cref="N"/> values. + /// </summary> + public static readonly EnumSerializer<N> NSerializer = + new EnumSerializer<N>(DataType.N, N.GetByValue); + /// <summary> /// A serializer for <see cref="Operator"/> values. /// </summary> diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs index 779c5594a1..52e26992a6 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs @@ -47,6 +47,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON { "g:Direction", new DirectionDeserializer() }, { "g:DT", new DTDeserializer() }, { "g:Merge", new MergeDeserializer() }, + { "g:N", new NDeserializer() }, { "g:UUID", new UuidDeserializer() }, { "g:Date", new DateDeserializer() }, { "g:Timestamp", new DateDeserializer() }, diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/NDeserializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/NDeserializer.cs new file mode 100644 index 0000000000..4e5c433495 --- /dev/null +++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/NDeserializer.cs @@ -0,0 +1,38 @@ +#region License + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#endregion + +using System.IO; +using System.Text.Json; +using Gremlin.Net.Process.Traversal; + +namespace Gremlin.Net.Structure.IO.GraphSON +{ + internal class NDeserializer : IGraphSONDeserializer + { + public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader) + { + return N.GetByValue(graphsonObject.GetString() ?? + throw new IOException($"Read null but expected a {nameof(N)} string representation")); + } + } +} \ No newline at end of file diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index c7b67628f8..3cfccca976 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -622,6 +622,7 @@ 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_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-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs index 5e2a49a166..1f172f6acc 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/GraphBinaryTests.cs @@ -565,6 +565,21 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphBinary Assert.Equal(expected, actual); } + + [Fact] + public async Task TestN() + { + var expected = N.Byte; + var writer = CreateGraphBinaryWriter(); + var reader = CreateGraphBinaryReader(); + var serializationStream = new MemoryStream(); + + await writer.WriteAsync(expected, serializationStream); + serializationStream.Position = 0; + var actual = await reader.ReadAsync(serializationStream); + + Assert.Equal(expected, actual); + } [Fact] public async Task TestOperator() diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs index 591e3b4378..e5c1d8a88a 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs @@ -336,6 +336,18 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON Assert.Equal(Merge.OnMatch, deserializedValue); } + + [Theory, MemberData(nameof(Versions))] + public void ShouldDeserializeN(int version) + { + const string serializedValue = "{\"@type\":\"g:N\",\"@value\":\"byte\"}"; + var reader = CreateStandardGraphSONReader(version); + + var jsonElement = JsonSerializer.Deserialize<JsonElement>(serializedValue); + var deserializedValue = reader.ToObject(jsonElement); + + Assert.Equal(N.Byte, deserializedValue); + } [Fact] public void ShouldDeserializePathFromGraphSON2() diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs index 98d924e2e1..34cdd8e534 100644 --- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs @@ -300,6 +300,17 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON Assert.Equal(expectedGraphSON, serializedEnum); } + [Theory, MemberData(nameof(Versions))] + public void ShouldSerializeN(int version) + { + var writer = CreateGraphSONWriter(version); + + var serializedEnum = writer.WriteObject(N.Byte); + + var expectedGraphSON = "{\"@type\":\"g:N\",\"@value\":\"byte\"}"; + Assert.Equal(expectedGraphSON, serializedEnum); + } + [Theory, MemberData(nameof(Versions))] public void ShouldSerializeList(int version) { diff --git a/gremlin-go/driver/anonymousTraversal.go b/gremlin-go/driver/anonymousTraversal.go index a1b3a3f0b1..6cf32581bb 100644 --- a/gremlin-go/driver/anonymousTraversal.go +++ b/gremlin-go/driver/anonymousTraversal.go @@ -386,6 +386,11 @@ func (anonymousTraversal *anonymousTraversal) AsDate(args ...interface{}) *Graph return anonymousTraversal.graphTraversal().AsDate(args...) } +// AsDate adds the AsNumber step to the GraphTraversal. +func (anonymousTraversal *anonymousTraversal) AsNumber(args ...interface{}) *GraphTraversal { + return anonymousTraversal.graphTraversal().AsNumber(args...) +} + // AsString adds the asString step to the GraphTraversal. func (anonymousTraversal *anonymousTraversal) AsString(args ...interface{}) *GraphTraversal { return anonymousTraversal.graphTraversal().AsString(args...) diff --git a/gremlin-go/driver/graphBinary.go b/gremlin-go/driver/graphBinary.go index 22de276a02..f89595c821 100644 --- a/gremlin-go/driver/graphBinary.go +++ b/gremlin-go/driver/graphBinary.go @@ -82,6 +82,7 @@ const ( bulkSetType dataType = 0x2a mergeType dataType = 0x2e dtType dataType = 0x2f + nType dataType = 0x30 metricsType dataType = 0x2c traversalMetricsType dataType = 0x2d durationType dataType = 0x81 @@ -748,6 +749,8 @@ func (serializer *graphBinaryTypeSerializer) getType(val interface{}) (dataType, return mergeType, nil case dt: return dtType, nil + case n: + return nType, nil case p, Predicate: return pType, nil case textP, TextPredicate: diff --git a/gremlin-go/driver/graphTraversal.go b/gremlin-go/driver/graphTraversal.go index c3f7fca266..b6b165f22d 100644 --- a/gremlin-go/driver/graphTraversal.go +++ b/gremlin-go/driver/graphTraversal.go @@ -112,6 +112,12 @@ func (g *GraphTraversal) AsDate(args ...interface{}) *GraphTraversal { return g } +// AsNumber adds the asNumber step to the GraphTraversal. +func (g *GraphTraversal) AsNumber(args ...interface{}) *GraphTraversal { + g.Bytecode.AddStep("asNumber", args...) + return g +} + // AsString adds the asString step to the GraphTraversal. func (g *GraphTraversal) AsString(args ...interface{}) *GraphTraversal { g.Bytecode.AddStep("asString", args...) diff --git a/gremlin-go/driver/serializer.go b/gremlin-go/driver/serializer.go index b7aa4a9750..8a2dec9d56 100644 --- a/gremlin-go/driver/serializer.go +++ b/gremlin-go/driver/serializer.go @@ -270,6 +270,7 @@ func initSerializers() { columnType: enumWriter, directionType: enumWriter, dtType: enumWriter, + nType: enumWriter, operatorType: enumWriter, orderType: enumWriter, pickType: enumWriter, @@ -327,6 +328,7 @@ func initDeserializers() { tType: enumReader, directionType: enumReader, dtType: enumReader, + nType: enumReader, bindingType: bindingReader, // Metrics diff --git a/gremlin-go/driver/traversal.go b/gremlin-go/driver/traversal.go index 6d82f6d0af..96cf361c07 100644 --- a/gremlin-go/driver/traversal.go +++ b/gremlin-go/driver/traversal.go @@ -359,6 +359,40 @@ var Merge = merges{ InV: "inV", } + +type n string + +type ns struct { + // number type byte + NByte n + // number type short + NShort n + // number type int + NInt n + // number type long + NLong n + // number type float + NFloat n + // number type double + NDouble n + // number type bigInt + NBigInt n + // number type bigDecimal + NBigDecimal n +} + +// Merge is a set of operations for Vertex and Edge merging. +var N = ns{ + NByte: "nbyte", + NShort: "nshort", + NInt: "nint", + NLong: "nlong", + NFloat: "nfloat", + NDouble: "ndouble", + NBigInt: "nbigInt", + NBigDecimal: "nbigDecimal", +} + type operator string type operators struct { diff --git a/gremlin-javascript/build/generate.groovy b/gremlin-javascript/build/generate.groovy index 9d04bc3e1b..7cf85b5c5d 100644 --- a/gremlin-javascript/build/generate.groovy +++ b/gremlin-javascript/build/generate.groovy @@ -82,6 +82,7 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer -> 'const IO = traversalModule.IO;\n' + 'const DT = traversalModule.dt;\n' + 'const Merge = traversalModule.merge;\n' + + 'const N = traversalModule.n;\n' + 'const P = traversalModule.P;\n' + 'const Pick = traversalModule.pick\n' + 'const Pop = traversalModule.pop\n' + diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js index b2a831b038..087a6c0a07 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js @@ -443,6 +443,16 @@ class GraphTraversal extends Traversal { return this; } + /** + * Graph traversal asNumber method. + * @param {...Object} args + * @returns {GraphTraversal} + */ + asNumber(...args) { + this.bytecode.addStep('asNumber', args); + return this; + } + /** * Graph traversal asString method. * @param {...Object} args diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js index a1ff9316dd..84c8482f8f 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js @@ -512,6 +512,7 @@ module.exports = { column: toEnum('Column', 'keys values'), direction: toDirectionEnum('Direction', 'BOTH IN OUT from_ to'), dt: toEnum('DT', 'second minute hour day'), + n: toEnum('N', 'nbyte nshort nint nlong nfloat ndouble nbigint nbigdecimal'), graphSONVersion: toEnum('GraphSONVersion', 'V1_0 V2_0 V3_0'), gryoVersion: toEnum('GryoVersion', 'V1_0 V3_0'), merge: toEnum('Merge', 'onCreate onMatch outV inV'), diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/DataType.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/DataType.js index 272a848d87..ee12739a10 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/DataType.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/DataType.js @@ -75,6 +75,7 @@ const DataType = { TRAVERSALMETRICS: 0x2d, MERGE: 0x2e, DT: 0x2f, + N: 0x30, CHAR: 0x80, DURATION: 0x81, diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/EnumSerializer.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/EnumSerializer.js index 03627772da..bb11c65cf8 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/EnumSerializer.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/EnumSerializer.js @@ -44,6 +44,7 @@ module.exports = class EnumSerializer { { name: 'Direction', code: DT.DIRECTION, enum: to_orig_enum(t.direction) }, { name: 'DT', code: DT.DT, enum: to_orig_enum(t.dt) }, { name: 'Merge', code: DT.MERGE, enum: to_orig_enum(t.merge) }, + { name: 'N', code: DT.N, enum: to_orig_enum(t.n) }, { name: 'Operator', code: DT.OPERATOR, enum: to_orig_enum(t.operator) }, { name: 'Order', code: DT.ORDER, enum: to_orig_enum(t.order) }, { name: 'Pick', code: DT.PICK, enum: to_orig_enum(t.pick) }, 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 e1a496e846..2dc4eb664f 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 @@ -52,6 +52,7 @@ const Direction = { const IO = traversalModule.IO; const DT = traversalModule.dt; const Merge = traversalModule.merge; +const N = traversalModule.n; const P = traversalModule.P; const Pick = traversalModule.pick const Pop = traversalModule.pop @@ -622,6 +623,26 @@ 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_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) }, 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_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_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-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index 0f22d6ec59..4f089e9cfd 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -307,6 +307,7 @@ traversalMethod | traversalMethod_asDate | traversalMethod_dateAdd | traversalMethod_dateDiff + | traversalMethod_asNumber ; traversalMethod_V @@ -353,6 +354,11 @@ traversalMethod_asDate : K_ASDATE LPAREN RPAREN ; + traversalMethod_asNumber + : K_ASNUMBER LPAREN RPAREN #traversalMethod_asNumber_Empty + | K_ASNUMBER LPAREN traversalN RPAREN #traversalMethod_asNumber_traversalN + ; + traversalMethod_asString : K_ASSTRING LPAREN RPAREN #traversalMethod_asString_Empty | K_ASSTRING LPAREN traversalScope RPAREN #traversalMethod_asString_Scope @@ -1071,6 +1077,17 @@ traversalDT | K_DAY | K_DT DOT K_DAY ; +traversalN + : K_BYTE | K_N DOT K_BYTE + | K_SHORT | K_N DOT K_SHORT + | K_INT | K_N DOT K_INT + | K_LONG | K_N DOT K_LONG + | K_FLOAT | K_N DOT K_FLOAT + | K_DOUBLE | K_N DOT K_DOUBLE + | K_BIGINT | K_N DOT K_BIGINT + | K_BIGDECIMAL | K_N DOT K_BIGDECIMAL + ; + traversalPredicate : traversalPredicate_eq | traversalPredicate_neq @@ -1569,6 +1586,7 @@ genericLiteral | traversalMerge | traversalPick | traversalDT + | traversalN | structureVertexLiteral | genericSetLiteral | genericCollectionLiteral @@ -1683,18 +1701,22 @@ keyword | K_AS | K_ASC | K_ASDATE + | K_ASNUMBER | K_ASSTRING | K_ASSIGN | K_BARRIER | K_BARRIERU | K_BEGIN | K_BETWEEN + | K_BIGINT + | K_BIGDECIMAL | K_BOTH | K_BOTHU | K_BOTHE | K_BOTHV | K_BRANCH | K_BY + | K_BYTE | K_CALL | K_CAP | K_CARDINALITY @@ -1726,6 +1748,7 @@ keyword | K_DISJUNCT | K_DISTANCE | K_DIV + | K_DOUBLE | K_DROP | K_DT | K_E @@ -1741,6 +1764,7 @@ keyword | K_FILTER | K_FIRST | K_FLATMAP + | K_FLOAT | K_FOLD | K_FORMAT | K_FROM @@ -1773,6 +1797,7 @@ keyword | K_INFINITY | K_INJECT | K_INSIDE + | K_INT | K_INTERSECT | K_INV | K_IO @@ -1788,6 +1813,7 @@ keyword | K_LIMIT | K_LIST | K_LOCAL + | K_LONG | K_LOOPS | K_LT | K_LTE @@ -1807,6 +1833,7 @@ keyword | K_MINUS | K_MIXED | K_MULT + | K_N | K_NAN | K_NEGATE | K_NEW @@ -1865,6 +1892,7 @@ keyword | K_SECOND | K_SELECT | K_SET + | K_SHORT | K_SHORTESTPATH | K_SHORTESTPATHU | K_SHUFFLE @@ -1944,18 +1972,22 @@ K_ANY: 'any'; K_AS: 'as'; K_ASC: 'asc'; K_ASDATE: 'asDate'; +K_ASNUMBER: 'asNumber'; K_ASSTRING: 'asString'; K_ASSIGN: 'assign'; K_BARRIER: 'barrier'; K_BARRIERU: 'Barrier'; K_BEGIN: 'begin'; K_BETWEEN: 'between'; +K_BIGDECIMAL: 'nbigDecimal'; +K_BIGINT: 'nbigInt'; K_BOTH: 'both'; K_BOTHU: 'BOTH'; K_BOTHE: 'bothE'; K_BOTHV: 'bothV'; K_BRANCH: 'branch'; K_BY: 'by'; +K_BYTE: 'nbyte'; K_CALL: 'call'; K_CAP: 'cap'; K_CARDINALITY: 'Cardinality'; @@ -1987,6 +2019,7 @@ K_DIRECTION: 'Direction'; K_DISJUNCT: 'disjunct'; K_DISTANCE: 'distance'; K_DIV: 'div'; +K_DOUBLE: 'ndouble'; K_DROP: 'drop'; K_DT: 'DT'; K_E: 'E'; @@ -2002,6 +2035,7 @@ K_FALSE: 'false'; K_FILTER: 'filter'; K_FIRST: 'first'; K_FLATMAP: 'flatMap'; +K_FLOAT: 'nfloat'; K_FOLD: 'fold'; K_FORMAT: 'format'; K_FROM: 'from'; @@ -2034,6 +2068,7 @@ K_INDEX: 'index'; K_INFINITY: 'Infinity'; K_INJECT: 'inject'; K_INSIDE: 'inside'; +K_INT: 'nint'; K_INTERSECT: 'intersect'; K_INV: 'inV'; K_IOU: 'IO'; @@ -2049,6 +2084,7 @@ K_LENGTH: 'length'; K_LIMIT: 'limit'; K_LIST: 'list'; K_LOCAL: 'local'; +K_LONG: 'nlong'; K_LOOPS: 'loops'; K_LT: 'lt'; K_LTE: 'lte'; @@ -2068,6 +2104,7 @@ K_MINUTE: 'minute'; K_MINUS: 'minus'; K_MIXED: 'mixed'; K_MULT: 'mult'; +K_N: 'N'; K_NAN: 'NaN'; K_NEGATE: 'negate'; K_NEXT: 'next'; @@ -2129,6 +2166,7 @@ K_SET: 'set'; K_SHORTESTPATHU: 'ShortestPath'; K_SHORTESTPATH: 'shortestPath'; K_SHUFFLE: 'shuffle'; +K_SHORT: 'nshort'; K_SIDEEFFECT: 'sideEffect'; K_SIMPLEPATH: 'simplePath'; K_SINGLE: 'single'; 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 new file mode 100644 index 0000000000..7fef5997f1 --- /dev/null +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature @@ -0,0 +1,275 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +@StepClassMap @StepAsNumber +Feature: Step - asNumber() + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5bX_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject(5b).asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5sX_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject(5s).asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].s | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5iX_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject(5i).asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].i | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5lX_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject(5l).asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].l | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5nX_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject(5n).asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].n | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5_0X_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject(5.0).asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].d | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5_75fX_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject(5.75f).asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5.75].d | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5_43X_asNumberXN_nintX + Given the empty graph + And the traversal of + """ + g.inject(5.43).asNumber(N.nint) + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].i | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5_67X_asNumberXN_nintX + Given the empty graph + And the traversal of + """ + g.inject(5.67).asNumber(N.nint) + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].i | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5X_asNumberXN_nlongX + Given the empty graph + And the traversal of + """ + g.inject(5).asNumber(N.nlong) + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].l | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX12X_asNumberXN_nbyteX + Given the empty graph + And the traversal of + """ + g.inject(12).asNumber(N.nbyte) + """ + When iterated to list + Then the result should be unordered + | result | + | d[12].b | + + @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." + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX300X_asNumberXN_nbyteX + Given the empty graph + And the traversal of + """ + 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." + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5X_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject("5").asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX5X_asNumberXN_nintX + Given the empty graph + And the traversal of + """ + g.inject("5").asNumber(N.nint) + """ + When iterated to list + Then the result should be unordered + | result | + | d[5].i | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX1_000X_asNumberXN_nintX + Given the empty graph + And the traversal of + """ + 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." + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectXtestX_asNumberXX + Given the empty graph + And the traversal of + """ + 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'" + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX_1__2__3__4_X_asNumberXX + Given the empty graph + And the traversal of + """ + 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." + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX_1__2__3__4_X_unfoldXX_asNumberXX + Given the empty graph + And the traversal of + """ + g.inject([1, 2, 3, 4]).unfold().asNumber() + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[2].i | + | d[3].i | + | d[4].i | + + @GraphComputerVerificationInjectionNotSupported + Scenario: g_injectX_1__2__3__4_X_unfoldXX_asNumberXX_foldXX + Given the empty graph + And the traversal of + """ + g.inject([1, 2, 3, 4]).unfold().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_VX1X_asNumberXN_nintX + Given the empty graph + And the traversal of + """ + g.V(1).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
