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