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