Skip to main content

lora_analyzer/
resolved.rs

1use crate::{analyzer::FunctionId, symbols::*};
2use lora_ast::{
3    BinaryOp, Direction, ListPredicateKind, RangeLiteral, SortDirection, Span, UnaryOp,
4};
5
6#[derive(Debug, Clone)]
7pub struct ResolvedQuery {
8    pub clauses: Vec<ResolvedClause>,
9    /// Additional UNION branches. Each branch is a separate resolved query
10    /// that produces rows to be combined with the head query's results.
11    pub unions: Vec<ResolvedUnionPart>,
12}
13
14#[derive(Debug, Clone)]
15pub struct ResolvedUnionPart {
16    /// If true, this is UNION ALL (no deduplication). If false, plain UNION (deduplicate).
17    pub all: bool,
18    /// The resolved clauses for this branch.
19    pub clauses: Vec<ResolvedClause>,
20}
21
22#[derive(Debug, Clone)]
23pub enum ResolvedClause {
24    Match(ResolvedMatch),
25    Unwind(ResolvedUnwind),
26    Create(ResolvedCreate),
27    Merge(ResolvedMerge),
28    Delete(ResolvedDelete),
29    Set(ResolvedSet),
30    Remove(ResolvedRemove),
31    Foreach(ResolvedForeach),
32    Return(ResolvedReturn),
33    With(ResolvedWith),
34    CallSubquery(ResolvedCallSubquery),
35}
36
37/// `CALL { ... }` subquery body. The inner clause list reads from
38/// the outer scope (variables visible at the call site are still
39/// visible inside the subquery), runs once per outer row, and
40/// projects the variables named in its final RETURN back into the
41/// outer scope.
42#[derive(Debug, Clone)]
43pub struct ResolvedCallSubquery {
44    pub clauses: Vec<ResolvedClause>,
45    /// VarIds produced by the inner final RETURN that become
46    /// available in the outer scope after the CALL.
47    pub return_vars: Vec<VarId>,
48}
49
50#[derive(Debug, Clone)]
51pub struct ResolvedMatch {
52    pub optional: bool,
53    pub pattern: ResolvedPattern,
54    pub where_: Option<ResolvedExpr>,
55}
56
57#[derive(Debug, Clone)]
58pub struct ResolvedUnwind {
59    pub expr: ResolvedExpr,
60    pub alias: VarId,
61}
62
63#[derive(Debug, Clone)]
64pub struct ResolvedCreate {
65    pub pattern: ResolvedPattern,
66}
67
68#[derive(Debug, Clone)]
69pub struct ResolvedMerge {
70    pub pattern_part: ResolvedPatternPart,
71    pub actions: Vec<ResolvedMergeAction>,
72}
73
74#[derive(Debug, Clone)]
75pub struct ResolvedMergeAction {
76    pub on_match: bool,
77    pub set: ResolvedSet,
78}
79
80#[derive(Debug, Clone)]
81pub struct ResolvedDelete {
82    pub detach: bool,
83    pub expressions: Vec<ResolvedExpr>,
84}
85
86#[derive(Debug, Clone)]
87pub struct ResolvedSet {
88    pub items: Vec<ResolvedSetItem>,
89}
90
91#[derive(Debug, Clone)]
92pub enum ResolvedSetItem {
93    SetProperty {
94        target: ResolvedExpr,
95        value: ResolvedExpr,
96    },
97    SetVariable {
98        variable: VarId,
99        value: ResolvedExpr,
100    },
101    MutateVariable {
102        variable: VarId,
103        value: ResolvedExpr,
104    },
105    SetLabels {
106        variable: VarId,
107        labels: Vec<String>,
108    },
109}
110
111#[derive(Debug, Clone)]
112pub struct ResolvedRemove {
113    pub items: Vec<ResolvedRemoveItem>,
114}
115
116/// `FOREACH (var IN list | body...)`. The body is restricted to
117/// updating clauses (Create / Merge / Delete / Set / Remove / nested
118/// Foreach). The analyzer enforces that restriction; the planner /
119/// executor treat each body item as a side-effect-only operation
120/// applied row-by-row inside the iteration.
121#[derive(Debug, Clone)]
122pub struct ResolvedForeach {
123    pub variable: VarId,
124    pub list: ResolvedExpr,
125    pub body: Vec<ResolvedClause>,
126}
127
128#[derive(Debug, Clone)]
129pub enum ResolvedRemoveItem {
130    Labels {
131        variable: VarId,
132        labels: Vec<String>,
133    },
134    Property {
135        expr: ResolvedExpr,
136    },
137}
138
139#[derive(Debug, Clone)]
140pub struct ResolvedReturn {
141    pub distinct: bool,
142    pub items: Vec<ResolvedProjection>,
143    pub include_existing: bool,
144    pub order: Vec<ResolvedSortItem>,
145    pub skip: Option<ResolvedExpr>,
146    pub limit: Option<ResolvedExpr>,
147}
148
149#[derive(Debug, Clone)]
150pub struct ResolvedWith {
151    pub distinct: bool,
152    pub items: Vec<ResolvedProjection>,
153    pub include_existing: bool,
154    pub order: Vec<ResolvedSortItem>,
155    pub skip: Option<ResolvedExpr>,
156    pub limit: Option<ResolvedExpr>,
157    pub where_: Option<ResolvedExpr>,
158}
159
160#[derive(Debug, Clone)]
161pub struct ResolvedProjection {
162    pub expr: ResolvedExpr,
163    pub output: VarId,
164    /// Output column name. `Arc<str>` because executors stamp it onto
165    /// every produced row; cloning it per row is a refcount bump rather
166    /// than a heap allocation per cell.
167    pub name: std::sync::Arc<str>,
168    /// True when the name came from an explicit `AS` alias.
169    pub explicit_alias: bool,
170    pub span: Span,
171}
172
173#[derive(Debug, Clone)]
174pub struct ResolvedSortItem {
175    pub expr: ResolvedExpr,
176    pub direction: SortDirection,
177}
178
179#[derive(Debug, Clone)]
180pub struct ResolvedPattern {
181    pub parts: Vec<ResolvedPatternPart>,
182}
183
184#[derive(Debug, Clone)]
185pub struct ResolvedPatternPart {
186    pub binding: Option<VarId>,
187    pub element: ResolvedPatternElement,
188}
189
190#[derive(Debug, Clone)]
191pub enum ResolvedPatternElement {
192    Node {
193        var: Option<VarId>,
194        /// Each inner Vec is a disjunctive group (OR). Outer Vec is conjunctive (AND).
195        labels: Vec<Vec<String>>,
196        properties: Option<ResolvedExpr>,
197    },
198    NodeChain {
199        head: ResolvedNode,
200        chain: Vec<ResolvedChain>,
201    },
202    ShortestPath {
203        all: bool,
204        head: ResolvedNode,
205        chain: Vec<ResolvedChain>,
206    },
207}
208
209#[derive(Debug, Clone)]
210pub struct ResolvedNode {
211    pub var: Option<VarId>,
212    /// Each inner Vec is a disjunctive group (OR). Outer Vec is conjunctive (AND).
213    pub labels: Vec<Vec<String>>,
214    pub properties: Option<ResolvedExpr>,
215}
216
217#[derive(Debug, Clone)]
218pub struct ResolvedChain {
219    pub rel: ResolvedRel,
220    pub node: ResolvedNode,
221}
222
223#[derive(Debug, Clone)]
224pub struct ResolvedRel {
225    pub var: Option<VarId>,
226    pub types: Vec<String>,
227    pub direction: Direction,
228    pub range: Option<RangeLiteral>,
229    pub properties: Option<ResolvedExpr>,
230}
231
232#[derive(Debug, Clone)]
233pub enum ResolvedExpr {
234    Variable(VarId),
235    Literal(LiteralValue),
236    Property {
237        expr: Box<ResolvedExpr>,
238        property: String,
239    },
240    Binary {
241        lhs: Box<ResolvedExpr>,
242        op: BinaryOp,
243        rhs: Box<ResolvedExpr>,
244    },
245    Unary {
246        op: UnaryOp,
247        expr: Box<ResolvedExpr>,
248    },
249    Function {
250        function: FunctionId,
251        distinct: bool,
252        args: Vec<ResolvedExpr>,
253    },
254    List(Vec<ResolvedExpr>),
255    Map(Vec<(String, ResolvedExpr)>),
256    Case {
257        input: Option<Box<ResolvedExpr>>,
258        alternatives: Vec<(ResolvedExpr, ResolvedExpr)>,
259        else_expr: Option<Box<ResolvedExpr>>,
260    },
261    Parameter(String),
262    ListPredicate {
263        kind: ListPredicateKind,
264        variable: VarId,
265        list: Box<ResolvedExpr>,
266        predicate: Box<ResolvedExpr>,
267    },
268    ListComprehension {
269        variable: VarId,
270        list: Box<ResolvedExpr>,
271        filter: Option<Box<ResolvedExpr>>,
272        map_expr: Option<Box<ResolvedExpr>>,
273    },
274    Reduce {
275        accumulator: VarId,
276        init: Box<ResolvedExpr>,
277        variable: VarId,
278        list: Box<ResolvedExpr>,
279        expr: Box<ResolvedExpr>,
280    },
281    MapProjection {
282        base: Box<ResolvedExpr>,
283        selectors: Vec<ResolvedMapSelector>,
284    },
285    Index {
286        expr: Box<ResolvedExpr>,
287        index: Box<ResolvedExpr>,
288    },
289    Slice {
290        expr: Box<ResolvedExpr>,
291        from: Option<Box<ResolvedExpr>>,
292        to: Option<Box<ResolvedExpr>>,
293    },
294    ExistsSubquery {
295        pattern: ResolvedPattern,
296        where_: Option<Box<ResolvedExpr>>,
297    },
298    PatternComprehension {
299        pattern: ResolvedPattern,
300        where_: Option<Box<ResolvedExpr>>,
301        map_expr: Box<ResolvedExpr>,
302    },
303}
304
305#[derive(Debug, Clone)]
306pub enum ResolvedMapSelector {
307    Property(String),
308    AllProperties,
309    Literal(String, ResolvedExpr),
310}
311
312#[derive(Debug, Clone, PartialEq)]
313pub enum LiteralValue {
314    Integer(i64),
315    Float(f64),
316    String(String),
317    TypeName(String),
318    Bool(bool),
319    Null,
320}