@coasys/ad4m / Exports / TraverseOptions
Interface: TraverseOptions
Everything a traversal says that is not how it names its predicate.
Hierarchy
-
TraverseOptions
Table of contents
Properties
Properties
direction
• Optional direction: "out" | "in"
'out' (default) matches anchor --predicate--> result; 'in' matches
result --predicate--> anchor, which is how to search among the things
pointing at a node — ordered, filtered, limited. A reverse include
answers the same question for rows already in hand, but cannot narrow them.
Defined in
core/src/model/types.ts:172 (opens in a new tab)
ids
• ids: string | string[]
The anchors to walk from. A bare string is the single-anchor spelling.
Defined in
core/src/model/types.ts:149 (opens in a new tab)
levels
• Optional levels: number[]
Walk the relation level by level, keeping this many results per anchor at each depth —
[10, 5, 3] is "ten replies, five under each of those, three under each of those".
The walk happens in the executor, which is the point of it. A caller can drive the same walk by asking for one level and using the ids as the next level's anchors, but each step is then a network round trip, and a UI that draws as each answer lands shows the tree assembling itself a level at a time. Inside the executor the levels are sequential queries against a local store with nothing serialised between them, and the records are hydrated once for the union — so three levels cost one request and one hydration rather than three of each.
Results come back flat and breadth-first; read the inverse relation alongside to rebuild the
tree, exactly as with transitive. The anchors are excluded from their own result, also as
with transitive — a walk that reaches an anchor again, through a cycle or because one anchor
was named below another, reports it at neither place.
Each record appears once, under whichever anchor the ordering reaches first — a reply to two of the anchors is one reply, not two. It does not spend a place in the other anchors' breadth either: they fill theirs with replies of their own, so a breadth of five means five distinct records wherever five exist.
A global limit/offset applies to that flat union once, after every level has been cut to
its own breadth — not to each level.
As with limitPerAnchor, each level is cut before any where the store cannot evaluate, so a
row that filter removes still took a place at its level. The walk has already descended below
that row by then, so its own replies can come back without it.
Combining this with transitive or limitPerAnchor is an error, not a preference the
executor resolves: transitive is the unbounded form of the same walk, and limitPerAnchor
has no place to act when the walk sets a per-anchor limit at every depth itself. (It is not a
substitute either — with a single anchor at the top there is one group, so it caps the total
rather than the breadth at each level.) Put the first level's breadth in levels[0].
Defined in
core/src/model/types.ts:231 (opens in a new tab)
limitPerAnchor
• Optional limitPerAnchor: number
Keep at most this many results per anchor — "the top 5 replies under each of these 20 comments" in one query.
Applied by the executor between selecting ids and hydrating them, because SPARQL has no per-group limit (no window functions, and sub-SELECTs are uncorrelated). The practical consequence is that the over-fetch is paid in ids, not records: a branch with 3,000 replies costs 3,000 strings and hydrates 5.
Pair it with order — without one the "top" N is whatever the store
happened to return first. A global limit/offset is applied to the
sliced union afterwards, not before it.
A where the store cannot evaluate (a bare author condition, for one)
is applied after hydration, so after the slice: a row it removes has
still taken one of its anchor's places, and that anchor comes back with
fewer than N even when more matching rows exist. Filtering first would
mean fetching every anchor's rows whole, which is what the limit avoids.
Refused alongside levels, which applies its own per-anchor limit at
every depth.
Defined in
core/src/model/types.ts:196 (opens in a new tab)
transitive
• Optional transitive: boolean
Follow the predicate as far as it goes rather than one step.
The result is a flat set of everything reachable, and it does not
describe the shape it came from: SPARQL property paths bind no intermediate
variables, so a row says that it is under the anchor and never where. To
rebuild a tree, read the inverse relation (@BelongsToOne) alongside it and
assemble from the parent each row reports.
Excludes every named anchor, not just the one a given row was reached through — a caller
naming two anchors where one sits below the other gets neither back, exactly as with levels.
An anchor is where the read started, not something it found, and that holds in a cycle too.
Refused alongside levels, which is the bounded form of the same walk.