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}