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 007fd228a9 [TINKERPOP-3149] Prevent multiple by modulators for sack
step and changed GroupCount.feature test to verify the error message received.
(#3102)
007fd228a9 is described below
commit 007fd228a992f1dccba22e25a88e647168e5ba4f
Author: andreachild <[email protected]>
AuthorDate: Mon May 5 09:58:23 2025 -0700
[TINKERPOP-3149] Prevent multiple by modulators for sack step and changed
GroupCount.feature test to verify the error message received. (#3102)
---
CHANGELOG.asciidoc | 2 +-
.../process/traversal/step/sideEffect/SackValueStep.java | 3 +++
.../process/traversal/step/sideEffect/SackValueStepTest.java | 6 ++++++
.../test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 1 +
gremlin-go/driver/cucumber/gremlin.go | 1 +
.../javascript/gremlin-javascript/test/cucumber/gremlin.js | 1 +
gremlin-python/src/main/python/radish/gremlin.py | 1 +
.../gremlin/test/features/sideEffect/GroupCount.feature | 2 +-
.../tinkerpop/gremlin/test/features/sideEffect/Sack.feature | 11 ++++++++++-
9 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index aead724472..6219bf76bf 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -66,7 +66,7 @@ This release also includes changes from <<release-3-7-XXX,
3.7.XXX>>.
* Added missing strategies in `gremlin-go`, updated certain strategies to take
varargs and updated `GoTranslatorVisitor` for corresponding translations.
* Fixed `BigInt` and `BigDecimal` parsing in `gremlin-go` cucumber test suite,
fixed `UnscaledValue` type in `BigDecimal` struct and added `ParseBigDecimal`
method.
* Added validation to `valueMap()`/`propertyMap()`/`groupCount()` to prevent
an invalid usage of multiple `by()` modulators.
-* Added validation to `groupCount()` to prevent an invalid usage of multiple
`by()` modulators.
+* Added validation to `groupCount()` and `sack()` to prevent an invalid usage
of multiple `by()` modulators.
* Deprecated `ProcessLimitedStandardSuite` and `ProcessLimitedComputerSuite`
in favor of `ProcessEmbeddedStandardSuite` and `ProcessEmbeddedComputerSuite`
respectively.
* Deprecated `ProcessStandardSuite` and the `ProcessComputerSuite` in favor of
Gherkin testing and the `ProcessEmbeddedStandardSuite` and
`ProcessEmbeddedComputerSuite` for testing JVM-specific Gremlin behaviors.
* Removed lambda oriented Gremlin testing from Gherkin test suite.
diff --git
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java
index b19f099bfe..f4f4383eb9 100644
---
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java
+++
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStep.java
@@ -51,6 +51,9 @@ public final class SackValueStep<S, A, B> extends
AbstractStep<S, S> implements
@Override
public void modulateBy(final Traversal.Admin<?, ?> sackTraversal) {
+ if (this.sackTraversal != null) {
+ throw new IllegalStateException("Sack step can only have one by
modulator");
+ }
this.sackTraversal = this.integrateChild(sackTraversal);
}
diff --git
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStepTest.java
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStepTest.java
index 0f6731bba9..51cb9048b0 100644
---
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStepTest.java
+++
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SackValueStepTest.java
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.structure.Vertex;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import org.junit.Test;
/**
* @author Daniel Kuppitz (http://gremlin.guru)
@@ -49,4 +50,9 @@ public class SackValueStepTest extends StepTest {
})
);
}
+
+ @Test(expected = IllegalStateException.class)
+ public void shouldThrowForMultipleByModulators() {
+ __.sack(Operator.assign).by("age").by("name");
+ }
}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 774cd7043c..ea2ce560b8 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -1640,6 +1640,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_sackXassignX_byXageX_sack", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().Sack(Operator.Assign).By("age").Sack<object>()}},
{"g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack",
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.WithSack(p["xx1"],
Operator.Assign).V().Local<object>(__.Out("knows").Barrier(Barrier.NormSack)).In("knows").Barrier().Sack<object>()}},
{"g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p)
=>g.WithSack(2).V().Sack(Operator.Div).By(__.Constant<object>(p["xx1"])).Sack<object>()}},
+ {"g_V_sackXassignX_byXageX_byXnameX_sack", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().Sack(Operator.Assign).By("age").By("name").Sack<object>()}},
{"g_V_sideEffectXidentityX", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().SideEffect(__.Identity())}},
{"g_V_sideEffectXidentity_valuesXnameXX", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.V().SideEffect(__.Identity().Values<object>("name"))}},
{"g_V_sideEffectXpropertyXage_22X", new
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>
{(g,p) =>g.AddV("person").Property("age", 21), (g,p)
=>g.V().SideEffect(__.Property("age", 22)), (g,p) =>g.V().Has("age", 21), (g,p)
=>g.V().Has("age", 22)}},
diff --git a/gremlin-go/driver/cucumber/gremlin.go
b/gremlin-go/driver/cucumber/gremlin.go
index 17ec0da51c..5e5564dc6d 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -1609,6 +1609,7 @@ var translationMap = map[string][]func(g
*gremlingo.GraphTraversalSource, p map[
"g_V_sackXassignX_byXageX_sack": {func(g *gremlingo.GraphTraversalSource,
p map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().Sack(gremlingo.Operator.Assign).By("age").Sack()}},
"g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack":
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.WithSack(p["xx1"],
gremlingo.Operator.Assign).V().Local(gremlingo.T__.Out("knows").Barrier(gremlingo.Barrier.NormSack)).In("knows").Barrier().Sack()}},
"g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.WithSack(2).V().Sack(gremlingo.Operator.Div).By(gremlingo.T__.Constant(p["xx1"])).Sack()}},
+ "g_V_sackXassignX_byXageX_byXnameX_sack": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().Sack(gremlingo.Operator.Assign).By("age").By("name").Sack()}},
"g_V_sideEffectXidentityX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().SideEffect(gremlingo.T__.Identity())}},
"g_V_sideEffectXidentity_valuesXnameXX": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().SideEffect(gremlingo.T__.Identity().Values("name"))}},
"g_V_sideEffectXpropertyXage_22X": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.AddV("person").Property("age", 21)}, func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return
g.V().SideEffect(gremlingo.T__.Property("age", 22))}, func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.V().Has("age", 21)}, func(g
*gremlingo.GraphTraversalSour [...]
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 c261f4f92d..074fb918ab 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
@@ -1639,6 +1639,7 @@ const gremlins = {
g_V_sackXassignX_byXageX_sack: [function({g}) { return
g.V().sack(Operator.assign).by("age").sack() }],
g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack:
[function({g, xx1}) { return g.withSack(xx1,
Operator.assign).V().local(__.out("knows").barrier(Barrier.normSack)).in_("knows").barrier().sack()
}],
g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack: [function({g, xx1}) {
return g.withSack(2).V().sack(Operator.div).by(__.constant(xx1)).sack() }],
+ g_V_sackXassignX_byXageX_byXnameX_sack: [function({g}) { return
g.V().sack(Operator.assign).by("age").by("name").sack() }],
g_V_sideEffectXidentityX: [function({g}) { return
g.V().sideEffect(__.identity()) }],
g_V_sideEffectXidentity_valuesXnameXX: [function({g}) { return
g.V().sideEffect(__.identity().values("name")) }],
g_V_sideEffectXpropertyXage_22X: [function({g}) { return
g.addV("person").property("age", 21) }, function({g}) { return
g.V().sideEffect(__.property("age", 22)) }, function({g}) { return
g.V().has("age", 21) }, function({g}) { return g.V().has("age", 22) }],
diff --git a/gremlin-python/src/main/python/radish/gremlin.py
b/gremlin-python/src/main/python/radish/gremlin.py
index 4985d650bc..e01425c3ae 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -1612,6 +1612,7 @@ world.gremlins = {
'g_V_sackXassignX_byXageX_sack': [(lambda
g:g.V().sack(Operator.assign).by('age').sack())],
'g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack':
[(lambda g, xx1=None:g.with_sack(xx1,
Operator.assign).V().local(__.out('knows').barrier(Barrier.norm_sack)).in_('knows').barrier().sack())],
'g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack': [(lambda g,
xx1=None:g.with_sack(2).V().sack(Operator.div).by(__.constant(xx1)).sack())],
+ 'g_V_sackXassignX_byXageX_byXnameX_sack': [(lambda
g:g.V().sack(Operator.assign).by('age').by('name').sack())],
'g_V_sideEffectXidentityX': [(lambda g:g.V().side_effect(__.identity()))],
'g_V_sideEffectXidentity_valuesXnameXX': [(lambda
g:g.V().side_effect(__.identity().values('name')))],
'g_V_sideEffectXpropertyXage_22X': [(lambda
g:g.add_v('person').property('age', 21)), (lambda
g:g.V().side_effect(__.property('age', 22))), (lambda g:g.V().has('age', 21)),
(lambda g:g.V().has('age', 22))],
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/GroupCount.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/GroupCount.feature
index b8533e4037..861ce5fbc4 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/GroupCount.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/GroupCount.feature
@@ -243,4 +243,4 @@ Feature: Step - groupCount()
g.V().out("created").groupCount("x").by("name").by("age")
"""
When iterated to list
- Then the traversal will raise an error
\ No newline at end of file
+ Then the traversal will raise an error with message containing text of
"GroupCount step can only have one by modulator"
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Sack.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Sack.feature
index 315b8f9cca..14a099e867 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Sack.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Sack.feature
@@ -140,4 +140,13 @@ Feature: Step - sack()
| d[0.5].d |
| d[0.5].d |
| d[0.5].d |
- | d[0.5].d |
\ No newline at end of file
+ | d[0.5].d |
+
+ Scenario: g_V_sackXassignX_byXageX_byXnameX_sack
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().sack(assign).by("age").by("name").sack()
+ """
+ When iterated to list
+ Then the traversal will raise an error with message containing text of
"Sack step can only have one by modulator"
\ No newline at end of file