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