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}
32
33/// A single step in the query pipeline.
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub enum QueryStep {
36    /// Unified adaptive retrieval entry step consumed by the Phase 12
37    /// retrieval planner.
38    ///
39    /// Carries the caller's raw query string (not a parsed [`TextQuery`]):
40    /// the planner decides how to interpret and route it across the text
41    /// strict, text relaxed, and (future) vector branches. See
42    /// `crate::compile_retrieval_plan` for the planner entry point.
43    Search {
44        /// The raw caller-supplied query string.
45        query: String,
46        /// Maximum number of candidate rows requested by the caller.
47        limit: usize,
48    },
49    /// Nearest-neighbor search over vector embeddings.
50    VectorSearch {
51        /// The search query text (to be embedded by the caller).
52        query: String,
53        /// Maximum number of candidate rows from the vector index.
54        limit: usize,
55    },
56    /// Full-text search over indexed chunk content using `FathomDB`'s supported
57    /// safe text-query subset.
58    TextSearch {
59        /// Parsed text-search intent to be lowered into safe FTS5 syntax.
60        query: TextQuery,
61        /// Maximum number of candidate rows from the FTS index.
62        limit: usize,
63    },
64    /// Graph traversal following edges of the given label.
65    Traverse {
66        /// Direction to traverse.
67        direction: TraverseDirection,
68        /// Edge kind to follow.
69        label: String,
70        /// Maximum hops from each candidate.
71        max_depth: usize,
72        /// Optional predicate to filter traversal results.
73        /// `None` is exactly equivalent to the pre-Pack-2 behavior.
74        /// `Some(_)` is not yet implemented; see Pack 3.
75        filter: Option<Predicate>,
76    },
77    /// Row-level filter predicate.
78    Filter(Predicate),
79}
80
81/// A filter predicate applied to candidate nodes.
82#[derive(Clone, Debug, PartialEq, Eq)]
83pub enum Predicate {
84    /// Match nodes with the exact logical ID.
85    LogicalIdEq(String),
86    /// Match nodes with the exact kind.
87    KindEq(String),
88    /// Equality check on a JSON property at the given path.
89    JsonPathEq {
90        /// JSON path expression (e.g. `$.status`).
91        path: String,
92        /// Value to compare against.
93        value: ScalarValue,
94    },
95    /// Ordered comparison on a JSON property at the given path.
96    JsonPathCompare {
97        /// JSON path expression.
98        path: String,
99        /// Comparison operator.
100        op: ComparisonOp,
101        /// Value to compare against.
102        value: ScalarValue,
103    },
104    /// Match nodes with the exact `source_ref`.
105    SourceRefEq(String),
106    /// Match nodes where `content_ref` is not NULL (i.e. content proxy nodes).
107    ContentRefNotNull,
108    /// Match nodes with the exact `content_ref` URI.
109    ContentRefEq(String),
110    /// Fused equality check on a JSON text property at the given path.
111    ///
112    /// Unlike [`Predicate::JsonPathEq`], this variant is classified as
113    /// **fusable** by [`crate::fusion::is_fusable`] and is pushed into
114    /// the search CTE's inner `WHERE` clause so the CTE `LIMIT` applies
115    /// after the predicate runs. The caller opts into fusion by
116    /// registering an FTS property schema that covers the path; the
117    /// tethered builder enforces that gate at filter-add time.
118    JsonPathFusedEq {
119        /// JSON path expression (e.g. `$.status`).
120        path: String,
121        /// Text value to compare against.
122        value: String,
123    },
124    /// Fused ordered comparison on a JSON integer/timestamp property at
125    /// the given path. See [`Predicate::JsonPathFusedEq`] for the fusion
126    /// contract.
127    JsonPathFusedTimestampCmp {
128        /// JSON path expression.
129        path: String,
130        /// Comparison operator.
131        op: ComparisonOp,
132        /// Integer value to compare against (epoch seconds for
133        /// timestamp semantics).
134        value: i64,
135    },
136}
137
138/// Ordered comparison operator for JSON property filters.
139#[derive(Clone, Copy, Debug, PartialEq, Eq)]
140pub enum ComparisonOp {
141    /// Greater than.
142    Gt,
143    /// Greater than or equal.
144    Gte,
145    /// Less than.
146    Lt,
147    /// Less than or equal.
148    Lte,
149}
150
151/// A typed scalar value used in query predicates.
152#[derive(Clone, Debug, PartialEq, Eq)]
153pub enum ScalarValue {
154    /// A UTF-8 text value.
155    Text(String),
156    /// A 64-bit signed integer.
157    Integer(i64),
158    /// A boolean value.
159    Bool(bool),
160}
161
162/// Direction for graph traversal steps and expansion slots.
163#[derive(Clone, Copy, Debug, PartialEq, Eq)]
164pub enum TraverseDirection {
165    /// Follow edges pointing toward the current node.
166    In,
167    /// Follow edges pointing away from the current node.
168    Out,
169}