Skip to content

Commit 3b984f3

Browse files
committed
Merge branch '3.8-dev'
2 parents 96991cd + 12aa078 commit 3b984f3

12 files changed

Lines changed: 84 additions & 7 deletions

File tree

CHANGELOG.asciidoc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ This release also includes changes from <<release-3-7-XXX, 3.7.XXX>>.
135135
* Added and made `OffsetDateTime` serializers the default for existing date types in Python, Go, JavaScript, and .NET. `Date` is only used to deserialize from server.
136136
* Added missing strategies in `gremlin-go`, updated certain strategies to take varargs and updated `GoTranslatorVisitor` for corresponding translations.
137137
* Fixed `BigInt` and `BigDecimal` parsing in `gremlin-go` cucumber test suite, fixed `UnscaledValue` type in `BigDecimal` struct and added `ParseBigDecimal` method.
138-
* Added validation to `valueMap()`/`propertyMap()`/`groupCount()` to prevent an invalid usage of multiple `by()` modulators.
139-
* Added validation to `groupCount()`, `sack()` and `dedup()` to prevent an invalid usage of multiple `by()` modulators.
138+
* Added validation to `valueMap()`, `propertyMap()`, `groupCount()`, `sack()`, `dedup()`, `sample()`, and `aggregate()` to prevent the invalid usage of multiple `by()` modulators.
140139
* Deprecated `ProcessLimitedStandardSuite` and `ProcessLimitedComputerSuite` in favor of `ProcessEmbeddedStandardSuite` and `ProcessEmbeddedComputerSuite` respectively.
141140
* Deprecated `ProcessStandardSuite` and the `ProcessComputerSuite` in favor of Gherkin testing and the `ProcessEmbeddedStandardSuite` and `ProcessEmbeddedComputerSuite` for testing JVM-specific Gremlin behaviors.
142141
* Removed lambda oriented Gremlin testing from Gherkin test suite.

docs/src/upgrade/release-3.8.x.asciidoc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,16 @@ The previous behavior attempted to round-robin the by() but this wasn't possible
303303
304304
See: link:https://issues.apache.org/jira/browse/TINKERPOP-2974[TINKERPOP-2974]
305305
306-
==== groupCount() By Modulation Semantics
306+
==== groupCount(), dedup(), sack(), sample(), aggregate() By Modulation Semantics
307307
308-
The `groupCount()` step has been changed to throw an error if multiple `by()` modulators are applied. The previous
309-
behavior would ignore previous `by()` modulators and apply the last one, which was not intuitive.
308+
The `groupCount()`, `dedup()`, `sack()`, `sample()`, and `aggregate()` steps has been changed to throw an error if
309+
multiple `by()` modulators are applied. The previous behavior would ignore previous `by()` modulators and apply the
310+
last one, which was not intuitive.
310311
311312
See: link:https://issues.apache.org/jira/browse/TINKERPOP-3121[TINKERPOP-3121]
312313
314+
==== Additional By Modulation Semantics
315+
313316
=== Upgrading for Providers
314317
315318
==== Graph System Providers

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
*/
4444
public final class SampleGlobalStep<S> extends CollectingBarrierStep<S> implements TraversalParent, ByModulating, Seedable {
4545

46-
private Traversal.Admin<S, Number> probabilityTraversal = new ConstantTraversal<>(1.0d);
46+
private boolean detectedMutipleBy = false;
47+
private Traversal.Admin<S, Number> probabilityTraversal = new ConstantTraversal<>(1.0d);;
4748
private final int amountToSample;
4849
private final Random random = new Random();
4950

@@ -68,13 +69,18 @@ public List<Traversal.Admin<S, Number>> getLocalChildren() {
6869

6970
@Override
7071
public void modulateBy(final Traversal.Admin<?, ?> probabilityTraversal) {
72+
if (this.detectedMutipleBy)
73+
throw new IllegalStateException("Sample step can only have one by modulator");
74+
this.detectedMutipleBy = true;
7175
this.probabilityTraversal = this.integrateChild(probabilityTraversal);
7276
}
7377

7478
@Override
7579
public void replaceLocalChild(final Traversal.Admin<?, ?> oldTraversal, final Traversal.Admin<?, ?> newTraversal) {
76-
if (null != this.probabilityTraversal && this.probabilityTraversal.equals(oldTraversal))
80+
if (null != this.probabilityTraversal && this.probabilityTraversal.equals(oldTraversal)) {
81+
this.detectedMutipleBy = true;
7782
this.probabilityTraversal = this.integrateChild(newTraversal);
83+
}
7884
}
7985

8086
@Override
@@ -155,6 +161,7 @@ public Set<TraverserRequirement> getRequirements() {
155161
public SampleGlobalStep<S> clone() {
156162
final SampleGlobalStep<S> clone = (SampleGlobalStep<S>) super.clone();
157163
clone.probabilityTraversal = this.probabilityTraversal.clone();
164+
clone.detectedMutipleBy = this.detectedMutipleBy;
158165
return clone;
159166
}
160167

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateGlobalStep.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ public String toString() {
6969

7070
@Override
7171
public void modulateBy(final Traversal.Admin<?, ?> aggregateTraversal) {
72+
if (this.aggregateTraversal != null)
73+
throw new IllegalStateException("Aggregate step can only have one by modulator");
7274
this.aggregateTraversal = this.integrateChild(aggregateTraversal);
7375
}
7476

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateLocalStep.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ public List<Traversal.Admin<S, Object>> getLocalChildren() {
8787

8888
@Override
8989
public void modulateBy(final Traversal.Admin<?, ?> storeTraversal) {
90+
if (this.storeTraversal != null)
91+
throw new IllegalStateException("Aggregate step can only have one by modulator");
9092
this.storeTraversal = this.integrateChild(storeTraversal);
9193
}
9294

gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStepTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
2323
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
2424
import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
25+
import org.apache.tinkerpop.gremlin.structure.T;
2526
import org.junit.Test;
2627

2728
import java.util.ArrayList;
@@ -59,4 +60,9 @@ public void shouldSelectSubsetsCorrectly() {
5960
assertTrue(list.containsAll(result));
6061
}
6162
}
63+
64+
@Test(expected = IllegalStateException.class)
65+
public void shouldThrowForMultipleByModulators() {
66+
__.V().sample(1).by("age").by(T.id);
67+
}
6268
}

gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,11 @@ private static IDictionary<string, List<Func<GraphTraversalSource, IDictionary<s
365365
{"g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Order().By("age").Values<object>("name").Skip<object>(1)}},
366366
{"g_VX1X_valuesXageX_rangeXlocal_20_30X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Values<object>("age").Range<object>(Scope.Local, 20, 30)}},
367367
{"g_V_mapXin_hasIdX1XX_limitX2X_valuesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Map<object>(__.In().HasId(p["vid1"])).Limit<object>(2).Values<object>("name")}},
368+
{"g_V_sampleX1X_byXageX_byXT_idX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Sample(1).By("age").By(T.Id)}},
368369
{"g_V_rangeX2_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Range<object>(2, 1)}},
369370
{"g_V_rangeX3_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Range<object>(3, 2)}},
371+
{"g_V_aggregateXxX_byXnameX_byXageX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Aggregate("x").By("name").By("age").Cap<object>("x")}},
372+
{"g_V_aggregateXScope_local_xX_byXnameX_byXageX_capXxX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Aggregate(Scope.Local, "x").By("name").By("age").Cap<object>("x")}},
370373
{"g_E_sampleX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Sample(1)}},
371374
{"g_E_sampleX2X_byXweightX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Sample(2).By("weight")}},
372375
{"g_V_localXoutE_sampleX1X_byXweightXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.OutE().Sample(1).By("weight"))}},

gremlin-go/driver/cucumber/gremlin.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,11 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
339339
"g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Order().By("age").Values("name").Skip(1)}},
340340
"g_VX1X_valuesXageX_rangeXlocal_20_30X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Values("age").Range(gremlingo.Scope.Local, 20, 30)}},
341341
"g_V_mapXin_hasIdX1XX_limitX2X_valuesXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Map(gremlingo.T__.In().HasId(p["vid1"])).Limit(2).Values("name")}},
342+
"g_V_sampleX1X_byXageX_byXT_idX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Sample(1).By("age").By(gremlingo.T.Id)}},
342343
"g_V_rangeX2_1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Range(2, 1)}},
343344
"g_V_rangeX3_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Range(3, 2)}},
345+
"g_V_aggregateXxX_byXnameX_byXageX_capXxX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Aggregate("x").By("name").By("age").Cap("x")}},
346+
"g_V_aggregateXScope_local_xX_byXnameX_byXageX_capXxX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Aggregate(gremlingo.Scope.Local, "x").By("name").By("age").Cap("x")}},
344347
"g_E_sampleX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Sample(1)}},
345348
"g_E_sampleX2X_byXweightX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Sample(2).By("weight")}},
346349
"g_V_localXoutE_sampleX1X_byXweightXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Local(gremlingo.T__.OutE().Sample(1).By("weight"))}},

gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gremlin-python/src/main/python/radish/gremlin.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,11 @@
350350
'g_V_hasLabelXpersonX_order_byXageX_valuesXnameX_skipX1X': [(lambda g:g.V().has_label('person').order().by('age').values('name').skip(1))],
351351
'g_VX1X_valuesXageX_rangeXlocal_20_30X': [(lambda g, vid1=None:g.V(vid1).values('age').range_(Scope.local, 20, 30))],
352352
'g_V_mapXin_hasIdX1XX_limitX2X_valuesXnameX': [(lambda g, vid1=None:g.V().map(__.in_().has_id(vid1)).limit(2).values('name'))],
353+
'g_V_sampleX1X_byXageX_byXT_idX': [(lambda g:g.V().sample(1).by('age').by(T.id_))],
353354
'g_V_rangeX2_1X': [(lambda g:g.V().range_(2, 1))],
354355
'g_V_rangeX3_2X': [(lambda g:g.V().range_(3, 2))],
356+
'g_V_aggregateXxX_byXnameX_byXageX_capXxX': [(lambda g:g.V().aggregate('x').by('name').by('age').cap('x'))],
357+
'g_V_aggregateXScope_local_xX_byXnameX_byXageX_capXxX': [(lambda g:g.V().aggregate(Scope.local, 'x').by('name').by('age').cap('x'))],
355358
'g_E_sampleX1X': [(lambda g:g.E().sample(1))],
356359
'g_E_sampleX2X_byXweightX': [(lambda g:g.E().sample(2).by('weight'))],
357360
'g_V_localXoutE_sampleX1X_byXweightXX': [(lambda g:g.V().local(__.out_e().sample(1).by('weight')))],

0 commit comments

Comments
 (0)