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}