@@ -1999,6 +1999,79 @@ from the resulting `Map`.
1999
1999
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java[source],
2000
2000
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#project-step[reference]
2001
2001
2002
+ [[repeat-step]]
2003
+ === repeat()
2004
+
2005
+ *Description:* Iteratively applies a traversal (the "loop body") to each incoming traverser until a stopping
2006
+ condition is met. Optionally, it can emit traversers on each iteration according to an emit predicate. The
2007
+ repeat step supports loop naming and a loop counter via `loops()`.
2008
+
2009
+ *Syntax:* `repeat(Traversal repeatTraversal)` | `repeat(String loopName, Traversal repeatTraversal)`
2010
+
2011
+ [width="100%",options="header"]
2012
+ |=========================================================
2013
+ |Start Step |Mid Step |Modulated |Domain |Range
2014
+ |N |Y |`emit()`, `until()`, `times()` |`any` |`any`
2015
+ |=========================================================
2016
+
2017
+ *Arguments:*
2018
+
2019
+ * `repeatTraversal` - The traversal that represents the loop body to apply on each iteration.
2020
+ * `loopName` - Optional name used to identify the loop for nested loops and to access a specific counter via
2021
+ `loops(loopName)`.
2022
+
2023
+ *Modulation:*
2024
+
2025
+ * `emit()` | `emit(Traversal<?, ?> emitTraversal)` | `emit(Predicate<Traverser<?>> emitPredicate)` - Controls if/when a
2026
+ traverser is emitted to the downstream of repeat() in addition to being looped again. If supplied before `repeat(...)`
2027
+ the predicate is evaluated prior to the first iteration (pre-emit). If supplied after `repeat(...)`, the predicate is
2028
+ evaluated after each completed iteration (post-emit). Calling `emit()` without arguments is equivalent to a predicate
2029
+ that always evaluates to true at the given check position.
2030
+ * `until(Traversal<?, ?> untilTraversal)` | `until(Predicate<Traverser<?>> untilPredicate)` - Controls when repetition
2031
+ stops. If supplied before `repeat(...)` the predicate is evaluated prior to the first iteration (pre-check). If the
2032
+ predicate is true, the traverser will pass downstream without any loop iteration. If supplied after `repeat(...)`, the
2033
+ predicate is evaluated after each completed iteration (post-check). When the predicate is true, the traverser stops
2034
+ repeating and passes downstream.
2035
+ * `times(int n)` - Convenience for a loop bound. Equivalent to `until(loops().is(n))` when placed after `repeat(...)`
2036
+ (post-check), and equivalent to `until(loops().is(n))` placed before `repeat(...)` (pre-check) when specified before.
2037
+ See Considerations for details and examples.
2038
+
2039
+ *Considerations:*
2040
+
2041
+ - Evaluation order matters. The placement of `emit()` and `until()` relative to `repeat()` controls whether their
2042
+ predicates are evaluated before the first iteration (pre) or after each iteration (post) allowing for `while/do` or
2043
+ `do/while` semantics respectively:
2044
+ - Pre-check / pre-emit: when the modulator appears before `repeat(...)`.
2045
+ - Post-check / post-emit: when the modulator appears after `repeat(...)`.
2046
+ - Loop counter semantics:
2047
+ - The loop counter for a given named or unnamed repeat is incremented once per completion of the loop body (i.e.,
2048
+ after the body finishes), not before. Therefore, `loops()` reflects the number of completed iterations.
2049
+ - `loops()` without arguments returns the counter for the closest (innermost) `repeat()`. `loops("name")` returns the
2050
+ counter for the named loop.
2051
+ - Re-queuing for the next iteration:
2052
+ - After each iteration, if `until` is not satisfied at the post-check, the traverser is sent back into the loop body
2053
+ for another iteration. If it is satisfied, the traverser exits the loop and proceeds downstream.
2054
+ - Interaction of `times(n)`:
2055
+ - `g.V().repeat(x).times(2)` applies `x` exactly twice; no values are emitted unless `emit()` is specified.
2056
+ - `g.V().emit().repeat(x).times(2)` emits the original input (pre-emit) and then the results of each iteration.
2057
+ - Placing `times(0)` before `repeat(...)` yields no iterations and passes the input downstream unchanged.
2058
+ - Placing `times(0)` after `repeat(...)` yields the same as `times(1)` because of `do/while` semantics.
2059
+ - Errors when `repeatTraversal` is missing:
2060
+ - Using `emit()`, `until()`, or `times()` without an associated `repeat()` will raise an error at iteration time with a
2061
+ message containing: `The repeat()-traversal was not defined`.
2062
+ - Nested repeats and loop names:
2063
+ - Nested `repeat()` steps maintain separate loop counters. Use `repeat("a", ...)` and `loops("a")` to reference a
2064
+ specific counter inside nested loops.
2065
+
2066
+ *Exceptions*
2067
+
2068
+ * Using `emit()`, `until()`, or `times()` without a matching `repeat()` will raise an `IllegalStateException` at runtime
2069
+ when the step is initialized during iteration with the message containing: `The repeat()-traversal was not defined`.
2070
+
2071
+ See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java[source],
2072
+ link:https://tinkerpop.apache.org/docs/x.y.z/reference/#repeat-step[reference],
2073
+ link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature[tests]
2074
+
2002
2075
[[replace-step]]
2003
2076
=== replace()
2004
2077
0 commit comments