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    pub if_not_exists: bool,
217}
218
219#[derive(Debug, Clone, PartialEq)]
220pub struct OptionalMatchClause {
221    pub patterns: Vec<Pattern>,
222}
223
224#[derive(Debug, Clone, PartialEq)]
225pub struct ReturnClause {
226    pub expressions: Vec<ReturnItem>,
227    pub distinct: bool,
228    /// Optional ORDER BY clause: list of sort items.
229    pub order_by: Option<Vec<OrderByItem>>,
230    /// Optional LIMIT — maximum number of rows to return.
231    pub limit: Option<u64>,
232    /// Optional SKIP — number of rows to skip before returning.
233    pub skip: Option<u64>,
234    /// Parameter name (e.g. `$limit`) referenced by LIMIT, resolved to a value
235    /// at prepare/execution time. Mutually exclusive with `limit`.
236    pub limit_param: Option<String>,
237    /// Parameter name (e.g. `$skip`) referenced by SKIP, resolved to a value
238    /// at prepare/execution time. Mutually exclusive with `skip`.
239    pub skip_param: Option<String>,
240}
241
242#[derive(Debug, Clone, PartialEq)]
243pub struct ReturnItem {
244    pub expression: Expression,
245    pub alias: Option<String>,
246}
247
248/// A single sort item in an ORDER BY clause.
249#[derive(Debug, Clone, PartialEq)]
250pub struct OrderByItem {
251    /// The expression to sort by.
252    pub expression: Expression,
253    /// Sort direction: `true` for ascending (default), `false` for descending.
254    pub ascending: bool,
255}
256
257#[derive(Debug, Clone, PartialEq)]
258pub struct WhereClause {
259    pub expression: Expression,
260}
261
262#[derive(Debug, Clone, PartialEq)]
263pub struct CreateClause {
264    pub patterns: Vec<Pattern>,
265}
266
267/// A graph pattern (node or relationship).
268#[derive(Debug, Clone, PartialEq)]
269pub struct Pattern {
270    pub node: Option<NodePattern>,
271    pub edge: Option<EdgePattern>,
272}
273
274#[derive(Debug, Clone, PartialEq)]
275pub struct NodePattern {
276    pub variable: Option<String>,
277    pub labels: Vec<String>,
278    pub properties: Vec<(String, Expression)>,
279}
280
281#[derive(Debug, Clone, PartialEq)]
282pub struct EdgePattern {
283    pub variable: Option<String>,
284    pub labels: Vec<String>,
285    pub direction: EdgeDirection,
286    pub properties: Vec<(String, Expression)>,
287    pub lower_bound: Option<u64>,
288    pub upper_bound: Option<u64>,
289}
290
291#[derive(Debug, Clone, PartialEq)]
292pub enum EdgeDirection {
293    LeftToRight,
294    RightToLeft,
295    Both,
296}
297
298impl ExplainStatement {
299    /// Create a new EXPLAIN statement wrapping the given inner statement.
300    pub fn new(statement: Statement, explain_type: ExplainType) -> Self {
301        Self {
302            statement: Box::new(statement),
303            explain_type,
304        }
305    }
306}
307
308/// An expression in a Cypher query.
309#[derive(Debug, Clone, PartialEq)]
310pub enum Expression {
311    Constant(Constant),
312    Variable(String),
313    /// A query parameter reference like `$name` or `$age`.
314    Parameter(String),
315    PropertyAccess(Box<Expression>, String),
316    FunctionCall(String, Vec<Expression>),
317    BinaryOp(BinaryOp, Box<Expression>, Box<Expression>),
318    UnaryOp(UnaryOp, Box<Expression>),
319    List(Vec<Expression>),
320    Map(Vec<(String, Expression)>),
321    /// EXISTS { MATCH ... WHERE ... } — returns true if the pattern matches.
322    ExistsSubquery(Box<Query>),
323    /// CASE [subject] WHEN ... THEN ... [ELSE ...] END
324    Case(CaseExpr),
325    /// STAR expression — represents `*` in `RETURN *`.
326    /// The binder expands this to all variables in scope.
327    Star,
328    /// ANY/ALL/NONE/SINGLE list predicates.
329    /// Example: ANY(x IN [1,2,3] WHERE x > 5)
330    ListPredicate {
331        quantifier: Quantifier,
332        list: Box<Expression>,
333        var_name: String,
334        predicate: Box<Expression>,
335    },
336    /// Lambda expression for list_transform, list_filter, list_reduce.
337    /// Example: x -> x + 1  or  (x, y) -> x + y
338    Lambda {
339        var_name: String,
340        body: Box<Expression>,
341    },
342}
343
344/// Quantifier for list predicates.
345#[derive(Debug, Clone, Copy, PartialEq)]
346pub enum Quantifier {
347    Any,
348    All,
349    None,
350    Single,
351}
352
353/// A single WHEN ... THEN ... branch inside a CASE expression.
354#[derive(Debug, Clone, PartialEq)]
355pub struct CaseAlternative {
356    /// The WHEN expression (a value for simple CASE, or a condition for searched CASE).
357    pub when: Expression,
358    /// The THEN expression returned when WHEN matches.
359    pub then: Expression,
360}
361
362/// A CASE expression (simple or searched).
363#[derive(Debug, Clone, PartialEq)]
364pub struct CaseExpr {
365    /// Optional subject expression for simple CASE: `CASE x WHEN v THEN ...`
366    pub subject: Option<Box<Expression>>,
367    /// The WHEN/THEN branches.
368    pub alternatives: Vec<CaseAlternative>,
369    /// Optional ELSE expression returned when no branch matches.
370    pub else_expr: Option<Box<Expression>>,
371}
372
373#[derive(Debug, Clone, PartialEq)]
374pub enum Constant {
375    Null,
376    Bool(bool),
377    Integer(i64),
378    Float(f64),
379    String(String),
380}
381
382#[derive(Debug, Clone, Copy, PartialEq)]
383pub enum BinaryOp {
384    Add,
385    Subtract,
386    Multiply,
387    Divide,
388    Modulo,
389    Equal,
390    NotEqual,
391    LessThan,
392    LessThanOrEqual,
393    GreaterThan,
394    GreaterThanOrEqual,
395    And,
396    Or,
397    Xor,
398    Concat,
399    /// x IN [list] — true if x equals any element of the list
400    In,
401    /// x NOT IN [list] — true if x equals no element of the list
402    NotIn,
403    /// x STARTS WITH prefix — true if string x starts with prefix
404    StartsWith,
405    /// x ENDS WITH suffix — true if string x ends with suffix
406    EndsWith,
407    /// x CONTAINS substr — true if string x contains substr
408    Contains,
409    /// x LIKE pattern — true if string x matches the SQL LIKE pattern
410    Like,
411}
412
413#[derive(Debug, Clone, Copy, PartialEq)]
414pub enum UnaryOp {
415    Not,
416    Negate,
417    /// x IS NULL — true if x evaluates to null
418    IsNull,
419    /// x IS NOT NULL — true if x does not evaluate to null
420    IsNotNull,
421}
422
423// DDL statements
424#[derive(Debug, Clone, PartialEq)]
425pub struct CreateNodeTable {
426    pub name: String,
427    pub columns: Vec<ColumnDef>,
428    pub primary_key: String,
429    pub if_not_exists: bool,
430}
431
432#[derive(Debug, Clone, PartialEq)]
433pub struct CreateRelTable {
434    pub name: String,
435    pub from: String,
436    pub to: String,
437    pub columns: Vec<ColumnDef>,
438    pub if_not_exists: bool,
439}
440
441#[derive(Debug, Clone, PartialEq)]
442pub struct DropTable {
443    pub name: String,
444}
445
446/// A `CREATE [ART|HASH] INDEX` statement.
447#[derive(Debug, Clone, PartialEq)]
448pub struct CreateIndex {
449    pub index_type: String,
450    pub index_name: String,
451    pub table_name: String,
452    pub variable: String,
453    pub property: String,
454    pub conflict_action: Option<String>,
455}
456
457/// A `DROP INDEX` statement.
458#[derive(Debug, Clone, PartialEq)]
459pub struct DropIndex {
460    pub index_name: String,
461    pub table_name: String,
462}
463
464/// ALTER TABLE statement.
465#[derive(Debug, Clone, PartialEq)]
466pub struct AlterTable {
467    pub table_name: String,
468    pub action: AlterAction,
469}
470
471#[derive(Debug, Clone, PartialEq)]
472pub enum AlterAction {
473    AddColumn { name: String, type_name: String },
474    DropColumn { name: String },
475    RenameColumn { old_name: String, new_name: String },
476    RenameTable { new_name: String },
477}
478
479/// UNION statement — combines results from two queries.
480#[derive(Debug, Clone, PartialEq)]
481pub struct UnionStatement {
482    pub left: Query,
483    pub right: Query,
484    pub all: bool,
485}
486
487/// COPY FROM statement — load data from a file into a table.
488#[derive(Debug, Clone, PartialEq)]
489pub struct CopyFrom {
490    pub table_name: String,
491    pub file_path: String,
492    pub options: std::collections::HashMap<String, String>,
493}
494
495/// COPY TO statement — export query results to a file.
496///
497/// Syntax: `COPY (query) TO 'path' (FORMAT 'CSV'|'PARQUET', HEADER true|false)`
498#[derive(Debug, Clone, PartialEq)]
499pub struct CopyTo {
500    pub query: Query,
501    pub file_path: String,
502    pub format: CopyToFormat,
503    pub header: bool,
504}
505
506#[derive(Debug, Clone, PartialEq)]
507pub enum CopyToFormat {
508    Csv,
509    Parquet,
510}
511
512/// MERGE statement — match or create a pattern with optional ON CREATE / ON MATCH actions.
513#[derive(Debug, Clone, PartialEq)]
514pub struct MergeStatement {
515    pub patterns: Vec<Pattern>,
516    pub on_create: Vec<SetItem>,
517    pub on_match: Vec<SetItem>,
518}
519
520/// CALL statement — invoke a table function or procedure as a standalone statement.
521#[derive(Debug, Clone, PartialEq)]
522pub struct StandaloneCall {
523    pub function_name: String,
524    pub args: Vec<Expression>,
525}
526
527/// CREATE SEQUENCE statement — creates a sequence for auto-incrementing counters.
528///
529/// Syntax:
530/// ```sql
531/// CREATE [OR REPLACE] SEQUENCE [IF NOT EXISTS] name
532///   [START WITH value]
533///   [INCREMENT [BY] value]
534///   [MINVALUE value | NO MINVALUE]
535///   [MAXVALUE value | NO MAXVALUE]
536///   [CYCLE | NO CYCLE]
537/// ```
538#[derive(Debug, Clone, PartialEq)]
539pub struct CreateSequence {
540    pub name: String,
541    pub if_not_exists: bool,
542    pub or_replace: bool,
543    /// START WITH value. Default: 1 for increment > 0, max_value for increment < 0.
544    pub start_with: Option<i64>,
545    /// INCREMENT BY value. Default: 1.
546    pub increment: Option<i64>,
547    /// MINVALUE. Auto-computed from defaults if None.
548    pub min_value: Option<i64>,
549    /// MAXVALUE. Auto-computed from defaults if None.
550    pub max_value: Option<i64>,
551    /// CYCLE behavior. Default: false (NO CYCLE).
552    pub cycle: Option<bool>,
553}
554
555/// DROP SEQUENCE statement.
556#[derive(Debug, Clone, PartialEq)]
557pub struct DropSequence {
558    pub name: String,
559    pub if_exists: bool,
560}
561
562/// CREATE MACRO statement — defines a Cypher scalar macro.
563///
564/// Syntax: `CREATE MACRO macroName(param1, param2, ...) AS expression`
565///
566/// Macros are expanded at binding time: macro invocations are replaced
567/// with the macro body expression (with parameters substituted).
568///
569/// Ported from C++ `parser/create_macro.h`.
570#[derive(Debug, Clone, PartialEq)]
571pub struct CreateMacro {
572    /// The macro name.
573    pub name: String,
574    /// Positional parameter names (no default value).
575    pub positional_args: Vec<String>,
576    /// Parameters with default values (name, default expression).
577    pub default_args: Vec<(String, Expression)>,
578    /// The macro body expression.
579    pub expression: Box<Expression>,
580}
581
582/// CREATE VECTOR INDEX statement — creates an HNSW index on a vector column.
583#[derive(Debug, Clone, PartialEq)]
584pub struct CreateVectorIndex {
585    pub index_name: String,
586    pub table_name: String,
587    pub column_name: String,
588    pub metric: String,
589    pub dimensions: u64,
590}
591
592#[derive(Debug, Clone, PartialEq)]
593pub struct ColumnDef {
594    pub name: String,
595    pub type_name: String,
596    pub compression: Option<String>,
597}
598
599/// CREATE TYPE name AS type — user-defined type alias.
600#[derive(Debug, Clone, PartialEq)]
601pub struct CreateType {
602    pub name: String,
603    pub type_name: String,
604}
605
606/// COMMENT ON TABLE name IS 'string' — add a comment to a table.
607#[derive(Debug, Clone, PartialEq)]
608pub struct CommentOnTable {
609    pub table_name: String,
610    pub comment: String,
611}
612
613/// CREATE [PROJECTION] GRAPH name [ANY] — create a projected graph.
614#[derive(Debug, Clone, PartialEq)]
615pub struct CreateGraph {
616    pub name: String,
617    pub is_any: bool,
618}
619
620/// USE GRAPH name — set the current graph context.
621#[derive(Debug, Clone, PartialEq)]
622pub struct UseGraph {
623    pub name: String,
624}
625
626/// DROP GRAPH name — remove a projected graph.
627#[derive(Debug, Clone, PartialEq)]
628pub struct DropGraph {
629    pub name: String,
630}