Skip to main content

kyu_parser/
ast.rs

1//! AST node types produced by the Cypher parser.
2
3use crate::span::{Span, Spanned};
4use smol_str::SmolStr;
5
6// =============================================================================
7// Top-Level Statement
8// =============================================================================
9
10/// A complete parsed statement.
11#[derive(Clone, Debug)]
12pub enum Statement {
13    Query(Query),
14    CreateNodeTable(CreateNodeTable),
15    CreateRelTable(CreateRelTable),
16    Drop(DropStatement),
17    AlterTable(AlterTable),
18    CopyFrom(CopyFrom),
19    CopyTo(CopyTo),
20    StandaloneCall(StandaloneCall),
21    Transaction(TransactionStatement),
22    ExportDatabase(ExportDatabase),
23    ImportDatabase(ImportDatabase),
24    AttachDatabase(AttachDatabase),
25    UseDatabase(UseDatabase),
26    CreateMacro(CreateMacro),
27    InstallExtension(InstallExtension),
28    LoadExtension(LoadExtension),
29    Explain(Box<Statement>),
30    Profile(Box<Statement>),
31}
32
33// =============================================================================
34// Query
35// =============================================================================
36
37#[derive(Clone, Debug)]
38pub struct Query {
39    pub parts: Vec<QueryPart>,
40    /// UNION / UNION ALL chains: (is_all, query).
41    pub union_all: Vec<(bool, Query)>,
42}
43
44#[derive(Clone, Debug)]
45pub struct QueryPart {
46    pub reading_clauses: Vec<ReadingClause>,
47    pub updating_clauses: Vec<UpdatingClause>,
48    pub projection: Option<ProjectionBody>,
49    /// `true` = RETURN, `false` = WITH.
50    pub is_return: bool,
51}
52
53// =============================================================================
54// Reading Clauses
55// =============================================================================
56
57#[derive(Clone, Debug)]
58pub enum ReadingClause {
59    Match(MatchClause),
60    Unwind(UnwindClause),
61    InQueryCall(InQueryCall),
62    LoadFrom(LoadFrom),
63}
64
65#[derive(Clone, Debug)]
66pub struct MatchClause {
67    pub is_optional: bool,
68    pub patterns: Vec<Pattern>,
69    pub where_clause: Option<Spanned<Expression>>,
70}
71
72#[derive(Clone, Debug)]
73pub struct UnwindClause {
74    pub expression: Spanned<Expression>,
75    pub alias: Spanned<SmolStr>,
76}
77
78#[derive(Clone, Debug)]
79pub struct InQueryCall {
80    pub procedure: Spanned<SmolStr>,
81    pub args: Vec<Spanned<Expression>>,
82    pub yield_items: Vec<Spanned<SmolStr>>,
83}
84
85#[derive(Clone, Debug)]
86pub struct LoadFrom {
87    pub source: Spanned<Expression>,
88}
89
90// =============================================================================
91// Patterns
92// =============================================================================
93
94#[derive(Clone, Debug)]
95pub struct Pattern {
96    pub variable: Option<Spanned<SmolStr>>,
97    pub elements: Vec<PatternElement>,
98}
99
100#[derive(Clone, Debug)]
101pub enum PatternElement {
102    Node(NodePattern),
103    Relationship(RelationshipPattern),
104}
105
106#[derive(Clone, Debug)]
107pub struct NodePattern {
108    pub variable: Option<Spanned<SmolStr>>,
109    pub labels: Vec<Spanned<SmolStr>>,
110    pub properties: Option<Vec<(Spanned<SmolStr>, Spanned<Expression>)>>,
111    pub span: Span,
112}
113
114#[derive(Clone, Debug)]
115pub struct RelationshipPattern {
116    pub variable: Option<Spanned<SmolStr>>,
117    pub rel_types: Vec<Spanned<SmolStr>>,
118    pub direction: Direction,
119    /// Variable-length range: `[*min..max]`.
120    pub range: Option<(Option<u32>, Option<u32>)>,
121    pub properties: Option<Vec<(Spanned<SmolStr>, Spanned<Expression>)>>,
122    pub span: Span,
123}
124
125#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126pub enum Direction {
127    Left,  // <-[]-
128    Right, // -[]->
129    Both,  // -[]-
130}
131
132// =============================================================================
133// Updating Clauses
134// =============================================================================
135
136#[derive(Clone, Debug)]
137pub enum UpdatingClause {
138    Create(Vec<Pattern>),
139    Merge(MergeClause),
140    Set(Vec<SetItem>),
141    Delete(DeleteClause),
142    Remove(Vec<RemoveItem>),
143}
144
145#[derive(Clone, Debug)]
146pub struct MergeClause {
147    pub pattern: Pattern,
148    pub on_match: Vec<SetItem>,
149    pub on_create: Vec<SetItem>,
150}
151
152#[derive(Clone, Debug)]
153pub struct DeleteClause {
154    pub detach: bool,
155    pub expressions: Vec<Spanned<Expression>>,
156}
157
158#[derive(Clone, Debug)]
159pub enum SetItem {
160    Property {
161        entity: Spanned<Expression>,
162        value: Spanned<Expression>,
163    },
164    AllProperties {
165        entity: Spanned<SmolStr>,
166        value: Spanned<Expression>,
167    },
168    Labels {
169        entity: Spanned<SmolStr>,
170        labels: Vec<Spanned<SmolStr>>,
171    },
172}
173
174#[derive(Clone, Debug)]
175pub enum RemoveItem {
176    Property(Spanned<Expression>),
177    Labels {
178        entity: Spanned<SmolStr>,
179        labels: Vec<Spanned<SmolStr>>,
180    },
181}
182
183// =============================================================================
184// Projection
185// =============================================================================
186
187#[derive(Clone, Debug)]
188pub struct ProjectionBody {
189    pub distinct: bool,
190    pub items: ProjectionItems,
191    pub order_by: Vec<(Spanned<Expression>, SortOrder)>,
192    pub skip: Option<Spanned<Expression>>,
193    pub limit: Option<Spanned<Expression>>,
194}
195
196#[derive(Clone, Debug)]
197pub enum ProjectionItems {
198    All,
199    Expressions(Vec<(Spanned<Expression>, Option<Spanned<SmolStr>>)>),
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum SortOrder {
204    Ascending,
205    Descending,
206}
207
208// =============================================================================
209// Expressions
210// =============================================================================
211
212#[derive(Clone, Debug)]
213pub enum Expression {
214    Literal(Literal),
215    Variable(SmolStr),
216    Parameter(SmolStr),
217    Property {
218        object: Box<Spanned<Expression>>,
219        key: Spanned<SmolStr>,
220    },
221    FunctionCall {
222        name: Vec<Spanned<SmolStr>>,
223        distinct: bool,
224        args: Vec<Spanned<Expression>>,
225    },
226    CountStar,
227    UnaryOp {
228        op: UnaryOp,
229        operand: Box<Spanned<Expression>>,
230    },
231    BinaryOp {
232        left: Box<Spanned<Expression>>,
233        op: BinaryOp,
234        right: Box<Spanned<Expression>>,
235    },
236    Comparison {
237        left: Box<Spanned<Expression>>,
238        ops: Vec<(ComparisonOp, Spanned<Expression>)>,
239    },
240    IsNull {
241        expr: Box<Spanned<Expression>>,
242        negated: bool,
243    },
244    ListLiteral(Vec<Spanned<Expression>>),
245    MapLiteral(Vec<(Spanned<SmolStr>, Spanned<Expression>)>),
246    Subscript {
247        expr: Box<Spanned<Expression>>,
248        index: Box<Spanned<Expression>>,
249    },
250    Slice {
251        expr: Box<Spanned<Expression>>,
252        from: Option<Box<Spanned<Expression>>>,
253        to: Option<Box<Spanned<Expression>>>,
254    },
255    Case {
256        operand: Option<Box<Spanned<Expression>>>,
257        whens: Vec<(Spanned<Expression>, Spanned<Expression>)>,
258        else_expr: Option<Box<Spanned<Expression>>>,
259    },
260    ExistsSubquery(Box<Query>),
261    CountSubquery(Box<Query>),
262    Quantifier {
263        kind: QuantifierKind,
264        variable: Spanned<SmolStr>,
265        list: Box<Spanned<Expression>>,
266        predicate: Box<Spanned<Expression>>,
267    },
268    StringOp {
269        left: Box<Spanned<Expression>>,
270        op: StringOp,
271        right: Box<Spanned<Expression>>,
272    },
273    InList {
274        expr: Box<Spanned<Expression>>,
275        list: Box<Spanned<Expression>>,
276        negated: bool,
277    },
278    /// Label predicate: `a:Label` (true if node has given label)
279    HasLabel {
280        expr: Box<Spanned<Expression>>,
281        labels: Vec<Spanned<SmolStr>>,
282    },
283    /// List comprehension: `[x IN list | expr]` or `[x IN list WHERE pred | expr]`
284    ListComprehension {
285        variable: Spanned<SmolStr>,
286        list: Box<Spanned<Expression>>,
287        filter: Option<Box<Spanned<Expression>>>,
288        projection: Option<Box<Spanned<Expression>>>,
289    },
290}
291
292#[derive(Clone, Debug)]
293pub enum Literal {
294    Integer(i64),
295    Float(f64),
296    String(SmolStr),
297    Bool(bool),
298    Null,
299}
300
301#[derive(Clone, Copy, Debug, PartialEq, Eq)]
302pub enum UnaryOp {
303    Not,
304    Minus,
305    BitwiseNot,
306}
307
308#[derive(Clone, Copy, Debug, PartialEq, Eq)]
309pub enum BinaryOp {
310    Add,
311    Sub,
312    Mul,
313    Div,
314    Mod,
315    Pow,
316    And,
317    Or,
318    Xor,
319    BitwiseAnd,
320    BitwiseOr,
321    ShiftLeft,
322    ShiftRight,
323    Concat,
324}
325
326#[derive(Clone, Copy, Debug, PartialEq, Eq)]
327pub enum ComparisonOp {
328    Eq,
329    Neq,
330    Lt,
331    Le,
332    Gt,
333    Ge,
334    RegexMatch,
335}
336
337#[derive(Clone, Copy, Debug, PartialEq, Eq)]
338pub enum StringOp {
339    StartsWith,
340    EndsWith,
341    Contains,
342}
343
344#[derive(Clone, Copy, Debug, PartialEq, Eq)]
345pub enum QuantifierKind {
346    All,
347    Any,
348    None,
349    Single,
350}
351
352// =============================================================================
353// DDL Statements
354// =============================================================================
355
356#[derive(Clone, Debug)]
357pub struct CreateNodeTable {
358    pub name: Spanned<SmolStr>,
359    pub if_not_exists: bool,
360    pub columns: Vec<ColumnDefinition>,
361    pub primary_key: Spanned<SmolStr>,
362}
363
364#[derive(Clone, Debug)]
365pub struct CreateRelTable {
366    pub name: Spanned<SmolStr>,
367    pub if_not_exists: bool,
368    pub from_table: Spanned<SmolStr>,
369    pub to_table: Spanned<SmolStr>,
370    pub columns: Vec<ColumnDefinition>,
371}
372
373#[derive(Clone, Debug)]
374pub struct ColumnDefinition {
375    pub name: Spanned<SmolStr>,
376    pub data_type: Spanned<SmolStr>,
377    pub default_value: Option<Spanned<Expression>>,
378}
379
380#[derive(Clone, Debug)]
381pub struct DropStatement {
382    pub object_type: DropObjectType,
383    pub name: Spanned<SmolStr>,
384    pub if_exists: bool,
385}
386
387#[derive(Clone, Copy, Debug, PartialEq, Eq)]
388pub enum DropObjectType {
389    Table,
390    Sequence,
391}
392
393#[derive(Clone, Debug)]
394pub struct AlterTable {
395    pub table_name: Spanned<SmolStr>,
396    pub action: AlterAction,
397}
398
399#[derive(Clone, Debug)]
400pub enum AlterAction {
401    AddColumn(ColumnDefinition),
402    DropColumn(Spanned<SmolStr>),
403    RenameColumn {
404        old_name: Spanned<SmolStr>,
405        new_name: Spanned<SmolStr>,
406    },
407    RenameTable(Spanned<SmolStr>),
408    Comment(SmolStr),
409}
410
411// =============================================================================
412// Copy / Import / Export
413// =============================================================================
414
415#[derive(Clone, Debug)]
416pub struct CopyFrom {
417    pub table_name: Spanned<SmolStr>,
418    pub source: Spanned<Expression>,
419    pub options: Vec<(Spanned<SmolStr>, Spanned<Expression>)>,
420}
421
422#[derive(Clone, Debug)]
423pub struct CopyTo {
424    pub source: CopyToSource,
425    pub destination: Spanned<Expression>,
426    pub options: Vec<(Spanned<SmolStr>, Spanned<Expression>)>,
427}
428
429#[derive(Clone, Debug)]
430pub enum CopyToSource {
431    Table(Spanned<SmolStr>),
432    Query(Box<Query>),
433}
434
435#[derive(Clone, Debug)]
436pub struct ExportDatabase {
437    pub path: Spanned<Expression>,
438    pub options: Vec<(Spanned<SmolStr>, Spanned<Expression>)>,
439}
440
441#[derive(Clone, Debug)]
442pub struct ImportDatabase {
443    pub path: Spanned<Expression>,
444}
445
446#[derive(Clone, Debug)]
447pub struct AttachDatabase {
448    pub path: Spanned<Expression>,
449    pub alias: Option<Spanned<SmolStr>>,
450    pub db_type: Option<Spanned<SmolStr>>,
451}
452
453#[derive(Clone, Debug)]
454pub struct UseDatabase {
455    pub name: Spanned<SmolStr>,
456}
457
458// =============================================================================
459// Procedures / Extensions / Macros
460// =============================================================================
461
462#[derive(Clone, Debug)]
463pub struct StandaloneCall {
464    pub procedure: Spanned<SmolStr>,
465    pub args: Vec<Spanned<Expression>>,
466}
467
468#[derive(Clone, Debug)]
469pub struct CreateMacro {
470    pub name: Spanned<SmolStr>,
471    pub params: Vec<Spanned<SmolStr>>,
472    pub body: Spanned<Expression>,
473}
474
475#[derive(Clone, Debug)]
476pub struct InstallExtension {
477    pub name: Spanned<SmolStr>,
478}
479
480#[derive(Clone, Debug)]
481pub struct LoadExtension {
482    pub path: Spanned<Expression>,
483}
484
485// =============================================================================
486// Transaction
487// =============================================================================
488
489#[derive(Clone, Debug)]
490pub enum TransactionStatement {
491    Begin(TransactionMode),
492    Commit,
493    Rollback,
494}
495
496#[derive(Clone, Copy, Debug, PartialEq, Eq)]
497pub enum TransactionMode {
498    ReadOnly,
499    ReadWrite,
500}