1use std::collections::BTreeSet;
2
3use crate::{analyzer::FunctionId, symbols::*};
4use lora_ast::{
5 BinaryOp, Direction, ListPredicateKind, RangeLiteral, SortDirection, Span, UnaryOp,
6};
7
8#[derive(Debug, Clone)]
9pub struct ResolvedQuery {
10 pub clauses: Vec<ResolvedClause>,
11 pub parameters: BTreeSet<String>,
14 pub unions: Vec<ResolvedUnionPart>,
17}
18
19#[derive(Debug, Clone)]
20pub struct ResolvedUnionPart {
21 pub all: bool,
23 pub clauses: Vec<ResolvedClause>,
25}
26
27#[derive(Debug, Clone)]
28pub enum ResolvedClause {
29 Match(ResolvedMatch),
30 Unwind(ResolvedUnwind),
31 Create(ResolvedCreate),
32 Merge(ResolvedMerge),
33 Delete(ResolvedDelete),
34 Set(ResolvedSet),
35 Remove(ResolvedRemove),
36 Foreach(ResolvedForeach),
37 Return(ResolvedReturn),
38 With(ResolvedWith),
39 CallSubquery(ResolvedCallSubquery),
40}
41
42#[derive(Debug, Clone)]
48pub struct ResolvedCallSubquery {
49 pub clauses: Vec<ResolvedClause>,
50 pub return_vars: Vec<VarId>,
53}
54
55#[derive(Debug, Clone)]
56pub struct ResolvedMatch {
57 pub optional: bool,
58 pub pattern: ResolvedPattern,
59 pub where_: Option<ResolvedExpr>,
60}
61
62#[derive(Debug, Clone)]
63pub struct ResolvedUnwind {
64 pub expr: ResolvedExpr,
65 pub alias: VarId,
66}
67
68#[derive(Debug, Clone)]
69pub struct ResolvedCreate {
70 pub pattern: ResolvedPattern,
71}
72
73#[derive(Debug, Clone)]
74pub struct ResolvedMerge {
75 pub pattern_part: ResolvedPatternPart,
76 pub actions: Vec<ResolvedMergeAction>,
77}
78
79#[derive(Debug, Clone)]
80pub struct ResolvedMergeAction {
81 pub on_match: bool,
82 pub set: ResolvedSet,
83}
84
85#[derive(Debug, Clone)]
86pub struct ResolvedDelete {
87 pub detach: bool,
88 pub expressions: Vec<ResolvedExpr>,
89}
90
91#[derive(Debug, Clone)]
92pub struct ResolvedSet {
93 pub items: Vec<ResolvedSetItem>,
94}
95
96#[derive(Debug, Clone)]
97pub enum ResolvedSetItem {
98 SetProperty {
99 target: ResolvedExpr,
100 value: ResolvedExpr,
101 },
102 SetVariable {
103 variable: VarId,
104 value: ResolvedExpr,
105 },
106 MutateVariable {
107 variable: VarId,
108 value: ResolvedExpr,
109 },
110 SetLabels {
111 variable: VarId,
112 labels: Vec<String>,
113 },
114}
115
116#[derive(Debug, Clone)]
117pub struct ResolvedRemove {
118 pub items: Vec<ResolvedRemoveItem>,
119}
120
121#[derive(Debug, Clone)]
127pub struct ResolvedForeach {
128 pub variable: VarId,
129 pub list: ResolvedExpr,
130 pub body: Vec<ResolvedClause>,
131}
132
133#[derive(Debug, Clone)]
134pub enum ResolvedRemoveItem {
135 Labels {
136 variable: VarId,
137 labels: Vec<String>,
138 },
139 Property {
140 expr: ResolvedExpr,
141 },
142}
143
144#[derive(Debug, Clone)]
145pub struct ResolvedReturn {
146 pub distinct: bool,
147 pub items: Vec<ResolvedProjection>,
148 pub lifted_aggregates: Vec<ResolvedProjection>,
153 pub include_existing: bool,
154 pub order: Vec<ResolvedSortItem>,
155 pub skip: Option<ResolvedExpr>,
156 pub limit: Option<ResolvedExpr>,
157}
158
159#[derive(Debug, Clone)]
160pub struct ResolvedWith {
161 pub distinct: bool,
162 pub items: Vec<ResolvedProjection>,
163 pub lifted_aggregates: Vec<ResolvedProjection>,
168 pub include_existing: bool,
169 pub order: Vec<ResolvedSortItem>,
170 pub skip: Option<ResolvedExpr>,
171 pub limit: Option<ResolvedExpr>,
172 pub where_: Option<ResolvedExpr>,
173}
174
175#[derive(Debug, Clone)]
176pub struct ResolvedProjection {
177 pub expr: ResolvedExpr,
178 pub output: VarId,
179 pub name: std::sync::Arc<str>,
183 pub explicit_alias: bool,
185 pub span: Span,
186}
187
188#[derive(Debug, Clone)]
189pub struct ResolvedSortItem {
190 pub expr: ResolvedExpr,
191 pub direction: SortDirection,
192}
193
194#[derive(Debug, Clone)]
195pub struct ResolvedPattern {
196 pub parts: Vec<ResolvedPatternPart>,
197}
198
199#[derive(Debug, Clone)]
200pub struct ResolvedPatternPart {
201 pub binding: Option<VarId>,
202 pub element: ResolvedPatternElement,
203}
204
205#[derive(Debug, Clone)]
206pub enum ResolvedPatternElement {
207 Node {
208 var: Option<VarId>,
209 labels: Vec<Vec<String>>,
211 properties: Option<ResolvedExpr>,
212 },
213 NodeChain {
214 head: ResolvedNode,
215 chain: Vec<ResolvedChain>,
216 },
217 ShortestPath {
218 all: bool,
219 head: ResolvedNode,
220 chain: Vec<ResolvedChain>,
221 },
222}
223
224#[derive(Debug, Clone)]
225pub struct ResolvedNode {
226 pub var: Option<VarId>,
227 pub labels: Vec<Vec<String>>,
229 pub properties: Option<ResolvedExpr>,
230}
231
232#[derive(Debug, Clone)]
233pub struct ResolvedChain {
234 pub rel: ResolvedRel,
235 pub node: ResolvedNode,
236}
237
238#[derive(Debug, Clone)]
239pub struct ResolvedRel {
240 pub var: Option<VarId>,
241 pub types: Vec<String>,
242 pub direction: Direction,
243 pub range: Option<RangeLiteral>,
244 pub properties: Option<ResolvedExpr>,
245}
246
247#[derive(Debug, Clone)]
248pub enum ResolvedExpr {
249 Variable(VarId),
250 Literal(LiteralValue),
251 Property {
252 expr: Box<ResolvedExpr>,
253 property: String,
254 },
255 Binary {
256 lhs: Box<ResolvedExpr>,
257 op: BinaryOp,
258 rhs: Box<ResolvedExpr>,
259 },
260 Unary {
261 op: UnaryOp,
262 expr: Box<ResolvedExpr>,
263 },
264 Function {
265 function: FunctionId,
266 distinct: bool,
267 args: Vec<ResolvedExpr>,
268 },
269 List(Vec<ResolvedExpr>),
270 Map(Vec<(String, ResolvedExpr)>),
271 Case {
272 input: Option<Box<ResolvedExpr>>,
273 alternatives: Vec<(ResolvedExpr, ResolvedExpr)>,
274 else_expr: Option<Box<ResolvedExpr>>,
275 },
276 Parameter(String),
277 ListPredicate {
278 kind: ListPredicateKind,
279 variable: VarId,
280 list: Box<ResolvedExpr>,
281 predicate: Box<ResolvedExpr>,
282 },
283 ListComprehension {
284 variable: VarId,
285 list: Box<ResolvedExpr>,
286 filter: Option<Box<ResolvedExpr>>,
287 map_expr: Option<Box<ResolvedExpr>>,
288 },
289 Reduce {
290 accumulator: VarId,
291 init: Box<ResolvedExpr>,
292 variable: VarId,
293 list: Box<ResolvedExpr>,
294 expr: Box<ResolvedExpr>,
295 },
296 MapProjection {
297 base: Box<ResolvedExpr>,
298 selectors: Vec<ResolvedMapSelector>,
299 },
300 Index {
301 expr: Box<ResolvedExpr>,
302 index: Box<ResolvedExpr>,
303 },
304 Slice {
305 expr: Box<ResolvedExpr>,
306 from: Option<Box<ResolvedExpr>>,
307 to: Option<Box<ResolvedExpr>>,
308 },
309 ExistsSubquery {
310 pattern: ResolvedPattern,
311 where_: Option<Box<ResolvedExpr>>,
312 reads: Vec<VarId>,
316 },
317 PatternComprehension {
318 pattern: ResolvedPattern,
319 where_: Option<Box<ResolvedExpr>>,
320 map_expr: Box<ResolvedExpr>,
321 reads: Vec<VarId>,
324 },
325}
326
327#[derive(Debug, Clone)]
328pub enum ResolvedMapSelector {
329 Property(String),
330 AllProperties,
331 Literal(String, ResolvedExpr),
332}
333
334#[derive(Debug, Clone, PartialEq)]
335pub enum LiteralValue {
336 Integer(i64),
337 Float(f64),
338 String(String),
339 TypeName(String),
340 Bool(bool),
341 Null,
342}
343
344impl ResolvedExpr {
345 pub fn collect_vars(&self, out: &mut BTreeSet<VarId>) {
351 let expr = self;
352 match expr {
353 ResolvedExpr::Variable(v) => {
354 out.insert(*v);
355 }
356 ResolvedExpr::Property { expr, .. } => ResolvedExpr::collect_vars(expr, out),
357 ResolvedExpr::Binary { lhs, rhs, .. } => {
358 ResolvedExpr::collect_vars(lhs, out);
359 ResolvedExpr::collect_vars(rhs, out);
360 }
361 ResolvedExpr::Unary { expr, .. } => ResolvedExpr::collect_vars(expr, out),
362 ResolvedExpr::Function { args, .. } => {
363 for arg in args {
364 ResolvedExpr::collect_vars(arg, out);
365 }
366 }
367 ResolvedExpr::List(items) => {
368 for item in items {
369 ResolvedExpr::collect_vars(item, out);
370 }
371 }
372 ResolvedExpr::Map(items) => {
373 for (_, v) in items {
374 ResolvedExpr::collect_vars(v, out);
375 }
376 }
377 ResolvedExpr::Case {
378 input,
379 alternatives,
380 else_expr,
381 } => {
382 if let Some(e) = input {
383 ResolvedExpr::collect_vars(e, out);
384 }
385 for (w, t) in alternatives {
386 ResolvedExpr::collect_vars(w, out);
387 ResolvedExpr::collect_vars(t, out);
388 }
389 if let Some(e) = else_expr {
390 ResolvedExpr::collect_vars(e, out);
391 }
392 }
393 ResolvedExpr::ListPredicate {
394 variable,
395 list,
396 predicate,
397 ..
398 } => {
399 out.insert(*variable);
400 ResolvedExpr::collect_vars(list, out);
401 ResolvedExpr::collect_vars(predicate, out);
402 }
403 ResolvedExpr::ListComprehension {
404 variable,
405 list,
406 filter,
407 map_expr,
408 ..
409 } => {
410 out.insert(*variable);
411 ResolvedExpr::collect_vars(list, out);
412 if let Some(f) = filter {
413 ResolvedExpr::collect_vars(f, out);
414 }
415 if let Some(m) = map_expr {
416 ResolvedExpr::collect_vars(m, out);
417 }
418 }
419 ResolvedExpr::Reduce {
420 accumulator,
421 init,
422 variable,
423 list,
424 expr,
425 ..
426 } => {
427 out.insert(*accumulator);
428 out.insert(*variable);
429 ResolvedExpr::collect_vars(init, out);
430 ResolvedExpr::collect_vars(list, out);
431 ResolvedExpr::collect_vars(expr, out);
432 }
433 ResolvedExpr::Index { expr, index } => {
434 ResolvedExpr::collect_vars(expr, out);
435 ResolvedExpr::collect_vars(index, out);
436 }
437 ResolvedExpr::Slice { expr, from, to } => {
438 ResolvedExpr::collect_vars(expr, out);
439 if let Some(f) = from {
440 ResolvedExpr::collect_vars(f, out);
441 }
442 if let Some(t) = to {
443 ResolvedExpr::collect_vars(t, out);
444 }
445 }
446 ResolvedExpr::MapProjection { base, selectors } => {
447 ResolvedExpr::collect_vars(base, out);
448 for sel in selectors {
449 if let ResolvedMapSelector::Literal(_, e) = sel {
450 ResolvedExpr::collect_vars(e, out);
451 }
452 }
453 }
454 ResolvedExpr::ExistsSubquery {
458 pattern, where_, ..
459 } => {
460 pattern.collect_vars(out);
461 if let Some(w) = where_ {
462 ResolvedExpr::collect_vars(w, out);
463 }
464 }
465 ResolvedExpr::PatternComprehension {
466 pattern,
467 where_,
468 map_expr,
469 ..
470 } => {
471 pattern.collect_vars(out);
472 if let Some(w) = where_ {
473 ResolvedExpr::collect_vars(w, out);
474 }
475 ResolvedExpr::collect_vars(map_expr, out);
476 }
477 ResolvedExpr::Literal(_) | ResolvedExpr::Parameter(_) => {}
478 }
479 }
480}
481
482impl ResolvedPattern {
483 pub fn collect_vars(&self, out: &mut BTreeSet<VarId>) {
486 let pattern = self;
487 let node = |n: &ResolvedNode, out: &mut BTreeSet<VarId>| {
488 out.extend(n.var);
489 if let Some(p) = &n.properties {
490 ResolvedExpr::collect_vars(p, out);
491 }
492 };
493 for part in &pattern.parts {
494 out.extend(part.binding);
495 match &part.element {
496 ResolvedPatternElement::Node {
497 var, properties, ..
498 } => {
499 out.extend(*var);
500 if let Some(p) = properties {
501 ResolvedExpr::collect_vars(p, out);
502 }
503 }
504 ResolvedPatternElement::NodeChain { head, chain }
505 | ResolvedPatternElement::ShortestPath { head, chain, .. } => {
506 node(head, out);
507 for link in chain {
508 out.extend(link.rel.var);
509 if let Some(p) = &link.rel.properties {
510 ResolvedExpr::collect_vars(p, out);
511 }
512 node(&link.node, out);
513 }
514 }
515 }
516 }
517 }
518}