Skip to main content

fathomdb_query/
ast.rs

1use crate::TextQuery;
2
3/// Abstract syntax tree representing a graph query.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct QueryAst {
6    /// Node kind used as the root of the query.
7    pub root_kind: String,
8    /// Ordered pipeline of search, traversal, and filter steps.
9    pub steps: Vec<QueryStep>,
10    /// Named expansion slots evaluated per root result in grouped queries.
11    pub expansions: Vec<ExpansionSlot>,
12    /// Optional hard cap on the number of result rows.
13    pub final_limit: Option<usize>,
14}
15
16/// A named expansion slot that traverses edges per root result.
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct ExpansionSlot {
19    /// Slot name used to key the expansion results.
20    pub slot: String,
21    /// Direction to traverse edges.
22    pub direction: TraverseDirection,
23    /// Edge kind (label) to follow.
24    pub label: String,
25    /// Maximum traversal depth.
26    pub max_depth: usize,
27    /// Optional predicate to filter target nodes in this expansion slot.
28    /// `None` is exactly equivalent to pre-Pack-2 behavior.
29    /// `Some(_)` is not yet implemented; see Pack 3.
30    pub filter: Option<Predicate>,
31    /// Optional predicate to filter the traversed edges in this expansion slot.
32    /// Only `EdgePropertyEq` and `EdgePropertyCompare` are valid here.
33    /// `None` preserves pre-Pack-D behavior (no edge filtering).
34    pub edge_filter: Option<Predicate>,
35}
36
37/// A single step in the query pipeline.
38#[derive(Clone, Debug, PartialEq, Eq)]
39pub enum QueryStep {
40    /// Unified adaptive retrieval entry step consumed by the Phase 12
41    /// retrieval planner.
42    ///
43    /// Carries the caller's raw query string (not a parsed [`TextQuery`]):
44    /// the planner decides how to interpret and route it across the text
45    /// strict, text relaxed, and (future) vector branches. See
46    /// `crate::compile_retrieval_plan` for the planner entry point.
47    Search {
48        /// The raw caller-supplied query string.
49        query: String,
50        /// Maximum number of candidate rows requested by the caller.
51        limit: usize,
52    },
53    /// Nearest-neighbor search over vector embeddings.
54    VectorSearch {
55        /// The search query text (to be embedded by the caller).
56        query: String,
57        /// Maximum number of candidate rows from the vector index.
58        limit: usize,
59    },
60    /// Full-text search over indexed chunk content using `FathomDB`'s supported
61    /// safe text-query subset.
62    TextSearch {
63        /// Parsed text-search intent to be lowered into safe FTS5 syntax.
64        query: TextQuery,
65        /// Maximum number of candidate rows from the FTS index.
66        limit: usize,
67    },
68    /// Graph traversal following edges of the given label.
69    Traverse {
70        /// Direction to traverse.
71        direction: TraverseDirection,
72        /// Edge kind to follow.
73        label: String,
74        /// Maximum hops from each candidate.
75        max_depth: usize,
76        /// Optional predicate to filter traversal results.
77        /// `None` is exactly equivalent to the pre-Pack-2 behavior.
78        /// `Some(_)` is not yet implemented; see Pack 3.
79        filter: Option<Predicate>,
80    },
81    /// Row-level filter predicate.
82    Filter(Predicate),
83}
84
85/// A filter predicate applied to candidate nodes.
86#[derive(Clone, Debug, PartialEq, Eq)]
87pub enum Predicate {
88    /// Match nodes with the exact logical ID.
89    LogicalIdEq(String),
90    /// Match nodes with the exact kind.
91    KindEq(String),
92    /// Equality check on a JSON property at the given path.
93    JsonPathEq {
94        /// JSON path expression (e.g. `$.status`).
95        path: String,
96        /// Value to compare against.
97        value: ScalarValue,
98    },
99    /// Ordered comparison on a JSON property at the given path.
100    JsonPathCompare {
101        /// JSON path expression.
102        path: String,
103        /// Comparison operator.
104        op: ComparisonOp,
105        /// Value to compare against.
106        value: ScalarValue,
107    },
108    /// Match nodes with the exact `source_ref`.
109    SourceRefEq(String),
110    /// Match nodes where `content_ref` is not NULL (i.e. content proxy nodes).
111    ContentRefNotNull,
112    /// Match nodes with the exact `content_ref` URI.
113    ContentRefEq(String),
114    /// Fused equality check on a JSON text property at the given path.
115    ///
116    /// Unlike [`Predicate::JsonPathEq`], this variant is classified as
117    /// **fusable** by [`crate::fusion::is_fusable`] and is pushed into
118    /// the search CTE's inner `WHERE` clause so the CTE `LIMIT` applies
119    /// after the predicate runs. The caller opts into fusion by
120    /// registering an FTS property schema that covers the path; the
121    /// tethered builder enforces that gate at filter-add time.
122    JsonPathFusedEq {
123        /// JSON path expression (e.g. `$.status`).
124        path: String,
125        /// Text value to compare against.
126        value: String,
127    },
128    /// Fused ordered comparison on a JSON integer/timestamp property at
129    /// the given path. See [`Predicate::JsonPathFusedEq`] for the fusion
130    /// contract.
131    JsonPathFusedTimestampCmp {
132        /// JSON path expression.
133        path: String,
134        /// Comparison operator.
135        op: ComparisonOp,
136        /// Integer value to compare against (epoch seconds for
137        /// timestamp semantics).
138        value: i64,
139    },
140    /// Fused equality check on a JSON boolean property at the given path.
141    /// See [`Predicate::JsonPathFusedEq`] for the fusion contract.
142    /// The boolean is stored as `SQLite` integer 1/0.
143    JsonPathFusedBoolEq {
144        /// JSON path expression (e.g. `$.resolved`).
145        path: String,
146        /// Boolean value to compare against (stored as 1 or 0).
147        value: bool,
148    },
149    /// Equality check on a JSON property of the traversed edge at the given path.
150    ///
151    /// Structurally identical to [`Predicate::JsonPathEq`] but targets
152    /// `e.properties` on the edge row rather than `n.properties` on the
153    /// target node. Only valid inside an expansion slot's `edge_filter`.
154    EdgePropertyEq {
155        /// JSON path expression (e.g. `$.rel`).
156        path: String,
157        /// Value to compare against.
158        value: ScalarValue,
159    },
160    /// Ordered comparison on a JSON property of the traversed edge at the given path.
161    ///
162    /// Structurally identical to [`Predicate::JsonPathCompare`] but targets
163    /// `e.properties` on the edge row rather than `n.properties` on the
164    /// target node. Only valid inside an expansion slot's `edge_filter`.
165    EdgePropertyCompare {
166        /// JSON path expression.
167        path: String,
168        /// Comparison operator.
169        op: ComparisonOp,
170        /// Value to compare against.
171        value: ScalarValue,
172    },
173    /// Fused IN-set check on a JSON text property at the given path.
174    ///
175    /// Like [`Predicate::JsonPathFusedEq`], this variant is classified as
176    /// **fusable** and is pushed into the search CTE's inner `WHERE` clause.
177    /// The caller must have a registered FTS property schema for the path.
178    JsonPathFusedIn {
179        /// JSON path expression (e.g. `$.status`).
180        path: String,
181        /// Non-empty set of text values; the node must match at least one.
182        values: Vec<String>,
183    },
184    /// IN-set check on a JSON property at the given path.
185    ///
186    /// Unlike [`Predicate::JsonPathFusedIn`], this variant is **not** fusable
187    /// and is applied as a residual WHERE clause on the Nodes driver scan.
188    JsonPathIn {
189        /// JSON path expression (e.g. `$.category`).
190        path: String,
191        /// Non-empty set of values; the node must match at least one.
192        values: Vec<ScalarValue>,
193    },
194}
195
196/// Ordered comparison operator for JSON property filters.
197#[derive(Clone, Copy, Debug, PartialEq, Eq)]
198pub enum ComparisonOp {
199    /// Greater than.
200    Gt,
201    /// Greater than or equal.
202    Gte,
203    /// Less than.
204    Lt,
205    /// Less than or equal.
206    Lte,
207}
208
209/// A typed scalar value used in query predicates.
210#[derive(Clone, Debug, PartialEq, Eq)]
211pub enum ScalarValue {
212    /// A UTF-8 text value.
213    Text(String),
214    /// A 64-bit signed integer.
215    Integer(i64),
216    /// A boolean value.
217    Bool(bool),
218}
219
220/// Direction for graph traversal steps and expansion slots.
221#[derive(Clone, Copy, Debug, PartialEq, Eq)]
222pub enum TraverseDirection {
223    /// Follow edges pointing toward the current node.
224    In,
225    /// Follow edges pointing away from the current node.
226    Out,
227}