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