This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch TINKERPOP-2524 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit c2b4f2fc0a02e0022602978faf21bea205e56460 Author: Stephen Mallette <[email protected]> AuthorDate: Fri Nov 5 09:57:00 2021 -0400 TINKERPOP-2524 Supported more explicit numeric literals in grammar Added byte, short, BigInteger, BigDecimal which basically just follows the pattern Java/Groovy have with a character suffix. While these literals have some specific use for Gremlin users they also have importance to the gherkin test suite where validating numeric semantics required a wider range of numeric types in the test definitions. --- CHANGELOG.asciidoc | 1 + docs/src/dev/developer/for-committers.asciidoc | 9 +- .../language/grammar/GenericLiteralVisitor.java | 40 ++++-- .../grammar/GeneralLiteralVisitorTest.java | 133 +++++++++--------- .../Gherkin/CommonSteps.cs | 8 +- .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 7 + .../test/cucumber/feature-steps.js | 2 +- .../gremlin-javascript/test/cucumber/gremlin.js | 7 + gremlin-language/src/main/antlr4/Gremlin.g4 | 4 +- .../src/main/python/radish/feature_steps.py | 2 +- gremlin-python/src/main/python/radish/gremlin.py | 7 + .../server/handler/SaslAuthenticationHandler.java | 3 +- gremlin-test/features/semantics/Equality.feature | 156 ++++++++++++++++++++- .../tinkerpop/gremlin/features/StepDefinition.java | 11 +- 14 files changed, 291 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index af06a51..f2c6522 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -31,6 +31,7 @@ limitations under the License. * Removed `groovy` and `groovy-json` dependencies from `gremlin-driver` as well as related `JsonBuilder` serialization support. * Replaced log4j usage with logback where builds rely on and packaged distributions now contain the latter. * Prevented metrics computation unless the traversal is in a locked state. +* Added syntax to Gremlin grammar to explicitly define `byte`, `short` and `BigInteger`. * Created a way to produce a corpus of Gremlin traversals via `FeatureReader` and `DocumentationReader` in `gremlin-language`. * Exposed Gherkin tests as part of the provider test suite. * Packaged Gherkin tests and data as standalone package as a convenience distribution. diff --git a/docs/src/dev/developer/for-committers.asciidoc b/docs/src/dev/developer/for-committers.asciidoc index 33465ee..c3c3453 100644 --- a/docs/src/dev/developer/for-committers.asciidoc +++ b/docs/src/dev/developer/for-committers.asciidoc @@ -357,11 +357,14 @@ they are required for the test. the type notation system so that it is possible to have maps containing arbitrary keys and values. * Numeric - *d[_xxx_]._y_* - The "xxx" should be replaced with a number. The suffix denoted by "y" should always be included to further qualify the type of numeric. The following options are available: -** *d* - 32-bit Double -** *f* - 32-bit Float +** *b* - 8-bit byte +** *s* - 16-bit Short ** *i* - 32-bit Integer +** *f* - 32-bit Float ** *l* - 64-bit Long -** *m* - Arbitrary-precision signed decimal numbers (i.e. BigDecimal in Java) +** *d* - 64-bit Double +** *m* - Arbitrary-precision signed decimal numbers (e.g. `BigDecimal` in Java) +** *n* - Arbitrary-precision integers (e.g. `BigInteger` in Java) * Path - *p[_xxx_,_yyy_,_zzz_,...]* - A comma separated collection of values that make up the `Path` should be added to between the square brackets. These values respect the type system thus allowing for creation of `Path` of vertices, edges, maps, and any other available type. diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java index 1529392..1d93387 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java @@ -308,12 +308,25 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> { @Override public Object visitIntegerLiteral(final GremlinParser.IntegerLiteralContext ctx) { String integerLiteral = ctx.getText().toLowerCase().replace("_", ""); - // handle suffix: L/l + // handle suffixes for specific types final int lastCharIndex = integerLiteral.length() - 1; - if (integerLiteral.charAt(lastCharIndex) == 'l') { - integerLiteral = integerLiteral.substring(0, lastCharIndex); - - return Long.decode(integerLiteral); + final char suffix = integerLiteral.charAt(lastCharIndex); + switch (suffix) { + case 'b': + integerLiteral = integerLiteral.substring(0, lastCharIndex); + return Byte.decode(integerLiteral); + case 's': + integerLiteral = integerLiteral.substring(0, lastCharIndex); + return Short.decode(integerLiteral); + case 'i': + integerLiteral = integerLiteral.substring(0, lastCharIndex); + return Integer.decode(integerLiteral); + case 'l': + integerLiteral = integerLiteral.substring(0, lastCharIndex); + return Long.decode(integerLiteral); + case 'n': + integerLiteral = integerLiteral.substring(0, lastCharIndex); + return new BigInteger(integerLiteral); } try { @@ -363,18 +376,19 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> { final String floatLiteral = ctx.getText().toLowerCase(); // check suffix - final char lastCharacter = floatLiteral.charAt(floatLiteral.length() - 1); - if (Character.isDigit(lastCharacter)) { - // if there is no suffix, parse it as BigDecimal - return new BigDecimal(floatLiteral); - } - - if (lastCharacter == 'f') { + final int lastCharIndex = floatLiteral.length() - 1; + final char lastCharacter = floatLiteral.charAt(lastCharIndex); + if (lastCharacter == 'm') { + // parse M/m or whatever which could be a parse exception + return new BigDecimal(floatLiteral.substring(0, lastCharIndex)); + } else if (lastCharacter == 'f') { // parse F/f suffix as Float return new Float(ctx.getText()); - } else { + } else if (lastCharacter == 'd'){ // parse D/d suffix as Double return new Double(floatLiteral); + } else { + return new BigDecimal(floatLiteral); } } diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java index c8a350e..7791a08 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java @@ -292,44 +292,54 @@ public class GeneralLiteralVisitorTest { public String script; @Parameterized.Parameter(value = 1) - public String expected; + public Object expected; @Parameterized.Parameters(name = "{0}") public static Iterable<Object[]> generateTestParameters() { return Arrays.asList(new Object[][]{ // decimal format - {"1", "1"}, - {"-11", "-11"}, - {"0", "0"}, - {"1L", "1L"}, - {"-1l", "-1l"}, - {"1_2_3", "123"}, - {"-1_2_3L", "-123L"}, - {"9223372036854775807", "9223372036854775807"}, - {"-9223372036854775808", "-9223372036854775808"}, - {"9223372036854775807L", "9223372036854775807"}, - {"-9223372036854775808l", "-9223372036854775808"}, + {"1", 1}, + {"-11", -11}, + {"0", 0}, + {"1B", (byte) 1}, + {"-1b", (byte) -1}, + {"1S", (short) 1}, + {"-1s", (short) -1}, + {"1I", 1}, + {"-1i", -1}, + {"1L", 1L}, + {"-1l", -1L}, + {"1_2_3", 123}, + {"-1_2_3L", -123L}, + {"1N", new BigInteger("1")}, + {"-1n", new BigInteger("-1")}, + {"9223372036854775807", 9223372036854775807L}, + {"-9223372036854775808", -9223372036854775808L}, + {"9223372036854775807L", 9223372036854775807L}, + {"-9223372036854775808l", -9223372036854775808L}, + {"9999999999999999999999999999999999999999999999999N", new BigInteger("9999999999999999999999999999999999999999999999999")}, + {"9999999999999999999999999999999999999999999999999n", new BigInteger("9999999999999999999999999999999999999999999999999")}, // hex format - {"0xA", "10"}, - {"-0xA", "-10"}, - {"0xaL", "10l"}, - {"-0xal", "-10l"}, - {"-0xA_0L", "-160l"}, - {"0x10", "16"}, - {"-0x10", "-16"}, - {"0x10", "16"}, - {"-0x10l", "-16l"}, - {"-0x1_0L", "-16l"}, + {"0xA", 10}, + {"-0xA", -10}, + {"0xaL", 10L}, + {"-0xal", -10L}, + {"-0xA_0L", -160L}, + {"0x10", 16}, + {"-0x10", -16}, + {"0x10", 16}, + {"-0x10l", -16L}, + {"-0x1_0L", -16L}, // oct format - {"01", "1"}, - {"-01", "-1"}, - {"01L", "1l"}, - {"-01l", "-1l"}, - {"010", "8"}, - {"-010", "-8"}, - {"010L", "8l"}, - {"-010l", "-8l"}, - {"-01_0L", "-8l"}, + {"01", 1}, + {"-01", -1}, + {"01L", 1L}, + {"-01l", -1L}, + {"010", 8}, + {"-010", -8}, + {"010L", 8L}, + {"-010l", -8L}, + {"-01_0L", -8L}, }); } @@ -340,19 +350,7 @@ public class GeneralLiteralVisitorTest { final GremlinParser.IntegerLiteralContext ctx = parser.integerLiteral(); final Object actualValue = GenericLiteralVisitor.getInstance().visitIntegerLiteral(ctx); - - // verify suffix L/l - if (expected.toUpperCase().charAt(expected.length() - 1) == 'L') { - assertEquals(Long.valueOf(expected.substring(0, expected.length() - 1)), actualValue); - return; - } - - // based on value range verify the value is parsed in correct type - try { - assertEquals(Integer.valueOf(expected), actualValue); - } catch (NumberFormatException ignoredException) { - assertEquals(Long.valueOf(expected), actualValue); - } + assertEquals(expected, actualValue); } } @@ -398,34 +396,33 @@ public class GeneralLiteralVisitorTest { public String script; @Parameterized.Parameter(value = 1) - public String expected; - - @Parameterized.Parameter(value = 2) - public String type; + public Object expected; @Parameterized.Parameters() public static Iterable<Object[]> generateTestParameters() { return Arrays.asList(new Object[][]{ - {"1.1", "1.1", "java.math.BigDecimal"}, - {"-0.1", "-0.1", "java.math.BigDecimal"}, - {"1.0E+12", "1.0E12", "java.math.BigDecimal"}, - {"-0.1E-12", "-0.1E-12", "java.math.BigDecimal"}, - {"1E12", "1E12", "java.math.BigDecimal"}, + {"1.1m", new BigDecimal("1.1")}, + {"1.1M", new BigDecimal("1.1")}, + {"1.1", new BigDecimal("1.1")}, + {"-0.1", new BigDecimal("-0.1")}, + {"1.0E+12", new BigDecimal("1.0E12")}, + {"-0.1E-12", new BigDecimal("-0.1E-12")}, + {"1E12", new BigDecimal("1E12")}, // float - {"1.1f", "1.1", "java.lang.Float"}, - {"-0.1F", "-0.1", "java.lang.Float"}, - {"1.0E+12f", "1.0E12", "java.lang.Float"}, - {"-0.1E-12F", "-0.1E-12", "java.lang.Float"}, - {"1E12f", "1E12", "java.lang.Float"}, - {"1F", "1", "java.lang.Float"}, + {"1.1f", 1.1F}, + {"-0.1F", -0.1F}, + {"1.0E+12f", 1.0E12F}, + {"-0.1E-12F", -0.1E-12F}, + {"1E12f", 1E12F}, + {"1F", 1F}, // double - {"1.1d", "1.1", "java.lang.Double"}, - {"-0.1D", "-0.1", "java.lang.Double"}, - {"1.0E+12d", "1.0E12", "java.lang.Double"}, - {"-0.1E-12D", "-0.1E-12", "java.lang.Double"}, - {"1E12d", "1E12", "java.lang.Double"}, - {"1D", "1", "java.lang.Double"} + {"1.1d", 1.1D}, + {"-0.1D", -0.1D}, + {"1.0E+12d", 1.0E12D}, + {"-0.1E-12D", -0.1E-12D}, + {"1E12d", 1E12D}, + {"1D", 1D} }); } @@ -435,11 +432,7 @@ public class GeneralLiteralVisitorTest { final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer)); final GremlinParser.FloatLiteralContext ctx = parser.floatLiteral(); - final Class<?> clazz = Class.forName(type); - final Constructor<?> ctor = clazz.getConstructor(String.class); - final Object expectedValue = ctor.newInstance(expected); - - assertEquals(expectedValue, GenericLiteralVisitor.getInstance().visitFloatLiteral(ctx)); + assertEquals(expected, GenericLiteralVisitor.getInstance().visitFloatLiteral(ctx)); } } diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs index a2941eb..11e71c8 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs @@ -26,6 +26,7 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Numerics; using System.Text.Json; using System.Text.RegularExpressions; using Gherkin.Ast; @@ -54,7 +55,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private static readonly IDictionary<Regex, Func<string, string, object>> Parsers = new Dictionary<string, Func<string, string, object>> { - {@"d\[(.*)\]\.([ilfdm])", ToNumber}, + {@"d\[(.*)\]\.([bsilfdmn])", ToNumber}, {@"D\[(.+)\]", ToDirection}, {@"v\[(.+)\]", ToVertex}, {@"v\[(.+)\]\.id", (x, graphName) => ToVertex(x, graphName).Id}, @@ -74,11 +75,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin private static readonly IDictionary<char, Func<string, object>> NumericParsers = new Dictionary<char, Func<string, object>> { + { 'b', s => Convert.ToByte(s) }, + { 's', s => Convert.ToInt16(s) }, { 'i', s => Convert.ToInt32(s) }, { 'l', s => Convert.ToInt64(s) }, { 'f', s => Convert.ToSingle(s, CultureInfo.InvariantCulture) }, { 'd', s => Convert.ToDouble(s, CultureInfo.InvariantCulture) }, - { 'm', s => Convert.ToDecimal(s, CultureInfo.InvariantCulture) } + { 'm', s => Convert.ToDecimal(s, CultureInfo.InvariantCulture) }, + { 'n', s => BigInteger.Parse(s) } }; [Given("the (\\w+) graph")] diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs index 2c8d242..bb8565b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs @@ -686,7 +686,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin {"g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").V().HasLabel("software").Values<object>("name")}}, {"g_V_hasLabelXloopsX_bothEXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").BothE("self")}}, {"g_V_hasLabelXloopsX_bothXselfX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("loops").Both("self")}}, + {"Primitives_Number_eqXbyteX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, + {"Primitives_Number_eqXshortX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, {"Primitives_Number_eqXintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, + {"Primitives_Number_eqXlongX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, + {"Primitives_Number_eqXbigintX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, + {"Primitives_Number_eqXfloatX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, + {"Primitives_Number_eqXdoubleX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, + {"Primitives_Number_eqXbigdecimalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(p["xx1"]).Unfold<object>().Where(__.Is(p["xx2"]))}}, {"g_V_valueXnameX_aggregateXxX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate("x").Cap<object>("x")}}, {"g_V_valueXnameX_aggregateXglobal_xX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Aggregate(Scope.Global,"x").Cap<object>("x")}}, {"g_V_aggregateXxX_byXnameX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Aggregate("x").By("name").Cap<object>("x")}}, diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js index 7a9c8ee..e9d39cf 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js @@ -42,7 +42,7 @@ const direction = traversalModule.direction; const mapAsObject = false; const parsers = [ - [ 'd\\[(.*)\\]\\.[ilfdm]', toNumeric ], + [ 'd\\[(.*)\\]\\.[bsilfdmn]', toNumeric ], [ 'v\\[(.+)\\]', toVertex ], [ 'v\\[(.+)\\]\\.id', toVertexId ], [ 'v\\[(.+)\\]\\.sid', toVertexIdString ], 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 8507405..a780192 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 @@ -675,7 +675,14 @@ const gremlins = { g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name: [function({g}) { return g.V().hasLabel("person").V().hasLabel("software").values("name") }], g_V_hasLabelXloopsX_bothEXselfX: [function({g}) { return g.V().hasLabel("loops").bothE("self") }], g_V_hasLabelXloopsX_bothXselfX: [function({g}) { return g.V().hasLabel("loops").both("self") }], + Primitives_Number_eqXbyteX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], + Primitives_Number_eqXshortX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], Primitives_Number_eqXintX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], + Primitives_Number_eqXlongX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], + Primitives_Number_eqXbigintX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], + Primitives_Number_eqXfloatX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], + Primitives_Number_eqXdoubleX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], + Primitives_Number_eqXbigdecimalX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], g_V_valueXnameX_aggregateXxX_capXxX: [function({g}) { return g.V().values("name").aggregate("x").cap("x") }], g_V_valueXnameX_aggregateXglobal_xX_capXxX: [function({g}) { return g.V().values("name").aggregate(Scope.global,"x").cap("x") }], g_V_aggregateXxX_byXnameX_capXxX: [function({g}) { return g.V().aggregate("x").by("name").cap("x") }], diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4 index 0844d67..e277baa 100644 --- a/gremlin-language/src/main/antlr4/Gremlin.g4 +++ b/gremlin-language/src/main/antlr4/Gremlin.g4 @@ -1362,7 +1362,7 @@ OctalIntegerLiteral fragment IntegerTypeSuffix - : [lL] + : [bBsSnNiIlL] ; fragment @@ -1489,7 +1489,7 @@ Sign fragment FloatTypeSuffix - : [fFdD] + : [fFdDmM] ; // Boolean Literals diff --git a/gremlin-python/src/main/python/radish/feature_steps.py b/gremlin-python/src/main/python/radish/feature_steps.py index eb225bd..9fd8cf6 100644 --- a/gremlin-python/src/main/python/radish/feature_steps.py +++ b/gremlin-python/src/main/python/radish/feature_steps.py @@ -162,7 +162,7 @@ def _convert(val, ctx): return [] if val == "l[]" else list(map((lambda x: _convert(x, ctx)), val[2:-1].split(","))) elif isinstance(val, str) and re.match(r"^s\[.*\]$", val): # parse set return set() if val == "s[]" else set(map((lambda x: _convert(x, ctx)), val[2:-1].split(","))) - elif isinstance(val, str) and re.match(r"^d\[.*\]\.[ilfdm]$", val): # parse numeric + elif isinstance(val, str) and re.match(r"^d\[.*\]\.[bsilfdmn]$", val): # parse numeric return float(val[2:-3]) if val[2:-3].__contains__(".") else long(val[2:-3]) elif isinstance(val, str) and re.match(r"^v\[.*\]\.id$", val): # parse vertex id return __find_cached_element(ctx, graph_name, val[2:-4], "v").id diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py index 5f9535a..0aa4c93 100644 --- a/gremlin-python/src/main/python/radish/gremlin.py +++ b/gremlin-python/src/main/python/radish/gremlin.py @@ -660,7 +660,14 @@ world.gremlins = { 'g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name': [(lambda g:g.V().hasLabel('person').V().hasLabel('software').name)], 'g_V_hasLabelXloopsX_bothEXselfX': [(lambda g:g.V().hasLabel('loops').bothE('self'))], 'g_V_hasLabelXloopsX_bothXselfX': [(lambda g:g.V().hasLabel('loops').both('self'))], + 'Primitives_Number_eqXbyteX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], + 'Primitives_Number_eqXshortX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], 'Primitives_Number_eqXintX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], + 'Primitives_Number_eqXlongX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], + 'Primitives_Number_eqXbigintX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], + 'Primitives_Number_eqXfloatX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], + 'Primitives_Number_eqXdoubleX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], + 'Primitives_Number_eqXbigdecimalX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).unfold().where(__.is_(xx2)))], 'g_V_valueXnameX_aggregateXxX_capXxX': [(lambda g:g.V().name.aggregate('x').cap('x'))], 'g_V_valueXnameX_aggregateXglobal_xX_capXxX': [(lambda g:g.V().name.aggregate(Scope.global_,'x').cap('x'))], 'g_V_aggregateXxX_byXnameX_capXxX': [(lambda g:g.V().aggregate('x').by('name').cap('x'))], diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java index 2adc97f..848be27 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java @@ -156,8 +156,7 @@ public class SaslAuthenticationHandler extends AbstractAuthenticationHandler { ctx.writeAndFlush(error); } } - } - else { + } else { logger.warn("{} only processes RequestMessage instances - received {} - channel closing", this.getClass().getSimpleName(), msg.getClass()); ctx.close(); diff --git a/gremlin-test/features/semantics/Equality.feature b/gremlin-test/features/semantics/Equality.feature index cb57121..58a1439 100644 --- a/gremlin-test/features/semantics/Equality.feature +++ b/gremlin-test/features/semantics/Equality.feature @@ -18,11 +18,52 @@ @StepClassSemantics Feature: Equality - # TODO: TINKERPOP-2524 to support all the number types (and others required for semantics checks) + @GraphComputerVerificationInjectionNotSupported + Scenario: Primitives_Number_eqXbyteX + Given the empty graph + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" + And using the parameter xx2 defined as "d[1].b" + And the traversal of + """ + g.inject(xx1).unfold().where(__.is(xx2)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[1].l | + | d[1].f | + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: Primitives_Number_eqXshortX + Given the empty graph + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" + And using the parameter xx2 defined as "d[1].s" + And the traversal of + """ + g.inject(xx1).unfold().where(__.is(xx2)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[1].l | + | d[1].f | + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | + @GraphComputerVerificationInjectionNotSupported Scenario: Primitives_Number_eqXintX Given the empty graph - And using the parameter xx1 defined as "l[d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i]" + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" And using the parameter xx2 defined as "d[1].i" And the traversal of """ @@ -34,4 +75,113 @@ Feature: Equality | d[1].i | | d[1].l | | d[1].f | - | d[1].d | \ No newline at end of file + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: Primitives_Number_eqXlongX + Given the empty graph + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" + And using the parameter xx2 defined as "d[1].l" + And the traversal of + """ + g.inject(xx1).unfold().where(__.is(xx2)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[1].l | + | d[1].f | + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: Primitives_Number_eqXbigintX + Given the empty graph + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" + And using the parameter xx2 defined as "d[1].n" + And the traversal of + """ + g.inject(xx1).unfold().where(__.is(xx2)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[1].l | + | d[1].f | + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: Primitives_Number_eqXfloatX + Given the empty graph + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" + And using the parameter xx2 defined as "d[1].f" + And the traversal of + """ + g.inject(xx1).unfold().where(__.is(xx2)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[1].l | + | d[1].f | + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: Primitives_Number_eqXdoubleX + Given the empty graph + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" + And using the parameter xx2 defined as "d[1].d" + And the traversal of + """ + g.inject(xx1).unfold().where(__.is(xx2)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[1].l | + | d[1].f | + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | + + @GraphComputerVerificationInjectionNotSupported + Scenario: Primitives_Number_eqXbigdecimalX + Given the empty graph + And using the parameter xx1 defined as "l[d[1].b,d[1].s,d[1].i,d[1].l,d[1].f,d[1].d,d[1000].i,d[1].m,d[1].n]" + And using the parameter xx2 defined as "d[1].m" + And the traversal of + """ + g.inject(xx1).unfold().where(__.is(xx2)) + """ + When iterated to list + Then the result should be unordered + | result | + | d[1].i | + | d[1].l | + | d[1].f | + | d[1].d | + | d[1].s | + | d[1].n | + | d[1].m | + | d[1].b | \ No newline at end of file diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java index 410858c..6b644a0 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java @@ -56,6 +56,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -93,11 +94,14 @@ public final class StepDefinition { final String listItems = Stream.of(items).map(String::trim).map(x -> convertToString(x)).collect(Collectors.joining(",")); return String.format("[%s]", listItems); })); - add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.i"), s -> s)); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.b"), s -> s + "b")); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.s"), s -> s + "s")); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.i"), s -> s + "i")); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.l"), s -> s + "l")); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.f"), s -> s + "f")); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.d"), s -> s + "d")); - add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.m"), s -> String.format("new BigDecimal(%s)", s))); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.m"), s -> s + "m")); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.n"), s -> s + "n")); add(Pair.with(Pattern.compile("v\\[(.+)\\]\\.id"), s -> g.V().has("name", s).id().next().toString())); add(Pair.with(Pattern.compile("v\\[(.+)\\]\\.sid"), s -> g.V().has("name", s).id().next().toString())); @@ -155,11 +159,14 @@ public final class StepDefinition { throw new AssumptionViolatedException("This test uses a Path as a parameter which is not supported by gremlin-language"); })); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.b"), Byte::parseByte)); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.s"), Short::parseShort)); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.i"), Integer::parseInt)); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.l"), Long::parseLong)); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.f"), Float::parseFloat)); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.d"), Double::parseDouble)); add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.m"), BigDecimal::new)); + add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.n"), BigInteger::new)); add(Pair.with(Pattern.compile("v\\[(.+)\\]\\.id"), s -> g.V().has("name", s).id().next())); add(Pair.with(Pattern.compile("v\\[(.+)\\]\\.sid"), s -> g.V().has("name", s).id().next().toString()));
