This is an automated email from the ASF dual-hosted git repository.
xiazcy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/master by this push:
new 81775cbcaf Change substring() to use `startIndex, endIndex` instead of
`startIndex, length` (#2296)
81775cbcaf is described below
commit 81775cbcafc511df4536cb4cf3ddf7cf470453ee
Author: Ryan Tan <[email protected]>
AuthorDate: Wed Oct 18 15:59:44 2023 -0700
Change substring() to use `startIndex, endIndex` instead of `startIndex,
length` (#2296)
---
docs/src/dev/provider/gremlin-semantics.asciidoc | 8 ++--
docs/src/upgrade/release-3.7.x.asciidoc | 21 +++++-----
.../traversal/dsl/graph/GraphTraversal.java | 18 ++++-----
.../gremlin/process/traversal/dsl/graph/__.java | 4 +-
.../process/traversal/step/map/SubstringStep.java | 43 ++++++++++----------
.../traversal/step/map/SubstringStepTest.java | 28 +++++++++----
.../Process/Traversal/GraphTraversal.cs | 4 +-
.../src/Gremlin.Net/Process/Traversal/__.cs | 4 +-
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 7 +++-
gremlin-go/driver/cucumber/gremlin.go | 7 +++-
.../gremlin-javascript/test/cucumber/gremlin.js | 7 +++-
gremlin-python/src/main/python/radish/gremlin.py | 7 +++-
.../gremlin/test/features/map/Substring.feature | 46 +++++++++++++++++++---
13 files changed, 132 insertions(+), 72 deletions(-)
diff --git a/docs/src/dev/provider/gremlin-semantics.asciidoc
b/docs/src/dev/provider/gremlin-semantics.asciidoc
index 74b69e5329..c1825c261d 100644
--- a/docs/src/dev/provider/gremlin-semantics.asciidoc
+++ b/docs/src/dev/provider/gremlin-semantics.asciidoc
@@ -1194,9 +1194,9 @@
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#split-step[reference]
[[substring-step]]
=== substring()
-*Description:* Returns a substring of the incoming string traverser with a
0-based start index (inclusive) and length specified.
+*Description:* Returns a substring of the incoming string traverser with a
0-based start index (inclusive) and end index (exclusive).
-*Syntax:* `substring(long, long)`
+*Syntax:* `substring(int, int)`
[width="100%",options="header"]
|=========================================================
@@ -1208,8 +1208,8 @@
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#split-step[reference]
* `int` - The start index, 0 based. If the start index is negative then it
will begin at the specified index counted
from the end of the string, or 0 if it exceeds the string length.
-* `int` - The number of characters to return. Optional, if it is not specific
or if it exceeds the length of the string
-then all remaining characters will be returned. Length ≤ 0 will return the
empty string.
+* `int` - The end index, 0 based. Optional, if it is not specific then all
remaining characters will be returned. End
+index ≤ start index will return the empty string.
Null values from the incoming traverser are not processed and remain as null
when returned.
diff --git a/docs/src/upgrade/release-3.7.x.asciidoc
b/docs/src/upgrade/release-3.7.x.asciidoc
index 75206c7076..40ee470eaa 100644
--- a/docs/src/upgrade/release-3.7.x.asciidoc
+++ b/docs/src/upgrade/release-3.7.x.asciidoc
@@ -187,15 +187,15 @@ gremlin>
g.V().hasLabel("person").values("name").split("a")
==>[peter]
----
-For `substring()`, the new Gremlin step follows the SQL standard, taking
parameters start index and desired length of substring,
-instead of start and end indices like Java/Groovy, enabling certain operations
that would be complex to achieve with closure:
+For `substring()`, the new Gremlin step follows the Python standard, taking
parameters start index and optionally an
+end index. This will enable certain operations that would be complex to
achieve with closure:
[source,text]
----
-gremlin> g.V().hasLabel("person").values("name").map{it.get().substring(1,3)}
-==>ar
-==>ad
-==>os
-==>et
+gremlin> g.V().hasLabel("person").values("name").map{it.get().substring(1,4)}
+==>ark
+==>ada
+==>osh
+==>ete
gremlin> g.V().hasLabel("person").values("name").map{it.get().substring(1)}
==>arko
==>adas
@@ -206,11 +206,12 @@ String index out of range: -2
Type ':help' or ':h' for help.
----
-The `substring()`-step will begin at the start index and return a substring
with the length specified. Negative start
-indices are allowed and will begin at the specified index counted from the end
of the string:
+The `substring()`-step will return a substring with indices specified by the
start and end indices, or from
+the start index to the remainder of the string if an end index is not
specified. Negative indices are allowed and will
+count from the end of the string:
[source,text]
----
-gremlin> g.V().hasLabel("person").values("name").substring(1,3)
+gremlin> g.V().hasLabel("person").values("name").substring(1,4)
==>ark
==>ada
==>osh
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 be9674e507..a6257a4eba 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
@@ -1608,20 +1608,20 @@ public interface GraphTraversal<S, E> extends
Traversal<S, E> {
}
/**
- * Returns a substring of the incoming string traverser with a 0-based
start index (inclusive) index and length
- * specified. If the start index is negative then it will begin at the
specified index counted from the end
- * of the string, or 0 if exceeding the string length. Length is optional,
if it is not specific or if it exceeds
- * the length of the string then all remaining characters will be
returned. Length <= 0 will return the empty string.
- * Null values are not processed and remain as null when returned. If the
incoming traverser is a non-String value then an
- * {@code IllegalArgumentException} will be thrown.
+ * Returns a substring of the incoming string traverser with a 0-based
start index (inclusive) and end index
+ * (exclusive). If the start index is negative then it will begin at the
specified index counted from the end of the
+ * string, or 0 if exceeding the string length. If the end index is
negative then it will end at the specified index
+ * counted from the end, or at the end of the string if exceeding the
string length. End index <= start index will
+ * return the empty string. Null values are not processed and remain as
null when returned. If the incoming
+ * traverser is a non-String value then an {@code
IllegalArgumentException} will be thrown.
*
* @return the traversal with an appended {@link SubstringStep}.
* @see <a
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#replace-step"
target="_blank">Reference Documentation - Substring Step</a>
* @since 3.7.1
*/
- public default GraphTraversal<S, String> substring(final int startIndex,
final int length) {
- this.asAdmin().getBytecode().addStep(Symbols.substring, startIndex,
length);
- return this.asAdmin().addStep(new SubstringStep<>(this.asAdmin(),
startIndex, length));
+ public default GraphTraversal<S, String> substring(final int startIndex,
final int endIndex) {
+ this.asAdmin().getBytecode().addStep(Symbols.substring, startIndex,
endIndex);
+ return this.asAdmin().addStep(new SubstringStep<>(this.asAdmin(),
startIndex, endIndex));
}
/**
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 f41f3506a6..cee80f1dad 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
@@ -684,8 +684,8 @@ public class __ {
/**
* @see GraphTraversal#substring(int, int)
*/
- public static <A> GraphTraversal<A, String> substring(final int
startIndex, final int length) {
- return __.<A>start().substring(startIndex, length);
+ public static <A> GraphTraversal<A, String> substring(final int
startIndex, final int endIndex) {
+ return __.<A>start().substring(startIndex, endIndex);
}
/**
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStep.java
index e28f40557e..6638a54c2f 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStep.java
@@ -28,10 +28,11 @@ import java.util.Set;
/**
* Reference implementation for substring step, a mid-traversal step which
returns a substring of the incoming string
- * traverser with a 0-based start index (inclusive) and length specified. If
the start index is negative then it will
- * begin at the specified index counted from the end of the string, or 0 if
exceeding the string length.
- * Length is optional, if it is not specific or if it exceeds the length of
the string then all remaining characters will
- * be returned. Length <= 0 will return the empty string. Null values are not
processed and remain as null when returned.
+ * traverser with a 0-based start index (inclusive) and optionally an end
index (exclusive). If the start index is negative then it will
+ * begin at the specified index counted from the end of the string, or 0 if
exceeding the string length. Likewise, if
+ * the end index is negative then it will end at the specified index counted
from the end of the string, or 0 if exceeding the string length.
+ * End index is optional, if it is not specified or if it exceeds the length
of the string then all remaining characters will
+ * be returned. End index <= start index will return the empty string. Null
values are not processed and remain as null when returned.
* If the incoming traverser is a non-String value then an {@code
IllegalArgumentException} will be thrown.
*
* @author David Bechberger (http://bechberger.com)
@@ -40,12 +41,12 @@ import java.util.Set;
public final class SubstringStep<S> extends ScalarMapStep<S, String> {
private final Integer start;
- private final Integer length;
+ private final Integer end;
- public SubstringStep(final Traversal.Admin traversal, final Integer
startIndex, final Integer length) {
+ public SubstringStep(final Traversal.Admin traversal, final Integer
startIndex, final Integer end) {
super(traversal);
this.start = startIndex;
- this.length = length;
+ this.end = end;
}
public SubstringStep(final Traversal.Admin traversal, final Integer
startIndex) {
@@ -67,17 +68,16 @@ public final class SubstringStep<S> extends
ScalarMapStep<S, String> {
if (null == strItem)
return null;
- final int newStart = processStartIndex(strItem.length());
- if (null == this.length)
+ final int newStart = processStringIndex(strItem.length(), this.start);
+ if (null == this.end)
return strItem.substring(newStart);
- // length < 0 will return the empty string.
- if (this.length <= 0)
+ final int newEnd = processStringIndex(strItem.length(), this.end);
+
+ if (newEnd <= newStart)
return "";
- // if length specified exceeds the string length it is assumed to be
equal to the length, which returns all
- // remaining characters in the string.
- return strItem.substring(newStart, Math.min(this.length + newStart,
strItem.length()));
+ return strItem.substring(newStart, newEnd);
}
@Override
@@ -89,19 +89,18 @@ public final class SubstringStep<S> extends
ScalarMapStep<S, String> {
public int hashCode() {
int result = super.hashCode();
result = 31 * result + this.start.hashCode();
- result = 31 * result + (null != this.length ? this.length.hashCode() :
0);
+ result = 31 * result + (null != this.end ? this.end.hashCode() : 0);
return result;
}
- // Helper function to process the start index, if it is negative (which
counts from end of string) it is converted
- // to the positive index position or 0 when negative index exceeds the
string length, if it is positive and exceeds
+ // Helper function to process indices. If it is negative (which counts
from end of string) it is converted
+ // to the positive index position or 0 when negative index exceeds the
string length. If it is positive and exceeds
// the length of the string, it is assumed to equal to the length, which
means an empty string will be returned.
- private int processStartIndex(int strLen) {
- if (this.start < 0) {
- return Math.max(0, (strLen + this.start) % strLen);
+ private int processStringIndex(int strLen, int index) {
+ if (index < 0) {
+ return Math.max(0, (strLen + index) % strLen);
} else {
- return Math.min(this.start, strLen);
+ return Math.min(index, strLen);
}
}
-
}
diff --git
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStepTest.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStepTest.java
index 3af4e06e13..10dc5c288d 100644
---
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStepTest.java
+++
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringStepTest.java
@@ -41,16 +41,28 @@ public class SubstringStepTest extends StepTest {
@Test
public void testReturnTypes() {
- assertEquals("ello wor", __.__("hello world").substring(1, 8).next());
- assertEquals("ello", __.__("hello").substring(1, 8).next());
- assertEquals("world", __.__("hello world").substring(6).next());
+ assertEquals("hello world", __.__("hello world").substring(0).next());
+ assertEquals("ello world", __.__("hello world").substring(1).next());
+ assertEquals("d", __.__("hello world").substring(-1).next());
+ assertEquals("d", __.__("hello world").substring(10).next());
+ assertEquals("", __.__("hello world").substring(11).next());
- assertEquals("world", __.__("world").substring(-10).next());
- assertEquals("orld", __.__("world").substring(-4).next());
- assertEquals("orl", __.__("world").substring(-4, 3).next());
- assertEquals("", __.__("world").substring(1, -1).next());
+ assertEquals("", __.__("hello world").substring(0, 0).next());
+ assertEquals("h", __.__("hello world").substring(0, 1).next());
+ assertEquals("", __.__("hello world").substring(1, 0).next());
+ assertEquals("hello worl", __.__("hello world").substring(0,
-1).next());
+ assertEquals("", __.__("hello world").substring(-1, 0).next());
+ assertEquals("ello worl", __.__("hello world").substring(1,
-1).next());
+ assertEquals("", __.__("hello world").substring(-1, 1).next());
+ assertEquals("rl", __.__("hello world").substring(-3, -1).next());
+ assertEquals("", __.__("hello world").substring(-1, -3).next());
+ assertEquals("d", __.__("hello world").substring(-1, 11).next());
+ assertEquals("ello world", __.__("hello world").substring(1,
11).next());
+ assertEquals("d", __.__("hello world").substring(10, 11).next());
+ assertEquals("hello world", __.__("hello world").substring(-11,
11).next());
+ assertEquals("h", __.__("hello world").substring(-11, 1).next());
- assertArrayEquals(new String[]{"st", "llo worl", null, ""},
+ assertArrayEquals(new String[]{"st", "llo wo", null, ""},
__.__("test", "hello world", null, "").substring(2,
8).toList().toArray());
}
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index 91df6644f7..d232bff33d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -1938,9 +1938,9 @@ namespace Gremlin.Net.Process.Traversal
/// <summary>
/// Adds the subgraph step to this <see
cref="GraphTraversal{SType, EType}" />.
/// </summary>
- public GraphTraversal<TStart, string?> Substring (int startIndex, int
length)
+ public GraphTraversal<TStart, string?> Substring (int startIndex, int
endIndex)
{
- Bytecode.AddStep("substring", startIndex, length);
+ Bytecode.AddStep("substring", startIndex, endIndex);
return Wrap<TStart, string?>(this);
}
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
index a0fdae1632..070644c89d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
@@ -1381,9 +1381,9 @@ namespace Gremlin.Net.Process.Traversal
/// <summary>
/// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds
the substring step to that traversal.
/// </summary>
- public static GraphTraversal<object, string?> Substring(int
startIndex, int length)
+ public static GraphTraversal<object, string?> Substring(int
startIndex, int endIndex)
{
- return new GraphTraversal<object, string?>().Substring(startIndex,
length);
+ return new GraphTraversal<object, string?>().Substring(startIndex,
endIndex);
}
/// <summary>
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 9e8f820019..718d60d0f9 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -1010,11 +1010,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_hasLabelXpersonX_valueXnameX_splitXnullX", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("person").Values<object>("name").Split(null)}},
{"g_V_hasLabelXpersonX_valueXnameX_splitXaX", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("person").Values<object>("name").Split("a")}},
{"g_injectXthat_this_testX_substringX1_8X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.Inject<object>("test","hello world",null).Substring(1,8)}},
- {"g_injectXListXa_bXcX_substringX1_1X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.Inject(p["xx1"]).Substring(1,1)}},
+ {"g_injectXListXa_bXcX_substringX1_2X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.Inject(p["xx1"]).Substring(1,2)}},
{"g_V_hasLabelXpersonX_valueXnameX_substringX2X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("software").Values<object>("name").Substring(2)}},
- {"g_V_hasLabelXsoftwareX_valueXnameX_substringX1_3X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("software").Values<object>("name").Substring(1,3)}},
+ {"g_V_hasLabelXsoftwareX_valueXnameX_substringX1_4X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("software").Values<object>("name").Substring(1,4)}},
{"g_V_hasLabelXsoftwareX_valueXnameX_substringX1_0X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("software").Values<object>("name").Substring(1,0)}},
{"g_V_hasLabelXpersonX_valueXnameX_substringXneg3X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("person").Values<object>("name").Substring(-3)}},
+ {"g_V_hasLabelXsoftwareX_valueXnameX_substringX1_neg1X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("software").Values<object>("name").Substring(1,-1)}},
+ {"g_V_hasLabelXsoftwareX_valueXnameX_substringXneg4_2X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("software").Values<object>("name").Substring(-4,2)}},
+ {"g_V_hasLabelXsoftwareX_valueXnameX_substringXneg3_neg1X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().HasLabel("software").Values<object>("name").Substring(-3,-1)}},
{"g_V_age_sum", new List<Func<GraphTraversalSource,
IDictionary<string, object>, ITraversal>> {(g,p)
=>g.V().Values<object>("age").Sum<object>()}},
{"g_V_foo_sum", new List<Func<GraphTraversalSource,
IDictionary<string, object>, ITraversal>> {(g,p)
=>g.V().Values<object>("foo").Sum<object>()}},
{"g_V_age_fold_sumXlocalX", new List<Func<GraphTraversalSource,
IDictionary<string, object>, ITraversal>> {(g,p)
=>g.V().Values<object>("age").Fold().Sum<object>(Scope.Local)}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go
b/gremlin-go/driver/cucumber/gremlin.go
index 5ff32812a9..b78f9629c0 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -981,11 +981,14 @@ var translationMap = map[string][]func(g
*gremlingo.GraphTraversalSource, p map[
"g_V_hasLabelXpersonX_valueXnameX_splitXnullX": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("person").Values("name").Split(nil)}},
"g_V_hasLabelXpersonX_valueXnameX_splitXaX": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("person").Values("name").Split("a")}},
"g_injectXthat_this_testX_substringX1_8X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.Inject("test", "hello world",
nil).Substring(1, 8)}},
- "g_injectXListXa_bXcX_substringX1_1X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Substring(1, 1)}},
+ "g_injectXListXa_bXcX_substringX1_2X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Substring(1, 2)}},
"g_V_hasLabelXpersonX_valueXnameX_substringX2X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("software").Values("name").Substring(2)}},
- "g_V_hasLabelXsoftwareX_valueXnameX_substringX1_3X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("software").Values("name").Substring(1, 3)}},
+ "g_V_hasLabelXsoftwareX_valueXnameX_substringX1_4X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("software").Values("name").Substring(1, 4)}},
"g_V_hasLabelXsoftwareX_valueXnameX_substringX1_0X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("software").Values("name").Substring(1, 0)}},
"g_V_hasLabelXpersonX_valueXnameX_substringXneg3X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("person").Values("name").Substring(-3)}},
+ "g_V_hasLabelXsoftwareX_valueXnameX_substringX1_neg1X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("software").Values("name").Substring(1, -1)}},
+ "g_V_hasLabelXsoftwareX_valueXnameX_substringXneg4_2X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("software").Values("name").Substring(-4, 2)}},
+ "g_V_hasLabelXsoftwareX_valueXnameX_substringXneg3_neg1X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().HasLabel("software").Values("name").Substring(-3, -1)}},
"g_V_age_sum": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().Values("age").Sum()}},
"g_V_foo_sum": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().Values("foo").Sum()}},
"g_V_age_fold_sumXlocalX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().Values("age").Fold().Sum(gremlingo.Scope.Local)}},
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 4bed5125c3..2fff0455c8 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
@@ -1001,11 +1001,14 @@ const gremlins = {
g_V_hasLabelXpersonX_valueXnameX_splitXnullX: [function({g}) { return
g.V().hasLabel("person").values("name").split(null) }],
g_V_hasLabelXpersonX_valueXnameX_splitXaX: [function({g}) { return
g.V().hasLabel("person").values("name").split("a") }],
g_injectXthat_this_testX_substringX1_8X: [function({g}) { return
g.inject("test","hello world",null).substring(1,8) }],
- g_injectXListXa_bXcX_substringX1_1X: [function({g, xx1}) { return
g.inject(xx1).substring(1,1) }],
+ g_injectXListXa_bXcX_substringX1_2X: [function({g, xx1}) { return
g.inject(xx1).substring(1,2) }],
g_V_hasLabelXpersonX_valueXnameX_substringX2X: [function({g}) { return
g.V().hasLabel("software").values("name").substring(2) }],
- g_V_hasLabelXsoftwareX_valueXnameX_substringX1_3X: [function({g}) { return
g.V().hasLabel("software").values("name").substring(1,3) }],
+ g_V_hasLabelXsoftwareX_valueXnameX_substringX1_4X: [function({g}) { return
g.V().hasLabel("software").values("name").substring(1,4) }],
g_V_hasLabelXsoftwareX_valueXnameX_substringX1_0X: [function({g}) { return
g.V().hasLabel("software").values("name").substring(1,0) }],
g_V_hasLabelXpersonX_valueXnameX_substringXneg3X: [function({g}) { return
g.V().hasLabel("person").values("name").substring(-3) }],
+ g_V_hasLabelXsoftwareX_valueXnameX_substringX1_neg1X: [function({g}) {
return g.V().hasLabel("software").values("name").substring(1,-1) }],
+ g_V_hasLabelXsoftwareX_valueXnameX_substringXneg4_2X: [function({g}) {
return g.V().hasLabel("software").values("name").substring(-4,2) }],
+ g_V_hasLabelXsoftwareX_valueXnameX_substringXneg3_neg1X: [function({g}) {
return g.V().hasLabel("software").values("name").substring(-3,-1) }],
g_V_age_sum: [function({g}) { return g.V().values("age").sum() }],
g_V_foo_sum: [function({g}) { return g.V().values("foo").sum() }],
g_V_age_fold_sumXlocalX: [function({g}) { return
g.V().values("age").fold().sum(Scope.local) }],
diff --git a/gremlin-python/src/main/python/radish/gremlin.py
b/gremlin-python/src/main/python/radish/gremlin.py
index 304a12cebc..71665597ae 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -983,11 +983,14 @@ world.gremlins = {
'g_V_hasLabelXpersonX_valueXnameX_splitXnullX': [(lambda
g:g.V().hasLabel('person').name.split(None))],
'g_V_hasLabelXpersonX_valueXnameX_splitXaX': [(lambda
g:g.V().hasLabel('person').name.split('a'))],
'g_injectXthat_this_testX_substringX1_8X': [(lambda
g:g.inject('test','hello world',None).substring(1,8))],
- 'g_injectXListXa_bXcX_substringX1_1X': [(lambda g,
xx1=None:g.inject(xx1).substring(1,1))],
+ 'g_injectXListXa_bXcX_substringX1_2X': [(lambda g,
xx1=None:g.inject(xx1).substring(1,2))],
'g_V_hasLabelXpersonX_valueXnameX_substringX2X': [(lambda
g:g.V().hasLabel('software').name.substring(2))],
- 'g_V_hasLabelXsoftwareX_valueXnameX_substringX1_3X': [(lambda
g:g.V().hasLabel('software').name.substring(1,3))],
+ 'g_V_hasLabelXsoftwareX_valueXnameX_substringX1_4X': [(lambda
g:g.V().hasLabel('software').name.substring(1,4))],
'g_V_hasLabelXsoftwareX_valueXnameX_substringX1_0X': [(lambda
g:g.V().hasLabel('software').name.substring(1,0))],
'g_V_hasLabelXpersonX_valueXnameX_substringXneg3X': [(lambda
g:g.V().hasLabel('person').name.substring(-3))],
+ 'g_V_hasLabelXsoftwareX_valueXnameX_substringX1_neg1X': [(lambda
g:g.V().hasLabel('software').name.substring(1,-1))],
+ 'g_V_hasLabelXsoftwareX_valueXnameX_substringXneg4_2X': [(lambda
g:g.V().hasLabel('software').name.substring(-4,2))],
+ 'g_V_hasLabelXsoftwareX_valueXnameX_substringXneg3_neg1X': [(lambda
g:g.V().hasLabel('software').name.substring(-3,-1))],
'g_V_age_sum': [(lambda g:g.V().age.sum_())],
'g_V_foo_sum': [(lambda g:g.V().foo.sum_())],
'g_V_age_fold_sumXlocalX': [(lambda
g:g.V().age.fold().sum_(Scope.local))],
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Substring.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Substring.feature
index 7aac365d6c..48b7780355 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Substring.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Substring.feature
@@ -29,16 +29,16 @@ Feature: Step - substring()
Then the result should be unordered
| result |
| est |
- | ello wor |
+ | ello wo |
| null |
@GraphComputerVerificationInjectionNotSupported
- Scenario: g_injectXListXa_bXcX_substringX1_1X
+ Scenario: g_injectXListXa_bXcX_substringX1_2X
Given the empty graph
And using the parameter xx1 defined as "l[aa,bb]"
And the traversal of
"""
- g.inject(xx1).substring(1, 1)
+ g.inject(xx1).substring(1, 2)
"""
When iterated to list
Then the traversal will raise an error with message containing text of
"The substring() step can only take string as argument"
@@ -55,11 +55,11 @@ Feature: Step - substring()
| p |
| pple |
- Scenario: g_V_hasLabelXsoftwareX_valueXnameX_substringX1_3X
+ Scenario: g_V_hasLabelXsoftwareX_valueXnameX_substringX1_4X
Given the modern graph
And the traversal of
"""
- g.V().hasLabel("software").values("name").substring(1, 3)
+ g.V().hasLabel("software").values("name").substring(1, 4)
"""
When iterated to list
Then the result should be unordered
@@ -92,3 +92,39 @@ Feature: Step - substring()
| osh |
| das |
| ter |
+
+Scenario: g_V_hasLabelXsoftwareX_valueXnameX_substringX1_neg1X
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().hasLabel("software").values("name").substring(1, -1)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | o |
+ | ippl |
+
+Scenario: g_V_hasLabelXsoftwareX_valueXnameX_substringXneg4_2X
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().hasLabel("software").values("name").substring(-4, 2)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | lo |
+ | str[] |
+
+Scenario: g_V_hasLabelXsoftwareX_valueXnameX_substringXneg3_neg1X
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().hasLabel("software").values("name").substring(-3, -1)
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | lo |
+ | pl |
\ No newline at end of file