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

colegreer pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.8-dev by this push:
     new 35a1eac8bc TINKERPOP-3023 Implement UUID in gremlin-lang which should 
have two forms: UUID() and UUID(“uuid”) (#3112)
35a1eac8bc is described below

commit 35a1eac8bc7afb799d12494da73273d6e5610466
Author: Peter Tribe <[email protected]>
AuthorDate: Mon May 5 17:29:15 2025 -0600

    TINKERPOP-3023 Implement UUID in gremlin-lang which should have two forms: 
UUID() and UUID(“uuid”) (#3112)
---
 CHANGELOG.asciidoc                                 |  1 +
 .../grammar/DefaultGremlinBaseVisitor.java         | 12 +++++--
 .../language/grammar/GenericLiteralVisitor.java    | 18 ++++++++++
 .../translator/AnonymizedTranslatorVisitor.java    |  3 ++
 .../translator/DotNetTranslateVisitor.java         | 12 +++++++
 .../language/translator/GoTranslateVisitor.java    | 12 +++++++
 .../translator/JavascriptTranslateVisitor.java     | 10 ++++++
 .../translator/PythonTranslateVisitor.java         | 12 +++++++
 .../language/translator/TranslateVisitor.java      |  6 ++++
 .../language/translator/GremlinTranslatorTest.java | 18 ++++++++++
 .../Gherkin/CommonSteps.cs                         | 10 ++++++
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  1 +
 gremlin-go/build/generate.groovy                   |  1 +
 gremlin-go/driver/cucumber/cucumberSteps_test.go   | 11 ++++++
 gremlin-go/driver/cucumber/gremlin.go              |  2 ++
 gremlin-javascript/build/generate.groovy           |  1 +
 .../test/cucumber/feature-steps.js                 |  5 +++
 .../gremlin-javascript/test/cucumber/gremlin.js    |  1 +
 gremlin-language/src/main/antlr4/Gremlin.g4        | 14 ++++++++
 gremlin-python/build/generate.groovy               |  1 +
 .../src/main/python/radish/feature_steps.py        |  4 +++
 gremlin-python/src/main/python/radish/gremlin.py   |  2 ++
 .../gremlin/server/GremlinDriverIntegrateTest.java | 14 ++++++++
 .../tinkerpop/gremlin/features/StepDefinition.java |  4 ++-
 .../gremlin/test/features/sideEffect/Uuid.feature  | 41 ++++++++++++++++++++++
 25 files changed, 212 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 579948f1f0..ec72e32411 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 This release also includes changes from <<release-3-7-XXX, 3.7.XXX>>.
 
+* Added UUID() + UUID(value) to grammar
 * Modified `TraversalStrategy` construction in Javascript where configurations 
are now supplied as a `Map` of options.
 * Fixed bug in GraphSON v2 and v3 where full round trip of `TraversalStrategy` 
implementations was failing.
 * Added missing strategies to the `TraversalStrategies` global cache as well 
as `CoreImports` in `gremlin-groovy`.
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 bfa4f36497..8ca46ef3fd 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
@@ -1335,6 +1335,10 @@ public class DefaultGremlinBaseVisitor<T> extends 
AbstractParseTreeVisitor<T> im
         * {@inheritDoc}
         */
        @Override public T visitInfLiteral(final 
GremlinParser.InfLiteralContext ctx) { notImplemented(ctx); return null; }
+       /**
+        * {@inheritDoc}
+        */
+       @Override public T visitUuidLiteral(final 
GremlinParser.UuidLiteralContext ctx) { notImplemented(ctx); return null; }
        /**
         * {@inheritDoc}
         */
@@ -1454,9 +1458,11 @@ public class DefaultGremlinBaseVisitor<T> extends 
AbstractParseTreeVisitor<T> im
        /**
         * {@inheritDoc}
         */
-       @Override
-       public T visitDateArgument(final GremlinParser.DateArgumentContext ctx) 
{ notImplemented(ctx); return null; }
-
+       @Override public T visitDateArgument(final 
GremlinParser.DateArgumentContext ctx) { notImplemented(ctx); return null; }
+       /**
+        * {@inheritDoc}
+        */
+       @Override public T visitUuidArgument(final 
GremlinParser.UuidArgumentContext ctx) { notImplemented(ctx); return null; }
        /**
         * {@inheritDoc}
         */
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 04499f1380..09669249cd 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
@@ -39,6 +39,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.UUID;
 
 /**
  * Visitor class to handle generic literal. All visitor methods return type is 
Object. It maybe used as a singleton
@@ -90,6 +91,13 @@ public class GenericLiteralVisitor extends 
DefaultGremlinBaseVisitor<Object> {
         return (OffsetDateTime) visitDateLiteral(dateLiteral);
     }
 
+    /**
+     * Parse a UUID based literal context and return the UUID.
+     */
+    public UUID parseUuid(final GremlinParser.UuidLiteralContext uuidLiteral) {
+        return (UUID) visitUuidLiteral(uuidLiteral);
+    }
+
     /**
      * Parse a map literal context and return the map literal
      */
@@ -506,6 +514,16 @@ public class GenericLiteralVisitor extends 
DefaultGremlinBaseVisitor<Object> {
         return DatetimeHelper.parse((String) 
antlr.argumentVisitor.visitStringArgument(ctx.stringArgument()));
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object visitUuidLiteral(final GremlinParser.UuidLiteralContext ctx) 
{
+        if (ctx.stringLiteral() == null)
+            return UUID.randomUUID();
+        return UUID.fromString((String) 
antlr.genericVisitor.visitStringLiteral(ctx.stringLiteral()));
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java
index 8537df8e32..9605722ab0 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java
@@ -184,4 +184,7 @@ public class AnonymizedTranslatorVisitor extends 
TranslateVisitor {
     public Void visitInfLiteral(final GremlinParser.InfLiteralContext ctx) {
         return anonymize(ctx, Number.class);
     }
+
+    @Override
+    public Void visitUuidLiteral(final GremlinParser.UuidLiteralContext ctx) { 
return anonymize(ctx, String.class); }
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
index 08c5de23eb..47924f96e4 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
@@ -1098,6 +1098,18 @@ public class DotNetTranslateVisitor extends 
AbstractTranslateVisitor {
         return null;
     }
 
+    @Override
+    public Void visitUuidLiteral(final GremlinParser.UuidLiteralContext ctx) {
+        if (ctx.stringLiteral() == null) {
+            sb.append("Guid.NewGuid()");
+            return null;
+        }
+        sb.append("Guid.Parse(");
+        sb.append(ctx.stringLiteral().getText());
+        sb.append(")");
+        return null;
+    }
+
     /**
      * Steps with a {@code <TNewEnd>} defined need special handling to append 
generics.
      */
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java
index 8b75a30182..dab9496146 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java
@@ -292,6 +292,18 @@ public class GoTranslateVisitor extends 
AbstractTranslateVisitor {
         return null;
     }
 
+    @Override
+    public Void visitUuidLiteral(final GremlinParser.UuidLiteralContext ctx) {
+        if (ctx.stringLiteral() == null) {
+            sb.append("uuid.New()");
+            return null;
+        }
+        sb.append("uuid.MustParse(");
+        visitStringLiteral(ctx.stringLiteral());
+        sb.append(")");
+        return null;
+    }
+
     @Override
     protected String getCardinalityFunctionClass() {
         return "CardinalityValue";
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java
index e247e5e749..7e1aaff4ce 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java
@@ -223,6 +223,16 @@ public class JavascriptTranslateVisitor extends 
AbstractTranslateVisitor {
         return null;
     }
 
+    @Override
+    public Void visitUuidLiteral(final GremlinParser.UuidLiteralContext ctx) {
+        if (ctx.stringLiteral() == null) {
+            sb.append("uuid.v4()");
+            return null;
+        }
+        visitStringLiteral(ctx.stringLiteral());
+        return null;
+    }
+
     @Override
     protected String getCardinalityFunctionClass() {
         return "CardinalityValue";
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java
index 4cf0eb8a61..a45d92bf16 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java
@@ -300,6 +300,18 @@ public class PythonTranslateVisitor extends 
AbstractTranslateVisitor {
         return null;
     }
 
+    @Override
+    public Void visitUuidLiteral(final GremlinParser.UuidLiteralContext ctx) {
+        if (ctx.stringLiteral() == null) {
+            sb.append("uuid.uuid4()");
+            return null;
+        }
+        sb.append("uuid.UUID(");
+        visitStringLiteral(ctx.stringLiteral());
+        sb.append(")");
+        return null;
+    }
+
     @Override
     protected String getCardinalityFunctionClass() {
         return "CardinalityValue";
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
index edfe9accd4..fb1b884693 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
@@ -431,6 +431,12 @@ public class TranslateVisitor extends 
GremlinBaseVisitor<Void> {
         return null;
     }
 
+    @Override
+    public Void visitUuidLiteral(final GremlinParser.UuidLiteralContext ctx) {
+        sb.append(ctx.getText());
+        return null;
+    }
+
     @Override
     public Void visitVariable(final GremlinParser.VariableContext ctx) {
         final String var = ctx.getText();
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
index 71a7630f35..f84b671eb0 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
@@ -151,6 +151,24 @@ public class GremlinTranslatorTest {
                             null,
                             "g.with_(\"x\")",
                             "g.with_('x')"},
+                    
{"g.inject(UUID(\"f47af10b-58cc-4372-a567-0f02b2f3d479\"))",
+                            null,
+                            "g.inject(string0)",
+                            
"g.Inject<object>(Guid.Parse(\"f47af10b-58cc-4372-a567-0f02b2f3d479\"))",
+                            
"g.Inject(uuid.MustParse(\"f47af10b-58cc-4372-a567-0f02b2f3d479\"))",
+                            null,
+                            null,
+                            
"g.inject(\"f47af10b-58cc-4372-a567-0f02b2f3d479\")",
+                            
"g.inject(uuid.UUID('f47af10b-58cc-4372-a567-0f02b2f3d479'))"},
+                    {"g.inject(UUID())",
+                            null,
+                            "g.inject(string0)",
+                            "g.Inject<object>(Guid.NewGuid())",
+                            "g.Inject(uuid.New())",
+                            null,
+                            null,
+                            "g.inject(uuid.v4())",
+                            "g.inject(uuid.uuid4())"},
                     {"g.with(\"x\n\\\"yz\")",
                             null,
                             "g.with(string0)",
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
index 0de6b3723f..14d96227c4 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
@@ -60,6 +60,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                 {@"str\[(.*)\]", (x, graphName) => x }, //returns the string 
value as is
                 {@"vp\[(.+)\]", ToVertexProperty},
                 {@"dt\[(.+)\]", ToDateTime},
+                {@"uuid\[(.+)\]", ToUuid},
                 {@"d\[(.*)\]\.([bsilfdmn])", ToNumber},
                 {@"D\[(.+)\]", ToDirection},
                 {@"M\[(.+)\]", ToMerge},
@@ -461,6 +462,15 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
             return DateTimeOffset.Parse(date);
         }
 
+        private static object ToUuid(string uuid, string graphName)
+        {
+            if (Guid.TryParse(uuid, out Guid result))
+            {
+                return result;
+            }
+            return null;
+        }
+
         private static Vertex ToVertex(string name, string graphName)
         {
             if 
(ScenarioData.GetByGraphName(graphName).Vertices.ContainsKey(name))
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 0ec2b51e13..1b6de4dddd 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -1686,6 +1686,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_VX1X_out_out_out_tree", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.V().Out().Out().Out().Tree<object>()}}, 
                {"g_VX1X_outE_inV_bothE_otherV_tree", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V(p["vid1"]).OutE().InV().BothE().OtherV().Tree<object>()}}, 
                {"g_VX1X_outE_inV_bothE_otherV_tree_byXnameX_byXlabelX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V(p["vid1"]).OutE().InV().BothE().OtherV().Tree<object>().By("name").By(T.Label)}},
 
+               {"g_injectXUUIDX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.Inject<object>(Guid.Parse("f47af10b-58cc-4372-a567-0f02b2f3d479"))}}, 
             };
 
         public static ITraversal UseTraversal(string scenarioName, 
GraphTraversalSource g, IDictionary<string, object> parameters)
diff --git a/gremlin-go/build/generate.groovy b/gremlin-go/build/generate.groovy
index 8b5ff2eb86..65897394cb 100644
--- a/gremlin-go/build/generate.groovy
+++ b/gremlin-go/build/generate.groovy
@@ -61,6 +61,7 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer ->
         '\t \"time\"\n' +
         '\t \"math\"\n' +
         '\t \"github.com/apache/tinkerpop/gremlin-go/v3/driver\"\n' +
+        '\t \"github.com/google/uuid\"\n' +
         ')\n'
     )
 
diff --git a/gremlin-go/driver/cucumber/cucumberSteps_test.go 
b/gremlin-go/driver/cucumber/cucumberSteps_test.go
index 1c90f81e7c..d7144cb2a4 100644
--- a/gremlin-go/driver/cucumber/cucumberSteps_test.go
+++ b/gremlin-go/driver/cucumber/cucumberSteps_test.go
@@ -37,6 +37,7 @@ import (
 
        gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver"
        "github.com/cucumber/godog"
+       "github.com/google/uuid"
 )
 
 type tinkerPopGraph struct {
@@ -50,6 +51,7 @@ func init() {
        parsers = map[*regexp.Regexp]func(string, string) interface{}{
                regexp.MustCompile(`^str\[(.*)]$`):        func(stringVal, 
graphName string) interface{} { return stringVal }, //returns the string value 
as is
                regexp.MustCompile(`^dt\[(.*)]$`):         toDateTime,
+               regexp.MustCompile(`^uuid\[(.*)]$`):       toUuid,
                regexp.MustCompile(`^d\[(.*)]\.[bslfd]$`): toNumeric,
                regexp.MustCompile(`^d\[(.*)]\.[m]$`):     toBigDecimal,
                regexp.MustCompile(`^d\[(.*)]\.[n]$`):     toBigInt,
@@ -120,6 +122,15 @@ func toDateTime(stringVal, graphName string) interface{} {
        return val.In(gremlingo.GetTimezoneFromOffset(os))
 }
 
+// Parse uuid.
+func toUuid(stringVal, graphName string) interface{} {
+       val, err := uuid.Parse(stringVal)
+       if err != nil {
+               return nil
+       }
+       return val
+}
+
 // Parse numeric.
 func toNumeric(stringVal, graphName string) interface{} {
        if strings.Contains(stringVal, ".") {
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index be5821231c..d232db2a9e 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -29,6 +29,7 @@ import (
         "time"
         "math"
         "github.com/apache/tinkerpop/gremlin-go/v3/driver"
+        "github.com/google/uuid"
 )
 
 var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal{
@@ -1655,6 +1656,7 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_VX1X_out_out_out_tree": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Out().Out().Out().Tree()}}, 
     "g_VX1X_outE_inV_bothE_otherV_tree": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid1"]).OutE().InV().BothE().OtherV().Tree()}}, 
     "g_VX1X_outE_inV_bothE_otherV_tree_byXnameX_byXlabelX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid1"]).OutE().InV().BothE().OtherV().Tree().By("name").By(gremlingo.T.Label)}},
 
+    "g_injectXUUIDX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject(uuid.MustParse("f47af10b-58cc-4372-a567-0f02b2f3d479"))}}, 
 }
 
    func GetTraversal(scenarioName string, g *gremlingo.GraphTraversalSource, 
parameters map[string]interface{}) (*gremlingo.GraphTraversal, error) {
diff --git a/gremlin-javascript/build/generate.groovy 
b/gremlin-javascript/build/generate.groovy
index 2cbb943656..9d04bc3e1b 100644
--- a/gremlin-javascript/build/generate.groovy
+++ b/gremlin-javascript/build/generate.groovy
@@ -54,6 +54,7 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer ->
     
writer.writeLine("//********************************************************************************\n\n")
 
     writer.writeLine(
+                    'const uuid = require(\'uuid\');\n' +
                     'const graphTraversalModule = 
require(\'../../lib/process/graph-traversal\');\n' +
                     'const traversalModule = 
require(\'../../lib/process/traversal\');\n' +
                     'const { TraversalStrategies, VertexProgramStrategy, 
OptionsStrategy, PartitionStrategy, \n' +
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 6553ace7fe..211d22e4a7 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
@@ -46,6 +46,7 @@ const parsers = [
   [ 'str\\[(.*)\\]', (stringValue) => stringValue ], //returns the string 
value as is
   [ 'vp\\[(.+)\\]', toVertexProperty ],
   [ 'dt\\[(.+)\\]', toDateTime ],
+  [ 'uuid\\[(.+)\\]', toUuid ],
   [ 'd\\[(.*)\\]\\.[bsilfdmn]', toNumeric ],
   [ 'v\\[(.+)\\]', toVertex ],
   [ 'v\\[(.+)\\]\\.id', toVertexId ],
@@ -407,6 +408,10 @@ function toDateTime(value) {
   return new Date(value);
 }
 
+function toUuid(value) {
+  return value;
+}
+
 function toMerge(value) {
   return merge[value];
 }
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 2d6e42b706..d2f89c8696 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
@@ -1685,6 +1685,7 @@ const gremlins = {
     g_VX1X_out_out_out_tree: [function({g}) { return 
g.V().out().out().out().tree() }], 
     g_VX1X_outE_inV_bothE_otherV_tree: [function({g, vid1}) { return 
g.V(vid1).outE().inV().bothE().otherV().tree() }], 
     g_VX1X_outE_inV_bothE_otherV_tree_byXnameX_byXlabelX: [function({g, vid1}) 
{ return g.V(vid1).outE().inV().bothE().otherV().tree().by("name").by(T.label) 
}], 
+    g_injectXUUIDX: [function({g}) { return 
g.inject("f47af10b-58cc-4372-a567-0f02b2f3d479") }], 
 }
 
 exports.gremlin = gremlins
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 
b/gremlin-language/src/main/antlr4/Gremlin.g4
index bb56af0785..c8a9ba68e8 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -1505,6 +1505,11 @@ structureVertexArgument
     | variable
     ;
 
+uuidArgument
+    : uuidLiteral
+    | variable
+    ;
+
 traversalStrategyList
     : traversalStrategyExpr?
     ;
@@ -1591,6 +1596,7 @@ genericLiteral
     | nestedTraversal
     | terminatedTraversal
     | genericLiteralMap
+    | uuidLiteral
     ;
 
 genericLiteralMap
@@ -1662,6 +1668,12 @@ infLiteral
     | SignedInfLiteral
     ;
 
+uuidLiteral
+    : K_UUID LPAREN RPAREN
+    | K_UUID LPAREN stringLiteral RPAREN
+    ;
+
+
 nakedKey
     : Identifier
     ;
@@ -1908,6 +1920,7 @@ keyword
     | K_UNFOLD
     | K_UNION
     | K_UNTIL
+    | K_UUID
     | K_V
     | K_VALUEMAP
     | K_VALUES
@@ -2167,6 +2180,7 @@ K_TX: 'tx';
 K_UNFOLD: 'unfold';
 K_UNION: 'union';
 K_UNTIL: 'until';
+K_UUID: 'UUID';
 K_V: 'V';
 K_VALUEMAP: 'valueMap';
 K_VALUES: 'values';
diff --git a/gremlin-python/build/generate.groovy 
b/gremlin-python/build/generate.groovy
index 026319bb1e..6da003cc54 100644
--- a/gremlin-python/build/generate.groovy
+++ b/gremlin-python/build/generate.groovy
@@ -56,6 +56,7 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer ->
     writer.writeLine(
                     'from radish import world\n' +
                     'import datetime\n' +
+                    'import uuid\n' +
                     'from gremlin_python.statics import long, bigint, 
GremlinType\n' +
                     'from gremlin_python.process.anonymous_traversal import 
traversal\n' +
                     'from gremlin_python.process.strategies import *\n' +
diff --git a/gremlin-python/src/main/python/radish/feature_steps.py 
b/gremlin-python/src/main/python/radish/feature_steps.py
index c1c145a56f..996a2fc1b9 100644
--- a/gremlin-python/src/main/python/radish/feature_steps.py
+++ b/gremlin-python/src/main/python/radish/feature_steps.py
@@ -20,6 +20,7 @@
 from datetime import datetime
 import json
 import re
+import uuid
 from gremlin_python.statics import long
 from gremlin_python.structure.graph import Path, Vertex
 from gremlin_python.process.anonymous_traversal import traversal
@@ -247,6 +248,9 @@ def _convert(val, ctx):
     elif isinstance(val, str) and re.match(r"^dt\[.*\]$", val):  # parse 
datetime
         # python 3.8 can handle only subset of ISO 8601 dates
         return datetime.fromisoformat(val[3:-1].replace('Z', '+00:00'))
+    elif isinstance(val, str) and re.match(r"^uuid\[.*\]$", val):  # parse uuid
+        name = val[5:-1]  # strip 'uuid[...]' or similar format
+        return uuid.UUID(name)
     elif isinstance(val, str) and re.match(r"^d\[NaN\]$", val):  # parse nan
         return float("nan")
     elif isinstance(val, str) and re.match(r"^d\[Infinity\]$", val):  # parse 
+inf
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index 97fa2afdcd..078afdcfee 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -26,6 +26,7 @@
 
 from radish import world
 import datetime
+import uuid
 from gremlin_python.statics import long, bigint, GremlinType
 from gremlin_python.process.anonymous_traversal import traversal
 from gremlin_python.process.strategies import *
@@ -1658,4 +1659,5 @@ world.gremlins = {
     'g_VX1X_out_out_out_tree': [(lambda g:g.V().out().out().out().tree())], 
     'g_VX1X_outE_inV_bothE_otherV_tree': [(lambda g, 
vid1=None:g.V(vid1).out_e().in_v().both_e().other_v().tree())], 
     'g_VX1X_outE_inV_bothE_otherV_tree_byXnameX_byXlabelX': [(lambda g, 
vid1=None:g.V(vid1).out_e().in_v().both_e().other_v().tree().by('name').by(T.label))],
 
+    'g_injectXUUIDX': [(lambda 
g:g.inject(uuid.UUID('f47af10b-58cc-4372-a567-0f02b2f3d479')))], 
 }
diff --git 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index 8b1b8da59f..6dc2e4fdb8 100644
--- 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
+++ 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
@@ -1903,4 +1903,18 @@ public class GremlinDriverIntegrateTest extends 
AbstractGremlinServerIntegration
     public void shouldFailOnInitiallyDeadHostForSessionClient() throws 
Exception {
         testShouldFailOnInitiallyDeadHost(false);
     }
+
+    @Test
+    public void shouldReturnUuid() throws Exception {
+        final Cluster cluster = 
TestClientFactory.build().serializer(Serializers.GRAPHSON_V3).create();
+        try {
+            final Client client = cluster.connect().alias("g");
+            List<Result> returnedList = client.submit("g.inject(UUID())", 
RequestOptions.build().language("gremlin-lang").create()).all().get();
+            assertEquals(1, returnedList.size());
+            Object value = returnedList.get(0).getObject();
+            assertTrue(value instanceof UUID);
+        } finally {
+            cluster.close();
+        }
+    }
 }
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 39e6338cbe..275166e06d 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
@@ -92,6 +92,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import java.util.UUID;
 
 @ScenarioScoped
 public final class StepDefinition {
@@ -228,7 +229,8 @@ public final class StepDefinition {
         add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.m"), BigDecimal::new));
         add(Pair.with(Pattern.compile("d\\[(.*)\\]\\.n"), BigInteger::new));
 
-        add(Pair.with(Pattern.compile("dt\\[(.*)\\]"), s -> 
DatetimeHelper.parse(s)));
+        add(Pair.with(Pattern.compile("dt\\[(.*)\\]"), DatetimeHelper::parse));
+        add(Pair.with(Pattern.compile("uuid\\[(.*)\\]"), UUID::fromString));
 
         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()));
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Uuid.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Uuid.feature
new file mode 100644
index 0000000000..ba00ef9ac9
--- /dev/null
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Uuid.feature
@@ -0,0 +1,41 @@
+# 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.
+
+@HelperUuid @ConstructorUuid
+Feature: Helper - uuid()
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectXUUIDX47af10b_58cc_4372_a567_0f02b2f3d479XX
+    Given the empty graph
+    And the traversal of
+      """
+      g.inject(UUID("f47af10b-58cc-4372-a567-0f02b2f3d479"))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | uuid[f47af10b-58cc-4372-a567-0f02b2f3d479] |
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectXUUIDXXX
+    Given the empty graph
+    And the traversal of
+      """
+      g.inject(UUID())
+      """
+    When iterated to list
+    Then the result should have a count of 1

Reply via email to