Skip to main content

lora_compiler/
physical.rs

1use lora_analyzer::symbols::VarId;
2use lora_analyzer::{
3    ResolvedClause, ResolvedExpr, ResolvedMergeAction, ResolvedPattern, ResolvedPatternPart,
4    ResolvedProjection, ResolvedRemoveItem, ResolvedSetItem, ResolvedSortItem,
5};
6use lora_ast::{Direction, RangeLiteral};
7
8pub type PhysicalNodeId = usize;
9
10#[derive(Debug, Clone)]
11pub struct PhysicalPlan {
12    pub root: PhysicalNodeId,
13    pub nodes: Vec<PhysicalOp>,
14}
15
16#[derive(Debug, Clone)]
17pub enum PhysicalOp {
18    Argument(ArgumentExec),
19    NodeScan(NodeScanExec),
20    NodeByLabelScan(NodeByLabelScanExec),
21    NodeByIdSeek(NodeByIdSeekExec),
22    NodeByPropertyScan(NodeByPropertyScanExec),
23    NodeByPropertyRangeScan(NodeByPropertyRangeScanExec),
24    NodeByTextScan(NodeByTextScanExec),
25    NodeByPointScan(NodeByPointScanExec),
26    RelByPropertyRangeScan(RelByPropertyRangeScanExec),
27    RelByTextScan(RelByTextScanExec),
28    RelByPointScan(RelByPointScanExec),
29    RelByIdSeek(RelByIdSeekExec),
30    Expand(ExpandExec),
31    Filter(FilterExec),
32    Projection(ProjectionExec),
33    Unwind(UnwindExec),
34    HashAggregation(HashAggregationExec),
35    Sort(SortExec),
36    Limit(LimitExec),
37    Create(CreateExec),
38    Merge(MergeExec),
39    Delete(DeleteExec),
40    Set(SetExec),
41    Remove(RemoveExec),
42    Foreach(ForeachExec),
43    OptionalMatch(OptionalMatchExec),
44    PathBuild(PathBuildExec),
45    CallSubquery(CallSubqueryExec),
46}
47
48/// See [`crate::logical::Foreach`].
49#[derive(Debug, Clone)]
50pub struct ForeachExec {
51    pub input: PhysicalNodeId,
52    pub variable: VarId,
53    pub list: ResolvedExpr,
54    pub body: Vec<ResolvedClause>,
55}
56
57/// `CALL { ... }` subquery executor node. See [`crate::logical::CallSubquery`].
58#[derive(Debug, Clone)]
59pub struct CallSubqueryExec {
60    pub input: PhysicalNodeId,
61    pub inner: PhysicalNodeId,
62    pub new_vars: Vec<VarId>,
63}
64
65#[derive(Debug, Clone)]
66pub struct PathBuildExec {
67    pub input: PhysicalNodeId,
68    pub output: VarId,
69    pub node_vars: Vec<VarId>,
70    pub rel_vars: Vec<VarId>,
71    pub shortest_path_all: Option<bool>,
72}
73
74/// Left-outer-join: for each input row, runs inner sub-plan.
75/// If inner produces nothing, emits one row with nulls for new_vars.
76#[derive(Debug, Clone)]
77pub struct OptionalMatchExec {
78    pub input: PhysicalNodeId,
79    pub inner: PhysicalNodeId,
80    pub new_vars: Vec<VarId>,
81}
82
83#[derive(Debug, Clone)]
84pub struct ArgumentExec;
85
86#[derive(Debug, Clone)]
87pub struct NodeScanExec {
88    pub input: Option<PhysicalNodeId>,
89    pub var: VarId,
90}
91
92#[derive(Debug, Clone)]
93pub struct NodeByLabelScanExec {
94    pub input: Option<PhysicalNodeId>,
95    pub var: VarId,
96    /// Each inner Vec is a disjunctive group (OR). Outer Vec is conjunctive (AND).
97    pub labels: Vec<Vec<String>>,
98}
99
100/// See [`crate::logical::NodeByIdSeek`].
101#[derive(Debug, Clone)]
102pub struct NodeByIdSeekExec {
103    pub input: Option<PhysicalNodeId>,
104    pub var: VarId,
105    pub labels: Vec<Vec<String>>,
106    pub ids: ResolvedExpr,
107    pub in_list: bool,
108}
109
110#[derive(Debug, Clone)]
111pub struct NodeByPropertyScanExec {
112    pub input: Option<PhysicalNodeId>,
113    pub var: VarId,
114    /// Each inner Vec is a disjunctive group (OR). Outer Vec is conjunctive (AND).
115    pub labels: Vec<Vec<String>>,
116    pub key: String,
117    pub value: ResolvedExpr,
118    /// `true` when `value` is a list and the scan seeks `key IN value`
119    /// (one index lookup per distinct element) instead of `key = value`.
120    pub in_list: bool,
121}
122
123#[derive(Debug, Clone)]
124pub struct NodeByPropertyRangeScanExec {
125    pub input: Option<PhysicalNodeId>,
126    pub var: VarId,
127    pub labels: Vec<Vec<String>>,
128    pub key: String,
129    pub lo: Option<ResolvedExpr>,
130    pub lo_inclusive: bool,
131    pub hi: Option<ResolvedExpr>,
132    pub hi_inclusive: bool,
133    /// Set when the optimizer replaced an `ORDER BY var.key` above this
134    /// scan: rows must come out in that order (from the index when it can
135    /// supply it, otherwise sorted by the operator itself).
136    pub order: Option<lora_ast::SortDirection>,
137}
138
139#[derive(Debug, Clone)]
140pub struct NodeByTextScanExec {
141    pub input: Option<PhysicalNodeId>,
142    pub var: VarId,
143    pub labels: Vec<Vec<String>>,
144    pub key: String,
145    pub predicate: crate::logical::TextPredicate,
146    pub query: ResolvedExpr,
147}
148
149#[derive(Debug, Clone)]
150pub struct NodeByPointScanExec {
151    pub input: Option<PhysicalNodeId>,
152    pub var: VarId,
153    pub labels: Vec<Vec<String>>,
154    pub key: String,
155    pub predicate: crate::logical::PointPredicate,
156}
157
158#[derive(Debug, Clone)]
159pub struct RelByPropertyRangeScanExec {
160    pub input: Option<PhysicalNodeId>,
161    pub src: VarId,
162    pub rel: VarId,
163    pub dst: VarId,
164    pub types: Vec<String>,
165    pub direction: Direction,
166    pub key: String,
167    pub lo: Option<ResolvedExpr>,
168    pub lo_inclusive: bool,
169    pub hi: Option<ResolvedExpr>,
170    pub hi_inclusive: bool,
171}
172
173#[derive(Debug, Clone)]
174pub struct RelByTextScanExec {
175    pub input: Option<PhysicalNodeId>,
176    pub src: VarId,
177    pub rel: VarId,
178    pub dst: VarId,
179    pub types: Vec<String>,
180    pub direction: Direction,
181    pub key: String,
182    pub predicate: crate::logical::TextPredicate,
183    pub query: ResolvedExpr,
184}
185
186#[derive(Debug, Clone)]
187pub struct RelByPointScanExec {
188    pub input: Option<PhysicalNodeId>,
189    pub src: VarId,
190    pub rel: VarId,
191    pub dst: VarId,
192    pub types: Vec<String>,
193    pub direction: Direction,
194    pub key: String,
195    pub predicate: crate::logical::PointPredicate,
196}
197
198/// See [`crate::logical::RelByIdSeek`].
199#[derive(Debug, Clone)]
200pub struct RelByIdSeekExec {
201    pub input: Option<PhysicalNodeId>,
202    pub src: VarId,
203    pub src_labels: Vec<Vec<String>>,
204    pub rel: VarId,
205    pub dst: VarId,
206    pub types: Vec<String>,
207    pub direction: Direction,
208    pub ids: ResolvedExpr,
209    pub in_list: bool,
210}
211
212#[derive(Debug, Clone)]
213pub struct ExpandExec {
214    pub input: PhysicalNodeId,
215    pub src: VarId,
216    pub rel: Option<VarId>,
217    pub dst: VarId,
218    pub types: Vec<String>,
219    pub direction: Direction,
220    pub rel_properties: Option<ResolvedExpr>,
221    pub range: Option<RangeLiteral>,
222}
223
224#[derive(Debug, Clone)]
225pub struct FilterExec {
226    pub input: PhysicalNodeId,
227    pub predicate: ResolvedExpr,
228}
229
230#[derive(Debug, Clone)]
231pub struct ProjectionExec {
232    pub input: PhysicalNodeId,
233    pub distinct: bool,
234    pub items: Vec<ResolvedProjection>,
235    pub include_existing: bool,
236}
237
238#[derive(Debug, Clone)]
239pub struct UnwindExec {
240    pub input: PhysicalNodeId,
241    pub expr: ResolvedExpr,
242    pub alias: VarId,
243}
244
245#[derive(Debug, Clone)]
246pub struct HashAggregationExec {
247    pub input: PhysicalNodeId,
248    pub group_by: Vec<ResolvedProjection>,
249    pub aggregates: Vec<ResolvedProjection>,
250}
251
252#[derive(Debug, Clone)]
253pub struct SortExec {
254    pub input: PhysicalNodeId,
255    pub items: Vec<ResolvedSortItem>,
256    /// Optional upper bound for rows Sort must retain before a parent LIMIT.
257    pub top_k: Option<usize>,
258    /// Run-time bound from a parent `LIMIT $n` (see
259    /// [`crate::logical::Sort::limit`]).
260    pub limit: Option<crate::logical::SortLimit>,
261}
262
263#[derive(Debug, Clone)]
264pub struct LimitExec {
265    pub input: PhysicalNodeId,
266    pub skip: Option<ResolvedExpr>,
267    pub limit: Option<ResolvedExpr>,
268}
269
270#[derive(Debug, Clone)]
271pub struct CreateExec {
272    pub input: PhysicalNodeId,
273    pub pattern: ResolvedPattern,
274}
275
276#[derive(Debug, Clone)]
277pub struct MergeExec {
278    pub input: PhysicalNodeId,
279    pub pattern_part: ResolvedPatternPart,
280    pub actions: Vec<ResolvedMergeAction>,
281}
282
283#[derive(Debug, Clone)]
284pub struct DeleteExec {
285    pub input: PhysicalNodeId,
286    pub detach: bool,
287    pub expressions: Vec<ResolvedExpr>,
288}
289
290#[derive(Debug, Clone)]
291pub struct SetExec {
292    pub input: PhysicalNodeId,
293    pub items: Vec<ResolvedSetItem>,
294}
295
296#[derive(Debug, Clone)]
297pub struct RemoveExec {
298    pub input: PhysicalNodeId,
299    pub items: Vec<ResolvedRemoveItem>,
300}