This is an automated email from the ASF dual-hosted git repository.

Cole-Greer pushed a commit to branch TINKERPOP-3256
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/TINKERPOP-3256 by this push:
     new ac7fa00a5c Fold TinkerGQL variable-length path docs into existing 
reference
ac7fa00a5c is described below

commit ac7fa00a5ce25480c9aa7b4862a96cf64e02f35c
Author: Cole Greer <[email protected]>
AuthorDate: Tue Oct 27 19:06:19 2026 -0700

    Fold TinkerGQL variable-length path docs into existing reference
    
    Replace the standalone variable-length path subsection with rows in the
    existing Supported Syntax table, a short note, and one modern-graph
    example. Move the CHANGELOG entry from the released 4.0.0-beta.3 section
    to the unreleased 4.0.0 section and restore the beta.3 section.
    
    Assisted-by: Kiro:claude-opus-5
---
 CHANGELOG.asciidoc                        |  4 +-
 docs/src/reference/the-traversal.asciidoc | 95 ++++++-------------------------
 2 files changed, 19 insertions(+), 80 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index a49c6d9c36..6570cb7295 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -28,6 +28,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Fixed `gremlin-go` to report a malformed or truncated GraphBinary response 
as a deserialization error rather than a bare decoder message.
 * Made `TinkerGraph` an interface and renamed the in-memory implementation to 
`TinkerMemoryGraph`; `TinkerGraph.open()` and `gremlin.graph=...TinkerGraph` 
behave as before. *(breaking)*
 * Renamed `TinkerTransactionGraph` to `TinkerStorageGraph`. *(breaking)*
+* Added variable-length path patterns to TinkerGQL using quantified 
relationships such as `(a)-[:knows]->{1,3}(b)`.
 
 [[release-4-0-0-beta-3]]
 === TinkerPop 4.0.0-beta.3 (July 20, 2026)
@@ -125,8 +126,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Deprecated the traversal-based `match(Traversal[])` in favor of the new 
string-based API.
 * Added the `gql-gremlin` module containing the TinkerGQL engine, a 
`MATCH`-pattern executor implementing a deliberate minimal subset of ISO GQL, 
usable by any graph provider.
 * Added `Graph.countVerticesByLabel(String)`, 
`Graph.countEdgesByLabel(String)`, and the `Graph.Index` nested interface as 
performance-hint extension points for the TinkerGQL engine.
-* Added GQL support to TinkerGraph with `gql-gremlin`.
-* Added variable-length path patterns to TinkerGQL via the 
quantified-relationship form `(a)-[r:label]->{m,n}(b)` (also `{m}`, `{m,}`, and 
`+`), across directed, reverse, and undirected edges.
+* Added GQL support to TinkerGraph with `gql-gremlin`,
 
 [[release-4-0-0-beta-2]]
 === TinkerPop 4.0.0-beta.2 (April 1, 2026)
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index ff76be1b6a..f24f0571b3 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -3269,6 +3269,10 @@ The following `MATCH` patterns are supported:
 |`-[:Label]-` |Labeled undirected edge
 |`-[e:Label]-` |Named and labeled undirected edge
 |`-[e:Label {key: 'value'}]-` |Named, labeled undirected edge with an inline 
property filter
+|`-[e:Label]->{m,n}` |Quantified edge that matches a walk of `m` to `n` 
repeated edges
+|`-[e:Label]->{m}` |Quantified edge that matches a walk of exactly `m` 
repeated edges
+|`-[e:Label]->{m,}` |Quantified edge that matches a walk of `m` or more 
repeated edges
+|`-[e:Label]->+` |Quantified edge that matches a walk of one or more repeated 
edges, equivalent to `{1,}`
 |=========================================================
 
 Multiple comma-separated path patterns are supported in a single `MATCH` 
clause. Patterns that share a variable
@@ -3276,6 +3280,10 @@ name are joined on that variable, which must resolve to 
the same element across
 clause — `match()` always returns the full binding `Map` and any projection is 
performed with Gremlin steps like
 `select()`.
 
+A quantifier may follow any directed, reverse, or undirected edge, as in 
`<-[e:Label]-{m,n}` or
+`-[e:Label]-{m,n}`, and the quantified walk matches once at every length in 
its range. A walk never repeats an
+edge, and a named edge variable binds to the ordered list of edges in the walk.
+
 The following examples use the modern toy graph to demonstrate more complex 
usage patterns.
 
 *Find all software and the person who created it, traversing the edge in 
reverse*
@@ -3312,6 +3320,14 @@ g.match("MATCH (a:person)-[e:knows]-(b:person)").
     by("name").by("weight").by("name")
 ----
 
+*Find people who created the same software as marko, using a quantified 
undirected edge to walk two `created` edges*
+
+[gremlin-groovy,modern]
+----
+g.match("MATCH (a:person {name: 'marko'})-[:created]-{2}(b:person)").
+  select("a", "b").by("name")
+----
+
 The `match()` step becomes arguably preferable when the query involves a 
multi-way join, where several paths
 must all connect through shared variables, because the pattern expresses the 
shape of the subgraph directly
 rather than requiring the reader to trace variable bindings through a chain of 
steps. For example, "find people
@@ -3450,83 +3466,6 @@ performs an index-backed seed lookup rather than a full 
scan. Whether `Graph.Ind
 structure depends on the graph system; see <<tinkerpop-providers-tinkergql,the 
provider documentation>> and
 your specific graph system's documentation for details.
 
-[[tinkergql-variable-length]]
-===== Variable-Length Path Patterns
-
-A relationship pattern can be quantified so that it matches a variable-length 
walk of repeated edges of the same
-shape rather than a single hop. The quantifier is written immediately after 
the closing arrow of the
-relationship, in the abbreviated form `(a)-[r:LABEL]->{q}(b)`. Four quantifier 
forms are supported, each with a
-lower bound of at least one:
-
-[width="100%",cols="2,4",options="header"]
-|=========================================================
-|Quantifier |Meaning
-|`{m,n}` |Between `m` and `n` repetitions, inclusive
-|`{m}`   |Exactly `m` repetitions
-|`{m,}`  |At least `m` repetitions, unbounded above
-|`+`     |One or more repetitions, equivalent to `{1,}`
-|=========================================================
-
-Quantification is available on all three edge directions. The examples below 
use the modern toy graph, where the
-`knows` relationship forms only single-hop paths, so a bounded quantifier 
there resolves to the same immediate
-neighbours as an unquantified edge:
-
-[gremlin-groovy,modern]
-----
-g.match("MATCH (a:person)-[:knows]->{1,2}(b:person)").
-  select("a", "b").by("name")
-----
-
-The reverse form `<-[r:LABEL]-{q}` walks incoming edges, and the undirected 
form `-[r:LABEL]-{q}` walks edges in
-either direction:
-
-[gremlin-groovy,modern]
-----
-g.match("MATCH (b:person)<-[:knows]-{1}(a:person)").
-  select("a", "b").by("name")
-----
-
-*Semantics*
-
-A quantified relationship expands from its already-bound endpoint outward, one 
hop at a time, up to the maximum
-repetition count. Three properties define the result set. First, expansion 
follows *trail* semantics: within a
-single walk no edge is traversed more than once, which guarantees termination 
even in the presence of cycles.
-Vertices, by contrast, may repeat when reached through distinct edges. Second, 
expansion *emits at each depth*
-within the quantifier range. A walk that reaches a valid target at every depth 
from the lower bound to the upper
-bound produces one result row per depth, not only at the final depth. Third, 
the edge variable `r` binds as an
-ordered `List<Edge>`, a *group variable* holding every edge traversed on that 
walk, in walk order. A result
-row's list has one element for a depth-one match, two for a depth-two match, 
and so on.
-
-The following illustrates these semantics over a linear chain 
`a-[route]->b-[route]->c-[route]->d`, which the
-modern graph does not contain. A `{1,3}` quantifier anchored at `a` emits `b` 
at depth one, `c` at depth two, and
-`d` at depth three, with `r` accumulating the traversed edges at each depth:
-
-[source,text]
-----
-MATCH (a:airport {code: 'AAA'})-[r:route]->{1,3}(x:airport)
-
-// three result rows, one per depth:
-//   x = BBB, r = [AAA->BBB]
-//   x = CCC, r = [AAA->BBB, BBB->CCC]
-//   x = DDD, r = [AAA->BBB, BBB->CCC, CCC->DDD]
-----
-
-A lower bound greater than one suppresses the shallower depths. Over the same 
chain, `{2,}` emits only `c` and `d`,
-while `+` (equivalent to `{1,}`) emits `b`, `c`, and `d`.
-
-*Limitations*
-
-Quantified relationships in the current release carry three restrictions:
-
-. *Forward expansion only.* A quantified edge expands outward from one bound 
endpoint to reach the other. A
-quantified edge whose endpoints are both already bound elsewhere in the 
pattern, one that closes a
-pattern cycle, is not yet supported and raises an error at plan time. Only 
unquantified edges may close a cycle.
-. *No zero-length forms.* Every quantifier must have a lower bound of at least 
one. The zero-length forms `*`,
-`{0,n}`, and `{,n}` are not yet supported and are rejected when the query is 
parsed or planned.
-. *Per-walk edge uniqueness only.* The trail (no-repeated-edge) guarantee 
applies within a single quantified
-walk. Edge uniqueness across an entire multi-pattern match is not enforced, so 
an edge traversed inside a
-quantified walk may also appear in another part of the same match.
-
 ===== Unsupported Features
 
 TinkerGQL is a minimal subset of ISO GQL. The following ISO GQL `MATCH` 
features are not yet implemented:
@@ -3537,7 +3476,7 @@ TinkerGQL is a minimal subset of ISO GQL. The following 
ISO GQL `MATCH` features
 |`WHERE` clause |Post-match filtering is not supported inside the `MATCH` 
string. Use Gremlin's `where()` step after `match()` instead.
 |`RETURN` clause |Projection inside the `MATCH` string is not supported. Use 
`select()` after `match()` to project named variables.
 |Inequality / range predicates |Only equality tests (`{key: value}`) are 
supported. Expressions like `n.age > 30` are not part of the grammar.
-|Zero-length and cyclic quantified paths |Quantified path patterns with a 
lower bound of at least one (`{m,n}`, `{m}`, `{m,}`, `+`) are supported (see 
<<tinkergql-variable-length>>). Zero-length forms (`*`, `{0,n}`, `{,n}`) and a 
quantified edge that closes a pattern cycle are not yet supported.
+|Some quantified paths |Zero-length quantifiers (`*`, `{0,n}`, `{,n}`) and 
quantified edges that close a pattern cycle are not supported. Edge uniqueness 
is enforced within each quantified walk rather than across the whole pattern.
 |Multiple labels per element |`(n:Person:Employee)` — more than one label per 
node pattern — is not supported.
 |`OPTIONAL MATCH` |Optional pattern matching (outer joins) is not supported.
 |Aggregation functions |`COUNT`, `SUM`, `AVG`, and similar functions are not 
part of the grammar.

Reply via email to