AshNeo4j.Functions.Traverse (AshNeo4j v0.10.0)

Copy Markdown View Source

A multi-hop graph traversal as an Ash.Expr value, pushed down to a Cypher path pattern (#321).

From the queried node, follow a chain of typed/directed edges and reach the node(s) at the far end — then use that reached node inside a filter:

# reached-node field comparison
Service
|> Ash.Query.filter(traverse(^chain, :status) == "active")
|> Ash.read!()

# compose with spatial — "services whose site is within 5 km of a point"
Service
|> Ash.Query.filter(st_dwithin(traverse(^chain, :location), ^point, 5_000))
|> Ash.read!()

# membership / cardinality over the reached set (#334)
Service |> Ash.Query.filter(traverse(^chain, :exists) == true)   # reaches a node
Service |> Ash.Query.filter(traverse(^chain, :exists) == false)  # reaches none
Service |> Ash.Query.filter(traverse(^chain, :count) > 0)        # cardinality

Arguments

  • hop_chain — a list of hops, each {:forward | :reverse, edge_selector}. :forward walks an outgoing edge, :reverse an incoming one. edge_selector is an Ash relationship name (atom, resolved on the source resource to its edge label + destination label) or an explicit {:edge, label} / {:edge, label, dest_label}.

  • projection (optional, default :node) — what to pull from the reached set:
    • :node (default) — the reached node itself
    • a field atom (e.g. :status, :location) — a field on the reached node, to compare or feed to st_dwithin/vector_similarity
    • :exists — membership; renders to EXISTS {} / NOT EXISTS {}, spelled == true / == false
    • :count — cardinality of distinct reached nodes; renders to COUNT { … } <op> n

Ash's count()/sum()/… are inline aggregates welded to a relationship path and expanded at filter hydration, so they can't nest as traverse(count()); the aggregate is carried as a projection literal (:count) instead.

Pushdown only

Traversal needs the graph, so it cannot be computed from argument values alone — evaluate/1 returns :unknown and the data layer must push it down to Cypher. In this first slice it is recognised in filter; sort/ calculate/policy contexts are a fast-follow.

Summary

Functions

args()

Callback implementation for Ash.Query.Function.args/0.

has_partial_evaluate?()