Skip to main content

akar_parser/
ast.rs

1//! Abstract Syntax Tree (AST) types for Cypher queries.
2
3/// EXPLAIN type — what kind of plan to show.
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum ExplainType {
6    /// `EXPLAIN` — show the physical plan (default).
7    PhysicalPlan,
8    /// `EXPLAIN LOGICAL` — show the logical plan.
9    LogicalPlan,
10    /// `EXPLAIN PROFILE` — execute and show profile.
11    Profile,
12}
13
14/// EXPORT DATABASE statement.
15#[derive(Debug, Clone, PartialEq)]
16pub struct ExportDatabase {
17    /// Path to the export directory.
18    pub file_path: String,
19    /// Export options (format, schema_only, etc.).
20    pub options: std::collections::HashMap<String, String>,
21}
22
23/// IMPORT DATABASE statement.
24#[derive(Debug, Clone, PartialEq)]
25pub struct ImportDatabase {
26    /// Path to the import directory (previously exported).
27    pub file_path: String,
28}
29
30/// ANALYZE statement — collect table statistics.
31#[derive(Debug, Clone, PartialEq)]
32pub struct AnalyzeStatement {
33    /// Table name to analyze, or None for all tables (ANALYZE *).
34    pub table_name: Option<String>,
35}
36
37/// Transaction action type.
38#[derive(Debug, Clone, Copy, PartialEq)]
39pub enum TransactionAction {
40    Begin,
41    Commit,
42    Rollback,
43    Checkpoint,
44}
45
46/// TRANSACTION statement (BEGIN, COMMIT, ROLLBACK, CHECKPOINT).
47#[derive(Debug, Clone, PartialEq)]
48pub struct TransactionStatement {
49    pub action: TransactionAction,
50}
51
52/// Extension management action.
53#[derive(Debug, Clone, Copy, PartialEq)]
54pub enum ExtensionAction {
55    Install,
56    Load,
57    Uninstall,
58}
59
60/// EXTENSION management statement (INSTALL/LOAD/UNINSTALL EXTENSION name).
61#[derive(Debug, Clone, PartialEq)]
62pub struct ExtensionStatement {
63    pub action: ExtensionAction,
64    pub name: String,
65}
66
67/// ATTACH DATABASE statement.
68#[derive(Debug, Clone, PartialEq)]
69pub struct AttachDatabase {
70    pub path: String,
71    pub alias: String,
72    pub options: std::collections::HashMap<String, String>,
73}
74
75/// DETACH DATABASE statement.
76#[derive(Debug, Clone, PartialEq)]
77pub struct DetachDatabase {
78    pub alias: String,
79}
80
81/// USE DATABASE statement.
82#[derive(Debug, Clone, PartialEq)]
83pub struct UseDatabase {
84    pub alias: String,
85}
86
87/// LOAD FROM statement — scan external file without importing.
88#[derive(Debug, Clone, PartialEq)]
89pub struct LoadFrom {
90    pub path: String,
91    pub options: std::collections::HashMap<String, String>,
92}
93
94/// EXPLAIN statement wrapper.
95#[derive(Debug, Clone, PartialEq)]
96pub struct ExplainStatement {
97    /// The statement being explained.
98    pub statement: Box<Statement>,
99    /// The type of explain output.
100    pub explain_type: ExplainType,
101}
102
103/// A Cypher statement (top-level AST node).
104#[derive(Debug, Clone, PartialEq)]
105pub enum Statement {
106    Query(Query),
107    CreateNodeTable(CreateNodeTable),
108    CreateRelTable(CreateRelTable),
109    DropTable(DropTable),
110    CopyFrom(CopyFrom),
111    CopyTo(CopyTo),
112    AlterTable(AlterTable),
113    CreateVectorIndex(CreateVectorIndex),
114    CreateIndex(CreateIndex),
115    DropIndex(DropIndex),
116    Union(UnionStatement),
117    Merge(MergeStatement),
118    StandaloneCall(StandaloneCall),
119    CreateDml(CreateClause),
120    Explain(ExplainStatement),
121    CreateSequence(CreateSequence),
122    DropSequence(DropSequence),
123    CreateMacro(CreateMacro),
124    ExportDatabase(ExportDatabase),
125    ImportDatabase(ImportDatabase),
126    Analyze(AnalyzeStatement),
127    CreateFtsIndex(CreateFtsIndex),
128    Transaction(TransactionStatement),
129    Extension(ExtensionStatement),
130    AttachDatabase(AttachDatabase),
131    DetachDatabase(DetachDatabase),
132    UseDatabase(UseDatabase),
133    LoadFrom(LoadFrom),
134    CreateType(CreateType),
135    CommentOnTable(CommentOnTable),
136    CreateGraph(CreateGraph),
137    UseGraph(UseGraph),
138    DropGraph(DropGraph),
139}
140
141/// A Cypher query (e.g., MATCH ... RETURN ...).
142#[derive(Debug, Clone, PartialEq)]
143pub struct Query {
144    pub clauses: Vec<Clause>,
145}
146
147/// A clause in a query.
148#[derive(Debug, Clone, PartialEq)]
149pub enum Clause {
150    Match(MatchClause),
151    Return(ReturnClause),
152    Where(WhereClause),
153    Create(CreateClause),
154    Delete(DeleteClause),
155    Set(SetClause),
156    OptionalMatch(OptionalMatchClause),
157    With(ReturnClause),
158    Unwind(UnwindClause),
159    Foreach(ForeachClause),
160}
161
162#[derive(Debug, Clone, PartialEq)]
163pub struct ForeachClause {
164    pub variable: String,
165    pub expression: Expression,
166    /// Sub-statements inside FOREACH (CREATE, SET, DELETE clauses).
167    pub clauses: Vec<Clause>,
168}
169
170#[derive(Debug, Clone, PartialEq)]
171pub struct UnwindClause {
172    pub expression: Expression,
173    pub variable: String,
174}
175
176#[derive(Debug, Clone, PartialEq)]
177pub struct SetClause {
178    pub items: Vec<SetItem>,
179}
180
181#[derive(Debug, Clone, PartialEq)]
182pub struct SetItem {
183    pub property: Expression,
184    pub value: Expression,
185}
186
187#[derive(Debug, Clone, PartialEq)]
188pub struct DeleteClause {
189    pub detach: bool,
190    pub expressions: Vec<Expression>,
191}
192
193#[derive(Debug, Clone, PartialEq)]
194pub struct MatchClause {
195    pub patterns: Vec<Pattern>,
196    /// Optional FTS query attached to this MATCH via `USING FTS INDEX name('query')`.
197    pub fts_query: Option<FtsQuery>,
198}
199
200/// A `USING FTS INDEX index_name('search string')` clause attached to a MATCH.
201#[derive(Debug, Clone, PartialEq)]
202pub struct FtsQuery {
203    pub index_name: String,
204    pub query_string: String,
205}
206
207/// CREATE FTS INDEX statement.
208#[derive(Debug, Clone, PartialEq)]
209pub struct CreateFtsIndex {
210    pub index_name: String,
211    pub table_name: String,
212    pub column_name: String,
213    pub if_not_exists: bool,
214}
215
216#[derive(Debug, Clone, PartialEq)]
217pub struct OptionalMatchClause {
218    pub patterns: Vec<Pattern>,
219}
220
221#[derive(Debug, Clone, PartialEq)]
222pub struct ReturnClause {
223    pub expressions: Vec<ReturnItem>,
224    pub distinct: bool,
225    /// Optional ORDER BY clause: list of sort items.
226    pub order_by: Option<Vec<OrderByItem>>,
227    /// Optional LIMIT — maximum number of rows to return.
228    pub limit: Option<u64>,
229    /// Optional SKIP — number of rows to skip before returning.
230    pub skip: Option<u64>,
231}
232
233#[derive(Debug, Clone, PartialEq)]
234pub struct ReturnItem {
235    pub expression: Expression,
236    pub alias: Option<String>,
237}
238
239/// A single sort item in an ORDER BY clause.
240#[derive(Debug, Clone, PartialEq)]
241pub struct OrderByItem {
242    /// The expression to sort by.
243    pub expression: Expression,
244    /// Sort direction: `true` for ascending (default), `false` for descending.
245    pub ascending: bool,
246}
247
248#[derive(Debug, Clone, PartialEq)]
249pub struct WhereClause {
250    pub expression: Expression,
251}
252
253#[derive(Debug, Clone, PartialEq)]
254pub struct CreateClause {
255    pub patterns: Vec<Pattern>,
256}
257
258/// A graph pattern (node or relationship).
259#[derive(Debug, Clone, PartialEq)]
260pub struct Pattern {
261    pub node: Option<NodePattern>,
262    pub edge: Option<EdgePattern>,
263}
264
265#[derive(Debug, Clone, PartialEq)]
266pub struct NodePattern {
267    pub variable: Option<String>,
268    pub labels: Vec<String>,
269    pub properties: Vec<(String, Expression)>,
270}
271
272#[derive(Debug, Clone, PartialEq)]
273pub struct EdgePattern {
274    pub variable: Option<String>,
275    pub labels: Vec<String>,
276    pub direction: EdgeDirection,
277    pub properties: Vec<(String, Expression)>,
278    pub lower_bound: Option<u64>,
279    pub upper_bound: Option<u64>,
280}
281
282#[derive(Debug, Clone, PartialEq)]
283pub enum EdgeDirection {
284    LeftToRight,
285    RightToLeft,
286    Both,
287}
288
289impl ExplainStatement {
290    /// Create a new EXPLAIN statement wrapping the given inner statement.
291    pub fn new(statement: Statement, explain_type: ExplainType) -> Self {
292        Self {
293            statement: Box::new(statement),
294            explain_type,
295        }
296    }
297}
298
299/// An expression in a Cypher query.
300#[derive(Debug, Clone, PartialEq)]
301pub enum Expression {
302    Constant(Constant),
303    Variable(String),
304    /// A query parameter reference like `$name` or `$age`.
305    Parameter(String),
306    PropertyAccess(Box<Expression>, String),
307    FunctionCall(String, Vec<Expression>),
308    BinaryOp(BinaryOp, Box<Expression>, Box<Expression>),
309    UnaryOp(UnaryOp, Box<Expression>),
310    List(Vec<Expression>),
311    Map(Vec<(String, Expression)>),
312    /// EXISTS { MATCH ... WHERE ... } — returns true if the pattern matches.
313    ExistsSubquery(Box<Query>),
314    /// CASE [subject] WHEN ... THEN ... [ELSE ...] END
315    Case(CaseExpr),
316    /// STAR expression — represents `*` in `RETURN *`.
317    /// The binder expands this to all variables in scope.
318    Star,
319    /// ANY/ALL/NONE/SINGLE list predicates.
320    /// Example: ANY(x IN [1,2,3] WHERE x > 5)
321    ListPredicate {
322        quantifier: Quantifier,
323        list: Box<Expression>,
324        var_name: String,
325        predicate: Box<Expression>,
326    },
327    /// Lambda expression for list_transform, list_filter, list_reduce.
328    /// Example: x -> x + 1  or  (x, y) -> x + y
329    Lambda {
330        var_name: String,
331        body: Box<Expression>,
332    },
333}
334
335/// Quantifier for list predicates.
336#[derive(Debug, Clone, Copy, PartialEq)]
337pub enum Quantifier {
338    Any,
339    All,
340    None,
341    Single,
342}
343
344/// A single WHEN ... THEN ... branch inside a CASE expression.
345#[derive(Debug, Clone, PartialEq)]
346pub struct CaseAlternative {
347    /// The WHEN expression (a value for simple CASE, or a condition for searched CASE).
348    pub when: Expression,
349    /// The THEN expression returned when WHEN matches.
350    pub then: Expression,
351}
352
353/// A CASE expression (simple or searched).
354#[derive(Debug, Clone, PartialEq)]
355pub struct CaseExpr {
356    /// Optional subject expression for simple CASE: `CASE x WHEN v THEN ...`
357    pub subject: Option<Box<Expression>>,
358    /// The WHEN/THEN branches.
359    pub alternatives: Vec<CaseAlternative>,
360    /// Optional ELSE expression returned when no branch matches.
361    pub else_expr: Option<Box<Expression>>,
362}
363
364#[derive(Debug, Clone, PartialEq)]
365pub enum Constant {
366    Null,
367    Bool(bool),
368    Integer(i64),
369    Float(f64),
370    String(String),
371}
372
373#[derive(Debug, Clone, Copy, PartialEq)]
374pub enum BinaryOp {
375    Add,
376    Subtract,
377    Multiply,
378    Divide,
379    Modulo,
380    Equal,
381    NotEqual,
382    LessThan,
383    LessThanOrEqual,
384    GreaterThan,
385    GreaterThanOrEqual,
386    And,
387    Or,
388    Xor,
389    Concat,
390    /// x IN [list] — true if x equals any element of the list
391    In,
392    /// x NOT IN [list] — true if x equals no element of the list
393    NotIn,
394    /// x STARTS WITH prefix — true if string x starts with prefix
395    StartsWith,
396    /// x ENDS WITH suffix — true if string x ends with suffix
397    EndsWith,
398    /// x CONTAINS substr — true if string x contains substr
399    Contains,
400    /// x LIKE pattern — true if string x matches the SQL LIKE pattern
401    Like,
402}
403
404#[derive(Debug, Clone, Copy, PartialEq)]
405pub enum UnaryOp {
406    Not,
407    Negate,
408    /// x IS NULL — true if x evaluates to null
409    IsNull,
410    /// x IS NOT NULL — true if x does not evaluate to null
411    IsNotNull,
412}
413
414// DDL statements
415#[derive(Debug, Clone, PartialEq)]
416pub struct CreateNodeTable {
417    pub name: String,
418    pub columns: Vec<ColumnDef>,
419    pub primary_key: String,
420}
421
422#[derive(Debug, Clone, PartialEq)]
423pub struct CreateRelTable {
424    pub name: String,
425    pub from: String,
426    pub to: String,
427    pub columns: Vec<ColumnDef>,
428}
429
430#[derive(Debug, Clone, PartialEq)]
431pub struct DropTable {
432    pub name: String,
433}
434
435/// A `CREATE [ART|HASH] INDEX` statement.
436#[derive(Debug, Clone, PartialEq)]
437pub struct CreateIndex {
438    pub index_type: String,
439    pub index_name: String,
440    pub table_name: String,
441    pub variable: String,
442    pub property: String,
443    pub conflict_action: Option<String>,
444}
445
446/// A `DROP INDEX` statement.
447#[derive(Debug, Clone, PartialEq)]
448pub struct DropIndex {
449    pub index_name: String,
450    pub table_name: String,
451}
452
453/// ALTER TABLE statement.
454#[derive(Debug, Clone, PartialEq)]
455pub struct AlterTable {
456    pub table_name: String,
457    pub action: AlterAction,
458}
459
460#[derive(Debug, Clone, PartialEq)]
461pub enum AlterAction {
462    AddColumn { name: String, type_name: String },
463    DropColumn { name: String },
464    RenameColumn { old_name: String, new_name: String },
465    RenameTable { new_name: String },
466}
467
468/// UNION statement — combines results from two queries.
469#[derive(Debug, Clone, PartialEq)]
470pub struct UnionStatement {
471    pub left: Query,
472    pub right: Query,
473    pub all: bool,
474}
475
476/// COPY FROM statement — load data from a file into a table.
477#[derive(Debug, Clone, PartialEq)]
478pub struct CopyFrom {
479    pub table_name: String,
480    pub file_path: String,
481    pub options: std::collections::HashMap<String, String>,
482}
483
484/// COPY TO statement — export query results to a file.
485///
486/// Syntax: `COPY (query) TO 'path' (FORMAT 'CSV'|'PARQUET', HEADER true|false)`
487#[derive(Debug, Clone, PartialEq)]
488pub struct CopyTo {
489    pub query: Query,
490    pub file_path: String,
491    pub format: CopyToFormat,
492    pub header: bool,
493}
494
495#[derive(Debug, Clone, PartialEq)]
496pub enum CopyToFormat {
497    Csv,
498    Parquet,
499}
500
501/// MERGE statement — match or create a pattern with optional ON CREATE / ON MATCH actions.
502#[derive(Debug, Clone, PartialEq)]
503pub struct MergeStatement {
504    pub patterns: Vec<Pattern>,
505    pub on_create: Vec<SetItem>,
506    pub on_match: Vec<SetItem>,
507}
508
509/// CALL statement — invoke a table function or procedure as a standalone statement.
510#[derive(Debug, Clone, PartialEq)]
511pub struct StandaloneCall {
512    pub function_name: String,
513    pub args: Vec<Expression>,
514}
515
516/// CREATE SEQUENCE statement — creates a sequence for auto-incrementing counters.
517///
518/// Syntax:
519/// ```sql
520/// CREATE [OR REPLACE] SEQUENCE [IF NOT EXISTS] name
521///   [START WITH value]
522///   [INCREMENT [BY] value]
523///   [MINVALUE value | NO MINVALUE]
524///   [MAXVALUE value | NO MAXVALUE]
525///   [CYCLE | NO CYCLE]
526/// ```
527#[derive(Debug, Clone, PartialEq)]
528pub struct CreateSequence {
529    pub name: String,
530    pub if_not_exists: bool,
531    pub or_replace: bool,
532    /// START WITH value. Default: 1 for increment > 0, max_value for increment < 0.
533    pub start_with: Option<i64>,
534    /// INCREMENT BY value. Default: 1.
535    pub increment: Option<i64>,
536    /// MINVALUE. Auto-computed from defaults if None.
537    pub min_value: Option<i64>,
538    /// MAXVALUE. Auto-computed from defaults if None.
539    pub max_value: Option<i64>,
540    /// CYCLE behavior. Default: false (NO CYCLE).
541    pub cycle: Option<bool>,
542}
543
544/// DROP SEQUENCE statement.
545#[derive(Debug, Clone, PartialEq)]
546pub struct DropSequence {
547    pub name: String,
548    pub if_exists: bool,
549}
550
551/// CREATE MACRO statement — defines a Cypher scalar macro.
552///
553/// Syntax: `CREATE MACRO macroName(param1, param2, ...) AS expression`
554///
555/// Macros are expanded at binding time: macro invocations are replaced
556/// with the macro body expression (with parameters substituted).
557///
558/// Ported from C++ `parser/create_macro.h`.
559#[derive(Debug, Clone, PartialEq)]
560pub struct CreateMacro {
561    /// The macro name.
562    pub name: String,
563    /// Positional parameter names (no default value).
564    pub positional_args: Vec<String>,
565    /// Parameters with default values (name, default expression).
566    pub default_args: Vec<(String, Expression)>,
567    /// The macro body expression.
568    pub expression: Box<Expression>,
569}
570
571/// CREATE VECTOR INDEX statement — creates an HNSW index on a vector column.
572#[derive(Debug, Clone, PartialEq)]
573pub struct CreateVectorIndex {
574    pub index_name: String,
575    pub table_name: String,
576    pub column_name: String,
577    pub metric: String,
578    pub dimensions: u64,
579}
580
581#[derive(Debug, Clone, PartialEq)]
582pub struct ColumnDef {
583    pub name: String,
584    pub type_name: String,
585    pub compression: Option<String>,
586}
587
588/// CREATE TYPE name AS type — user-defined type alias.
589#[derive(Debug, Clone, PartialEq)]
590pub struct CreateType {
591    pub name: String,
592    pub type_name: String,
593}
594
595/// COMMENT ON TABLE name IS 'string' — add a comment to a table.
596#[derive(Debug, Clone, PartialEq)]
597pub struct CommentOnTable {
598    pub table_name: String,
599    pub comment: String,
600}
601
602/// CREATE [PROJECTION] GRAPH name [ANY] — create a projected graph.
603#[derive(Debug, Clone, PartialEq)]
604pub struct CreateGraph {
605    pub name: String,
606    pub is_any: bool,
607}
608
609/// USE GRAPH name — set the current graph context.
610#[derive(Debug, Clone, PartialEq)]
611pub struct UseGraph {
612    pub name: String,
613}
614
615/// DROP GRAPH name — remove a projected graph.
616#[derive(Debug, Clone, PartialEq)]
617pub struct DropGraph {
618    pub name: String,
619}