Skip to main content

plexus_parser/
ast.rs

1/// Phase 1 Cypher AST.
2///
3/// Mirrors the grammar closely. All strings are owned; no lifetimes in the AST.
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct Query {
7    pub clauses: Vec<Clause>,
8}
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum Clause {
12    Match(MatchClause),
13    Create(CreateClause),
14    Merge(MergeClause),
15    Delete(DeleteClause),
16    Set(SetClause),
17    Remove(RemoveClause),
18    Unwind(UnwindClause),
19    Union(UnionClause),
20    With(WithClause),
21    Return(ReturnClause),
22}
23
24#[derive(Debug, Clone, PartialEq)]
25pub struct MatchClause {
26    pub optional: bool,
27    pub pattern: Pattern,
28    pub where_: Option<Expr>,
29}
30
31#[derive(Debug, Clone, PartialEq)]
32pub struct CreateClause {
33    pub pattern: Pattern,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub struct MergeClause {
38    pub pattern: MergePattern,
39}
40
41#[derive(Debug, Clone, PartialEq)]
42pub struct MergePattern {
43    pub nodes: Vec<NodePattern>,
44    pub rels: Vec<MergeRelPattern>,
45}
46
47#[derive(Debug, Clone, PartialEq)]
48pub struct MergeRelPattern {
49    pub src: usize,
50    pub dst: usize,
51    pub var: Option<String>,
52    pub types: Vec<String>,
53    pub dir: Dir,
54}
55
56#[derive(Debug, Clone, PartialEq)]
57pub struct DeleteClause {
58    pub detach: bool,
59    pub exprs: Vec<Expr>,
60}
61
62#[derive(Debug, Clone, PartialEq)]
63pub struct SetClause {
64    pub items: Vec<SetItem>,
65}
66
67#[derive(Debug, Clone, PartialEq)]
68pub struct SetItem {
69    pub lhs: Expr,
70    pub rhs: Expr,
71}
72
73#[derive(Debug, Clone, PartialEq)]
74pub struct RemoveClause {
75    pub exprs: Vec<Expr>,
76}
77
78#[derive(Debug, Clone, PartialEq)]
79pub struct UnwindClause {
80    pub expr: Expr,
81    pub alias: String,
82}
83
84#[derive(Debug, Clone, PartialEq)]
85pub struct WithClause {
86    pub items: Vec<ReturnItem>,
87    pub where_: Option<Expr>,
88    pub order_by: Vec<SortItem>,
89    pub limit: Option<i64>,
90    pub skip: Option<i64>,
91}
92
93#[derive(Debug, Clone, PartialEq)]
94pub struct ReturnClause {
95    pub items: Vec<ReturnItem>,
96    pub order_by: Vec<SortItem>,
97    pub limit: Option<i64>,
98    pub skip: Option<i64>,
99}
100
101/// A linear path pattern: node (rel node)*.
102/// Must have at least one node; rels.len() == nodes.len() - 1.
103#[derive(Debug, Clone, PartialEq)]
104pub struct Pattern {
105    pub nodes: Vec<NodePattern>,
106    pub rels: Vec<RelPattern>,
107}
108
109#[derive(Debug, Clone, PartialEq)]
110pub struct NodePattern {
111    pub var: Option<String>,
112    pub labels: Vec<String>,
113}
114
115#[derive(Debug, Clone, PartialEq)]
116pub struct RelPattern {
117    pub var: Option<String>,
118    pub types: Vec<String>,
119    pub hops: Option<HopRange>,
120    pub dir: Dir,
121}
122
123#[derive(Debug, Clone, PartialEq, Copy)]
124pub struct HopRange {
125    pub min: i32,
126    pub max: i32,
127}
128
129#[derive(Debug, Clone, PartialEq)]
130pub struct UnionClause {
131    pub all: bool,
132}
133
134#[derive(Debug, Clone, PartialEq, Copy)]
135pub enum Dir {
136    Out,  // -->
137    In,   // <--
138    Both, // --
139}
140
141#[derive(Debug, Clone, PartialEq)]
142pub struct ReturnItem {
143    pub expr: Expr,
144    pub alias: Option<String>,
145}
146
147#[derive(Debug, Clone, PartialEq)]
148pub struct SortItem {
149    pub expr: Expr,
150    pub dir: SortDir,
151}
152
153#[derive(Debug, Clone, PartialEq, Copy)]
154pub enum SortDir {
155    Asc,
156    Desc,
157}
158
159#[derive(Debug, Clone, PartialEq)]
160pub enum Expr {
161    Cmp {
162        op: CmpOp,
163        lhs: Box<Expr>,
164        rhs: Box<Expr>,
165    },
166    And(Box<Expr>, Box<Expr>),
167    Or(Box<Expr>, Box<Expr>),
168    Not(Box<Expr>),
169    IsNull(Box<Expr>),
170    IsNotNull(Box<Expr>),
171    StartsWith {
172        expr: Box<Expr>,
173        pattern: String,
174    },
175    EndsWith {
176        expr: Box<Expr>,
177        pattern: String,
178    },
179    Contains {
180        expr: Box<Expr>,
181        pattern: String,
182    },
183    /// `var.prop` property access
184    PropAccess {
185        var: String,
186        prop: String,
187    },
188    /// Bare variable reference (used in RETURN, ORDER BY, etc.)
189    VarRef(String),
190    Lit(Literal),
191    /// Aggregation function. `expr` is None for COUNT(*).
192    Agg {
193        fn_: AggFn,
194        expr: Option<Box<Expr>>,
195    },
196    Arith {
197        op: ArithOp,
198        lhs: Box<Expr>,
199        rhs: Box<Expr>,
200    },
201    Param {
202        name: String,
203    },
204    Case {
205        arms: Vec<CaseArm>,
206        else_expr: Option<Box<Expr>>,
207    },
208    /// `expr IN [item1, item2, ...]`
209    In {
210        expr: Box<Expr>,
211        items: Vec<Expr>,
212    },
213    /// `[item1, item2, ...]`
214    ListLiteral {
215        items: Vec<Expr>,
216    },
217    /// `{key: value, ...}`
218    MapLiteral {
219        entries: Vec<(String, Expr)>,
220    },
221    /// `exists(inner)`
222    Exists {
223        inner: Box<Expr>,
224    },
225    /// `[var IN list WHERE predicate | map]`
226    ListComprehension {
227        var: String,
228        list: Box<Expr>,
229        predicate: Option<Box<Expr>>,
230        map: Box<Expr>,
231    },
232}
233
234#[derive(Debug, Clone, PartialEq)]
235pub struct CaseArm {
236    pub when_expr: Expr,
237    pub then_expr: Expr,
238}
239
240#[derive(Debug, Clone, PartialEq)]
241pub enum Literal {
242    Int(i64),
243    Float(f64),
244    Str(String),
245    Bool(bool),
246    Null,
247}
248
249#[derive(Debug, Clone, PartialEq, Copy)]
250pub enum CmpOp {
251    Eq,
252    Ne,
253    Lt,
254    Gt,
255    Le,
256    Ge,
257}
258
259#[derive(Debug, Clone, PartialEq, Copy)]
260pub enum AggFn {
261    CountStar,
262    Count,
263    Sum,
264    Avg,
265    Min,
266    Max,
267    Collect,
268}
269
270#[derive(Debug, Clone, PartialEq, Copy)]
271pub enum ArithOp {
272    Add,
273    Sub,
274    Mul,
275    Div,
276}