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    pub name: String,
165    /// True when the name came from an explicit `AS` alias.
166    pub explicit_alias: bool,
167    pub span: Span,
168}
169
170#[derive(Debug, Clone)]
171pub struct ResolvedSortItem {
172    pub expr: ResolvedExpr,
173    pub direction: SortDirection,
174}
175
176#[derive(Debug, Clone)]
177pub struct ResolvedPattern {
178    pub parts: Vec<ResolvedPatternPart>,
179}
180
181#[derive(Debug, Clone)]
182pub struct ResolvedPatternPart {
183    pub binding: Option<VarId>,
184    pub element: ResolvedPatternElement,
185}
186
187#[derive(Debug, Clone)]
188pub enum ResolvedPatternElement {
189    Node {
190        var: Option<VarId>,
191        /// Each inner Vec is a disjunctive group (OR). Outer Vec is conjunctive (AND).
192        labels: Vec<Vec<String>>,
193        properties: Option<ResolvedExpr>,
194    },
195    NodeChain {
196        head: ResolvedNode,
197        chain: Vec<ResolvedChain>,
198    },
199    ShortestPath {
200        all: bool,
201        head: ResolvedNode,
202        chain: Vec<ResolvedChain>,
203    },
204}
205
206#[derive(Debug, Clone)]
207pub struct ResolvedNode {
208    pub var: Option<VarId>,
209    /// Each inner Vec is a disjunctive group (OR). Outer Vec is conjunctive (AND).
210    pub labels: Vec<Vec<String>>,
211    pub properties: Option<ResolvedExpr>,
212}
213
214#[derive(Debug, Clone)]
215pub struct ResolvedChain {
216    pub rel: ResolvedRel,
217    pub node: ResolvedNode,
218}
219
220#[derive(Debug, Clone)]
221pub struct ResolvedRel {
222    pub var: Option<VarId>,
223    pub types: Vec<String>,
224    pub direction: Direction,
225    pub range: Option<RangeLiteral>,
226    pub properties: Option<ResolvedExpr>,
227}
228
229#[derive(Debug, Clone)]
230pub enum ResolvedExpr {
231    Variable(VarId),
232    Literal(LiteralValue),
233    Property {
234        expr: Box<ResolvedExpr>,
235        property: String,
236    },
237    Binary {
238        lhs: Box<ResolvedExpr>,
239        op: BinaryOp,
240        rhs: Box<ResolvedExpr>,
241    },
242    Unary {
243        op: UnaryOp,
244        expr: Box<ResolvedExpr>,
245    },
246    Function {
247        function: FunctionId,
248        distinct: bool,
249        args: Vec<ResolvedExpr>,
250    },
251    List(Vec<ResolvedExpr>),
252    Map(Vec<(String, ResolvedExpr)>),
253    Case {
254        input: Option<Box<ResolvedExpr>>,
255        alternatives: Vec<(ResolvedExpr, ResolvedExpr)>,
256        else_expr: Option<Box<ResolvedExpr>>,
257    },
258    Parameter(String),
259    ListPredicate {
260        kind: ListPredicateKind,
261        variable: VarId,
262        list: Box<ResolvedExpr>,
263        predicate: Box<ResolvedExpr>,
264    },
265    ListComprehension {
266        variable: VarId,
267        list: Box<ResolvedExpr>,
268        filter: Option<Box<ResolvedExpr>>,
269        map_expr: Option<Box<ResolvedExpr>>,
270    },
271    Reduce {
272        accumulator: VarId,
273        init: Box<ResolvedExpr>,
274        variable: VarId,
275        list: Box<ResolvedExpr>,
276        expr: Box<ResolvedExpr>,
277    },
278    MapProjection {
279        base: Box<ResolvedExpr>,
280        selectors: Vec<ResolvedMapSelector>,
281    },
282    Index {
283        expr: Box<ResolvedExpr>,
284        index: Box<ResolvedExpr>,
285    },
286    Slice {
287        expr: Box<ResolvedExpr>,
288        from: Option<Box<ResolvedExpr>>,
289        to: Option<Box<ResolvedExpr>>,
290    },
291    ExistsSubquery {
292        pattern: ResolvedPattern,
293        where_: Option<Box<ResolvedExpr>>,
294    },
295    PatternComprehension {
296        pattern: ResolvedPattern,
297        where_: Option<Box<ResolvedExpr>>,
298        map_expr: Box<ResolvedExpr>,
299    },
300}
301
302#[derive(Debug, Clone)]
303pub enum ResolvedMapSelector {
304    Property(String),
305    AllProperties,
306    Literal(String, ResolvedExpr),
307}
308
309#[derive(Debug, Clone, PartialEq)]
310pub enum LiteralValue {
311    Integer(i64),
312    Float(f64),
313    String(String),
314    TypeName(String),
315    Bool(bool),
316    Null,
317}