@@ -1380,6 +1380,79 @@ applies to list types which means that non-iterable types (including null) will
1380
1380
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java[source],
1381
1381
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#product-step[reference]
1382
1382
1383
+ [[repeat-step]]
1384
+ === repeat()
1385
+
1386
+ *Description:* Iteratively applies a traversal (the "loop body") to each incoming traverser until a stopping
1387
+ condition is met. Optionally, it can emit traversers on each iteration according to an emit predicate. The
1388
+ repeat step supports loop naming and a loop counter via `loops()`.
1389
+
1390
+ *Syntax:* `repeat(Traversal repeatTraversal)` | `repeat(String loopName, Traversal repeatTraversal)`
1391
+
1392
+ [width="100%",options="header"]
1393
+ |=========================================================
1394
+ |Start Step |Mid Step |Modulated |Domain |Range
1395
+ |N |Y |`emit()`, `until()`, `times()` |`any` |`any`
1396
+ |=========================================================
1397
+
1398
+ *Arguments:*
1399
+
1400
+ * `repeatTraversal` - The traversal that represents the loop body to apply on each iteration.
1401
+ * `loopName` - Optional name used to identify the loop for nested loops and to access a specific counter via
1402
+ `loops(loopName)`.
1403
+
1404
+ *Modulation:*
1405
+
1406
+ * `emit()` | `emit(Traversal<?, ?> emitTraversal)` | `emit(Predicate<Traverser<?>> emitPredicate)` - Controls if/when a
1407
+ traverser is emitted to the downstream of repeat() in addition to being looped again. If supplied before `repeat(...)`
1408
+ the predicate is evaluated prior to the first iteration (pre-emit). If supplied after `repeat(...)`, the predicate is
1409
+ evaluated after each completed iteration (post-emit). Calling `emit()` without arguments is equivalent to a predicate
1410
+ that always evaluates to true at the given check position.
1411
+ * `until(Traversal<?, ?> untilTraversal)` | `until(Predicate<Traverser<?>> untilPredicate)` - Controls when repetition
1412
+ stops. If supplied before `repeat(...)` the predicate is evaluated prior to the first iteration (pre-check). If the
1413
+ predicate is true, the traverser will pass downstream without any loop iteration. If supplied after `repeat(...)`, the
1414
+ predicate is evaluated after each completed iteration (post-check). When the predicate is true, the traverser stops
1415
+ repeating and passes downstream.
1416
+ * `times(int n)` - Convenience for a loop bound. Equivalent to `until(loops().is(n))` when placed after `repeat(...)`
1417
+ (post-check), and equivalent to `until(loops().is(n))` placed before `repeat(...)` (pre-check) when specified before.
1418
+ See Considerations for details and examples.
1419
+
1420
+ *Considerations:*
1421
+
1422
+ - Evaluation order matters. The placement of `emit()` and `until()` relative to `repeat()` controls whether their
1423
+ predicates are evaluated before the first iteration (pre) or after each iteration (post) allowing for `while/do` or
1424
+ `do/while` semantics respectively:
1425
+ - Pre-check / pre-emit: when the modulator appears before `repeat(...)`.
1426
+ - Post-check / post-emit: when the modulator appears after `repeat(...)`.
1427
+ - Loop counter semantics:
1428
+ - The loop counter for a given named or unnamed repeat is incremented once per completion of the loop body (i.e.,
1429
+ after the body finishes), not before. Therefore, `loops()` reflects the number of completed iterations.
1430
+ - `loops()` without arguments returns the counter for the closest (innermost) `repeat()`. `loops("name")` returns the
1431
+ counter for the named loop.
1432
+ - Re-queuing for the next iteration:
1433
+ - After each iteration, if `until` is not satisfied at the post-check, the traverser is sent back into the loop body
1434
+ for another iteration. If it is satisfied, the traverser exits the loop and proceeds downstream.
1435
+ - Interaction of `times(n)`:
1436
+ - `g.V().repeat(x).times(2)` applies `x` exactly twice; no values are emitted unless `emit()` is specified.
1437
+ - `g.V().emit().repeat(x).times(2)` emits the original input (pre-emit) and then the results of each iteration.
1438
+ - Placing `times(0)` before `repeat(...)` yields no iterations and passes the input downstream unchanged.
1439
+ - Placing `times(0)` after `repeat(...)` yields the same as `times(1)` because of `do/while` semantics.
1440
+ - Errors when `repeatTraversal` is missing:
1441
+ - Using `emit()`, `until()`, or `times()` without an associated `repeat()` will raise an error at iteration time with a
1442
+ message containing: `The repeat()-traversal was not defined`.
1443
+ - Nested repeats and loop names:
1444
+ - Nested `repeat()` steps maintain separate loop counters. Use `repeat("a", ...)` and `loops("a")` to reference a
1445
+ specific counter inside nested loops.
1446
+
1447
+ *Exceptions*
1448
+
1449
+ * Using `emit()`, `until()`, or `times()` without a matching `repeat()` will raise an `IllegalStateException` at runtime
1450
+ when the step is initialized during iteration with the message containing: `The repeat()-traversal was not defined`.
1451
+
1452
+ 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],
1453
+ link:https://tinkerpop.apache.org/docs/x.y.z/reference/#repeat-step[reference],
1454
+ 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]
1455
+
1383
1456
[[replace-step]]
1384
1457
=== replace()
1385
1458
0 commit comments