Skip to main content

grafeo_adapters/query/gql/
parser.rs

1//! GQL Parser.
2
3#[allow(clippy::wildcard_imports)]
4use super::ast::*;
5use super::lexer::{Lexer, Token, TokenKind};
6use grafeo_common::utils::error::{Error, QueryError, QueryErrorKind, Result, SourceSpan};
7
8/// Unescapes backslash-escaped characters in a string literal.
9fn unescape_string(s: &str) -> String {
10    let mut result = String::with_capacity(s.len());
11    let mut chars = s.chars();
12    while let Some(ch) = chars.next() {
13        if ch == '\\' {
14            match chars.next() {
15                Some('n') => result.push('\n'),
16                Some('r') => result.push('\r'),
17                Some('t') => result.push('\t'),
18                Some('\\') => result.push('\\'),
19                Some('\'') => result.push('\''),
20                Some('"') => result.push('"'),
21                Some(other) => {
22                    result.push('\\');
23                    result.push(other);
24                }
25                None => result.push('\\'),
26            }
27        } else {
28            result.push(ch);
29        }
30    }
31    result
32}
33
34/// GQL Parser.
35pub struct Parser<'a> {
36    lexer: Lexer<'a>,
37    current: Token,
38    peeked: Option<Token>,
39    peeked_second: Option<Token>,
40    source: &'a str,
41}
42
43impl<'a> Parser<'a> {
44    /// Creates a new parser for the given input.
45    pub fn new(input: &'a str) -> Self {
46        let mut lexer = Lexer::new(input);
47        let current = lexer.next_token();
48        Self {
49            lexer,
50            current,
51            peeked: None,
52            peeked_second: None,
53            source: input,
54        }
55    }
56
57    /// Checks if the current token can be used as a label or type name.
58    /// This includes identifiers, quoted identifiers, and certain reserved keywords that are
59    /// commonly used as labels (Node, Edge, Type, etc.)
60    fn is_label_or_type_name(&self) -> bool {
61        matches!(
62            self.current.kind,
63            TokenKind::Identifier
64                | TokenKind::QuotedIdentifier
65                | TokenKind::Node
66                | TokenKind::Edge
67                | TokenKind::Type
68                | TokenKind::Match
69                | TokenKind::Return
70                | TokenKind::Where
71                | TokenKind::And
72                | TokenKind::Or
73                | TokenKind::Not
74                | TokenKind::Insert
75                | TokenKind::Delete
76                | TokenKind::Set
77                | TokenKind::Create
78                | TokenKind::As
79                | TokenKind::Distinct
80                | TokenKind::Order
81                | TokenKind::By
82                | TokenKind::Asc
83                | TokenKind::Desc
84                | TokenKind::Limit
85                | TokenKind::Skip
86                | TokenKind::With
87                | TokenKind::Optional
88                | TokenKind::Null
89                | TokenKind::True
90                | TokenKind::False
91                | TokenKind::In
92                | TokenKind::Is
93                | TokenKind::Like
94                | TokenKind::Case
95                | TokenKind::When
96                | TokenKind::Then
97                | TokenKind::Else
98                | TokenKind::End
99                | TokenKind::Exists
100                | TokenKind::Call
101                | TokenKind::Yield
102                | TokenKind::Detach
103                | TokenKind::Unwind
104                | TokenKind::Merge
105                | TokenKind::On
106                | TokenKind::Starts
107                | TokenKind::Ends
108                | TokenKind::Contains
109                | TokenKind::Nodetach
110                | TokenKind::Fetch
111                | TokenKind::First
112                | TokenKind::Next
113                | TokenKind::Rows
114                | TokenKind::Row
115                | TokenKind::Only
116        )
117    }
118
119    /// Checks if the current token is an identifier (regular or backtick-quoted).
120    fn is_identifier(&self) -> bool {
121        matches!(
122            self.current.kind,
123            TokenKind::Identifier | TokenKind::QuotedIdentifier
124        ) || self.is_contextual_keyword()
125    }
126
127    /// Checks if the current token is a keyword that can be used as an identifier in context.
128    /// In GQL/Cypher, many keywords can be used as variable names or labels.
129    fn is_contextual_keyword(&self) -> bool {
130        matches!(
131            self.current.kind,
132            TokenKind::End       // CASE...END
133                | TokenKind::Node    // CREATE NODE TYPE
134                | TokenKind::Edge    // CREATE EDGE TYPE
135                | TokenKind::Type    // type() function
136                | TokenKind::Case    // CASE expression
137                | TokenKind::When    // CASE WHEN
138                | TokenKind::Then    // CASE THEN
139                | TokenKind::Else    // CASE ELSE
140                | TokenKind::In      // IN operator (can be label/variable)
141                | TokenKind::Is      // IS NULL
142                | TokenKind::And     // AND operator
143                | TokenKind::Or      // OR operator
144                | TokenKind::Not     // NOT operator
145                | TokenKind::Null    // NULL literal
146                | TokenKind::True    // TRUE literal
147                | TokenKind::False   // FALSE literal
148                | TokenKind::Vector  // vector() function
149                | TokenKind::Index   // index-related usage
150                | TokenKind::Dimension // dimension option
151                | TokenKind::Metric  // metric option
152                | TokenKind::Set     // SESSION SET
153                | TokenKind::All     // SESSION RESET ALL, UNION ALL
154                | TokenKind::Filter  // FILTER as clause name
155                | TokenKind::Having // HAVING as identifier
156                | TokenKind::Fetch  // FETCH FIRST
157                | TokenKind::First  // FETCH FIRST
158                | TokenKind::Next   // FETCH NEXT
159                | TokenKind::Rows   // ROWS ONLY
160                | TokenKind::Row    // ROW ONLY
161                | TokenKind::Only // ROWS ONLY
162        )
163    }
164
165    /// Gets the identifier name from the current token.
166    /// For quoted identifiers, strips the backticks.
167    fn get_identifier_name(&self) -> String {
168        let text = &self.current.text;
169        if self.current.kind == TokenKind::QuotedIdentifier {
170            // Strip backticks from `name` -> name
171            text[1..text.len() - 1].to_string()
172        } else {
173            text.clone()
174        }
175    }
176
177    /// Parses the input into a statement.
178    pub fn parse(&mut self) -> Result<Statement> {
179        // Handle EXPLAIN/PROFILE prefix: wraps the entire following statement
180        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("EXPLAIN") {
181            self.advance(); // consume EXPLAIN
182            let inner = self.parse()?;
183            return Ok(Statement::Explain(Box::new(inner)));
184        }
185        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("PROFILE") {
186            self.advance(); // consume PROFILE
187            let inner = self.parse()?;
188            return Ok(Statement::Profile(Box::new(inner)));
189        }
190
191        let mut left = self.parse_single_statement()?;
192
193        // Handle NEXT (linear composition): output of left becomes input of right
194        while self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("NEXT") {
195            self.advance(); // consume NEXT
196            let right = self.parse_single_statement()?;
197            // NEXT semantics: chain right after left (like WITH pipe).
198            // Represent as CompositeQuery with a dedicated op.
199            left = Statement::CompositeQuery {
200                left: Box::new(left),
201                op: CompositeOp::Next,
202                right: Box::new(right),
203            };
204        }
205
206        // Check for composite query operators (UNION, EXCEPT, INTERSECT, OTHERWISE)
207        while matches!(
208            self.current.kind,
209            TokenKind::Union | TokenKind::Except | TokenKind::Intersect | TokenKind::Otherwise
210        ) {
211            let op = match self.current.kind {
212                TokenKind::Union => {
213                    self.advance();
214                    if self.current.kind == TokenKind::All {
215                        self.advance();
216                        CompositeOp::UnionAll
217                    } else {
218                        // UNION DISTINCT is explicit form of the default
219                        if self.current.kind == TokenKind::Distinct {
220                            self.advance();
221                        }
222                        CompositeOp::Union
223                    }
224                }
225                TokenKind::Except => {
226                    self.advance();
227                    if self.current.kind == TokenKind::All {
228                        self.advance();
229                        CompositeOp::ExceptAll
230                    } else {
231                        // EXCEPT DISTINCT is explicit form of the default
232                        if self.current.kind == TokenKind::Distinct {
233                            self.advance();
234                        }
235                        CompositeOp::Except
236                    }
237                }
238                TokenKind::Intersect => {
239                    self.advance();
240                    if self.current.kind == TokenKind::All {
241                        self.advance();
242                        CompositeOp::IntersectAll
243                    } else {
244                        // INTERSECT DISTINCT is explicit form of the default
245                        if self.current.kind == TokenKind::Distinct {
246                            self.advance();
247                        }
248                        CompositeOp::Intersect
249                    }
250                }
251                TokenKind::Otherwise => {
252                    self.advance();
253                    CompositeOp::Otherwise
254                }
255                _ => unreachable!(),
256            };
257            let right = self.parse_single_statement()?;
258            left = Statement::CompositeQuery {
259                left: Box::new(left),
260                op,
261                right: Box::new(right),
262            };
263        }
264
265        Ok(left)
266    }
267
268    fn parse_single_statement(&mut self) -> Result<Statement> {
269        match self.current.kind {
270            TokenKind::Match
271            | TokenKind::Optional
272            | TokenKind::Unwind
273            | TokenKind::Merge
274            | TokenKind::For
275            | TokenKind::Return => self.parse_query().map(Statement::Query),
276            TokenKind::Insert => self
277                .parse_insert()
278                .map(|s| Statement::DataModification(DataModificationStatement::Insert(s))),
279            TokenKind::Delete | TokenKind::Detach | TokenKind::Nodetach => self
280                .parse_delete()
281                .map(|s| Statement::DataModification(DataModificationStatement::Delete(s))),
282            TokenKind::Create => {
283                // Check if CREATE is followed by a pattern (Cypher-style) or a DDL keyword
284                let next = self.peek_kind();
285                if next == TokenKind::LParen {
286                    // Cypher-style: CREATE (n:Label {...}) - treat as INSERT
287                    self.parse_create_as_insert()
288                        .map(|s| Statement::DataModification(DataModificationStatement::Insert(s)))
289                } else {
290                    // GQL schema/session: dispatches between DDL (NODE TYPE, EDGE TYPE,
291                    // GRAPH TYPE, INDEX, CONSTRAINT, SCHEMA) and session (GRAPH instance)
292                    self.parse_create_dispatch()
293                }
294            }
295            TokenKind::Call => {
296                if self.peek_kind() == TokenKind::LBrace {
297                    // CALL { subquery } RETURN ... : treat as a query
298                    self.parse_query().map(Statement::Query)
299                } else {
300                    self.parse_call_statement().map(Statement::Call)
301                }
302            }
303            _ if self.is_identifier() => {
304                let name = self.get_identifier_name();
305                match name.to_uppercase().as_str() {
306                    "DROP" => self.parse_drop(),
307                    "USE" => self.parse_use_graph().map(Statement::SessionCommand),
308                    "SESSION" => self.parse_session_command().map(Statement::SessionCommand),
309                    "START" => self
310                        .parse_start_transaction()
311                        .map(Statement::SessionCommand),
312                    "COMMIT" => {
313                        self.advance();
314                        Ok(Statement::SessionCommand(SessionCommand::Commit))
315                    }
316                    "ROLLBACK" => {
317                        self.advance();
318                        // Check for ROLLBACK TO SAVEPOINT name
319                        if self.is_identifier()
320                            && self.get_identifier_name().eq_ignore_ascii_case("TO")
321                        {
322                            self.advance(); // consume TO
323                            if !(self.is_identifier()
324                                && self.get_identifier_name().eq_ignore_ascii_case("SAVEPOINT"))
325                            {
326                                return Err(self.error("Expected SAVEPOINT after ROLLBACK TO"));
327                            }
328                            self.advance(); // consume SAVEPOINT
329                            let name = self.get_identifier_name();
330                            self.advance(); // consume name
331                            Ok(Statement::SessionCommand(
332                                SessionCommand::RollbackToSavepoint(name),
333                            ))
334                        } else {
335                            Ok(Statement::SessionCommand(SessionCommand::Rollback))
336                        }
337                    }
338                    "SAVEPOINT" => {
339                        self.advance();
340                        let name = self.get_identifier_name();
341                        self.advance();
342                        Ok(Statement::SessionCommand(SessionCommand::Savepoint(name)))
343                    }
344                    "RELEASE" => {
345                        self.advance();
346                        if !(self.is_identifier()
347                            && self.get_identifier_name().eq_ignore_ascii_case("SAVEPOINT"))
348                        {
349                            return Err(self.error("Expected SAVEPOINT after RELEASE"));
350                        }
351                        self.advance(); // consume SAVEPOINT
352                        let name = self.get_identifier_name();
353                        self.advance();
354                        Ok(Statement::SessionCommand(SessionCommand::ReleaseSavepoint(
355                            name,
356                        )))
357                    }
358                    "ALTER" => self.parse_alter(),
359                    "SHOW" => self.parse_show().map(Statement::Schema),
360                    "LOAD" => self.parse_query().map(Statement::Query),
361                    _ => Err(self.error(
362                        "Expected MATCH, INSERT, DELETE, MERGE, UNWIND, FOR, CREATE, CALL, \
363                         DROP, ALTER, SHOW, LOAD, USE, SESSION, START, COMMIT, ROLLBACK, or SAVEPOINT",
364                    )),
365                }
366            }
367            _ => Err(self.error(
368                "Expected MATCH, INSERT, DELETE, MERGE, UNWIND, FOR, CREATE, CALL, \
369                 DROP, SHOW, LOAD, USE, SESSION, START, COMMIT, or ROLLBACK",
370            )),
371        }
372    }
373
374    /// Parses a CALL procedure statement.
375    ///
376    /// ```text
377    /// CALL name.space(args) [YIELD field [AS alias], ...]
378    /// ```
379    fn parse_call_statement(&mut self) -> Result<CallStatement> {
380        let span_start = self.current.span.start;
381        self.expect(TokenKind::Call)?;
382
383        // Parse dotted procedure name: ident { . ident }
384        if !self.is_identifier() {
385            return Err(self.error("Expected procedure name after CALL"));
386        }
387        let mut name_parts = vec![self.get_identifier_name()];
388        self.advance();
389        while self.current.kind == TokenKind::Dot {
390            self.advance();
391            if !self.is_identifier() {
392                return Err(self.error("Expected identifier after '.'"));
393            }
394            name_parts.push(self.get_identifier_name());
395            self.advance();
396        }
397
398        // Parse argument list: ( [expr { , expr }] )
399        self.expect(TokenKind::LParen)?;
400        let mut arguments = Vec::new();
401        if self.current.kind != TokenKind::RParen {
402            arguments.push(self.parse_expression()?);
403            while self.current.kind == TokenKind::Comma {
404                self.advance();
405                arguments.push(self.parse_expression()?);
406            }
407        }
408        self.expect(TokenKind::RParen)?;
409
410        // Parse optional YIELD clause
411        let yield_items = if self.current.kind == TokenKind::Yield {
412            self.advance();
413            Some(self.parse_yield_list()?)
414        } else {
415            None
416        };
417
418        // Parse optional WHERE clause (only valid after YIELD)
419        let where_clause = if yield_items.is_some() && self.current.kind == TokenKind::Where {
420            Some(self.parse_where_clause()?)
421        } else {
422            None
423        };
424
425        // Parse optional RETURN clause (only valid after YIELD)
426        let return_clause = if yield_items.is_some() && self.current.kind == TokenKind::Return {
427            Some(self.parse_return_clause()?)
428        } else {
429            None
430        };
431
432        Ok(CallStatement {
433            procedure_name: name_parts,
434            arguments,
435            yield_items,
436            where_clause,
437            return_clause,
438            span: Some(SourceSpan::new(span_start, self.current.span.start, 1, 1)),
439        })
440    }
441
442    /// Parses an inline CALL { subquery }.
443    ///
444    /// ```text
445    /// CALL { [WITH var [, var]*] query_body RETURN ... }
446    /// ```
447    fn parse_inline_call(&mut self) -> Result<QueryStatement> {
448        self.expect(TokenKind::Call)?;
449        self.expect(TokenKind::LBrace)?;
450
451        // Parse the inner query body (MATCH ... RETURN ...)
452        let inner = self.parse_query()?;
453
454        self.expect(TokenKind::RBrace)?;
455        Ok(inner)
456    }
457
458    /// Parses a YIELD item list: `field [AS alias] { , field [AS alias] }`.
459    fn parse_yield_list(&mut self) -> Result<Vec<YieldItem>> {
460        let mut items = vec![self.parse_yield_item()?];
461        while self.current.kind == TokenKind::Comma {
462            self.advance();
463            items.push(self.parse_yield_item()?);
464        }
465        Ok(items)
466    }
467
468    /// Parses a single YIELD item: `field_name [AS alias]`.
469    fn parse_yield_item(&mut self) -> Result<YieldItem> {
470        let span_start = self.current.span.start;
471        if !self.is_identifier() {
472            return Err(self.error("Expected field name in YIELD"));
473        }
474        let field_name = self.get_identifier_name();
475        self.advance();
476        let alias = if self.current.kind == TokenKind::As {
477            self.advance();
478            if !self.is_identifier() {
479                return Err(self.error("Expected alias after AS"));
480            }
481            let alias_name = self.get_identifier_name();
482            self.advance();
483            Some(alias_name)
484        } else {
485            None
486        };
487        Ok(YieldItem {
488            field_name,
489            alias,
490            span: Some(SourceSpan::new(span_start, self.current.span.start, 1, 1)),
491        })
492    }
493
494    fn parse_query(&mut self) -> Result<QueryStatement> {
495        let span_start = self.current.span.start;
496
497        let mut match_clauses = Vec::new();
498        let mut unwind_clauses = Vec::new();
499        let mut merge_clauses = Vec::new();
500        let mut create_clauses = Vec::new();
501        let mut delete_clauses = Vec::new();
502        let mut ordered_clauses = Vec::new();
503
504        // Parse clauses in source order, preserving sequence for variable scoping.
505        // MATCH, OPTIONAL MATCH, UNWIND, FOR, MERGE, CREATE/INSERT, DELETE can appear
506        // in any order before RETURN.
507        loop {
508            match self.current.kind {
509                TokenKind::Match => {
510                    let clause = self.parse_match_clause()?;
511                    ordered_clauses.push(QueryClause::Match(clause.clone()));
512                    match_clauses.push(clause);
513                }
514                TokenKind::Optional => {
515                    // OPTIONAL MATCH or OPTIONAL CALL { subquery }
516                    let pk = self.peek_kind();
517                    if pk == TokenKind::Call {
518                        self.advance(); // consume OPTIONAL
519                        if self.peek_kind() == TokenKind::LBrace {
520                            // OPTIONAL CALL { subquery }
521                            let subquery = self.parse_inline_call()?;
522                            ordered_clauses.push(QueryClause::InlineCall {
523                                subquery,
524                                optional: true,
525                            });
526                        } else {
527                            // OPTIONAL CALL procedure(...)
528                            let call = self.parse_call_statement()?;
529                            ordered_clauses.push(QueryClause::CallProcedure(call));
530                        }
531                    } else {
532                        let clause = self.parse_match_clause()?;
533                        ordered_clauses.push(QueryClause::Match(clause.clone()));
534                        match_clauses.push(clause);
535                    }
536                }
537                TokenKind::Unwind => {
538                    let clause = self.parse_unwind_clause()?;
539                    ordered_clauses.push(QueryClause::Unwind(clause.clone()));
540                    unwind_clauses.push(clause);
541                }
542                TokenKind::For => {
543                    let clause = self.parse_for_clause()?;
544                    ordered_clauses.push(QueryClause::For(clause.clone()));
545                    unwind_clauses.push(clause);
546                }
547                TokenKind::Merge => {
548                    let clause = self.parse_merge_clause()?;
549                    ordered_clauses.push(QueryClause::Merge(clause.clone()));
550                    merge_clauses.push(clause);
551                }
552                TokenKind::Create => {
553                    let clause = self.parse_create_clause_in_query()?;
554                    ordered_clauses.push(QueryClause::Create(clause.clone()));
555                    create_clauses.push(clause);
556                }
557                TokenKind::Insert => {
558                    let clause = self.parse_insert()?;
559                    ordered_clauses.push(QueryClause::Create(clause.clone()));
560                    create_clauses.push(clause);
561                }
562                TokenKind::Delete | TokenKind::Detach | TokenKind::Nodetach => {
563                    let clause = self.parse_delete_clause_in_query()?;
564                    ordered_clauses.push(QueryClause::Delete(clause.clone()));
565                    delete_clauses.push(clause);
566                }
567                TokenKind::Call => {
568                    // CALL { subquery } (inline) or CALL procedure(...) (within query)
569                    if self.peek_kind() == TokenKind::LBrace {
570                        let subquery = self.parse_inline_call()?;
571                        ordered_clauses.push(QueryClause::InlineCall {
572                            subquery,
573                            optional: false,
574                        });
575                    } else {
576                        let call = self.parse_call_statement()?;
577                        ordered_clauses.push(QueryClause::CallProcedure(call));
578                    }
579                }
580                _ if self.is_identifier()
581                    && self.get_identifier_name().eq_ignore_ascii_case("LET") =>
582                {
583                    let bindings = self.parse_let_clause()?;
584                    ordered_clauses.push(QueryClause::Let(bindings));
585                }
586                _ if self.is_identifier()
587                    && self.get_identifier_name().eq_ignore_ascii_case("LOAD") =>
588                {
589                    let clause = self.parse_load_data_clause()?;
590                    ordered_clauses.push(QueryClause::LoadData(clause));
591                }
592                _ => break,
593            }
594        }
595
596        // Parse WHERE or FILTER clause (after all MATCH clauses)
597        let where_clause = if matches!(self.current.kind, TokenKind::Where | TokenKind::Filter) {
598            Some(self.parse_where_or_filter_clause()?)
599        } else {
600            None
601        };
602
603        // After WHERE, allow CREATE/INSERT/DELETE/DETACH clauses
604        loop {
605            match self.current.kind {
606                TokenKind::Create => {
607                    let clause = self.parse_create_clause_in_query()?;
608                    ordered_clauses.push(QueryClause::Create(clause.clone()));
609                    create_clauses.push(clause);
610                }
611                TokenKind::Insert => {
612                    let clause = self.parse_insert()?;
613                    ordered_clauses.push(QueryClause::Create(clause.clone()));
614                    create_clauses.push(clause);
615                }
616                TokenKind::Delete | TokenKind::Detach | TokenKind::Nodetach => {
617                    let clause = self.parse_delete_clause_in_query()?;
618                    ordered_clauses.push(QueryClause::Delete(clause.clone()));
619                    delete_clauses.push(clause);
620                }
621                _ => break,
622            }
623        }
624
625        // Parse SET clauses
626        let mut set_clauses = Vec::new();
627        while self.current.kind == TokenKind::Set {
628            let clause = self.parse_set_clause()?;
629            ordered_clauses.push(QueryClause::Set(clause.clone()));
630            set_clauses.push(clause);
631        }
632
633        // Parse REMOVE clauses
634        let mut remove_clauses = Vec::new();
635        while self.current.kind == TokenKind::Remove {
636            remove_clauses.push(self.parse_remove_clause()?);
637        }
638
639        // Parse WITH clauses
640        let mut with_clauses = Vec::new();
641        while self.current.kind == TokenKind::With {
642            let mut wc = self.parse_with_clause()?;
643
644            // Attach LET bindings that immediately follow the WITH clause
645            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("LET") {
646                wc.let_bindings = self.parse_let_clause()?;
647            }
648
649            with_clauses.push(wc);
650
651            // After WITH (+ optional LET), we can have more clauses
652            loop {
653                match self.current.kind {
654                    TokenKind::Match | TokenKind::Optional => {
655                        let clause = self.parse_match_clause()?;
656                        ordered_clauses.push(QueryClause::Match(clause.clone()));
657                        match_clauses.push(clause);
658                    }
659                    TokenKind::Unwind => {
660                        let clause = self.parse_unwind_clause()?;
661                        ordered_clauses.push(QueryClause::Unwind(clause.clone()));
662                        unwind_clauses.push(clause);
663                    }
664                    TokenKind::For => {
665                        let clause = self.parse_for_clause()?;
666                        ordered_clauses.push(QueryClause::For(clause.clone()));
667                        unwind_clauses.push(clause);
668                    }
669                    TokenKind::Merge => {
670                        let clause = self.parse_merge_clause()?;
671                        ordered_clauses.push(QueryClause::Merge(clause.clone()));
672                        merge_clauses.push(clause);
673                    }
674                    _ => break,
675                }
676            }
677        }
678
679        // Parse RETURN, FINISH, or SELECT clause
680        let return_clause = if self.current.kind == TokenKind::Return {
681            self.parse_return_clause()?
682        } else if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("FINISH")
683        {
684            // FINISH: consume input, return empty result
685            self.advance();
686            ReturnClause {
687                distinct: false,
688                items: Vec::new(),
689                is_wildcard: false,
690                group_by: Vec::new(),
691                order_by: None,
692                skip: None,
693                limit: None,
694                is_finish: true,
695                span: None,
696            }
697        } else if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("SELECT")
698        {
699            // SELECT: SQL-style projection, parsed as RETURN
700            self.advance(); // consume SELECT
701            self.parse_select_clause()?
702        } else if !set_clauses.is_empty()
703            || !remove_clauses.is_empty()
704            || !merge_clauses.is_empty()
705            || !create_clauses.is_empty()
706            || !delete_clauses.is_empty()
707        {
708            // For mutation-only queries, return empty clause
709            ReturnClause {
710                distinct: false,
711                items: Vec::new(),
712                is_wildcard: false,
713                group_by: Vec::new(),
714                order_by: None,
715                skip: None,
716                limit: None,
717                is_finish: false,
718                span: None,
719            }
720        } else {
721            return Err(self.error("Expected RETURN, FINISH, or SELECT"));
722        };
723
724        // Parse optional HAVING clause (after RETURN, filters aggregate results)
725        let having_clause = if self.current.kind == TokenKind::Having {
726            Some(self.parse_having_clause()?)
727        } else {
728            None
729        };
730
731        Ok(QueryStatement {
732            match_clauses,
733            where_clause,
734            set_clauses,
735            remove_clauses,
736            with_clauses,
737            unwind_clauses,
738            merge_clauses,
739            create_clauses,
740            delete_clauses,
741            return_clause,
742            having_clause,
743            ordered_clauses,
744            span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
745        })
746    }
747
748    /// Parses a FOR clause (GQL standard, ISO/IEC 39075 section 14.8).
749    /// `FOR variable IN expression`: desugars to an UnwindClause.
750    fn parse_for_clause(&mut self) -> Result<UnwindClause> {
751        let span_start = self.current.span.start;
752        self.expect(TokenKind::For)?;
753
754        // Parse variable name
755        if !self.is_identifier() {
756            return Err(self.error("Expected variable name after FOR"));
757        }
758        let alias = self.get_identifier_name();
759        self.advance();
760
761        // Expect IN keyword
762        self.expect(TokenKind::In)?;
763
764        // Parse expression (the list to iterate)
765        let expression = self.parse_expression()?;
766
767        // Parse optional WITH ORDINALITY/OFFSET
768        let (ordinality_var, offset_var) = if self.current.kind == TokenKind::With {
769            self.advance(); // consume WITH
770            if self.current.kind == TokenKind::Ordinality {
771                self.advance(); // consume ORDINALITY
772                if !self.is_identifier() {
773                    return Err(self.error("Expected variable name after ORDINALITY"));
774                }
775                let var = self.get_identifier_name();
776                self.advance();
777                (Some(var), None)
778            } else if self.current.kind == TokenKind::Offset {
779                self.advance(); // consume OFFSET
780                if !self.is_identifier() {
781                    return Err(self.error("Expected variable name after OFFSET"));
782                }
783                let var = self.get_identifier_name();
784                self.advance();
785                (None, Some(var))
786            } else {
787                return Err(self.error("Expected ORDINALITY or OFFSET after WITH"));
788            }
789        } else {
790            (None, None)
791        };
792
793        Ok(UnwindClause {
794            expression,
795            alias,
796            ordinality_var,
797            offset_var,
798            span: Some(SourceSpan::new(span_start, self.current.span.start, 1, 1)),
799        })
800    }
801
802    fn parse_set_clause(&mut self) -> Result<SetClause> {
803        let span_start = self.current.span.start;
804        self.expect(TokenKind::Set)?;
805
806        let mut assignments = Vec::new();
807        let mut map_assignments = Vec::new();
808        let mut label_operations = Vec::new();
809
810        loop {
811            // Parse variable name
812            if !self.is_identifier() {
813                return Err(self.error("Expected variable name in SET"));
814            }
815            let variable = self.current.text.clone();
816            self.advance();
817
818            // Check if this is a label operation (n:Label) or property assignment (n.prop = value)
819            // or map assignment (n = {map} or n += {map})
820            if self.current.kind == TokenKind::Colon {
821                // Label operation: SET n:Label1:Label2
822                let mut labels = Vec::new();
823                while self.current.kind == TokenKind::Colon {
824                    self.advance();
825                    if !self.is_label_or_type_name() {
826                        return Err(self.error("Expected label name after colon in SET"));
827                    }
828                    labels.push(self.current.text.clone());
829                    self.advance();
830                }
831                label_operations.push(LabelOperation { variable, labels });
832            } else if self.current.kind == TokenKind::Dot {
833                // Property assignment: SET n.prop = value
834                self.advance();
835
836                if !self.is_label_or_type_name() {
837                    return Err(self.error("Expected property name in SET"));
838                }
839                let property = self.current.text.clone();
840                self.advance();
841
842                self.expect(TokenKind::Eq)?;
843
844                let value = self.parse_expression()?;
845
846                assignments.push(PropertyAssignment {
847                    variable,
848                    property,
849                    value,
850                });
851            } else if self.current.kind == TokenKind::Eq {
852                // Map replace: SET n = {key: value, ...}
853                self.advance();
854                let map_expr = self.parse_expression()?;
855                map_assignments.push(MapAssignment {
856                    variable,
857                    map_expr,
858                    replace: true,
859                });
860            } else if self.current.kind == TokenKind::Plus {
861                // Map merge: SET n += {key: value, ...}
862                self.advance();
863                self.expect(TokenKind::Eq)?;
864                let map_expr = self.parse_expression()?;
865                map_assignments.push(MapAssignment {
866                    variable,
867                    map_expr,
868                    replace: false,
869                });
870            } else {
871                return Err(self.error("Expected '.', ':', '=', or '+=' after variable in SET"));
872            }
873
874            // Check for more assignments/operations
875            if self.current.kind != TokenKind::Comma {
876                break;
877            }
878            self.advance();
879        }
880
881        Ok(SetClause {
882            assignments,
883            map_assignments,
884            label_operations,
885            span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
886        })
887    }
888
889    fn parse_remove_clause(&mut self) -> Result<RemoveClause> {
890        let span_start = self.current.span.start;
891        self.expect(TokenKind::Remove)?;
892
893        let mut label_operations = Vec::new();
894        let mut property_removals = Vec::new();
895
896        loop {
897            // Parse variable name
898            if !self.is_identifier() {
899                return Err(self.error("Expected variable name in REMOVE"));
900            }
901            let variable = self.current.text.clone();
902            self.advance();
903
904            // Check if this is a label removal (n:Label) or property removal (n.prop)
905            if self.current.kind == TokenKind::Colon {
906                // Label removal: REMOVE n:Label1:Label2
907                let mut labels = Vec::new();
908                while self.current.kind == TokenKind::Colon {
909                    self.advance();
910                    if !self.is_label_or_type_name() {
911                        return Err(self.error("Expected label name after colon in REMOVE"));
912                    }
913                    labels.push(self.current.text.clone());
914                    self.advance();
915                }
916                label_operations.push(LabelOperation { variable, labels });
917            } else if self.current.kind == TokenKind::Dot {
918                // Property removal: REMOVE n.prop
919                self.advance();
920
921                if !self.is_label_or_type_name() {
922                    return Err(self.error("Expected property name in REMOVE"));
923                }
924                let property = self.current.text.clone();
925                self.advance();
926
927                property_removals.push((variable, property));
928            } else {
929                return Err(self.error("Expected '.' or ':' after variable in REMOVE"));
930            }
931
932            // Check for more removal operations
933            if self.current.kind != TokenKind::Comma {
934                break;
935            }
936            self.advance();
937        }
938
939        Ok(RemoveClause {
940            label_operations,
941            property_removals,
942            span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
943        })
944    }
945
946    fn parse_unwind_clause(&mut self) -> Result<UnwindClause> {
947        let span_start = self.current.span.start;
948        self.expect(TokenKind::Unwind)?;
949
950        // Parse the expression to unwind
951        let expression = self.parse_expression()?;
952
953        // Expect AS keyword
954        self.expect(TokenKind::As)?;
955
956        // Parse the alias
957        if !self.is_identifier() {
958            return Err(self.error("Expected alias after AS in UNWIND"));
959        }
960        let alias = self.get_identifier_name();
961        self.advance();
962
963        Ok(UnwindClause {
964            expression,
965            alias,
966            ordinality_var: None,
967            offset_var: None,
968            span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
969        })
970    }
971
972    /// Parses `LET var = expr [, var2 = expr2]*` as a clause.
973    fn parse_let_clause(&mut self) -> Result<Vec<(String, Expression)>> {
974        self.advance(); // consume LET
975        let mut bindings = Vec::new();
976        loop {
977            if !self.is_identifier() {
978                return Err(self.error("Expected variable name in LET clause"));
979            }
980            let var = self.get_identifier_name();
981            self.advance();
982            self.expect(TokenKind::Eq)?;
983            let expr = self.parse_expression()?;
984            bindings.push((var, expr));
985            if self.current.kind != TokenKind::Comma {
986                break;
987            }
988            self.advance(); // consume comma
989        }
990        Ok(bindings)
991    }
992
993    /// Parses `LOAD DATA FROM 'path' FORMAT CSV|JSONL|PARQUET [WITH HEADERS] AS variable [FIELDTERMINATOR 'char']`
994    /// Also accepts Cypher-compatible `LOAD CSV [WITH HEADERS] FROM 'path' AS variable [FIELDTERMINATOR 'char']`
995    fn parse_load_data_clause(&mut self) -> Result<LoadDataClause> {
996        let span_start = self.current.span.start;
997        self.advance(); // consume LOAD
998
999        // Check for Cypher-compatible LOAD CSV syntax
1000        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("CSV") {
1001            return self.parse_load_csv_compat(span_start);
1002        }
1003
1004        // GQL syntax: LOAD DATA FROM 'path' FORMAT CSV|JSONL|PARQUET [WITH HEADERS] AS variable
1005        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("DATA") {
1006            return Err(self.error("Expected DATA or CSV after LOAD"));
1007        }
1008        self.advance(); // consume DATA
1009
1010        // FROM 'path'
1011        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("FROM") {
1012            return Err(self.error("Expected FROM after DATA in LOAD DATA"));
1013        }
1014        self.advance(); // consume FROM
1015        let path = self.parse_string_value()?;
1016
1017        // FORMAT CSV|JSONL|PARQUET
1018        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("FORMAT") {
1019            return Err(self.error("Expected FORMAT after file path in LOAD DATA"));
1020        }
1021        self.advance(); // consume FORMAT
1022
1023        let format = if self.is_identifier() {
1024            let name = self.get_identifier_name();
1025            self.advance();
1026            match name.to_ascii_uppercase().as_str() {
1027                "CSV" => LoadFormat::Csv,
1028                "JSONL" | "NDJSON" => LoadFormat::Jsonl,
1029                "PARQUET" => LoadFormat::Parquet,
1030                _ => {
1031                    return Err(self.error(&format!(
1032                        "Unknown format '{name}', expected CSV, JSONL, or PARQUET"
1033                    )));
1034                }
1035            }
1036        } else {
1037            return Err(self.error("Expected format name (CSV, JSONL, or PARQUET)"));
1038        };
1039
1040        // Optional: WITH HEADERS (CSV only)
1041        let with_headers = if self.current.kind == TokenKind::With {
1042            self.advance();
1043            if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("HEADERS")
1044            {
1045                return Err(self.error("Expected HEADERS after WITH in LOAD DATA"));
1046            }
1047            self.advance();
1048            true
1049        } else {
1050            false
1051        };
1052
1053        // AS variable
1054        self.expect(TokenKind::As)?;
1055        if !self.is_identifier() {
1056            return Err(self.error("Expected variable name after AS in LOAD DATA"));
1057        }
1058        let variable = self.get_identifier_name();
1059        self.advance();
1060
1061        // Optional: FIELDTERMINATOR 'char'
1062        let field_terminator = self.parse_optional_field_terminator()?;
1063
1064        Ok(LoadDataClause {
1065            path,
1066            format,
1067            with_headers,
1068            variable,
1069            field_terminator,
1070            span: SourceSpan::new(span_start, self.current.span.end, 1, 1),
1071        })
1072    }
1073
1074    /// Parses Cypher-compatible `LOAD CSV [WITH HEADERS] FROM 'path' AS variable [FIELDTERMINATOR 'char']`.
1075    fn parse_load_csv_compat(&mut self, span_start: usize) -> Result<LoadDataClause> {
1076        self.advance(); // consume CSV
1077
1078        // Optional: WITH HEADERS
1079        let with_headers = if self.current.kind == TokenKind::With {
1080            self.advance();
1081            if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("HEADERS")
1082            {
1083                return Err(self.error("Expected HEADERS after WITH"));
1084            }
1085            self.advance();
1086            true
1087        } else {
1088            false
1089        };
1090
1091        // FROM 'path'
1092        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("FROM") {
1093            return Err(self.error("Expected FROM after WITH HEADERS or CSV"));
1094        }
1095        self.advance(); // consume FROM
1096        let path = self.parse_string_value()?;
1097
1098        // AS variable
1099        self.expect(TokenKind::As)?;
1100        if !self.is_identifier() {
1101            return Err(self.error("Expected variable name after AS"));
1102        }
1103        let variable = self.get_identifier_name();
1104        self.advance();
1105
1106        // Optional: FIELDTERMINATOR 'char'
1107        let field_terminator = self.parse_optional_field_terminator()?;
1108
1109        Ok(LoadDataClause {
1110            path,
1111            format: LoadFormat::Csv,
1112            with_headers,
1113            variable,
1114            field_terminator,
1115            span: SourceSpan::new(span_start, self.current.span.end, 1, 1),
1116        })
1117    }
1118
1119    /// Expects and consumes a string literal, returning the unescaped value.
1120    fn parse_string_value(&mut self) -> Result<String> {
1121        if self.current.kind != TokenKind::String {
1122            return Err(self.error("Expected string literal"));
1123        }
1124        let text = &self.current.text;
1125        let inner = &text[1..text.len() - 1];
1126        let value = unescape_string(inner);
1127        self.advance();
1128        Ok(value)
1129    }
1130
1131    /// Parses an optional `FIELDTERMINATOR 'char'` clause.
1132    fn parse_optional_field_terminator(&mut self) -> Result<Option<char>> {
1133        if self.is_identifier()
1134            && self
1135                .get_identifier_name()
1136                .eq_ignore_ascii_case("FIELDTERMINATOR")
1137        {
1138            self.advance();
1139            let term = self.parse_string_value()?;
1140            Ok(term.chars().next())
1141        } else {
1142            Ok(None)
1143        }
1144    }
1145
1146    fn parse_merge_clause(&mut self) -> Result<MergeClause> {
1147        let span_start = self.current.span.start;
1148        self.expect(TokenKind::Merge)?;
1149
1150        // Parse the pattern to merge
1151        let pattern = self.parse_pattern()?;
1152
1153        // Parse optional ON CREATE and ON MATCH clauses
1154        let mut on_create = None;
1155        let mut on_match = None;
1156
1157        while self.current.kind == TokenKind::On {
1158            self.advance();
1159
1160            if self.current.kind == TokenKind::Create {
1161                self.advance();
1162                self.expect(TokenKind::Set)?;
1163                on_create = Some(self.parse_property_assignments()?);
1164            } else if self.current.kind == TokenKind::Match {
1165                self.advance();
1166                self.expect(TokenKind::Set)?;
1167                on_match = Some(self.parse_property_assignments()?);
1168            } else {
1169                return Err(self.error("Expected CREATE or MATCH after ON in MERGE"));
1170            }
1171        }
1172
1173        Ok(MergeClause {
1174            pattern,
1175            on_create,
1176            on_match,
1177            span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
1178        })
1179    }
1180
1181    fn parse_property_assignments(&mut self) -> Result<Vec<PropertyAssignment>> {
1182        let mut assignments = Vec::new();
1183        loop {
1184            // Parse variable.property = expression
1185            if !self.is_identifier() {
1186                return Err(self.error("Expected variable name"));
1187            }
1188            let variable = self.get_identifier_name();
1189            self.advance();
1190
1191            self.expect(TokenKind::Dot)?;
1192
1193            if !self.is_label_or_type_name() {
1194                return Err(self.error("Expected property name"));
1195            }
1196            let property = self.get_identifier_name();
1197            self.advance();
1198
1199            self.expect(TokenKind::Eq)?;
1200
1201            let value = self.parse_expression()?;
1202
1203            assignments.push(PropertyAssignment {
1204                variable,
1205                property,
1206                value,
1207            });
1208
1209            // Check for more assignments
1210            if self.current.kind != TokenKind::Comma {
1211                break;
1212            }
1213            self.advance();
1214        }
1215
1216        Ok(assignments)
1217    }
1218
1219    fn parse_match_clause(&mut self) -> Result<MatchClause> {
1220        let span_start = self.current.span.start;
1221
1222        // Check for OPTIONAL MATCH
1223        let optional = if self.current.kind == TokenKind::Optional {
1224            self.advance();
1225            true
1226        } else {
1227            false
1228        };
1229
1230        self.expect(TokenKind::Match)?;
1231
1232        // Check for path mode (WALK, TRAIL, SIMPLE, ACYCLIC)
1233        let path_mode = match self.current.kind {
1234            TokenKind::Walk => {
1235                self.advance();
1236                Some(PathMode::Walk)
1237            }
1238            TokenKind::Trail => {
1239                self.advance();
1240                Some(PathMode::Trail)
1241            }
1242            TokenKind::Simple => {
1243                self.advance();
1244                Some(PathMode::Simple)
1245            }
1246            TokenKind::Acyclic => {
1247                self.advance();
1248                Some(PathMode::Acyclic)
1249            }
1250            _ => None,
1251        };
1252
1253        // Check for match mode (DIFFERENT EDGES, REPEATABLE ELEMENTS)
1254        let match_mode = if self.is_identifier()
1255            && self.get_identifier_name().eq_ignore_ascii_case("DIFFERENT")
1256        {
1257            self.advance(); // consume DIFFERENT
1258            // Expect EDGES (contextual keyword)
1259            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("EDGES") {
1260                self.advance();
1261            }
1262            Some(MatchMode::DifferentEdges)
1263        } else if self.is_identifier()
1264            && self
1265                .get_identifier_name()
1266                .eq_ignore_ascii_case("REPEATABLE")
1267        {
1268            self.advance(); // consume REPEATABLE
1269            // Expect ELEMENTS (contextual keyword)
1270            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("ELEMENTS") {
1271                self.advance();
1272            }
1273            Some(MatchMode::RepeatableElements)
1274        } else {
1275            None
1276        };
1277
1278        // Check for path search prefix (ANY, ALL SHORTEST, ANY SHORTEST, SHORTEST k)
1279        let search_prefix = self.parse_path_search_prefix()?;
1280
1281        let mut patterns = Vec::new();
1282        patterns.push(self.parse_aliased_pattern()?);
1283
1284        while self.current.kind == TokenKind::Comma {
1285            self.advance();
1286            patterns.push(self.parse_aliased_pattern()?);
1287        }
1288
1289        Ok(MatchClause {
1290            optional,
1291            path_mode,
1292            search_prefix,
1293            match_mode,
1294            patterns,
1295            span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
1296        })
1297    }
1298
1299    /// Parses an optional path search prefix before patterns.
1300    ///
1301    /// ```text
1302    /// ANY [k]
1303    /// ALL SHORTEST
1304    /// ANY SHORTEST
1305    /// SHORTEST k [GROUPS]
1306    /// ```
1307    fn parse_path_search_prefix(&mut self) -> Result<Option<PathSearchPrefix>> {
1308        if self.current.kind == TokenKind::All {
1309            let next = self.peek_kind();
1310            if next == TokenKind::Shortest {
1311                // ALL SHORTEST
1312                self.advance(); // consume ALL
1313                self.advance(); // consume SHORTEST
1314                return Ok(Some(PathSearchPrefix::AllShortest));
1315            }
1316            if next == TokenKind::LParen {
1317                // ALL (pattern...) - enumerate all matching paths
1318                self.advance(); // consume ALL
1319                return Ok(Some(PathSearchPrefix::All));
1320            }
1321        }
1322        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("ANY") {
1323            let next = self.peek_kind();
1324            if next == TokenKind::Shortest {
1325                // ANY SHORTEST
1326                self.advance(); // consume ANY
1327                self.advance(); // consume SHORTEST
1328                return Ok(Some(PathSearchPrefix::AnyShortest));
1329            }
1330            if next == TokenKind::Integer {
1331                // ANY k
1332                self.advance(); // consume ANY
1333                let k: usize = self.current.text.parse().unwrap_or(1);
1334                self.advance(); // consume k
1335                return Ok(Some(PathSearchPrefix::AnyK(k)));
1336            }
1337            if next == TokenKind::LParen {
1338                // ANY (pattern...) - just ANY prefix
1339                self.advance(); // consume ANY
1340                return Ok(Some(PathSearchPrefix::Any));
1341            }
1342        }
1343        if self.current.kind == TokenKind::Shortest {
1344            self.advance(); // consume SHORTEST
1345            if self.current.kind == TokenKind::Integer {
1346                let k: usize = self.current.text.parse().unwrap_or(1);
1347                self.advance(); // consume k
1348                if self.current.kind == TokenKind::Groups {
1349                    self.advance(); // consume GROUPS
1350                    return Ok(Some(PathSearchPrefix::ShortestKGroups(k)));
1351                }
1352                return Ok(Some(PathSearchPrefix::ShortestK(k)));
1353            }
1354            // SHORTEST without k: treat as SHORTEST 1
1355            return Ok(Some(PathSearchPrefix::ShortestK(1)));
1356        }
1357        Ok(None)
1358    }
1359
1360    /// Parses a pattern with optional alias and path function.
1361    /// Supports: `p = shortestPath((a)-[*]-(b))` and `p = (a)-[*]-(b)` and `(a)-[*]-(b)`
1362    fn parse_aliased_pattern(&mut self) -> Result<AliasedPattern> {
1363        let mut alias = None;
1364        let mut path_function = None;
1365
1366        // Check for pattern alias: identifier = ...
1367        if self.is_identifier() && self.peek_kind() == TokenKind::Eq {
1368            alias = Some(self.get_identifier_name());
1369            self.advance(); // consume identifier
1370            self.advance(); // consume =
1371
1372            // Check for path function: shortestPath(...) or allShortestPaths(...)
1373            if self.is_identifier() {
1374                let func_name = self.get_identifier_name().to_lowercase();
1375                if func_name == "shortestpath" {
1376                    path_function = Some(PathFunction::ShortestPath);
1377                    self.advance(); // consume function name
1378                    self.expect(TokenKind::LParen)?;
1379                } else if func_name == "allshortestpaths" {
1380                    path_function = Some(PathFunction::AllShortestPaths);
1381                    self.advance(); // consume function name
1382                    self.expect(TokenKind::LParen)?;
1383                }
1384            }
1385        }
1386
1387        let pattern = self.parse_pattern()?;
1388
1389        if path_function.is_some() {
1390            self.expect(TokenKind::RParen)?;
1391        }
1392
1393        // Parse optional KEEP clause: KEEP DIFFERENT EDGES | KEEP REPEATABLE ELEMENTS
1394        let keep =
1395            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("KEEP") {
1396                self.advance(); // consume KEEP
1397                if self.is_identifier() {
1398                    let mode_name = self.get_identifier_name().to_uppercase();
1399                    match mode_name.as_str() {
1400                        "DIFFERENT" => {
1401                            self.advance();
1402                            // Optionally consume EDGES
1403                            if self.is_identifier()
1404                                && self.get_identifier_name().eq_ignore_ascii_case("EDGES")
1405                            {
1406                                self.advance();
1407                            }
1408                            Some(MatchMode::DifferentEdges)
1409                        }
1410                        "REPEATABLE" => {
1411                            self.advance();
1412                            // Optionally consume ELEMENTS
1413                            if self.is_identifier()
1414                                && self.get_identifier_name().eq_ignore_ascii_case("ELEMENTS")
1415                            {
1416                                self.advance();
1417                            }
1418                            Some(MatchMode::RepeatableElements)
1419                        }
1420                        _ => return Err(self.error("Expected DIFFERENT or REPEATABLE after KEEP")),
1421                    }
1422                } else {
1423                    return Err(self.error("Expected DIFFERENT or REPEATABLE after KEEP"));
1424                }
1425            } else {
1426                None
1427            };
1428
1429        Ok(AliasedPattern {
1430            alias,
1431            path_function,
1432            keep,
1433            pattern,
1434        })
1435    }
1436
1437    fn parse_with_clause(&mut self) -> Result<WithClause> {
1438        let span_start = self.current.span.start;
1439        self.expect(TokenKind::With)?;
1440
1441        let distinct = if self.current.kind == TokenKind::Distinct {
1442            self.advance();
1443            true
1444        } else {
1445            false
1446        };
1447
1448        // Check for WITH *
1449        let is_wildcard = if self.current.kind == TokenKind::Star {
1450            self.advance();
1451            true
1452        } else {
1453            false
1454        };
1455
1456        let mut items = Vec::new();
1457        if !is_wildcard {
1458            items.push(self.parse_return_item()?);
1459
1460            while self.current.kind == TokenKind::Comma {
1461                self.advance();
1462                items.push(self.parse_return_item()?);
1463            }
1464        }
1465
1466        // Optional WHERE after WITH
1467        let where_clause = if self.current.kind == TokenKind::Where {
1468            Some(self.parse_where_clause()?)
1469        } else {
1470            None
1471        };
1472
1473        Ok(WithClause {
1474            distinct,
1475            items,
1476            is_wildcard,
1477            where_clause,
1478            let_bindings: Vec::new(),
1479            span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
1480        })
1481    }
1482
1483    fn parse_pattern(&mut self) -> Result<Pattern> {
1484        // Check for parenthesized (grouped) pattern: ((a)-[]->(b)){2,5}
1485        // Also handles G048 subpath var `(p = (a)-[]->(b)){2,5}`,
1486        // G049 path mode prefix `(TRAIL (a)-[]->(b)){2,5}`,
1487        // and G050 WHERE inside `((a)-[e]->(b) WHERE e.w > 5){2,5}`.
1488        if self.current.kind == TokenKind::LParen {
1489            let peek = self.peek_kind();
1490            if matches!(
1491                peek,
1492                TokenKind::LParen
1493                    | TokenKind::Walk
1494                    | TokenKind::Trail
1495                    | TokenKind::Simple
1496                    | TokenKind::Acyclic
1497            ) {
1498                return self.parse_parenthesized_pattern();
1499            }
1500            // G048: `(identifier = ...)` is a subpath variable declaration
1501            if matches!(peek, TokenKind::Identifier | TokenKind::QuotedIdentifier)
1502                && self.peek_second_kind() == TokenKind::Eq
1503            {
1504                return self.parse_parenthesized_pattern();
1505            }
1506        }
1507
1508        let node = self.parse_node_pattern()?;
1509
1510        // Check for path continuation
1511        // Handle both `-[...]->`/`<-[...]-` style and `->` style
1512        if matches!(
1513            self.current.kind,
1514            TokenKind::Arrow
1515                | TokenKind::LeftArrow
1516                | TokenKind::DoubleDash
1517                | TokenKind::Minus
1518                | TokenKind::Tilde
1519        ) {
1520            let mut edges = Vec::new();
1521
1522            while matches!(
1523                self.current.kind,
1524                TokenKind::Arrow
1525                    | TokenKind::LeftArrow
1526                    | TokenKind::DoubleDash
1527                    | TokenKind::Minus
1528                    | TokenKind::Tilde
1529            ) {
1530                edges.push(self.parse_edge_pattern()?);
1531            }
1532
1533            Ok(Pattern::Path(PathPattern {
1534                source: node,
1535                edges,
1536                span: None,
1537            }))
1538        } else {
1539            Ok(Pattern::Node(node))
1540        }
1541    }
1542
1543    /// Parses a parenthesized path pattern with optional quantifier.
1544    ///
1545    /// ```text
1546    /// ( [subpath_var =] [path_mode] pattern [| pattern]* [WHERE expr] ) [ {min,max} ]
1547    /// ```
1548    ///
1549    /// G048: subpath variable declaration `(p = (a)-[e]->(b)){2,5}`
1550    /// G049: path mode prefix `(TRAIL (a)-[e]->(b)){2,5}`
1551    /// G050: WHERE clause `((a)-[e]->(b) WHERE e.w > 5){2,5}`
1552    fn parse_parenthesized_pattern(&mut self) -> Result<Pattern> {
1553        self.expect(TokenKind::LParen)?;
1554
1555        // G049: Check for optional path mode prefix (WALK, TRAIL, SIMPLE, ACYCLIC)
1556        let path_mode = match self.current.kind {
1557            TokenKind::Walk => {
1558                self.advance();
1559                Some(PathMode::Walk)
1560            }
1561            TokenKind::Trail => {
1562                self.advance();
1563                Some(PathMode::Trail)
1564            }
1565            TokenKind::Simple => {
1566                self.advance();
1567                Some(PathMode::Simple)
1568            }
1569            TokenKind::Acyclic => {
1570                self.advance();
1571                Some(PathMode::Acyclic)
1572            }
1573            _ => None,
1574        };
1575
1576        // G048: Check for subpath variable declaration: `name = pattern`
1577        // We detect this by checking if the current token is an identifier
1578        // and the next token is `=` (assignment).
1579        let subpath_var = if self.is_identifier() && self.peek_kind() == TokenKind::Eq {
1580            let name = self.get_identifier_name();
1581            self.advance(); // consume identifier
1582            self.advance(); // consume `=`
1583            Some(name)
1584        } else {
1585            None
1586        };
1587
1588        // Parse the inner pattern(s), potentially with union via | or multiset union via |+|
1589        let mut patterns = vec![self.parse_pattern()?];
1590        let mut is_multiset = false;
1591        while self.current.kind == TokenKind::Pipe || self.current.kind == TokenKind::PipePlusPipe {
1592            if self.current.kind == TokenKind::PipePlusPipe {
1593                is_multiset = true;
1594            }
1595            self.advance();
1596            patterns.push(self.parse_pattern()?);
1597        }
1598
1599        // G050: Check for optional WHERE clause inside the parenthesized pattern
1600        let where_clause = if self.current.kind == TokenKind::Where {
1601            self.advance();
1602            Some(self.parse_expression()?)
1603        } else {
1604            None
1605        };
1606
1607        self.expect(TokenKind::RParen)?;
1608
1609        let inner = if patterns.len() == 1 {
1610            patterns.remove(0)
1611        } else if is_multiset {
1612            Pattern::MultisetUnion(patterns)
1613        } else {
1614            Pattern::Union(patterns)
1615        };
1616
1617        // Check for quantifier: {min,max} or {n}
1618        if self.current.kind == TokenKind::LBrace {
1619            let (min, max) = self.parse_path_quantifier()?;
1620            Ok(Pattern::Quantified {
1621                pattern: Box::new(inner),
1622                min: min.unwrap_or(1),
1623                max,
1624                subpath_var,
1625                path_mode,
1626                where_clause,
1627            })
1628        } else if subpath_var.is_some() || path_mode.is_some() || where_clause.is_some() {
1629            // Has parenthesized-pattern features but no quantifier: treat as {1,1}
1630            Ok(Pattern::Quantified {
1631                pattern: Box::new(inner),
1632                min: 1,
1633                max: Some(1),
1634                subpath_var,
1635                path_mode,
1636                where_clause,
1637            })
1638        } else {
1639            // No quantifier, no extra features: just a grouped pattern (or union)
1640            Ok(inner)
1641        }
1642    }
1643
1644    fn parse_node_pattern(&mut self) -> Result<NodePattern> {
1645        self.expect(TokenKind::LParen)?;
1646
1647        let variable = if self.is_identifier() {
1648            let name = self.get_identifier_name();
1649            self.advance();
1650            Some(name)
1651        } else {
1652            None
1653        };
1654
1655        let mut labels = Vec::new();
1656        let mut label_expression = None;
1657
1658        if self.current.kind == TokenKind::Is {
1659            // GQL IS syntax: (n IS Person | Employee)
1660            self.advance();
1661            label_expression = Some(self.parse_label_expression()?);
1662        } else {
1663            // Colon syntax: (n:Person:Employee)
1664            while self.current.kind == TokenKind::Colon {
1665                self.advance();
1666                if !self.is_label_or_type_name() {
1667                    return Err(self.error("Expected label name"));
1668                }
1669                labels.push(self.get_identifier_name());
1670                self.advance();
1671            }
1672        }
1673
1674        // Parse properties { key: value, ... }
1675        let properties = if self.current.kind == TokenKind::LBrace {
1676            self.parse_property_map()?
1677        } else {
1678            Vec::new()
1679        };
1680
1681        // Parse optional element pattern WHERE clause: (n WHERE n.age > 30)
1682        let where_clause = if self.current.kind == TokenKind::Where {
1683            self.advance();
1684            Some(self.parse_expression()?)
1685        } else {
1686            None
1687        };
1688
1689        self.expect(TokenKind::RParen)?;
1690
1691        Ok(NodePattern {
1692            variable,
1693            labels,
1694            label_expression,
1695            properties,
1696            where_clause,
1697            span: None,
1698        })
1699    }
1700
1701    /// Parses a label expression with precedence: `|` < `&` < `!`.
1702    fn parse_label_expression(&mut self) -> Result<LabelExpression> {
1703        let mut left = self.parse_label_conjunction()?;
1704
1705        while self.current.kind == TokenKind::Pipe {
1706            let mut operands = vec![left];
1707            while self.current.kind == TokenKind::Pipe {
1708                self.advance();
1709                operands.push(self.parse_label_conjunction()?);
1710            }
1711            left = LabelExpression::Disjunction(operands);
1712        }
1713
1714        Ok(left)
1715    }
1716
1717    fn parse_label_conjunction(&mut self) -> Result<LabelExpression> {
1718        let mut left = self.parse_label_negation()?;
1719
1720        while self.current.kind == TokenKind::Ampersand {
1721            let mut operands = vec![left];
1722            while self.current.kind == TokenKind::Ampersand {
1723                self.advance();
1724                operands.push(self.parse_label_negation()?);
1725            }
1726            left = LabelExpression::Conjunction(operands);
1727        }
1728
1729        Ok(left)
1730    }
1731
1732    fn parse_label_negation(&mut self) -> Result<LabelExpression> {
1733        if self.current.kind == TokenKind::Exclamation {
1734            self.advance();
1735            let inner = self.parse_label_primary()?;
1736            return Ok(LabelExpression::Negation(Box::new(inner)));
1737        }
1738        self.parse_label_primary()
1739    }
1740
1741    fn parse_label_primary(&mut self) -> Result<LabelExpression> {
1742        if self.current.kind == TokenKind::Percent {
1743            self.advance();
1744            return Ok(LabelExpression::Wildcard);
1745        }
1746        if self.current.kind == TokenKind::LParen {
1747            self.advance();
1748            let expr = self.parse_label_expression()?;
1749            self.expect(TokenKind::RParen)?;
1750            return Ok(expr);
1751        }
1752        if self.is_label_or_type_name() {
1753            let name = self.get_identifier_name();
1754            self.advance();
1755            return Ok(LabelExpression::Label(name));
1756        }
1757        Err(self.error("Expected label name, %, or ("))
1758    }
1759
1760    fn parse_edge_pattern(&mut self) -> Result<EdgePattern> {
1761        // Handle both styles:
1762        // 1. `-[...]->` or `-[:TYPE]->` or `-[:TYPE*1..3]->` (direction determined by trailing arrow)
1763        // 2. `->` or `<-` or `--` (direction determined by leading arrow)
1764
1765        let mut edge_where_clause = None;
1766        let (variable, types, min_hops, max_hops, properties, direction) =
1767            if self.current.kind == TokenKind::Minus {
1768                // Pattern: -[...]->(target) or -[...]-(target)
1769                self.advance();
1770
1771                // G080: Simplified path pattern: -/:Label/-> desugars to -[:Label]->
1772                if self.current.kind == TokenKind::Slash {
1773                    return self.parse_simplified_edge(false);
1774                }
1775
1776                // Parse [variable:TYPE*min..max {props}]
1777                let (var, edge_types, min_h, max_h, props) =
1778                    if self.current.kind == TokenKind::LBracket {
1779                        self.advance();
1780
1781                        // Parse variable name if present
1782                        // Variable is followed by : (type), * (quantifier), { (properties),
1783                        // WHERE (element filter), or ] (end)
1784                        let v = if self.is_identifier() {
1785                            let peek = self.peek_kind();
1786                            if matches!(
1787                                peek,
1788                                TokenKind::Colon
1789                                    | TokenKind::Star
1790                                    | TokenKind::LBrace
1791                                    | TokenKind::RBracket
1792                                    | TokenKind::Where
1793                            ) {
1794                                let name = self.get_identifier_name();
1795                                self.advance();
1796                                Some(name)
1797                            } else {
1798                                None
1799                            }
1800                        } else {
1801                            None
1802                        };
1803
1804                        let mut tps = Vec::new();
1805                        while self.current.kind == TokenKind::Colon {
1806                            self.advance();
1807                            if !self.is_label_or_type_name() {
1808                                return Err(self.error("Expected edge type"));
1809                            }
1810                            tps.push(self.get_identifier_name());
1811                            self.advance();
1812                            // Support pipe-separated alternatives: :T1|T2|T3
1813                            while self.current.kind == TokenKind::Pipe {
1814                                self.advance();
1815                                if !self.is_label_or_type_name() {
1816                                    return Err(self.error("Expected edge type after |"));
1817                                }
1818                                tps.push(self.get_identifier_name());
1819                                self.advance();
1820                            }
1821                        }
1822
1823                        // Parse variable-length path quantifier: *min..max
1824                        let (min_h, max_h) = self.parse_path_quantifier()?;
1825
1826                        // Parse edge properties: {key: value, ...}
1827                        let edge_props = if self.current.kind == TokenKind::LBrace {
1828                            self.parse_property_map()?
1829                        } else {
1830                            Vec::new()
1831                        };
1832
1833                        // Parse element WHERE clause: [e:TYPE WHERE expr]
1834                        if self.current.kind == TokenKind::Where {
1835                            self.advance();
1836                            edge_where_clause = Some(self.parse_expression()?);
1837                        }
1838
1839                        self.expect(TokenKind::RBracket)?;
1840                        (v, tps, min_h, max_h, edge_props)
1841                    } else {
1842                        (None, Vec::new(), None, None, Vec::new())
1843                    };
1844
1845                // Now determine direction from trailing symbol
1846                let dir = if self.current.kind == TokenKind::Arrow {
1847                    self.advance();
1848                    EdgeDirection::Outgoing
1849                } else if self.current.kind == TokenKind::Minus {
1850                    self.advance();
1851                    EdgeDirection::Undirected
1852                } else {
1853                    return Err(self.error("Expected -> or - after edge pattern"));
1854                };
1855
1856                (var, edge_types, min_h, max_h, props, dir)
1857            } else if self.current.kind == TokenKind::LeftArrow {
1858                // Pattern: <-[...]-(target)
1859                self.advance();
1860
1861                // G080: Simplified path pattern: <-/:Label/- desugars to <-[:Label]-
1862                if self.current.kind == TokenKind::Slash {
1863                    return self.parse_simplified_edge(true);
1864                }
1865
1866                let (var, edge_types, min_h, max_h, props) =
1867                    if self.current.kind == TokenKind::LBracket {
1868                        self.advance();
1869
1870                        // Parse variable name if present
1871                        // Variable is followed by : (type), * (quantifier), { (properties),
1872                        // WHERE (element filter), or ] (end)
1873                        let v = if self.is_identifier() {
1874                            let peek = self.peek_kind();
1875                            if matches!(
1876                                peek,
1877                                TokenKind::Colon
1878                                    | TokenKind::Star
1879                                    | TokenKind::LBrace
1880                                    | TokenKind::RBracket
1881                                    | TokenKind::Where
1882                            ) {
1883                                let name = self.get_identifier_name();
1884                                self.advance();
1885                                Some(name)
1886                            } else {
1887                                None
1888                            }
1889                        } else {
1890                            None
1891                        };
1892
1893                        let mut tps = Vec::new();
1894                        while self.current.kind == TokenKind::Colon {
1895                            self.advance();
1896                            if !self.is_label_or_type_name() {
1897                                return Err(self.error("Expected edge type"));
1898                            }
1899                            tps.push(self.get_identifier_name());
1900                            self.advance();
1901                            // Support pipe-separated alternatives: :T1|T2|T3
1902                            while self.current.kind == TokenKind::Pipe {
1903                                self.advance();
1904                                if !self.is_label_or_type_name() {
1905                                    return Err(self.error("Expected edge type after |"));
1906                                }
1907                                tps.push(self.get_identifier_name());
1908                                self.advance();
1909                            }
1910                        }
1911
1912                        // Parse variable-length path quantifier
1913                        let (min_h, max_h) = self.parse_path_quantifier()?;
1914
1915                        // Parse edge properties: {key: value, ...}
1916                        let edge_props = if self.current.kind == TokenKind::LBrace {
1917                            self.parse_property_map()?
1918                        } else {
1919                            Vec::new()
1920                        };
1921
1922                        // Parse element WHERE clause: [e:TYPE WHERE expr]
1923                        if self.current.kind == TokenKind::Where {
1924                            self.advance();
1925                            edge_where_clause = Some(self.parse_expression()?);
1926                        }
1927
1928                        self.expect(TokenKind::RBracket)?;
1929                        (v, tps, min_h, max_h, edge_props)
1930                    } else {
1931                        (None, Vec::new(), None, None, Vec::new())
1932                    };
1933
1934                // Consume trailing -
1935                if self.current.kind == TokenKind::Minus {
1936                    self.advance();
1937                }
1938
1939                (
1940                    var,
1941                    edge_types,
1942                    min_h,
1943                    max_h,
1944                    props,
1945                    EdgeDirection::Incoming,
1946                )
1947            } else if self.current.kind == TokenKind::Arrow {
1948                // Simple ->
1949                self.advance();
1950                (
1951                    None,
1952                    Vec::new(),
1953                    None,
1954                    None,
1955                    Vec::new(),
1956                    EdgeDirection::Outgoing,
1957                )
1958            } else if self.current.kind == TokenKind::DoubleDash {
1959                // `--` (undirected) or `-->` (outgoing shorthand)
1960                self.advance();
1961                if self.current.kind == TokenKind::Gt {
1962                    // --> shorthand: directed outgoing, no bracket
1963                    self.advance();
1964                    (
1965                        None,
1966                        Vec::new(),
1967                        None,
1968                        None,
1969                        Vec::new(),
1970                        EdgeDirection::Outgoing,
1971                    )
1972                } else {
1973                    (
1974                        None,
1975                        Vec::new(),
1976                        None,
1977                        None,
1978                        Vec::new(),
1979                        EdgeDirection::Undirected,
1980                    )
1981                }
1982            } else if self.current.kind == TokenKind::Tilde {
1983                // GQL undirected edge: ~[variable:TYPE*min..max {props}]~
1984                self.advance();
1985
1986                // G080: Simplified undirected path: ~/:Label/~
1987                if self.current.kind == TokenKind::Slash {
1988                    return self.parse_simplified_edge_undirected();
1989                }
1990
1991                let (var, edge_types, min_h, max_h, props) =
1992                    if self.current.kind == TokenKind::LBracket {
1993                        self.advance();
1994
1995                        let v = if self.is_identifier() {
1996                            let peek = self.peek_kind();
1997                            if matches!(
1998                                peek,
1999                                TokenKind::Colon
2000                                    | TokenKind::Star
2001                                    | TokenKind::LBrace
2002                                    | TokenKind::RBracket
2003                                    | TokenKind::Where
2004                            ) {
2005                                let name = self.get_identifier_name();
2006                                self.advance();
2007                                Some(name)
2008                            } else {
2009                                None
2010                            }
2011                        } else {
2012                            None
2013                        };
2014
2015                        let mut tps = Vec::new();
2016                        while self.current.kind == TokenKind::Colon {
2017                            self.advance();
2018                            if !self.is_label_or_type_name() {
2019                                return Err(self.error("Expected edge type"));
2020                            }
2021                            tps.push(self.get_identifier_name());
2022                            self.advance();
2023                            while self.current.kind == TokenKind::Pipe {
2024                                self.advance();
2025                                if !self.is_label_or_type_name() {
2026                                    return Err(self.error("Expected edge type after |"));
2027                                }
2028                                tps.push(self.get_identifier_name());
2029                                self.advance();
2030                            }
2031                        }
2032
2033                        let (min_h, max_h) = self.parse_path_quantifier()?;
2034
2035                        let edge_props = if self.current.kind == TokenKind::LBrace {
2036                            self.parse_property_map()?
2037                        } else {
2038                            Vec::new()
2039                        };
2040
2041                        // Parse element WHERE clause: [e:TYPE WHERE expr]
2042                        if self.current.kind == TokenKind::Where {
2043                            self.advance();
2044                            edge_where_clause = Some(self.parse_expression()?);
2045                        }
2046
2047                        self.expect(TokenKind::RBracket)?;
2048                        (v, tps, min_h, max_h, edge_props)
2049                    } else {
2050                        (None, Vec::new(), None, None, Vec::new())
2051                    };
2052
2053                // Consume trailing ~
2054                if self.current.kind == TokenKind::Tilde {
2055                    self.advance();
2056                }
2057
2058                (
2059                    var,
2060                    edge_types,
2061                    min_h,
2062                    max_h,
2063                    props,
2064                    EdgeDirection::Undirected,
2065                )
2066            } else {
2067                return Err(self.error("Expected edge pattern"));
2068            };
2069
2070        // Check for questioned edge: ->?(node) means optional (0 or 1 hop)
2071        let questioned = if self.current.kind == TokenKind::QuestionMark {
2072            self.advance();
2073            true
2074        } else {
2075            false
2076        };
2077
2078        let target = self.parse_node_pattern()?;
2079
2080        Ok(EdgePattern {
2081            variable,
2082            types,
2083            direction,
2084            target,
2085            min_hops,
2086            max_hops,
2087            properties,
2088            where_clause: edge_where_clause,
2089            questioned,
2090            span: None,
2091        })
2092    }
2093
2094    /// Parses a simplified path pattern (G080/G039/G082).
2095    ///
2096    /// Called after consuming `-` (outgoing) or `<-` (incoming). The current token
2097    /// is `/`. Syntax: `/:Label1|Label2/->` or `/:Label/-` or `/:Label/->`.
2098    ///
2099    /// Desugars to a regular `EdgePattern` with the parsed label types.
2100    fn parse_simplified_edge(&mut self, incoming: bool) -> Result<EdgePattern> {
2101        self.expect(TokenKind::Slash)?; // consume opening /
2102
2103        // Parse label(s): `:Label` or `:Label1|Label2`
2104        let mut types = Vec::new();
2105        if self.current.kind == TokenKind::Colon {
2106            self.advance();
2107            if !self.is_label_or_type_name() {
2108                return Err(self.error("Expected label in simplified path pattern"));
2109            }
2110            types.push(self.get_identifier_name());
2111            self.advance();
2112            // Support pipe-separated alternatives: :T1|T2
2113            while self.current.kind == TokenKind::Pipe {
2114                self.advance();
2115                if !self.is_label_or_type_name() {
2116                    return Err(self.error("Expected label after | in simplified path pattern"));
2117                }
2118                types.push(self.get_identifier_name());
2119                self.advance();
2120            }
2121        }
2122
2123        self.expect(TokenKind::Slash)?; // consume closing /
2124
2125        // Determine direction from trailing token
2126        let direction = if incoming {
2127            // <-/:Label/- form: consume trailing -
2128            if self.current.kind == TokenKind::Minus {
2129                self.advance();
2130            }
2131            EdgeDirection::Incoming
2132        } else if self.current.kind == TokenKind::Arrow {
2133            // -/:Label/-> form
2134            self.advance();
2135            EdgeDirection::Outgoing
2136        } else if self.current.kind == TokenKind::Minus {
2137            // -/:Label/- form (undirected)
2138            self.advance();
2139            EdgeDirection::Undirected
2140        } else {
2141            return Err(self.error("Expected ->, -, or end after simplified path pattern"));
2142        };
2143
2144        let target = self.parse_node_pattern()?;
2145
2146        Ok(EdgePattern {
2147            variable: None,
2148            types,
2149            direction,
2150            target,
2151            min_hops: None,
2152            max_hops: None,
2153            properties: Vec::new(),
2154            where_clause: None,
2155            questioned: false,
2156            span: None,
2157        })
2158    }
2159
2160    /// Parses a simplified undirected path pattern with tilde syntax.
2161    ///
2162    /// Called after consuming `~`. The current token is `/`.
2163    /// Syntax: `~/:Label/~` desugars to `~[:Label]~`.
2164    fn parse_simplified_edge_undirected(&mut self) -> Result<EdgePattern> {
2165        self.expect(TokenKind::Slash)?; // consume opening /
2166
2167        let mut types = Vec::new();
2168        if self.current.kind == TokenKind::Colon {
2169            self.advance();
2170            if !self.is_label_or_type_name() {
2171                return Err(self.error("Expected label in simplified path pattern"));
2172            }
2173            types.push(self.get_identifier_name());
2174            self.advance();
2175            while self.current.kind == TokenKind::Pipe {
2176                self.advance();
2177                if !self.is_label_or_type_name() {
2178                    return Err(self.error("Expected label after | in simplified path pattern"));
2179                }
2180                types.push(self.get_identifier_name());
2181                self.advance();
2182            }
2183        }
2184
2185        self.expect(TokenKind::Slash)?; // consume closing /
2186
2187        // Consume trailing ~
2188        if self.current.kind == TokenKind::Tilde {
2189            self.advance();
2190        }
2191
2192        let target = self.parse_node_pattern()?;
2193
2194        Ok(EdgePattern {
2195            variable: None,
2196            types,
2197            direction: EdgeDirection::Undirected,
2198            target,
2199            min_hops: None,
2200            max_hops: None,
2201            properties: Vec::new(),
2202            where_clause: None,
2203            questioned: false,
2204            span: None,
2205        })
2206    }
2207
2208    /// Parses a path quantifier like `*`, `*2`, `*1..3`, `*..5`, `*2..`,
2209    /// or ISO `{m,n}`, `{m,}`, `{,n}`, `{m}`.
2210    /// Returns (min_hops, max_hops) where None means no quantifier was present.
2211    fn parse_path_quantifier(&mut self) -> Result<(Option<u32>, Option<u32>)> {
2212        // ISO GQL {m,n} quantifier syntax.
2213        // Disambiguate from property map {key: value}: quantifiers start with
2214        // an integer or comma, property maps start with an identifier.
2215        if self.current.kind == TokenKind::LBrace {
2216            let next = self.peek_kind();
2217            if next != TokenKind::Integer && next != TokenKind::Comma {
2218                // Not a quantifier (likely a property map), bail out
2219                return Ok((None, None));
2220            }
2221            self.advance(); // consume {
2222            if self.current.kind == TokenKind::Comma {
2223                // {,n}
2224                self.advance();
2225                let max_text = self.current.text.clone();
2226                let max: u32 = max_text
2227                    .parse()
2228                    .map_err(|_| self.error("Invalid path length"))?;
2229                self.advance();
2230                self.expect(TokenKind::RBrace)?;
2231                return Ok((Some(1), Some(max)));
2232            }
2233            let min_text = self.current.text.clone();
2234            let min: u32 = min_text
2235                .parse()
2236                .map_err(|_| self.error("Invalid path length"))?;
2237            self.advance();
2238            if self.current.kind == TokenKind::RBrace {
2239                // {m} means exactly m
2240                self.advance();
2241                return Ok((Some(min), Some(min)));
2242            }
2243            self.expect(TokenKind::Comma)?;
2244            if self.current.kind == TokenKind::RBrace {
2245                // {m,} means m to unbounded
2246                self.advance();
2247                return Ok((Some(min), None));
2248            }
2249            let max_text = self.current.text.clone();
2250            let max: u32 = max_text
2251                .parse()
2252                .map_err(|_| self.error("Invalid path length"))?;
2253            self.advance();
2254            self.expect(TokenKind::RBrace)?;
2255            return Ok((Some(min), Some(max)));
2256        }
2257
2258        if self.current.kind != TokenKind::Star {
2259            return Ok((None, None));
2260        }
2261        self.advance(); // consume *
2262
2263        // Check for bounds
2264        if self.current.kind == TokenKind::Integer {
2265            let min_text = self.current.text.clone();
2266            let min: u32 = min_text
2267                .parse()
2268                .map_err(|_| self.error("Invalid path length"))?;
2269            self.advance();
2270
2271            if self.current.kind == TokenKind::Dot {
2272                self.advance();
2273                self.expect(TokenKind::Dot)?; // expect second dot for ..
2274
2275                if self.current.kind == TokenKind::Integer {
2276                    let max_text = self.current.text.clone();
2277                    let max: u32 = max_text
2278                        .parse()
2279                        .map_err(|_| self.error("Invalid path length"))?;
2280                    self.advance();
2281                    Ok((Some(min), Some(max))) // *min..max
2282                } else {
2283                    Ok((Some(min), None)) // *min.. (unbounded max)
2284                }
2285            } else {
2286                Ok((Some(min), Some(min))) // *n means exactly n hops
2287            }
2288        } else if self.current.kind == TokenKind::Dot {
2289            self.advance();
2290            self.expect(TokenKind::Dot)?; // expect second dot for ..
2291
2292            if self.current.kind == TokenKind::Integer {
2293                let max_text = self.current.text.clone();
2294                let max: u32 = max_text
2295                    .parse()
2296                    .map_err(|_| self.error("Invalid path length"))?;
2297                self.advance();
2298                Ok((Some(1), Some(max))) // *..max (min defaults to 1)
2299            } else {
2300                Err(self.error("Expected max hops after .."))
2301            }
2302        } else {
2303            Ok((Some(1), None)) // * alone means 1 to unbounded
2304        }
2305    }
2306
2307    fn parse_where_clause(&mut self) -> Result<WhereClause> {
2308        self.expect(TokenKind::Where)?;
2309        let expression = self.parse_expression()?;
2310
2311        Ok(WhereClause {
2312            expression,
2313            span: None,
2314        })
2315    }
2316
2317    /// Parses either WHERE or FILTER clause (FILTER is a GQL alias for WHERE).
2318    fn parse_where_or_filter_clause(&mut self) -> Result<WhereClause> {
2319        // Accept both WHERE and FILTER
2320        if self.current.kind == TokenKind::Filter {
2321            self.advance();
2322        } else {
2323            self.expect(TokenKind::Where)?;
2324        }
2325        let expression = self.parse_expression()?;
2326
2327        Ok(WhereClause {
2328            expression,
2329            span: None,
2330        })
2331    }
2332
2333    fn parse_having_clause(&mut self) -> Result<HavingClause> {
2334        self.expect(TokenKind::Having)?;
2335        let expression = self.parse_expression()?;
2336
2337        Ok(HavingClause {
2338            expression,
2339            span: None,
2340        })
2341    }
2342
2343    fn parse_return_clause(&mut self) -> Result<ReturnClause> {
2344        self.expect(TokenKind::Return)?;
2345
2346        let distinct = if self.current.kind == TokenKind::Distinct {
2347            self.advance();
2348            true
2349        } else {
2350            false
2351        };
2352
2353        // Check for RETURN *
2354        let is_wildcard = if self.current.kind == TokenKind::Star {
2355            self.advance();
2356            true
2357        } else {
2358            false
2359        };
2360
2361        let mut items = Vec::new();
2362        if !is_wildcard {
2363            items.push(self.parse_return_item()?);
2364
2365            while self.current.kind == TokenKind::Comma {
2366                self.advance();
2367                items.push(self.parse_return_item()?);
2368            }
2369        }
2370
2371        // Parse optional GROUP BY
2372        let group_by = if self.current.kind == TokenKind::Group {
2373            self.advance();
2374            self.expect(TokenKind::By)?;
2375            let mut exprs = vec![self.parse_expression()?];
2376            while self.current.kind == TokenKind::Comma {
2377                self.advance();
2378                exprs.push(self.parse_expression()?);
2379            }
2380            exprs
2381        } else {
2382            Vec::new()
2383        };
2384
2385        let order_by = if self.current.kind == TokenKind::Order {
2386            Some(self.parse_order_by()?)
2387        } else {
2388            None
2389        };
2390
2391        let skip = if matches!(self.current.kind, TokenKind::Skip | TokenKind::Offset) {
2392            self.advance();
2393            Some(self.parse_expression()?)
2394        } else {
2395            None
2396        };
2397
2398        let limit = if self.current.kind == TokenKind::Limit {
2399            self.advance();
2400            Some(self.parse_expression()?)
2401        } else if self.current.kind == TokenKind::Fetch {
2402            Some(self.parse_fetch_first()?)
2403        } else {
2404            None
2405        };
2406
2407        Ok(ReturnClause {
2408            distinct,
2409            items,
2410            is_wildcard,
2411            group_by,
2412            order_by,
2413            skip,
2414            limit,
2415            is_finish: false,
2416            span: None,
2417        })
2418    }
2419
2420    /// Parses a SELECT clause (SQL-style projection, same semantics as RETURN).
2421    /// Called after SELECT token has already been consumed.
2422    fn parse_select_clause(&mut self) -> Result<ReturnClause> {
2423        let distinct = if self.current.kind == TokenKind::Distinct {
2424            self.advance();
2425            true
2426        } else {
2427            false
2428        };
2429
2430        let mut items = Vec::new();
2431        items.push(self.parse_return_item()?);
2432        while self.current.kind == TokenKind::Comma {
2433            self.advance();
2434            items.push(self.parse_return_item()?);
2435        }
2436
2437        // Parse optional GROUP BY
2438        let group_by = if self.current.kind == TokenKind::Group {
2439            self.advance();
2440            self.expect(TokenKind::By)?;
2441            let mut exprs = vec![self.parse_expression()?];
2442            while self.current.kind == TokenKind::Comma {
2443                self.advance();
2444                exprs.push(self.parse_expression()?);
2445            }
2446            exprs
2447        } else {
2448            Vec::new()
2449        };
2450
2451        let order_by = if self.current.kind == TokenKind::Order {
2452            Some(self.parse_order_by()?)
2453        } else {
2454            None
2455        };
2456
2457        let skip = if matches!(self.current.kind, TokenKind::Skip | TokenKind::Offset) {
2458            self.advance();
2459            Some(self.parse_expression()?)
2460        } else {
2461            None
2462        };
2463
2464        let limit = if self.current.kind == TokenKind::Limit {
2465            self.advance();
2466            Some(self.parse_expression()?)
2467        } else if self.current.kind == TokenKind::Fetch {
2468            Some(self.parse_fetch_first()?)
2469        } else {
2470            None
2471        };
2472
2473        Ok(ReturnClause {
2474            distinct,
2475            items,
2476            is_wildcard: false,
2477            group_by,
2478            order_by,
2479            skip,
2480            limit,
2481            is_finish: false,
2482            span: None,
2483        })
2484    }
2485
2486    fn parse_return_item(&mut self) -> Result<ReturnItem> {
2487        let expression = self.parse_expression()?;
2488
2489        let alias = if self.current.kind == TokenKind::As {
2490            self.advance();
2491            if !self.is_identifier() {
2492                return Err(self.error("Expected alias name"));
2493            }
2494            let name = self.get_identifier_name();
2495            self.advance();
2496            Some(name)
2497        } else {
2498            None
2499        };
2500
2501        Ok(ReturnItem {
2502            expression,
2503            alias,
2504            span: None,
2505        })
2506    }
2507
2508    /// Parses `FETCH FIRST|NEXT n ROWS|ROW ONLY` as a LIMIT expression.
2509    /// The FETCH token has already been peeked but not consumed.
2510    fn parse_fetch_first(&mut self) -> Result<Expression> {
2511        self.expect(TokenKind::Fetch)?;
2512        // FIRST or NEXT (both accepted)
2513        if !matches!(self.current.kind, TokenKind::First | TokenKind::Next) {
2514            return Err(self.error("Expected FIRST or NEXT after FETCH"));
2515        }
2516        self.advance();
2517        // Parse the count expression
2518        let count = self.parse_expression()?;
2519        // ROWS or ROW (both accepted, optional)
2520        if matches!(self.current.kind, TokenKind::Rows | TokenKind::Row) {
2521            self.advance();
2522        }
2523        // ONLY (optional)
2524        if self.current.kind == TokenKind::Only {
2525            self.advance();
2526        }
2527        Ok(count)
2528    }
2529
2530    /// Parses a list comprehension after `[` and identifier have been peeked.
2531    /// Current token is the variable name, next is IN.
2532    /// Syntax: `[x IN list WHERE predicate | map_expression]`
2533    fn parse_list_comprehension_inner(&mut self) -> Result<Expression> {
2534        let variable = self.get_identifier_name();
2535        self.advance(); // consume variable
2536        self.expect(TokenKind::In)?;
2537        let list_expr = self.parse_expression()?;
2538
2539        // Optional WHERE filter
2540        let filter_expr = if self.current.kind == TokenKind::Where {
2541            self.advance();
2542            Some(Box::new(self.parse_expression()?))
2543        } else {
2544            None
2545        };
2546
2547        // Required | (pipe) followed by mapping expression
2548        let map_expr = if self.current.kind == TokenKind::Pipe {
2549            self.advance();
2550            Box::new(self.parse_expression()?)
2551        } else {
2552            // If no pipe, the mapping is just the variable itself
2553            Box::new(Expression::Variable(variable.clone()))
2554        };
2555
2556        self.expect(TokenKind::RBracket)?;
2557        Ok(Expression::ListComprehension {
2558            variable,
2559            list_expr: Box::new(list_expr),
2560            filter_expr,
2561            map_expr,
2562        })
2563    }
2564
2565    /// Parses a list predicate: `all/any/none/single(x IN list WHERE predicate)`.
2566    /// The function name has already been consumed; current token is `(`.
2567    fn parse_list_predicate(&mut self, kind: ListPredicateKind) -> Result<Expression> {
2568        self.expect(TokenKind::LParen)?;
2569        if !self.is_identifier() {
2570            return Err(self.error("Expected variable name in list predicate"));
2571        }
2572        let variable = self.get_identifier_name();
2573        self.advance();
2574        self.expect(TokenKind::In)?;
2575        let list_expr = self.parse_expression()?;
2576        // WHERE is required for list predicates
2577        self.expect(TokenKind::Where)?;
2578        let predicate = self.parse_expression()?;
2579        self.expect(TokenKind::RParen)?;
2580        Ok(Expression::ListPredicate {
2581            kind,
2582            variable,
2583            list_expr: Box::new(list_expr),
2584            predicate: Box::new(predicate),
2585        })
2586    }
2587
2588    /// Parses `reduce(accumulator = init, x IN list | expression)`.
2589    /// The function name has already been consumed; current token is `(`.
2590    fn parse_reduce(&mut self) -> Result<Expression> {
2591        self.expect(TokenKind::LParen)?;
2592        if !self.is_identifier() {
2593            return Err(self.error("Expected accumulator variable in reduce"));
2594        }
2595        let accumulator = self.get_identifier_name();
2596        self.advance();
2597        self.expect(TokenKind::Eq)?;
2598        let initial = self.parse_expression()?;
2599        self.expect(TokenKind::Comma)?;
2600        if !self.is_identifier() {
2601            return Err(self.error("Expected iteration variable in reduce"));
2602        }
2603        let variable = self.get_identifier_name();
2604        self.advance();
2605        self.expect(TokenKind::In)?;
2606        let list = self.parse_expression()?;
2607        self.expect(TokenKind::Pipe)?;
2608        let expression = self.parse_expression()?;
2609        self.expect(TokenKind::RParen)?;
2610        Ok(Expression::Reduce {
2611            accumulator,
2612            initial: Box::new(initial),
2613            variable,
2614            list: Box::new(list),
2615            expression: Box::new(expression),
2616        })
2617    }
2618
2619    fn parse_order_by(&mut self) -> Result<OrderByClause> {
2620        self.expect(TokenKind::Order)?;
2621        self.expect(TokenKind::By)?;
2622
2623        let mut items = Vec::new();
2624        items.push(self.parse_order_item()?);
2625
2626        while self.current.kind == TokenKind::Comma {
2627            self.advance();
2628            items.push(self.parse_order_item()?);
2629        }
2630
2631        Ok(OrderByClause { items, span: None })
2632    }
2633
2634    fn parse_order_item(&mut self) -> Result<OrderByItem> {
2635        let expression = self.parse_expression()?;
2636
2637        let order = match self.current.kind {
2638            TokenKind::Asc => {
2639                self.advance();
2640                SortOrder::Asc
2641            }
2642            TokenKind::Desc => {
2643                self.advance();
2644                SortOrder::Desc
2645            }
2646            _ => SortOrder::Asc,
2647        };
2648
2649        // Parse optional NULLS FIRST / NULLS LAST (ISO GQL feature GA03)
2650        let nulls =
2651            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("NULLS") {
2652                self.advance();
2653                if self.is_identifier() {
2654                    let kw = self.get_identifier_name().to_uppercase();
2655                    match kw.as_str() {
2656                        "FIRST" => {
2657                            self.advance();
2658                            Some(NullsOrdering::First)
2659                        }
2660                        "LAST" => {
2661                            self.advance();
2662                            Some(NullsOrdering::Last)
2663                        }
2664                        _ => return Err(self.error("Expected FIRST or LAST after NULLS")),
2665                    }
2666                } else {
2667                    return Err(self.error("Expected FIRST or LAST after NULLS"));
2668                }
2669            } else {
2670                None
2671            };
2672
2673        Ok(OrderByItem {
2674            expression,
2675            order,
2676            nulls,
2677        })
2678    }
2679
2680    fn parse_expression(&mut self) -> Result<Expression> {
2681        self.parse_or_expression()
2682    }
2683
2684    fn parse_or_expression(&mut self) -> Result<Expression> {
2685        let mut left = self.parse_xor_expression()?;
2686
2687        while self.current.kind == TokenKind::Or {
2688            self.advance();
2689            let right = self.parse_xor_expression()?;
2690            left = Expression::Binary {
2691                left: Box::new(left),
2692                op: BinaryOp::Or,
2693                right: Box::new(right),
2694            };
2695        }
2696
2697        Ok(left)
2698    }
2699
2700    fn parse_xor_expression(&mut self) -> Result<Expression> {
2701        let mut left = self.parse_and_expression()?;
2702
2703        while self.current.kind == TokenKind::Xor {
2704            self.advance();
2705            let right = self.parse_and_expression()?;
2706            left = Expression::Binary {
2707                left: Box::new(left),
2708                op: BinaryOp::Xor,
2709                right: Box::new(right),
2710            };
2711        }
2712
2713        Ok(left)
2714    }
2715
2716    fn parse_and_expression(&mut self) -> Result<Expression> {
2717        let mut left = self.parse_not_expression()?;
2718
2719        while self.current.kind == TokenKind::And {
2720            self.advance();
2721            let right = self.parse_not_expression()?;
2722            left = Expression::Binary {
2723                left: Box::new(left),
2724                op: BinaryOp::And,
2725                right: Box::new(right),
2726            };
2727        }
2728
2729        Ok(left)
2730    }
2731
2732    fn parse_not_expression(&mut self) -> Result<Expression> {
2733        if self.current.kind == TokenKind::Not {
2734            self.advance();
2735            let operand = self.parse_not_expression()?;
2736            return Ok(Expression::Unary {
2737                op: UnaryOp::Not,
2738                operand: Box::new(operand),
2739            });
2740        }
2741        self.parse_comparison_expression()
2742    }
2743
2744    fn parse_comparison_expression(&mut self) -> Result<Expression> {
2745        let left = self.parse_additive_expression()?;
2746
2747        // Check for regular comparison operators
2748        let op = match self.current.kind {
2749            TokenKind::Eq => Some(BinaryOp::Eq),
2750            TokenKind::Ne => Some(BinaryOp::Ne),
2751            TokenKind::Lt => Some(BinaryOp::Lt),
2752            TokenKind::Le => Some(BinaryOp::Le),
2753            TokenKind::Gt => Some(BinaryOp::Gt),
2754            TokenKind::Ge => Some(BinaryOp::Ge),
2755            _ => None,
2756        };
2757
2758        if let Some(op) = op {
2759            self.advance();
2760            let right = self.parse_additive_expression()?;
2761            return Ok(Expression::Binary {
2762                left: Box::new(left),
2763                op,
2764                right: Box::new(right),
2765            });
2766        }
2767
2768        // Check for IN, STARTS WITH, ENDS WITH, CONTAINS
2769        match self.current.kind {
2770            TokenKind::In => {
2771                self.advance(); // consume IN
2772                let right = self.parse_primary_expression()?;
2773                return Ok(Expression::Binary {
2774                    left: Box::new(left),
2775                    op: BinaryOp::In,
2776                    right: Box::new(right),
2777                });
2778            }
2779            TokenKind::Starts => {
2780                self.advance(); // consume STARTS
2781                self.expect(TokenKind::With)?; // expect WITH
2782                let right = self.parse_additive_expression()?;
2783                return Ok(Expression::Binary {
2784                    left: Box::new(left),
2785                    op: BinaryOp::StartsWith,
2786                    right: Box::new(right),
2787                });
2788            }
2789            TokenKind::Ends => {
2790                self.advance(); // consume ENDS
2791                self.expect(TokenKind::With)?; // expect WITH
2792                let right = self.parse_additive_expression()?;
2793                return Ok(Expression::Binary {
2794                    left: Box::new(left),
2795                    op: BinaryOp::EndsWith,
2796                    right: Box::new(right),
2797                });
2798            }
2799            TokenKind::Contains => {
2800                self.advance(); // consume CONTAINS
2801                let right = self.parse_additive_expression()?;
2802                return Ok(Expression::Binary {
2803                    left: Box::new(left),
2804                    op: BinaryOp::Contains,
2805                    right: Box::new(right),
2806                });
2807            }
2808            TokenKind::Like => {
2809                self.advance(); // consume LIKE
2810                let right = self.parse_additive_expression()?;
2811                return Ok(Expression::Binary {
2812                    left: Box::new(left),
2813                    op: BinaryOp::Like,
2814                    right: Box::new(right),
2815                });
2816            }
2817            TokenKind::Is => {
2818                self.advance(); // consume IS
2819                let negated = self.current.kind == TokenKind::Not;
2820                if negated {
2821                    self.advance(); // consume NOT
2822                }
2823
2824                let predicate = if self.current.kind == TokenKind::Null {
2825                    // IS [NOT] NULL
2826                    self.advance();
2827                    Expression::Unary {
2828                        op: if negated {
2829                            UnaryOp::IsNotNull
2830                        } else {
2831                            UnaryOp::IsNull
2832                        },
2833                        operand: Box::new(left),
2834                    }
2835                } else if self.is_identifier() {
2836                    let kw = self.get_identifier_name().to_uppercase();
2837                    match kw.as_str() {
2838                        "TYPED" => {
2839                            // IS [NOT] TYPED <type_name>
2840                            // Supports LIST<element_type> parameterized form
2841                            self.advance();
2842                            let type_name = if self.is_identifier() {
2843                                let base = self.get_identifier_name().to_uppercase();
2844                                self.advance();
2845                                // Handle LIST<type> parameterized syntax
2846                                if base == "LIST" && self.current.kind == TokenKind::Lt {
2847                                    self.advance(); // consume <
2848                                    if self.is_identifier() {
2849                                        let elem = self.get_identifier_name().to_uppercase();
2850                                        self.advance();
2851                                        self.expect(TokenKind::Gt)?;
2852                                        format!("LIST<{elem}>")
2853                                    } else {
2854                                        return Err(self.error("Expected element type after LIST<"));
2855                                    }
2856                                } else {
2857                                    base
2858                                }
2859                            } else {
2860                                return Err(self.error("Expected type name after IS TYPED"));
2861                            };
2862                            let call = Expression::FunctionCall {
2863                                name: "isTyped".to_string(),
2864                                args: vec![left, Expression::Literal(Literal::String(type_name))],
2865                                distinct: false,
2866                            };
2867                            if negated {
2868                                Expression::Unary {
2869                                    op: UnaryOp::Not,
2870                                    operand: Box::new(call),
2871                                }
2872                            } else {
2873                                call
2874                            }
2875                        }
2876                        "DIRECTED" => {
2877                            // IS [NOT] DIRECTED
2878                            self.advance();
2879                            let call = Expression::FunctionCall {
2880                                name: "isDirected".to_string(),
2881                                args: vec![left],
2882                                distinct: false,
2883                            };
2884                            if negated {
2885                                Expression::Unary {
2886                                    op: UnaryOp::Not,
2887                                    operand: Box::new(call),
2888                                }
2889                            } else {
2890                                call
2891                            }
2892                        }
2893                        "LABELED" => {
2894                            // IS [NOT] LABELED <label>
2895                            self.advance();
2896                            let label = if self.is_identifier() {
2897                                self.get_identifier_name()
2898                            } else {
2899                                return Err(self.error("Expected label name after IS LABELED"));
2900                            };
2901                            self.advance();
2902                            let call = Expression::FunctionCall {
2903                                name: "hasLabel".to_string(),
2904                                args: vec![left, Expression::Literal(Literal::String(label))],
2905                                distinct: false,
2906                            };
2907                            if negated {
2908                                Expression::Unary {
2909                                    op: UnaryOp::Not,
2910                                    operand: Box::new(call),
2911                                }
2912                            } else {
2913                                call
2914                            }
2915                        }
2916                        "SOURCE" => {
2917                            // IS [NOT] SOURCE OF <variable>
2918                            self.advance();
2919                            if !(self.is_identifier()
2920                                && self.get_identifier_name().eq_ignore_ascii_case("OF"))
2921                            {
2922                                return Err(self.error("Expected OF after IS SOURCE"));
2923                            }
2924                            self.advance(); // consume OF
2925                            let var = if self.is_identifier() {
2926                                self.get_identifier_name()
2927                            } else {
2928                                return Err(self.error("Expected variable after IS SOURCE OF"));
2929                            };
2930                            self.advance();
2931                            let call = Expression::FunctionCall {
2932                                name: "isSource".to_string(),
2933                                args: vec![left, Expression::Variable(var)],
2934                                distinct: false,
2935                            };
2936                            if negated {
2937                                Expression::Unary {
2938                                    op: UnaryOp::Not,
2939                                    operand: Box::new(call),
2940                                }
2941                            } else {
2942                                call
2943                            }
2944                        }
2945                        "DESTINATION" => {
2946                            // IS [NOT] DESTINATION OF <variable>
2947                            self.advance();
2948                            if !(self.is_identifier()
2949                                && self.get_identifier_name().eq_ignore_ascii_case("OF"))
2950                            {
2951                                return Err(self.error("Expected OF after IS DESTINATION"));
2952                            }
2953                            self.advance(); // consume OF
2954                            let var = if self.is_identifier() {
2955                                self.get_identifier_name()
2956                            } else {
2957                                return Err(self.error("Expected variable after IS DESTINATION OF"));
2958                            };
2959                            self.advance();
2960                            let call = Expression::FunctionCall {
2961                                name: "isDestination".to_string(),
2962                                args: vec![left, Expression::Variable(var)],
2963                                distinct: false,
2964                            };
2965                            if negated {
2966                                Expression::Unary {
2967                                    op: UnaryOp::Not,
2968                                    operand: Box::new(call),
2969                                }
2970                            } else {
2971                                call
2972                            }
2973                        }
2974                        "NFC" | "NFD" | "NFKC" | "NFKD" => {
2975                            // IS [NOT] NFC|NFD|NFKC|NFKD NORMALIZED
2976                            let form = kw.clone();
2977                            self.advance();
2978                            if !(self.is_identifier()
2979                                && self
2980                                    .get_identifier_name()
2981                                    .eq_ignore_ascii_case("NORMALIZED"))
2982                            {
2983                                return Err(
2984                                    self.error(&format!("Expected NORMALIZED after IS {form}"))
2985                                );
2986                            }
2987                            self.advance();
2988                            let call = Expression::FunctionCall {
2989                                name: "isNormalized".to_string(),
2990                                args: vec![left, Expression::Literal(Literal::String(form))],
2991                                distinct: false,
2992                            };
2993                            if negated {
2994                                Expression::Unary {
2995                                    op: UnaryOp::Not,
2996                                    operand: Box::new(call),
2997                                }
2998                            } else {
2999                                call
3000                            }
3001                        }
3002                        "NORMALIZED" => {
3003                            // IS [NOT] NORMALIZED (default NFC)
3004                            self.advance();
3005                            let call = Expression::FunctionCall {
3006                                name: "isNormalized".to_string(),
3007                                args: vec![
3008                                    left,
3009                                    Expression::Literal(Literal::String("NFC".to_string())),
3010                                ],
3011                                distinct: false,
3012                            };
3013                            if negated {
3014                                Expression::Unary {
3015                                    op: UnaryOp::Not,
3016                                    operand: Box::new(call),
3017                                }
3018                            } else {
3019                                call
3020                            }
3021                        }
3022                        _ => {
3023                            return Err(self.error(
3024                                "Expected NULL, TYPED, DIRECTED, LABELED, SOURCE, DESTINATION, NORMALIZED, or NFC/NFD/NFKC/NFKD after IS",
3025                            ));
3026                        }
3027                    }
3028                } else {
3029                    return Err(self.error(
3030                        "Expected NULL, TYPED, DIRECTED, LABELED, SOURCE, DESTINATION, NORMALIZED, or NFC/NFD/NFKC/NFKD after IS",
3031                    ));
3032                };
3033
3034                return Ok(predicate);
3035            }
3036            _ => {}
3037        }
3038
3039        Ok(left)
3040    }
3041
3042    fn parse_additive_expression(&mut self) -> Result<Expression> {
3043        let mut left = self.parse_multiplicative_expression()?;
3044
3045        loop {
3046            let op = match self.current.kind {
3047                TokenKind::Plus => BinaryOp::Add,
3048                TokenKind::Minus => BinaryOp::Sub,
3049                TokenKind::Concat => BinaryOp::Concat,
3050                _ => break,
3051            };
3052            self.advance();
3053            let right = self.parse_multiplicative_expression()?;
3054            left = Expression::Binary {
3055                left: Box::new(left),
3056                op,
3057                right: Box::new(right),
3058            };
3059        }
3060
3061        Ok(left)
3062    }
3063
3064    fn parse_multiplicative_expression(&mut self) -> Result<Expression> {
3065        let mut left = self.parse_unary_expression()?;
3066
3067        loop {
3068            let op = match self.current.kind {
3069                TokenKind::Star => BinaryOp::Mul,
3070                TokenKind::Slash => BinaryOp::Div,
3071                TokenKind::Percent => BinaryOp::Mod,
3072                _ => break,
3073            };
3074            self.advance();
3075            let right = self.parse_unary_expression()?;
3076            left = Expression::Binary {
3077                left: Box::new(left),
3078                op,
3079                right: Box::new(right),
3080            };
3081        }
3082
3083        Ok(left)
3084    }
3085
3086    fn parse_unary_expression(&mut self) -> Result<Expression> {
3087        match self.current.kind {
3088            TokenKind::Minus => {
3089                self.advance();
3090                let operand = self.parse_unary_expression()?;
3091                Ok(Expression::Unary {
3092                    op: UnaryOp::Neg,
3093                    operand: Box::new(operand),
3094                })
3095            }
3096            TokenKind::Plus => {
3097                self.advance();
3098                let operand = self.parse_unary_expression()?;
3099                Ok(Expression::Unary {
3100                    op: UnaryOp::Pos,
3101                    operand: Box::new(operand),
3102                })
3103            }
3104            _ => self.parse_postfix_expression(),
3105        }
3106    }
3107
3108    fn parse_postfix_expression(&mut self) -> Result<Expression> {
3109        let mut expr = self.parse_primary_expression()?;
3110
3111        loop {
3112            match self.current.kind {
3113                TokenKind::LBracket => {
3114                    self.advance();
3115                    let index = self.parse_expression()?;
3116                    self.expect(TokenKind::RBracket)?;
3117                    expr = Expression::IndexAccess {
3118                        base: Box::new(expr),
3119                        index: Box::new(index),
3120                    };
3121                }
3122                // n:Label label-check syntax (compact form of IS LABELED).
3123                // Multiple labels (n:Person:Actor) are ANDead together.
3124                TokenKind::Colon => {
3125                    let base = expr;
3126                    let mut combined: Option<Expression> = None;
3127                    while self.current.kind == TokenKind::Colon {
3128                        self.advance();
3129                        if !self.is_label_or_type_name() {
3130                            return Err(self.error("Expected label name after ':'"));
3131                        }
3132                        let label = self.get_identifier_name();
3133                        self.advance();
3134                        let check = Expression::FunctionCall {
3135                            name: "hasLabel".to_string(),
3136                            args: vec![base.clone(), Expression::Literal(Literal::String(label))],
3137                            distinct: false,
3138                        };
3139                        combined = Some(match combined {
3140                            None => check,
3141                            Some(prev) => Expression::Binary {
3142                                left: Box::new(prev),
3143                                op: BinaryOp::And,
3144                                right: Box::new(check),
3145                            },
3146                        });
3147                    }
3148                    expr = combined
3149                        .ok_or_else(|| self.error("Expected at least one label after ':'"))?;
3150                }
3151                _ => break,
3152            }
3153        }
3154
3155        Ok(expr)
3156    }
3157
3158    fn parse_primary_expression(&mut self) -> Result<Expression> {
3159        match self.current.kind {
3160            TokenKind::Null => {
3161                self.advance();
3162                Ok(Expression::Literal(Literal::Null))
3163            }
3164            TokenKind::True => {
3165                self.advance();
3166                Ok(Expression::Literal(Literal::Bool(true)))
3167            }
3168            TokenKind::False => {
3169                self.advance();
3170                Ok(Expression::Literal(Literal::Bool(false)))
3171            }
3172            TokenKind::Integer => {
3173                let text = &self.current.text;
3174                let value = if text.starts_with("0x") || text.starts_with("0X") {
3175                    i64::from_str_radix(&text[2..], 16)
3176                } else if text.starts_with("0o") || text.starts_with("0O") {
3177                    i64::from_str_radix(&text[2..], 8)
3178                } else if text.starts_with("0b") || text.starts_with("0B") {
3179                    i64::from_str_radix(&text[2..], 2)
3180                } else {
3181                    text.parse()
3182                }
3183                .map_err(|_| self.error("Invalid integer"))?;
3184                self.advance();
3185                Ok(Expression::Literal(Literal::Integer(value)))
3186            }
3187            TokenKind::Float => {
3188                let value = self
3189                    .current
3190                    .text
3191                    .parse()
3192                    .map_err(|_| self.error("Invalid float"))?;
3193                self.advance();
3194                Ok(Expression::Literal(Literal::Float(value)))
3195            }
3196            TokenKind::String => {
3197                let text = &self.current.text;
3198                let inner = &text[1..text.len() - 1]; // Remove quotes
3199                let value = unescape_string(inner);
3200                self.advance();
3201                Ok(Expression::Literal(Literal::String(value)))
3202            }
3203            // CASE expression - check if it's actually a CASE expression or just a variable named 'case'
3204            TokenKind::Case => {
3205                // Look ahead: if followed by WHEN, it's a CASE expression
3206                // If followed by : , ) AS ORDER LIMIT SKIP or EOF, it's a variable named 'case'
3207                let next = self.peek_kind();
3208                if matches!(
3209                    next,
3210                    TokenKind::Colon
3211                        | TokenKind::Comma
3212                        | TokenKind::RParen
3213                        | TokenKind::RBracket
3214                        | TokenKind::As
3215                        | TokenKind::Order
3216                        | TokenKind::Limit
3217                        | TokenKind::Skip
3218                        | TokenKind::Eof
3219                ) {
3220                    // It's a variable named 'case'
3221                    let name = "case".to_string();
3222                    self.advance();
3223                    Ok(Expression::Variable(name))
3224                } else {
3225                    // It's a CASE expression
3226                    self.parse_case_expression()
3227                }
3228            }
3229            // Handle type() function - must be checked BEFORE is_identifier() since TYPE is a contextual keyword
3230            TokenKind::Type => {
3231                let name = "type".to_string();
3232                self.advance();
3233                if self.current.kind != TokenKind::LParen {
3234                    // If not followed by (, treat as identifier/variable
3235                    return Ok(Expression::Variable(name));
3236                }
3237                self.advance();
3238                let mut args = Vec::new();
3239                if self.current.kind != TokenKind::RParen {
3240                    args.push(self.parse_expression()?);
3241                    while self.current.kind == TokenKind::Comma {
3242                        self.advance();
3243                        args.push(self.parse_expression()?);
3244                    }
3245                }
3246                self.expect(TokenKind::RParen)?;
3247                Ok(Expression::FunctionCall {
3248                    name,
3249                    args,
3250                    distinct: false,
3251                })
3252            }
3253            _ if self.is_identifier() => {
3254                let name = self.get_identifier_name();
3255
3256                // SESSION_USER: ISO GQL system value expression
3257                if name.eq_ignore_ascii_case("SESSION_USER") {
3258                    self.advance();
3259                    return Ok(Expression::FunctionCall {
3260                        name: "session_user".to_string(),
3261                        args: Vec::new(),
3262                        distinct: false,
3263                    });
3264                }
3265
3266                // ISO/IEC 39075 Section 17.1 / Section 21: pre-reserved schema/graph references
3267                if name.eq_ignore_ascii_case("CURRENT_SCHEMA") {
3268                    self.advance();
3269                    return Ok(Expression::FunctionCall {
3270                        name: "current_schema".to_string(),
3271                        args: Vec::new(),
3272                        distinct: false,
3273                    });
3274                }
3275                if name.eq_ignore_ascii_case("CURRENT_GRAPH")
3276                    || name.eq_ignore_ascii_case("CURRENT_PROPERTY_GRAPH")
3277                {
3278                    self.advance();
3279                    return Ok(Expression::FunctionCall {
3280                        name: "current_graph".to_string(),
3281                        args: Vec::new(),
3282                        distinct: false,
3283                    });
3284                }
3285                if name.eq_ignore_ascii_case("HOME_SCHEMA") {
3286                    self.advance();
3287                    return Ok(Expression::FunctionCall {
3288                        name: "home_schema".to_string(),
3289                        args: Vec::new(),
3290                        distinct: false,
3291                    });
3292                }
3293                if name.eq_ignore_ascii_case("HOME_GRAPH")
3294                    || name.eq_ignore_ascii_case("HOME_PROPERTY_GRAPH")
3295                {
3296                    self.advance();
3297                    return Ok(Expression::FunctionCall {
3298                        name: "home_graph".to_string(),
3299                        args: Vec::new(),
3300                        distinct: false,
3301                    });
3302                }
3303
3304                // NULLIF(expr1, expr2) - ISO GQL keyword syntax (Section 20.7)
3305                if name.eq_ignore_ascii_case("NULLIF") && self.peek_kind() == TokenKind::LParen {
3306                    self.advance(); // consume NULLIF
3307                    self.advance(); // consume (
3308                    let expr1 = self.parse_expression()?;
3309                    self.expect(TokenKind::Comma)?;
3310                    let expr2 = self.parse_expression()?;
3311                    self.expect(TokenKind::RParen)?;
3312                    return Ok(Expression::FunctionCall {
3313                        name: "nullif".to_string(),
3314                        args: vec![expr1, expr2],
3315                        distinct: false,
3316                    });
3317                }
3318
3319                // COALESCE(expr1, expr2, ...) - ISO GQL keyword syntax (Section 20.7)
3320                if name.eq_ignore_ascii_case("COALESCE") && self.peek_kind() == TokenKind::LParen {
3321                    self.advance(); // consume COALESCE
3322                    self.advance(); // consume (
3323                    let mut args = vec![self.parse_expression()?];
3324                    while self.current.kind == TokenKind::Comma {
3325                        self.advance();
3326                        args.push(self.parse_expression()?);
3327                    }
3328                    self.expect(TokenKind::RParen)?;
3329                    return Ok(Expression::FunctionCall {
3330                        name: "coalesce".to_string(),
3331                        args,
3332                        distinct: false,
3333                    });
3334                }
3335
3336                // TRIM(BOTH|LEADING|TRAILING 'chars' FROM string)
3337                // ISO GQL enhanced TRIM with trim specification (GF05)
3338                if name.eq_ignore_ascii_case("TRIM") && self.peek_kind() == TokenKind::LParen {
3339                    self.advance(); // consume TRIM
3340                    self.advance(); // consume (
3341                    // Determine trim mode and characters
3342                    let mut mode = 0i64; // 0=both, 1=leading, 2=trailing
3343                    let mut trim_chars: Option<Expression> = None;
3344
3345                    // Check for BOTH/LEADING/TRAILING keyword
3346                    if self.is_identifier() {
3347                        let kw = self.get_identifier_name().to_uppercase();
3348                        match kw.as_str() {
3349                            "BOTH" => {
3350                                self.advance();
3351                            }
3352                            "LEADING" => {
3353                                mode = 1;
3354                                self.advance();
3355                            }
3356                            "TRAILING" => {
3357                                mode = 2;
3358                                self.advance();
3359                            }
3360                            "FROM" => {
3361                                // TRIM(FROM string) - default both, no trim chars
3362                                self.advance();
3363                                let string_expr = self.parse_expression()?;
3364                                self.expect(TokenKind::RParen)?;
3365                                return Ok(Expression::FunctionCall {
3366                                    name: "trim".to_string(),
3367                                    args: vec![string_expr],
3368                                    distinct: false,
3369                                });
3370                            }
3371                            _ => {
3372                                // Not a keyword, parse as the only arg (simple trim(expr))
3373                                let expr = self.parse_expression()?;
3374                                self.expect(TokenKind::RParen)?;
3375                                return Ok(Expression::FunctionCall {
3376                                    name: "trim".to_string(),
3377                                    args: vec![expr],
3378                                    distinct: false,
3379                                });
3380                            }
3381                        }
3382                    }
3383
3384                    // After mode keyword, check for trim chars or FROM
3385                    if self.is_identifier()
3386                        && self.get_identifier_name().eq_ignore_ascii_case("FROM")
3387                    {
3388                        // TRIM(BOTH FROM string) - no trim chars
3389                        self.advance(); // consume FROM
3390                        let string_expr = self.parse_expression()?;
3391                        self.expect(TokenKind::RParen)?;
3392                        return Ok(Expression::FunctionCall {
3393                            name: "trim".to_string(),
3394                            args: vec![
3395                                string_expr,
3396                                Expression::Literal(Literal::String(" ".into())),
3397                                Expression::Literal(Literal::Integer(mode)),
3398                            ],
3399                            distinct: false,
3400                        });
3401                    }
3402
3403                    // Parse trim character expression
3404                    if self.current.kind != TokenKind::RParen {
3405                        trim_chars = Some(self.parse_expression()?);
3406                    }
3407
3408                    // Check for FROM keyword
3409                    if self.is_identifier()
3410                        && self.get_identifier_name().eq_ignore_ascii_case("FROM")
3411                    {
3412                        self.advance(); // consume FROM
3413                        let string_expr = self.parse_expression()?;
3414                        self.expect(TokenKind::RParen)?;
3415                        let chars_expr =
3416                            trim_chars.unwrap_or(Expression::Literal(Literal::String(" ".into())));
3417                        return Ok(Expression::FunctionCall {
3418                            name: "trim".to_string(),
3419                            args: vec![
3420                                string_expr,
3421                                chars_expr,
3422                                Expression::Literal(Literal::Integer(mode)),
3423                            ],
3424                            distinct: false,
3425                        });
3426                    }
3427
3428                    // Simple trim(expr) - single argument
3429                    self.expect(TokenKind::RParen)?;
3430                    let arg = trim_chars.unwrap_or(Expression::Literal(Literal::Null));
3431                    return Ok(Expression::FunctionCall {
3432                        name: "trim".to_string(),
3433                        args: vec![arg],
3434                        distinct: false,
3435                    });
3436                }
3437
3438                // List predicates: all/any/none/single(x IN list WHERE pred)
3439                // Disambiguate from regular function calls by checking for x IN pattern
3440                if self.peek_kind() == TokenKind::LParen {
3441                    let lower = name.to_lowercase();
3442                    let predicate_kind = match lower.as_str() {
3443                        "all" => Some(ListPredicateKind::All),
3444                        "any" => Some(ListPredicateKind::Any),
3445                        "none" => Some(ListPredicateKind::None),
3446                        "single" => Some(ListPredicateKind::Single),
3447                        _ => None,
3448                    };
3449                    if let Some(kind) = predicate_kind {
3450                        // Save position to restore if this is a regular function call
3451                        self.advance(); // consume function name
3452                        // Now peek inside: if ( identifier IN ... ), it's a list predicate
3453                        // We've consumed the name, current is LParen, peek is potentially identifier
3454                        // We can't easily look 2 ahead, so try parsing and fall back
3455                        return self.parse_list_predicate(kind);
3456                    }
3457
3458                    // reduce(acc = init, x IN list | expr)
3459                    if lower == "reduce" {
3460                        self.advance(); // consume 'reduce'
3461                        return self.parse_reduce();
3462                    }
3463                }
3464
3465                // LET ... IN ... END expression
3466                if name.eq_ignore_ascii_case("LET") {
3467                    self.advance(); // consume LET
3468                    let mut bindings = Vec::new();
3469                    loop {
3470                        if !self.is_identifier() {
3471                            return Err(self.error("Expected variable name in LET expression"));
3472                        }
3473                        let var = self.get_identifier_name();
3474                        self.advance();
3475                        self.expect(TokenKind::Eq)?;
3476                        // Use additive_expression to stop before IN (which is a
3477                        // comparison-level operator) so the LET's own IN keyword
3478                        // is not consumed by the binding expression.
3479                        let expr = self.parse_additive_expression()?;
3480                        bindings.push((var, expr));
3481                        if self.current.kind != TokenKind::Comma {
3482                            break;
3483                        }
3484                        self.advance(); // consume comma
3485                    }
3486                    // Expect IN keyword
3487                    if self.current.kind != TokenKind::In {
3488                        return Err(self.error("Expected IN after LET bindings"));
3489                    }
3490                    self.advance(); // consume IN
3491                    let body = self.parse_expression()?;
3492                    self.expect(TokenKind::End)?;
3493                    return Ok(Expression::LetIn {
3494                        bindings,
3495                        body: Box::new(body),
3496                    });
3497                }
3498
3499                self.advance();
3500
3501                // Typed temporal literals: DATE 'str', TIME 'str', DURATION 'str', DATETIME 'str'
3502                if self.current.kind == TokenKind::String {
3503                    let upper = name.to_uppercase();
3504                    let make_val = |parser: &Self| {
3505                        let text = &parser.current.text;
3506                        let inner = &text[1..text.len() - 1];
3507                        unescape_string(inner)
3508                    };
3509                    let typed_lit = match upper.as_str() {
3510                        "DATE" => Some(Literal::Date(make_val(self))),
3511                        "TIME" => Some(Literal::Time(make_val(self))),
3512                        "DURATION" => Some(Literal::Duration(make_val(self))),
3513                        "DATETIME" => Some(Literal::Datetime(make_val(self))),
3514                        _ => None,
3515                    };
3516                    if let Some(lit) = typed_lit {
3517                        self.advance();
3518                        return Ok(Expression::Literal(lit));
3519                    }
3520                }
3521
3522                // Compound typed literals: ZONED DATETIME 'str', ZONED TIME 'str'
3523                if name.eq_ignore_ascii_case("ZONED") && self.is_identifier() {
3524                    let sub = self.get_identifier_name().to_uppercase();
3525                    if sub == "DATETIME" || sub == "TIME" {
3526                        self.advance(); // consume DATETIME/TIME
3527                        if self.current.kind == TokenKind::String {
3528                            let text = &self.current.text;
3529                            let inner = &text[1..text.len() - 1];
3530                            let val = unescape_string(inner);
3531                            self.advance();
3532                            return Ok(Expression::Literal(if sub == "DATETIME" {
3533                                Literal::ZonedDatetime(val)
3534                            } else {
3535                                Literal::ZonedTime(val)
3536                            }));
3537                        }
3538                    }
3539                }
3540
3541                if self.current.kind == TokenKind::Dot {
3542                    self.advance();
3543                    if !self.is_identifier() {
3544                        return Err(self.error("Expected property name"));
3545                    }
3546                    let property = self.get_identifier_name();
3547                    self.advance();
3548                    Ok(Expression::PropertyAccess {
3549                        variable: name,
3550                        property,
3551                    })
3552                } else if self.current.kind == TokenKind::LBrace
3553                    && name.eq_ignore_ascii_case("count")
3554                {
3555                    // COUNT { MATCH ... } subquery expression
3556                    self.advance(); // consume {
3557                    let inner_query = self.parse_exists_inner_query()?;
3558                    self.expect(TokenKind::RBrace)?;
3559                    Ok(Expression::CountSubquery {
3560                        query: Box::new(inner_query),
3561                    })
3562                } else if self.current.kind == TokenKind::LBrace
3563                    && name.eq_ignore_ascii_case("value")
3564                {
3565                    // VALUE { subquery } expression
3566                    self.advance(); // consume {
3567                    let inner_query = self.parse_value_subquery_inner()?;
3568                    self.expect(TokenKind::RBrace)?;
3569                    Ok(Expression::ValueSubquery {
3570                        query: Box::new(inner_query),
3571                    })
3572                } else if self.current.kind == TokenKind::LParen {
3573                    // Function call
3574                    self.advance();
3575                    // COUNT(*) per ISO/IEC 39075 sec 20.9
3576                    if name.eq_ignore_ascii_case("count") && self.current.kind == TokenKind::Star {
3577                        self.advance(); // consume *
3578                        self.expect(TokenKind::RParen)?;
3579                        return Ok(Expression::FunctionCall {
3580                            name,
3581                            args: Vec::new(),
3582                            distinct: false,
3583                        });
3584                    }
3585                    // Check for DISTINCT keyword in aggregate functions
3586                    let distinct = if self.current.kind == TokenKind::Distinct {
3587                        self.advance();
3588                        true
3589                    } else {
3590                        false
3591                    };
3592                    let mut args = Vec::new();
3593                    if self.current.kind != TokenKind::RParen {
3594                        args.push(self.parse_expression()?);
3595                        while self.current.kind == TokenKind::Comma {
3596                            self.advance();
3597                            args.push(self.parse_expression()?);
3598                        }
3599                    }
3600                    self.expect(TokenKind::RParen)?;
3601                    Ok(Expression::FunctionCall {
3602                        name,
3603                        args,
3604                        distinct,
3605                    })
3606                } else {
3607                    Ok(Expression::Variable(name))
3608                }
3609            }
3610            TokenKind::LParen => {
3611                self.advance();
3612                let expr = self.parse_expression()?;
3613                self.expect(TokenKind::RParen)?;
3614                Ok(expr)
3615            }
3616            TokenKind::LBracket => {
3617                self.advance(); // consume [
3618                // Disambiguate: [x IN list WHERE ... | expr] vs [elem, ...]
3619                // List comprehension if: identifier followed by IN keyword
3620                if self.is_identifier() && self.peek_kind() == TokenKind::In {
3621                    return self.parse_list_comprehension_inner();
3622                }
3623                let mut elements = Vec::new();
3624                if self.current.kind != TokenKind::RBracket {
3625                    elements.push(self.parse_expression()?);
3626                    while self.current.kind == TokenKind::Comma {
3627                        self.advance();
3628                        elements.push(self.parse_expression()?);
3629                    }
3630                }
3631                self.expect(TokenKind::RBracket)?;
3632                Ok(Expression::List(elements))
3633            }
3634            TokenKind::Parameter => {
3635                // Parameter token includes the $ prefix, so we extract just the name
3636                let full_text = &self.current.text;
3637                let name = full_text.trim_start_matches('$').to_string();
3638                self.advance();
3639                Ok(Expression::Parameter(name))
3640            }
3641            TokenKind::Exists => {
3642                self.advance();
3643                if self.current.kind == TokenKind::LBrace {
3644                    // EXISTS { MATCH ... } subquery form
3645                    self.advance(); // consume {
3646                    let inner_query = self.parse_exists_inner_query()?;
3647                    self.expect(TokenKind::RBrace)?;
3648                    Ok(Expression::ExistsSubquery {
3649                        query: Box::new(inner_query),
3650                    })
3651                } else {
3652                    // exists(expr) function form
3653                    self.expect(TokenKind::LParen)?;
3654                    let arg = self.parse_expression()?;
3655                    self.expect(TokenKind::RParen)?;
3656                    Ok(Expression::FunctionCall {
3657                        name: "exists".to_string(),
3658                        args: vec![arg],
3659                        distinct: false,
3660                    })
3661                }
3662            }
3663            TokenKind::LBrace => {
3664                // Map literal: {key: value, ...}
3665                let entries = self.parse_property_map()?;
3666                Ok(Expression::Map(entries))
3667            }
3668            TokenKind::Cast => {
3669                // CAST(expr AS type) -> desugar to toInteger/toFloat/toString
3670                self.advance();
3671                self.expect(TokenKind::LParen)?;
3672                let expr = self.parse_expression()?;
3673                self.expect(TokenKind::As)?;
3674                let type_name = if self.is_identifier() {
3675                    let mut name = self.get_identifier_name().to_uppercase();
3676                    self.advance();
3677                    // Handle compound type names: ZONED DATETIME, ZONED TIME
3678                    if name == "ZONED" && self.is_identifier() {
3679                        let sub = self.get_identifier_name().to_uppercase();
3680                        if sub == "DATETIME" || sub == "TIME" {
3681                            name = format!("ZONED {sub}");
3682                            self.advance();
3683                        }
3684                    }
3685                    // Handle LIST<type> parameterized type
3686                    if name == "LIST" && self.current.kind == TokenKind::Lt {
3687                        self.advance(); // consume <
3688                        if self.is_identifier() {
3689                            let elem = self.get_identifier_name().to_uppercase();
3690                            self.advance();
3691                            self.expect(TokenKind::Gt)?;
3692                            name = format!("LIST<{elem}>");
3693                        } else {
3694                            return Err(self.error("Expected element type after LIST<"));
3695                        }
3696                    }
3697                    name
3698                } else {
3699                    return Err(self.error("Expected type name after AS"));
3700                };
3701                self.expect(TokenKind::RParen)?;
3702                let (func_name, extra_arg) = match type_name.as_str() {
3703                    "INTEGER" | "INT" | "INT64" | "BIGINT" => ("toInteger", None),
3704                    "FLOAT" | "DOUBLE" | "FLOAT64" | "REAL" => ("toFloat", None),
3705                    "STRING" | "VARCHAR" | "TEXT" => ("toString", None),
3706                    "BOOLEAN" | "BOOL" => ("toBoolean", None),
3707                    "DATE" => ("toDate", None),
3708                    "TIME" | "LOCALTIME" => ("toTime", None),
3709                    "DATETIME" | "TIMESTAMP" | "LOCALDATETIME" => ("toDatetime", None),
3710                    "DURATION" => ("toDuration", None),
3711                    "ZONED DATETIME" => ("toZonedDatetime", None),
3712                    "ZONED TIME" => ("toZonedTime", None),
3713                    "LIST" => ("toList", None),
3714                    s if s.starts_with("LIST<") => {
3715                        let elem_type = &s[5..s.len() - 1]; // extract type between < and >
3716                        ("toTypedList", Some(elem_type.to_string()))
3717                    }
3718                    _ => return Err(self.error(&format!("Unsupported CAST type: {type_name}"))),
3719                };
3720                let mut args = vec![expr];
3721                if let Some(elem) = extra_arg {
3722                    args.push(Expression::Literal(Literal::String(elem)));
3723                }
3724                Ok(Expression::FunctionCall {
3725                    name: func_name.to_string(),
3726                    args,
3727                    distinct: false,
3728                })
3729            }
3730            _ => Err(self.error("Expected expression")),
3731        }
3732    }
3733
3734    /// Parses a CASE expression.
3735    /// CASE [input] WHEN condition THEN result [WHEN ...] [ELSE default] END
3736    fn parse_case_expression(&mut self) -> Result<Expression> {
3737        self.expect(TokenKind::Case)?;
3738
3739        // Check for simple CASE (CASE expr WHEN value THEN ...)
3740        // vs searched CASE (CASE WHEN condition THEN ...)
3741        let input = if self.current.kind != TokenKind::When {
3742            Some(Box::new(self.parse_expression()?))
3743        } else {
3744            None
3745        };
3746
3747        // Parse WHEN clauses
3748        let mut whens = Vec::new();
3749        while self.current.kind == TokenKind::When {
3750            self.advance();
3751            let condition = self.parse_expression()?;
3752            self.expect(TokenKind::Then)?;
3753            let result = self.parse_expression()?;
3754            whens.push((condition, result));
3755        }
3756
3757        if whens.is_empty() {
3758            return Err(self.error("CASE requires at least one WHEN clause"));
3759        }
3760
3761        // Parse optional ELSE
3762        let else_clause = if self.current.kind == TokenKind::Else {
3763            self.advance();
3764            Some(Box::new(self.parse_expression()?))
3765        } else {
3766            None
3767        };
3768
3769        self.expect(TokenKind::End)?;
3770
3771        Ok(Expression::Case {
3772            input,
3773            whens,
3774            else_clause,
3775        })
3776    }
3777
3778    /// Parses the inner query of an EXISTS subquery.
3779    /// Handles: EXISTS { MATCH (n)-[:REL]->() [WHERE ...] }
3780    fn parse_exists_inner_query(&mut self) -> Result<QueryStatement> {
3781        let mut match_clauses = Vec::new();
3782
3783        // Parse MATCH clauses
3784        while self.current.kind == TokenKind::Match || self.current.kind == TokenKind::Optional {
3785            match_clauses.push(self.parse_match_clause()?);
3786        }
3787
3788        // Bare pattern form: EXISTS { (a)-[r]->(b) WHERE ... }
3789        // Treat as implicit MATCH when no MATCH keyword but a pattern starts with (
3790        if match_clauses.is_empty() && self.current.kind == TokenKind::LParen {
3791            let span_start = self.current.span.start;
3792            let mut patterns = Vec::new();
3793            patterns.push(self.parse_aliased_pattern()?);
3794            while self.current.kind == TokenKind::Comma {
3795                self.advance();
3796                patterns.push(self.parse_aliased_pattern()?);
3797            }
3798            match_clauses.push(MatchClause {
3799                optional: false,
3800                path_mode: None,
3801                search_prefix: None,
3802                match_mode: None,
3803                patterns,
3804                span: Some(SourceSpan::new(span_start, self.current.span.end, 1, 1)),
3805            });
3806        }
3807
3808        if match_clauses.is_empty() {
3809            return Err(self.error("EXISTS subquery requires at least one MATCH clause"));
3810        }
3811
3812        // Parse optional WHERE
3813        let where_clause = if self.current.kind == TokenKind::Where {
3814            Some(self.parse_where_clause()?)
3815        } else {
3816            None
3817        };
3818
3819        // EXISTS doesn't need RETURN - create empty return clause
3820        Ok(QueryStatement {
3821            match_clauses,
3822            where_clause,
3823            set_clauses: vec![],
3824            remove_clauses: vec![],
3825            with_clauses: vec![],
3826            unwind_clauses: vec![],
3827            merge_clauses: vec![],
3828            create_clauses: vec![],
3829            delete_clauses: vec![],
3830            return_clause: ReturnClause {
3831                distinct: false,
3832                items: vec![],
3833                is_wildcard: false,
3834                group_by: vec![],
3835                order_by: None,
3836                skip: None,
3837                limit: None,
3838                is_finish: false,
3839                span: None,
3840            },
3841            having_clause: None,
3842            ordered_clauses: vec![],
3843            span: None,
3844        })
3845    }
3846
3847    /// Parses the inner query of a VALUE subquery.
3848    /// Handles: VALUE { MATCH ... [WHERE ...] RETURN expr }
3849    fn parse_value_subquery_inner(&mut self) -> Result<QueryStatement> {
3850        let mut match_clauses = Vec::new();
3851
3852        // Parse MATCH clauses
3853        while self.current.kind == TokenKind::Match || self.current.kind == TokenKind::Optional {
3854            match_clauses.push(self.parse_match_clause()?);
3855        }
3856
3857        if match_clauses.is_empty() {
3858            return Err(self.error("VALUE subquery requires at least one MATCH clause"));
3859        }
3860
3861        // Parse optional WHERE
3862        let where_clause = if self.current.kind == TokenKind::Where {
3863            Some(self.parse_where_clause()?)
3864        } else {
3865            None
3866        };
3867
3868        // Parse required RETURN
3869        let return_clause = if self.current.kind == TokenKind::Return {
3870            self.parse_return_clause()?
3871        } else {
3872            return Err(self.error("VALUE subquery requires a RETURN clause"));
3873        };
3874
3875        Ok(QueryStatement {
3876            match_clauses,
3877            where_clause,
3878            set_clauses: vec![],
3879            remove_clauses: vec![],
3880            with_clauses: vec![],
3881            unwind_clauses: vec![],
3882            merge_clauses: vec![],
3883            create_clauses: vec![],
3884            delete_clauses: vec![],
3885            return_clause,
3886            having_clause: None,
3887            ordered_clauses: vec![],
3888            span: None,
3889        })
3890    }
3891
3892    fn parse_property_map(&mut self) -> Result<Vec<(String, Expression)>> {
3893        self.expect(TokenKind::LBrace)?;
3894
3895        let mut properties = Vec::new();
3896
3897        if self.current.kind != TokenKind::RBrace {
3898            loop {
3899                if !self.is_identifier() {
3900                    return Err(self.error("Expected property name"));
3901                }
3902                let key = self.get_identifier_name();
3903                self.advance();
3904
3905                self.expect(TokenKind::Colon)?;
3906
3907                let value = self.parse_expression()?;
3908                properties.push((key, value));
3909
3910                if self.current.kind != TokenKind::Comma {
3911                    break;
3912                }
3913                self.advance();
3914            }
3915        }
3916
3917        self.expect(TokenKind::RBrace)?;
3918        Ok(properties)
3919    }
3920
3921    fn parse_insert(&mut self) -> Result<InsertStatement> {
3922        self.expect(TokenKind::Insert)?;
3923
3924        let mut patterns = Vec::new();
3925        patterns.push(self.parse_pattern()?);
3926
3927        while self.current.kind == TokenKind::Comma {
3928            self.advance();
3929            patterns.push(self.parse_pattern()?);
3930        }
3931
3932        Ok(InsertStatement {
3933            patterns,
3934            span: None,
3935        })
3936    }
3937
3938    /// Parses CREATE as INSERT (Cypher-style data modification).
3939    fn parse_create_as_insert(&mut self) -> Result<InsertStatement> {
3940        self.expect(TokenKind::Create)?;
3941
3942        let mut patterns = Vec::new();
3943        patterns.push(self.parse_pattern()?);
3944
3945        while self.current.kind == TokenKind::Comma {
3946            self.advance();
3947            patterns.push(self.parse_pattern()?);
3948        }
3949
3950        Ok(InsertStatement {
3951            patterns,
3952            span: None,
3953        })
3954    }
3955
3956    /// Parses CREATE clause within a query (e.g., MATCH ... CREATE ...).
3957    fn parse_create_clause_in_query(&mut self) -> Result<InsertStatement> {
3958        self.expect(TokenKind::Create)?;
3959
3960        let mut patterns = Vec::new();
3961        patterns.push(self.parse_pattern()?);
3962
3963        while self.current.kind == TokenKind::Comma {
3964            self.advance();
3965            patterns.push(self.parse_pattern()?);
3966        }
3967
3968        Ok(InsertStatement {
3969            patterns,
3970            span: None,
3971        })
3972    }
3973
3974    /// Parses a DELETE target: either a plain variable or a general expression (GD04).
3975    fn parse_delete_target(&mut self) -> Result<DeleteTarget> {
3976        // Try to parse a general expression (handles variables, property access,
3977        // function calls, subqueries, etc.)
3978        let expr = self.parse_expression()?;
3979        // If it's a plain variable reference, store as Variable for backwards compat
3980        if let Expression::Variable(name) = expr {
3981            Ok(DeleteTarget::Variable(name))
3982        } else {
3983            Ok(DeleteTarget::Expression(expr))
3984        }
3985    }
3986
3987    /// Parses the DETACH / NODETACH prefix and DELETE keyword.
3988    fn parse_delete_prefix(&mut self) -> Result<bool> {
3989        let detach = if self.current.kind == TokenKind::Detach {
3990            self.advance();
3991            true
3992        } else {
3993            // NODETACH is explicit non-detach (same as bare DELETE)
3994            if self.current.kind == TokenKind::Nodetach {
3995                self.advance();
3996            }
3997            false
3998        };
3999        self.expect(TokenKind::Delete)?;
4000        Ok(detach)
4001    }
4002
4003    /// Parses DELETE clause within a query (e.g., MATCH ... DELETE ...).
4004    fn parse_delete_clause_in_query(&mut self) -> Result<DeleteStatement> {
4005        let detach = self.parse_delete_prefix()?;
4006
4007        let mut targets = Vec::new();
4008        targets.push(self.parse_delete_target()?);
4009
4010        while self.current.kind == TokenKind::Comma {
4011            self.advance();
4012            targets.push(self.parse_delete_target()?);
4013        }
4014
4015        Ok(DeleteStatement {
4016            targets,
4017            detach,
4018            span: None,
4019        })
4020    }
4021
4022    fn parse_delete(&mut self) -> Result<DeleteStatement> {
4023        let detach = self.parse_delete_prefix()?;
4024
4025        let mut targets = Vec::new();
4026        targets.push(self.parse_delete_target()?);
4027
4028        while self.current.kind == TokenKind::Comma {
4029            self.advance();
4030            targets.push(self.parse_delete_target()?);
4031        }
4032
4033        Ok(DeleteStatement {
4034            targets,
4035            detach,
4036            span: None,
4037        })
4038    }
4039
4040    fn parse_create_schema(&mut self) -> Result<SchemaStatement> {
4041        self.expect(TokenKind::Create)?;
4042
4043        // Optional OR REPLACE
4044        let or_replace = self.try_parse_or_replace();
4045
4046        match self.current.kind {
4047            TokenKind::Node => {
4048                self.advance();
4049                self.expect(TokenKind::Type)?;
4050
4051                // Optional IF NOT EXISTS
4052                let if_not_exists = self.try_parse_if_not_exists();
4053
4054                if !self.is_identifier() {
4055                    return Err(self.error("Expected type name"));
4056                }
4057                let name = self.get_identifier_name();
4058                self.advance();
4059
4060                // Optional EXTENDS <parent1>, <parent2>
4061                let parent_types = if self.is_identifier()
4062                    && self.get_identifier_name().eq_ignore_ascii_case("EXTENDS")
4063                {
4064                    self.advance();
4065                    let mut parents = Vec::new();
4066                    if self.is_identifier() || self.is_label_or_type_name() {
4067                        parents.push(self.get_identifier_name());
4068                        self.advance();
4069                        while self.current.kind == TokenKind::Comma {
4070                            self.advance();
4071                            if self.is_identifier() || self.is_label_or_type_name() {
4072                                parents.push(self.get_identifier_name());
4073                                self.advance();
4074                            }
4075                        }
4076                    }
4077                    parents
4078                } else {
4079                    Vec::new()
4080                };
4081
4082                // Parse property definitions
4083                let properties = if self.current.kind == TokenKind::LParen {
4084                    self.parse_property_definitions()?
4085                } else {
4086                    Vec::new()
4087                };
4088
4089                Ok(SchemaStatement::CreateNodeType(CreateNodeTypeStatement {
4090                    name,
4091                    properties,
4092                    parent_types,
4093                    if_not_exists,
4094                    or_replace,
4095                    span: None,
4096                }))
4097            }
4098            TokenKind::Edge => {
4099                self.advance();
4100                self.expect(TokenKind::Type)?;
4101
4102                // Optional IF NOT EXISTS
4103                let if_not_exists = self.try_parse_if_not_exists();
4104
4105                if !self.is_identifier() {
4106                    return Err(self.error("Expected type name"));
4107                }
4108                let name = self.get_identifier_name();
4109                self.advance();
4110
4111                // Optional CONNECTING (Source) TO (Target)
4112                let (source_node_types, target_node_types) = if self.is_identifier()
4113                    && self.get_identifier_name().eq_ignore_ascii_case("CONNECTING")
4114                {
4115                    self.advance();
4116                    self.expect(TokenKind::LParen)?;
4117                    let mut sources = Vec::new();
4118                    while self.is_identifier() || self.is_label_or_type_name() {
4119                        sources.push(self.get_identifier_name());
4120                        self.advance();
4121                        if self.current.kind == TokenKind::Comma {
4122                            self.advance();
4123                        } else {
4124                            break;
4125                        }
4126                    }
4127                    self.expect(TokenKind::RParen)?;
4128                    if !(self.is_identifier()
4129                        && self.get_identifier_name().eq_ignore_ascii_case("TO"))
4130                    {
4131                        return Err(self.error("Expected 'TO' after source node types"));
4132                    }
4133                    self.advance();
4134                    self.expect(TokenKind::LParen)?;
4135                    let mut targets = Vec::new();
4136                    while self.is_identifier() || self.is_label_or_type_name() {
4137                        targets.push(self.get_identifier_name());
4138                        self.advance();
4139                        if self.current.kind == TokenKind::Comma {
4140                            self.advance();
4141                        } else {
4142                            break;
4143                        }
4144                    }
4145                    self.expect(TokenKind::RParen)?;
4146                    (sources, targets)
4147                } else {
4148                    (Vec::new(), Vec::new())
4149                };
4150
4151                let properties = if self.current.kind == TokenKind::LParen {
4152                    self.parse_property_definitions()?
4153                } else {
4154                    Vec::new()
4155                };
4156
4157                Ok(SchemaStatement::CreateEdgeType(CreateEdgeTypeStatement {
4158                    name,
4159                    properties,
4160                    source_node_types,
4161                    target_node_types,
4162                    if_not_exists,
4163                    or_replace,
4164                    span: None,
4165                }))
4166            }
4167            TokenKind::Vector => {
4168                self.advance();
4169                self.expect(TokenKind::Index)?;
4170
4171                // Parse index name
4172                if !self.is_identifier() {
4173                    return Err(self.error("Expected index name"));
4174                }
4175                let name = self.get_identifier_name();
4176                self.advance();
4177
4178                // Expect ON
4179                self.expect(TokenKind::On)?;
4180
4181                // Parse :Label(property)
4182                self.expect(TokenKind::Colon)?;
4183
4184                if !self.is_identifier() && !self.is_label_or_type_name() {
4185                    return Err(self.error("Expected node label"));
4186                }
4187                let node_label = self.get_identifier_name();
4188                self.advance();
4189
4190                self.expect(TokenKind::LParen)?;
4191
4192                if !self.is_identifier() {
4193                    return Err(self.error("Expected property name"));
4194                }
4195                let property = self.get_identifier_name();
4196                self.advance();
4197
4198                self.expect(TokenKind::RParen)?;
4199
4200                // Parse optional DIMENSION
4201                let dimensions = if self.current.kind == TokenKind::Dimension {
4202                    self.advance();
4203                    if self.current.kind != TokenKind::Integer {
4204                        return Err(self.error("Expected integer dimension"));
4205                    }
4206                    let dim: usize = self
4207                        .current
4208                        .text
4209                        .parse()
4210                        .map_err(|_| self.error("Invalid dimension value"))?;
4211                    self.advance();
4212                    Some(dim)
4213                } else {
4214                    None
4215                };
4216
4217                // Parse optional METRIC
4218                let metric = if self.current.kind == TokenKind::Metric {
4219                    self.advance();
4220                    if self.current.kind != TokenKind::String {
4221                        return Err(self.error("Expected metric name as string"));
4222                    }
4223                    // Remove quotes from string literal
4224                    let metric_str = self
4225                        .current
4226                        .text
4227                        .trim_matches('\'')
4228                        .trim_matches('"')
4229                        .to_string();
4230                    self.advance();
4231                    Some(metric_str)
4232                } else {
4233                    None
4234                };
4235
4236                Ok(SchemaStatement::CreateVectorIndex(
4237                    CreateVectorIndexStatement {
4238                        name,
4239                        node_label,
4240                        property,
4241                        dimensions,
4242                        metric,
4243                        span: None,
4244                    },
4245                ))
4246            }
4247            TokenKind::Index => {
4248                // CREATE INDEX name FOR (n:Label) ON (n.property) [USING TEXT|VECTOR|BTREE]
4249                self.advance();
4250
4251                // Optional IF NOT EXISTS
4252                let if_not_exists = self.try_parse_if_not_exists();
4253
4254                if !self.is_identifier() {
4255                    return Err(self.error("Expected index name"));
4256                }
4257                let name = self.get_identifier_name();
4258                self.advance();
4259
4260                self.parse_create_index_body(name, if_not_exists)
4261            }
4262            _ if self.is_identifier()
4263                && self
4264                    .get_identifier_name()
4265                    .eq_ignore_ascii_case("CONSTRAINT") =>
4266            {
4267                // CREATE CONSTRAINT [name] FOR (n:Label) ON (n.prop) UNIQUE|NOT NULL
4268                self.advance(); // consume CONSTRAINT
4269
4270                // Optional IF NOT EXISTS
4271                let if_not_exists = self.try_parse_if_not_exists();
4272
4273                // Optional constraint name
4274                let name = if self.is_identifier()
4275                    && !self.get_identifier_name().eq_ignore_ascii_case("FOR")
4276                {
4277                    let n = self.get_identifier_name();
4278                    self.advance();
4279                    Some(n)
4280                } else {
4281                    None
4282                };
4283
4284                self.parse_create_constraint_body(name, if_not_exists)
4285            }
4286            _ if self.is_identifier()
4287                && self.get_identifier_name().eq_ignore_ascii_case("GRAPH") =>
4288            {
4289                self.advance(); // consume GRAPH
4290                self.expect(TokenKind::Type)?;
4291
4292                let if_not_exists = self.try_parse_if_not_exists();
4293
4294                if !self.is_identifier() {
4295                    return Err(self.error("Expected graph type name"));
4296                }
4297                let name = self.get_identifier_name();
4298                self.advance();
4299
4300                // GG04: LIKE <graph_name> clause
4301                let like_graph = if self.current.kind == TokenKind::Like {
4302                    self.advance();
4303                    if !self.is_identifier() {
4304                        return Err(self.error("Expected graph name after LIKE"));
4305                    }
4306                    let graph_name = self.get_identifier_name();
4307                    self.advance();
4308                    Some(graph_name)
4309                } else {
4310                    None
4311                };
4312
4313                // Parse optional body: ISO syntax or JSON-like syntax
4314                let (node_types, edge_types, inline_types, open) =
4315                    if self.current.kind == TokenKind::LBrace {
4316                        let (nt, et, open) = self.parse_graph_type_body()?;
4317                        (nt, et, Vec::new(), open)
4318                    } else if self.current.kind == TokenKind::LParen {
4319                        let inline = self.parse_graph_type_iso_body()?;
4320                        let nt: Vec<String> = inline
4321                            .iter()
4322                            .filter_map(|t| match t {
4323                                InlineElementType::Node { name, .. } => Some(name.clone()),
4324                                InlineElementType::Edge { .. } => None,
4325                            })
4326                            .collect();
4327                        let et: Vec<String> = inline
4328                            .iter()
4329                            .filter_map(|t| match t {
4330                                InlineElementType::Edge { name, .. } => Some(name.clone()),
4331                                InlineElementType::Node { .. } => None,
4332                            })
4333                            .collect();
4334                        (nt, et, inline, false)
4335                    } else {
4336                        (Vec::new(), Vec::new(), Vec::new(), true)
4337                    };
4338
4339                Ok(SchemaStatement::CreateGraphType(CreateGraphTypeStatement {
4340                    name,
4341                    node_types,
4342                    edge_types,
4343                    inline_types,
4344                    like_graph,
4345                    open,
4346                    if_not_exists,
4347                    or_replace,
4348                    span: None,
4349                }))
4350            }
4351            _ if self.is_identifier()
4352                && self.get_identifier_name().eq_ignore_ascii_case("SCHEMA") =>
4353            {
4354                self.advance(); // consume SCHEMA
4355
4356                let if_not_exists = self.try_parse_if_not_exists();
4357
4358                if !self.is_identifier() {
4359                    return Err(self.error("Expected schema name"));
4360                }
4361                let name = self.get_identifier_name();
4362                self.advance();
4363
4364                Ok(SchemaStatement::CreateSchema {
4365                    name,
4366                    if_not_exists,
4367                })
4368            }
4369            _ if self.is_identifier()
4370                && self.get_identifier_name().eq_ignore_ascii_case("PROCEDURE") =>
4371            {
4372                self.advance(); // consume PROCEDURE
4373                self.parse_create_procedure(or_replace)
4374            }
4375            _ => Err(self.error(
4376                "Expected NODE, EDGE, VECTOR, INDEX, CONSTRAINT, GRAPH, SCHEMA, or PROCEDURE after CREATE",
4377            )),
4378        }
4379    }
4380
4381    /// Parses the body of CREATE INDEX after name: `FOR (n:Label) ON (n.prop) [USING kind] [options]`.
4382    fn parse_create_index_body(
4383        &mut self,
4384        name: String,
4385        if_not_exists: bool,
4386    ) -> Result<SchemaStatement> {
4387        // Expect FOR
4388        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("FOR") {
4389            return Err(self.error("Expected FOR after index name"));
4390        }
4391        self.advance();
4392
4393        // Parse (n:Label)
4394        self.expect(TokenKind::LParen)?;
4395        if !self.is_identifier() {
4396            return Err(self.error("Expected variable in FOR clause"));
4397        }
4398        let var_name = self.get_identifier_name();
4399        self.advance();
4400        self.expect(TokenKind::Colon)?;
4401        if !self.is_identifier() && !self.is_label_or_type_name() {
4402            return Err(self.error("Expected label"));
4403        }
4404        let label = self.get_identifier_name();
4405        self.advance();
4406        self.expect(TokenKind::RParen)?;
4407
4408        // Expect ON
4409        self.expect(TokenKind::On)?;
4410
4411        // Parse (n.property, ...)
4412        self.expect(TokenKind::LParen)?;
4413        let mut properties = Vec::new();
4414        loop {
4415            if !self.is_identifier() {
4416                return Err(self.error("Expected variable.property"));
4417            }
4418            let prop_var = self.get_identifier_name();
4419            self.advance();
4420            self.expect(TokenKind::Dot)?;
4421            if !self.is_identifier() {
4422                return Err(self.error("Expected property name"));
4423            }
4424            // Validate variable matches
4425            if !prop_var.eq_ignore_ascii_case(&var_name) {
4426                return Err(self.error(&format!(
4427                    "Variable '{prop_var}' does not match FOR variable '{var_name}'"
4428                )));
4429            }
4430            let prop = self.get_identifier_name();
4431            self.advance();
4432            properties.push(prop);
4433            if self.current.kind != TokenKind::Comma {
4434                break;
4435            }
4436            self.advance();
4437        }
4438        self.expect(TokenKind::RParen)?;
4439
4440        // Optional USING TEXT|VECTOR|BTREE
4441        let mut index_kind = IndexKind::Property;
4442        let mut options = IndexOptions::default();
4443
4444        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("USING") {
4445            self.advance();
4446            if !self.is_identifier() && self.current.kind != TokenKind::Vector {
4447                return Err(self.error("Expected TEXT, VECTOR, or BTREE after USING"));
4448            }
4449            let kind_text = if self.current.kind == TokenKind::Vector {
4450                "VECTOR".to_string()
4451            } else {
4452                self.get_identifier_name()
4453            };
4454            self.advance();
4455            match kind_text.to_uppercase().as_str() {
4456                "TEXT" => index_kind = IndexKind::Text,
4457                "VECTOR" => {
4458                    index_kind = IndexKind::Vector;
4459                    // Parse optional {dimensions: N, metric: 'name'}
4460                    if self.current.kind == TokenKind::LBrace {
4461                        self.advance();
4462                        while self.current.kind != TokenKind::RBrace {
4463                            if !self.is_identifier() {
4464                                return Err(self.error("Expected option name"));
4465                            }
4466                            let opt_name = self.get_identifier_name();
4467                            self.advance();
4468                            self.expect(TokenKind::Colon)?;
4469                            match opt_name.to_uppercase().as_str() {
4470                                "DIMENSIONS" | "DIMENSION" => {
4471                                    if self.current.kind != TokenKind::Integer {
4472                                        return Err(self.error("Expected integer for dimensions"));
4473                                    }
4474                                    let dim: usize = self
4475                                        .current
4476                                        .text
4477                                        .parse()
4478                                        .map_err(|_| self.error("Invalid dimension value"))?;
4479                                    self.advance();
4480                                    options.dimensions = Some(dim);
4481                                }
4482                                "METRIC" => {
4483                                    if self.current.kind != TokenKind::String {
4484                                        return Err(self.error("Expected string for metric"));
4485                                    }
4486                                    let metric = self
4487                                        .current
4488                                        .text
4489                                        .trim_matches('\'')
4490                                        .trim_matches('"')
4491                                        .to_string();
4492                                    self.advance();
4493                                    options.metric = Some(metric);
4494                                }
4495                                _ => {
4496                                    return Err(
4497                                        self.error(&format!("Unknown index option '{opt_name}'"))
4498                                    );
4499                                }
4500                            }
4501                            if self.current.kind == TokenKind::Comma {
4502                                self.advance();
4503                            }
4504                        }
4505                        self.expect(TokenKind::RBrace)?;
4506                    }
4507                }
4508                "BTREE" => index_kind = IndexKind::BTree,
4509                _ => {
4510                    return Err(self.error(&format!("Unknown index type '{kind_text}'")));
4511                }
4512            }
4513        }
4514
4515        Ok(SchemaStatement::CreateIndex(CreateIndexStatement {
4516            name,
4517            index_kind,
4518            label,
4519            properties,
4520            options,
4521            if_not_exists,
4522            span: None,
4523        }))
4524    }
4525
4526    /// Parses the body of CREATE CONSTRAINT: `FOR (n:Label) ON (n.prop) kind`.
4527    fn parse_create_constraint_body(
4528        &mut self,
4529        name: Option<String>,
4530        if_not_exists: bool,
4531    ) -> Result<SchemaStatement> {
4532        // Expect FOR
4533        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("FOR") {
4534            return Err(self.error("Expected FOR after constraint name"));
4535        }
4536        self.advance();
4537
4538        // Parse (n:Label)
4539        self.expect(TokenKind::LParen)?;
4540        if !self.is_identifier() {
4541            return Err(self.error("Expected variable in FOR clause"));
4542        }
4543        let var_name = self.get_identifier_name();
4544        self.advance();
4545        self.expect(TokenKind::Colon)?;
4546        if !self.is_identifier() && !self.is_label_or_type_name() {
4547            return Err(self.error("Expected label"));
4548        }
4549        let label = self.get_identifier_name();
4550        self.advance();
4551        self.expect(TokenKind::RParen)?;
4552
4553        // Expect ON
4554        self.expect(TokenKind::On)?;
4555
4556        // Parse (n.property, ...)
4557        self.expect(TokenKind::LParen)?;
4558        let mut properties = Vec::new();
4559        loop {
4560            if !self.is_identifier() {
4561                return Err(self.error("Expected variable.property"));
4562            }
4563            let prop_var = self.get_identifier_name();
4564            self.advance();
4565            self.expect(TokenKind::Dot)?;
4566            if !self.is_identifier() {
4567                return Err(self.error("Expected property name"));
4568            }
4569            if !prop_var.eq_ignore_ascii_case(&var_name) {
4570                return Err(self.error(&format!(
4571                    "Variable '{prop_var}' does not match FOR variable '{var_name}'"
4572                )));
4573            }
4574            let prop = self.get_identifier_name();
4575            self.advance();
4576            properties.push(prop);
4577            if self.current.kind != TokenKind::Comma {
4578                break;
4579            }
4580            self.advance();
4581        }
4582        self.expect(TokenKind::RParen)?;
4583
4584        // Parse constraint kind: UNIQUE, NOT NULL, NODE KEY
4585        let constraint_kind = if self.is_identifier()
4586            && self.get_identifier_name().eq_ignore_ascii_case("UNIQUE")
4587        {
4588            self.advance();
4589            ConstraintKind::Unique
4590        } else if self.current.kind == TokenKind::Not {
4591            self.advance();
4592            if self.current.kind != TokenKind::Null {
4593                return Err(self.error("Expected NULL after NOT"));
4594            }
4595            self.advance();
4596            ConstraintKind::NotNull
4597        } else if self.current.kind == TokenKind::Node {
4598            self.advance();
4599            if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("KEY") {
4600                return Err(self.error("Expected KEY after NODE"));
4601            }
4602            self.advance();
4603            ConstraintKind::NodeKey
4604        } else if self.current.kind == TokenKind::Exists {
4605            self.advance();
4606            ConstraintKind::Exists
4607        } else {
4608            return Err(self.error("Expected UNIQUE, NOT NULL, NODE KEY, or EXISTS"));
4609        };
4610
4611        Ok(SchemaStatement::CreateConstraint(
4612            CreateConstraintStatement {
4613                name,
4614                constraint_kind,
4615                label,
4616                properties,
4617                if_not_exists,
4618                span: None,
4619            },
4620        ))
4621    }
4622
4623    /// Tries to parse `IF NOT EXISTS`, returning true if found.
4624    fn try_parse_if_not_exists(&mut self) -> bool {
4625        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("IF") {
4626            self.advance();
4627            if self.current.kind == TokenKind::Not {
4628                self.advance();
4629                if self.current.kind == TokenKind::Exists {
4630                    self.advance();
4631                    return true;
4632                }
4633            }
4634        }
4635        false
4636    }
4637
4638    /// Tries to parse `IF EXISTS`, returning true if found.
4639    fn try_parse_if_exists(&mut self) -> bool {
4640        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("IF") {
4641            self.advance();
4642            if self.current.kind == TokenKind::Exists {
4643                self.advance();
4644                return true;
4645            }
4646        }
4647        false
4648    }
4649
4650    /// Tries to parse `OR REPLACE`, returning true if found.
4651    ///
4652    /// Since the parser has no backtrack beyond single lookahead, this peeks
4653    /// at the current and next token. If current is "OR" and next is "REPLACE",
4654    /// consumes both and returns true.
4655    fn try_parse_or_replace(&mut self) -> bool {
4656        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("OR") {
4657            let pk = self.peek_kind();
4658            if pk == TokenKind::Identifier {
4659                let text = self.peek_text_upper();
4660                if text == "REPLACE" {
4661                    self.advance(); // consume OR
4662                    self.advance(); // consume REPLACE
4663                    return true;
4664                }
4665            }
4666        }
4667        false
4668    }
4669
4670    /// Dispatches CREATE to either a schema DDL or session (graph instance) command.
4671    ///
4672    /// Called after detecting CREATE followed by something other than `(`.
4673    /// Handles: CREATE [OR REPLACE] NODE TYPE, EDGE TYPE, GRAPH TYPE, VECTOR INDEX,
4674    /// INDEX, CONSTRAINT, SCHEMA, and CREATE [PROPERTY] GRAPH.
4675    fn parse_create_dispatch(&mut self) -> Result<Statement> {
4676        // Check: is this CREATE [PROPERTY] GRAPH <name> (session command)?
4677        // We need to distinguish from CREATE GRAPH TYPE (schema DDL).
4678        // Peek: if next is GRAPH/PROPERTY and the token after that is NOT TYPE, it's an instance.
4679        if self.peek_is_graph_instance_keyword() {
4680            return self.parse_create_graph().map(Statement::SessionCommand);
4681        }
4682        self.parse_create_schema().map(Statement::Schema)
4683    }
4684
4685    /// Parses the body of CREATE GRAPH TYPE: `{ node_types: [A, B], edge_types: [E1] }`.
4686    ///
4687    /// Returns (node_types, edge_types, open). If no body, returns open=true.
4688    fn parse_graph_type_body(&mut self) -> Result<(Vec<String>, Vec<String>, bool)> {
4689        self.expect(TokenKind::LBrace)?;
4690
4691        let mut node_types = Vec::new();
4692        let mut edge_types = Vec::new();
4693        let mut open = false;
4694
4695        while self.current.kind != TokenKind::RBrace && self.current.kind != TokenKind::Eof {
4696            if self.is_identifier() {
4697                let key = self.get_identifier_name();
4698                self.advance();
4699                self.expect(TokenKind::Colon)?;
4700
4701                match key.to_uppercase().as_str() {
4702                    "NODE_TYPES" | "NODETYPES" => {
4703                        node_types = self.parse_identifier_list()?;
4704                    }
4705                    "EDGE_TYPES" | "EDGETYPES" => {
4706                        edge_types = self.parse_identifier_list()?;
4707                    }
4708                    "OPEN" => {
4709                        if self.current.kind == TokenKind::True {
4710                            open = true;
4711                            self.advance();
4712                        } else if self.current.kind == TokenKind::False {
4713                            open = false;
4714                            self.advance();
4715                        } else {
4716                            return Err(self.error("Expected true or false for 'open'"));
4717                        }
4718                    }
4719                    _ => return Err(self.error("Expected node_types, edge_types, or open")),
4720                }
4721
4722                // Optional comma separator
4723                if self.current.kind == TokenKind::Comma {
4724                    self.advance();
4725                }
4726            } else {
4727                return Err(self.error("Expected property name in graph type body"));
4728            }
4729        }
4730
4731        self.expect(TokenKind::RBrace)?;
4732        Ok((node_types, edge_types, open))
4733    }
4734
4735    /// Parses the ISO-syntax body of CREATE GRAPH TYPE.
4736    ///
4737    /// Supports two forms:
4738    /// - Verbose: `(NODE TYPE Name (props), EDGE TYPE Name (props), ...)`
4739    /// - Pattern: `((:Person {name STRING})-[:KNOWS {since INT64}]->(:Person), ...)`
4740    ///
4741    /// Returns a list of inline element type definitions.
4742    fn parse_graph_type_iso_body(&mut self) -> Result<Vec<InlineElementType>> {
4743        self.expect(TokenKind::LParen)?;
4744
4745        // Detect which form: pattern form starts with `(` (nested paren for node pattern),
4746        // verbose form starts with NODE or EDGE.
4747        if self.current.kind == TokenKind::LParen {
4748            self.parse_graph_type_pattern_body()
4749        } else {
4750            self.parse_graph_type_verbose_body()
4751        }
4752    }
4753
4754    /// Parses the verbose form: `NODE TYPE Name (props), EDGE TYPE Name (props), ...)`
4755    /// (closing `)` included).
4756    fn parse_graph_type_verbose_body(&mut self) -> Result<Vec<InlineElementType>> {
4757        let mut types = Vec::new();
4758
4759        while self.current.kind != TokenKind::RParen && self.current.kind != TokenKind::Eof {
4760            let is_node = if self.current.kind == TokenKind::Node {
4761                self.advance();
4762                self.expect(TokenKind::Type)?;
4763                true
4764            } else if self.current.kind == TokenKind::Edge {
4765                self.advance();
4766                self.expect(TokenKind::Type)?;
4767                false
4768            } else {
4769                return Err(self.error("Expected NODE TYPE or EDGE TYPE in graph type body"));
4770            };
4771
4772            if !self.is_identifier() && !self.is_label_or_type_name() {
4773                return Err(self.error("Expected type name"));
4774            }
4775            let type_name = self.get_identifier_name();
4776            self.advance();
4777
4778            // GG21: Optional KEY label set: KEY (Label1, Label2)
4779            let key_labels =
4780                if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("KEY") {
4781                    self.advance();
4782                    self.expect(TokenKind::LParen)?;
4783                    let mut labels = Vec::new();
4784                    loop {
4785                        if !self.is_identifier() && !self.is_label_or_type_name() {
4786                            return Err(self.error("Expected label name in KEY clause"));
4787                        }
4788                        labels.push(self.get_identifier_name());
4789                        self.advance();
4790                        if self.current.kind != TokenKind::Comma {
4791                            break;
4792                        }
4793                        self.advance();
4794                    }
4795                    self.expect(TokenKind::RParen)?;
4796                    labels
4797                } else {
4798                    Vec::new()
4799                };
4800
4801            // Optional property definitions
4802            let properties = if self.current.kind == TokenKind::LParen {
4803                self.parse_property_definitions()?
4804            } else {
4805                Vec::new()
4806            };
4807
4808            if is_node {
4809                types.push(InlineElementType::Node {
4810                    name: type_name,
4811                    properties,
4812                    key_labels,
4813                });
4814            } else {
4815                types.push(InlineElementType::Edge {
4816                    name: type_name,
4817                    properties,
4818                    key_labels,
4819                    source_node_types: Vec::new(),
4820                    target_node_types: Vec::new(),
4821                });
4822            }
4823
4824            // Optional comma separator
4825            if self.current.kind == TokenKind::Comma {
4826                self.advance();
4827            }
4828        }
4829
4830        self.expect(TokenKind::RParen)?;
4831        Ok(types)
4832    }
4833
4834    /// Parses the pattern form of a graph type body:
4835    /// `(:Person {name STRING})-[:KNOWS {since INT64}]->(:Person), ...)`
4836    /// (closing `)` included).
4837    fn parse_graph_type_pattern_body(&mut self) -> Result<Vec<InlineElementType>> {
4838        let mut types = Vec::new();
4839        // Track which node type names we've already emitted so we don't duplicate them.
4840        let mut seen_node_types = std::collections::HashSet::new();
4841
4842        while self.current.kind != TokenKind::RParen && self.current.kind != TokenKind::Eof {
4843            // Parse the first node pattern: (:Label {props})
4844            let (src_label, src_props) = self.parse_graph_type_node_pattern()?;
4845
4846            // Check if an edge follows: `-[` or `<-[`
4847            if self.current.kind == TokenKind::Minus || self.current.kind == TokenKind::LeftArrow {
4848                let backward = self.current.kind == TokenKind::LeftArrow;
4849                if backward {
4850                    // <-[ : incoming direction
4851                    self.advance(); // consume `<-`
4852                } else {
4853                    // -[ : outgoing or undirected
4854                    self.advance(); // consume `-`
4855                }
4856
4857                self.expect(TokenKind::LBracket)?;
4858
4859                // Parse edge label: `:EdgeType`
4860                self.expect(TokenKind::Colon)?;
4861                if !self.is_identifier() && !self.is_label_or_type_name() {
4862                    return Err(self.error("Expected edge type name after `:` in pattern"));
4863                }
4864                let edge_label = self.get_identifier_name();
4865                self.advance();
4866
4867                // Optional properties: { prop TYPE, ... }
4868                let edge_props = if self.current.kind == TokenKind::LBrace {
4869                    self.parse_property_definitions_braces()?
4870                } else {
4871                    Vec::new()
4872                };
4873
4874                self.expect(TokenKind::RBracket)?;
4875
4876                // Parse direction after `]`: `->` for outgoing, `-` for undirected
4877                let forward = if self.current.kind == TokenKind::Arrow {
4878                    self.advance(); // consume `->`
4879                    true
4880                } else if self.current.kind == TokenKind::Minus {
4881                    self.advance(); // consume `-` (undirected)
4882                    false
4883                } else {
4884                    return Err(self.error("Expected `->` or `-` after edge pattern `]`"));
4885                };
4886
4887                // Parse target node: (:Label {props})
4888                let (tgt_label, tgt_props) = self.parse_graph_type_node_pattern()?;
4889
4890                // Determine source and target based on direction
4891                let (effective_src, effective_tgt) = if backward {
4892                    (tgt_label.clone(), src_label.clone())
4893                } else {
4894                    (src_label.clone(), tgt_label.clone())
4895                };
4896
4897                let (src_types, tgt_types) = if !forward && !backward {
4898                    // Undirected: both directions
4899                    (
4900                        vec![src_label.clone(), tgt_label.clone()],
4901                        vec![src_label.clone(), tgt_label.clone()],
4902                    )
4903                } else {
4904                    (vec![effective_src], vec![effective_tgt])
4905                };
4906
4907                // Add node types (deduplicated)
4908                if seen_node_types.insert(src_label.clone()) {
4909                    types.push(InlineElementType::Node {
4910                        name: src_label,
4911                        properties: src_props,
4912                        key_labels: Vec::new(),
4913                    });
4914                }
4915                if seen_node_types.insert(tgt_label.clone()) {
4916                    types.push(InlineElementType::Node {
4917                        name: tgt_label,
4918                        properties: tgt_props,
4919                        key_labels: Vec::new(),
4920                    });
4921                }
4922
4923                // Add edge type
4924                types.push(InlineElementType::Edge {
4925                    name: edge_label,
4926                    properties: edge_props,
4927                    key_labels: Vec::new(),
4928                    source_node_types: src_types,
4929                    target_node_types: tgt_types,
4930                });
4931            } else {
4932                // Standalone node pattern
4933                if seen_node_types.insert(src_label.clone()) {
4934                    types.push(InlineElementType::Node {
4935                        name: src_label,
4936                        properties: src_props,
4937                        key_labels: Vec::new(),
4938                    });
4939                }
4940            }
4941
4942            // Optional comma separator
4943            if self.current.kind == TokenKind::Comma {
4944                self.advance();
4945            }
4946        }
4947
4948        self.expect(TokenKind::RParen)?;
4949        Ok(types)
4950    }
4951
4952    /// Parses a node pattern inside a graph type pattern body: `(:Label {prop TYPE, ...})`.
4953    ///
4954    /// Returns `(label, properties)`.
4955    fn parse_graph_type_node_pattern(&mut self) -> Result<(String, Vec<PropertyDefinition>)> {
4956        self.expect(TokenKind::LParen)?;
4957        self.expect(TokenKind::Colon)?;
4958
4959        if !self.is_identifier() && !self.is_label_or_type_name() {
4960            return Err(self.error("Expected label name in node pattern"));
4961        }
4962        let label = self.get_identifier_name();
4963        self.advance();
4964
4965        // Optional property definitions in braces
4966        let properties = if self.current.kind == TokenKind::LBrace {
4967            self.parse_property_definitions_braces()?
4968        } else {
4969            Vec::new()
4970        };
4971
4972        self.expect(TokenKind::RParen)?;
4973        Ok((label, properties))
4974    }
4975
4976    /// Parses `[T1, T2, T3]`, returning a list of identifiers.
4977    fn parse_identifier_list(&mut self) -> Result<Vec<String>> {
4978        self.expect(TokenKind::LBracket)?;
4979        let mut items = Vec::new();
4980
4981        if self.current.kind != TokenKind::RBracket {
4982            loop {
4983                if !self.is_identifier() && !self.is_label_or_type_name() {
4984                    return Err(self.error("Expected identifier in list"));
4985                }
4986                items.push(self.get_identifier_name());
4987                self.advance();
4988                if self.current.kind != TokenKind::Comma {
4989                    break;
4990                }
4991                self.advance();
4992            }
4993        }
4994
4995        self.expect(TokenKind::RBracket)?;
4996        Ok(items)
4997    }
4998
4999    /// Parses a DROP statement, dispatching to schema or session commands.
5000    ///
5001    /// Handles: DROP NODE TYPE, DROP EDGE TYPE, DROP INDEX, DROP CONSTRAINT,
5002    /// DROP GRAPH TYPE, DROP SCHEMA, DROP [PROPERTY] GRAPH.
5003    fn parse_drop(&mut self) -> Result<Statement> {
5004        self.advance(); // consume DROP
5005
5006        match self.current.kind {
5007            TokenKind::Node => {
5008                // DROP NODE TYPE [IF EXISTS] name
5009                self.advance();
5010                self.expect(TokenKind::Type)?;
5011                let if_exists = self.try_parse_if_exists();
5012                if !self.is_identifier() {
5013                    return Err(self.error("Expected type name"));
5014                }
5015                let name = self.get_identifier_name();
5016                self.advance();
5017                Ok(Statement::Schema(SchemaStatement::DropNodeType {
5018                    name,
5019                    if_exists,
5020                }))
5021            }
5022            TokenKind::Edge => {
5023                // DROP EDGE TYPE [IF EXISTS] name
5024                self.advance();
5025                self.expect(TokenKind::Type)?;
5026                let if_exists = self.try_parse_if_exists();
5027                if !self.is_identifier() {
5028                    return Err(self.error("Expected type name"));
5029                }
5030                let name = self.get_identifier_name();
5031                self.advance();
5032                Ok(Statement::Schema(SchemaStatement::DropEdgeType {
5033                    name,
5034                    if_exists,
5035                }))
5036            }
5037            TokenKind::Index => {
5038                // DROP INDEX [IF EXISTS] name
5039                self.advance();
5040                let if_exists = self.try_parse_if_exists();
5041                if !self.is_identifier() {
5042                    return Err(self.error("Expected index name"));
5043                }
5044                let name = self.get_identifier_name();
5045                self.advance();
5046                Ok(Statement::Schema(SchemaStatement::DropIndex {
5047                    name,
5048                    if_exists,
5049                }))
5050            }
5051            _ if self.is_identifier()
5052                && self
5053                    .get_identifier_name()
5054                    .eq_ignore_ascii_case("CONSTRAINT") =>
5055            {
5056                // DROP CONSTRAINT [IF EXISTS] name
5057                self.advance(); // consume CONSTRAINT
5058                let if_exists = self.try_parse_if_exists();
5059                if !self.is_identifier() {
5060                    return Err(self.error("Expected constraint name"));
5061                }
5062                let name = self.get_identifier_name();
5063                self.advance();
5064                Ok(Statement::Schema(SchemaStatement::DropConstraint {
5065                    name,
5066                    if_exists,
5067                }))
5068            }
5069            _ if self.is_identifier()
5070                && self.get_identifier_name().eq_ignore_ascii_case("SCHEMA") =>
5071            {
5072                // DROP SCHEMA [IF EXISTS] name
5073                self.advance(); // consume SCHEMA
5074                let if_exists = self.try_parse_if_exists();
5075                if !self.is_identifier() {
5076                    return Err(self.error("Expected schema name"));
5077                }
5078                let name = self.get_identifier_name();
5079                self.advance();
5080                Ok(Statement::Schema(SchemaStatement::DropSchema {
5081                    name,
5082                    if_exists,
5083                }))
5084            }
5085            _ if self.is_identifier()
5086                && self.get_identifier_name().eq_ignore_ascii_case("PROCEDURE") =>
5087            {
5088                // DROP PROCEDURE [IF EXISTS] name
5089                self.advance(); // consume PROCEDURE
5090                let if_exists = self.try_parse_if_exists();
5091                if !self.is_identifier() {
5092                    return Err(self.error("Expected procedure name"));
5093                }
5094                let name = self.get_identifier_name();
5095                self.advance();
5096                Ok(Statement::Schema(SchemaStatement::DropProcedure {
5097                    name,
5098                    if_exists,
5099                }))
5100            }
5101            _ if self.is_identifier()
5102                && self.get_identifier_name().eq_ignore_ascii_case("GRAPH") =>
5103            {
5104                // Could be DROP GRAPH TYPE or DROP GRAPH <name>
5105                // Peek ahead: if next token is TYPE, it's schema DDL
5106                if self.peek_kind() == TokenKind::Type {
5107                    // DROP GRAPH TYPE [IF EXISTS] name
5108                    self.advance(); // consume GRAPH
5109                    self.advance(); // consume TYPE
5110                    let if_exists = self.try_parse_if_exists();
5111                    if !self.is_identifier() {
5112                        return Err(self.error("Expected graph type name"));
5113                    }
5114                    let name = self.get_identifier_name();
5115                    self.advance();
5116                    Ok(Statement::Schema(SchemaStatement::DropGraphType {
5117                        name,
5118                        if_exists,
5119                    }))
5120                } else {
5121                    // DROP [PROPERTY] GRAPH <name>
5122                    self.parse_drop_graph_body().map(Statement::SessionCommand)
5123                }
5124            }
5125            _ => {
5126                // Fall through to DROP [PROPERTY] GRAPH
5127                self.parse_drop_graph_body().map(Statement::SessionCommand)
5128            }
5129        }
5130    }
5131
5132    /// Parses ALTER NODE TYPE, ALTER EDGE TYPE, ALTER GRAPH TYPE.
5133    fn parse_alter(&mut self) -> Result<Statement> {
5134        let span_start = self.current.span.start;
5135        self.advance(); // consume ALTER
5136
5137        match self.current.kind {
5138            TokenKind::Node => {
5139                // ALTER NODE TYPE name ADD/DROP ...
5140                self.advance();
5141                self.expect(TokenKind::Type)?;
5142                self.parse_alter_type(true, span_start)
5143            }
5144            TokenKind::Edge => {
5145                // ALTER EDGE TYPE name ADD/DROP ...
5146                self.advance();
5147                self.expect(TokenKind::Type)?;
5148                self.parse_alter_type(false, span_start)
5149            }
5150            _ if self.is_identifier()
5151                && self.get_identifier_name().eq_ignore_ascii_case("GRAPH") =>
5152            {
5153                // ALTER GRAPH TYPE name ADD/DROP ...
5154                self.advance(); // consume GRAPH
5155                self.expect(TokenKind::Type)?;
5156                self.parse_alter_graph_type(span_start)
5157            }
5158            _ => Err(self.error("Expected NODE, EDGE, or GRAPH after ALTER")),
5159        }
5160    }
5161
5162    /// Parses ALTER NODE TYPE name / ALTER EDGE TYPE name alterations.
5163    fn parse_alter_type(&mut self, is_node: bool, span_start: usize) -> Result<Statement> {
5164        if !self.is_identifier() {
5165            return Err(self.error("Expected type name"));
5166        }
5167        let name = self.get_identifier_name();
5168        self.advance();
5169
5170        let mut alterations = Vec::new();
5171        loop {
5172            if !self.is_identifier() {
5173                break;
5174            }
5175            let action = self.get_identifier_name().to_uppercase();
5176            match action.as_str() {
5177                "ADD" => {
5178                    self.advance();
5179                    // ADD property_name type [NOT NULL]
5180                    if !self.is_identifier() {
5181                        return Err(self.error("Expected property name after ADD"));
5182                    }
5183                    let prop_name = self.get_identifier_name();
5184                    self.advance();
5185                    if !self.is_identifier() {
5186                        return Err(self.error("Expected type name"));
5187                    }
5188                    let data_type = self.get_identifier_name();
5189                    self.advance();
5190                    let nullable = if self.current.kind == TokenKind::Not {
5191                        self.advance();
5192                        if self.current.kind != TokenKind::Null {
5193                            return Err(self.error("Expected NULL after NOT"));
5194                        }
5195                        self.advance();
5196                        false
5197                    } else {
5198                        true
5199                    };
5200                    // Optional DEFAULT <literal>
5201                    let default_value = if self.is_identifier()
5202                        && self.get_identifier_name().eq_ignore_ascii_case("DEFAULT")
5203                    {
5204                        self.advance();
5205                        let lit = match self.current.kind {
5206                            TokenKind::String
5207                            | TokenKind::Integer
5208                            | TokenKind::Float
5209                            | TokenKind::True
5210                            | TokenKind::False
5211                            | TokenKind::Null => self.current.text.clone(),
5212                            _ => return Err(self.error("Expected literal value after DEFAULT")),
5213                        };
5214                        self.advance();
5215                        Some(lit)
5216                    } else {
5217                        None
5218                    };
5219                    alterations.push(TypeAlteration::AddProperty(PropertyDefinition {
5220                        name: prop_name,
5221                        data_type,
5222                        nullable,
5223                        default_value,
5224                    }));
5225                }
5226                "DROP" => {
5227                    self.advance();
5228                    if !self.is_identifier() {
5229                        return Err(self.error("Expected property name after DROP"));
5230                    }
5231                    let prop_name = self.get_identifier_name();
5232                    self.advance();
5233                    alterations.push(TypeAlteration::DropProperty(prop_name));
5234                }
5235                _ => break,
5236            }
5237        }
5238
5239        if alterations.is_empty() {
5240            return Err(self.error("Expected ADD or DROP alteration"));
5241        }
5242
5243        let span = Some(SourceSpan::new(span_start, self.current.span.end, 1, 1));
5244        let stmt = AlterTypeStatement {
5245            name,
5246            alterations,
5247            span,
5248        };
5249        if is_node {
5250            Ok(Statement::Schema(SchemaStatement::AlterNodeType(stmt)))
5251        } else {
5252            Ok(Statement::Schema(SchemaStatement::AlterEdgeType(stmt)))
5253        }
5254    }
5255
5256    /// Parses ALTER GRAPH TYPE name alterations.
5257    fn parse_alter_graph_type(&mut self, span_start: usize) -> Result<Statement> {
5258        if !self.is_identifier() {
5259            return Err(self.error("Expected graph type name"));
5260        }
5261        let name = self.get_identifier_name();
5262        self.advance();
5263
5264        let mut alterations = Vec::new();
5265        loop {
5266            if !self.is_identifier() {
5267                break;
5268            }
5269            let action = self.get_identifier_name().to_uppercase();
5270            match action.as_str() {
5271                "ADD" => {
5272                    self.advance();
5273                    // ADD NODE TYPE name or ADD EDGE TYPE name
5274                    let kind = self.current.kind;
5275                    match kind {
5276                        TokenKind::Node => {
5277                            self.advance();
5278                            self.expect(TokenKind::Type)?;
5279                            if !self.is_identifier() {
5280                                return Err(self.error("Expected node type name"));
5281                            }
5282                            let type_name = self.get_identifier_name();
5283                            self.advance();
5284                            alterations.push(GraphTypeAlteration::AddNodeType(type_name));
5285                        }
5286                        TokenKind::Edge => {
5287                            self.advance();
5288                            self.expect(TokenKind::Type)?;
5289                            if !self.is_identifier() {
5290                                return Err(self.error("Expected edge type name"));
5291                            }
5292                            let type_name = self.get_identifier_name();
5293                            self.advance();
5294                            alterations.push(GraphTypeAlteration::AddEdgeType(type_name));
5295                        }
5296                        _ => return Err(self.error("Expected NODE or EDGE after ADD")),
5297                    }
5298                }
5299                "DROP" => {
5300                    self.advance();
5301                    let kind = self.current.kind;
5302                    match kind {
5303                        TokenKind::Node => {
5304                            self.advance();
5305                            self.expect(TokenKind::Type)?;
5306                            if !self.is_identifier() {
5307                                return Err(self.error("Expected node type name"));
5308                            }
5309                            let type_name = self.get_identifier_name();
5310                            self.advance();
5311                            alterations.push(GraphTypeAlteration::DropNodeType(type_name));
5312                        }
5313                        TokenKind::Edge => {
5314                            self.advance();
5315                            self.expect(TokenKind::Type)?;
5316                            if !self.is_identifier() {
5317                                return Err(self.error("Expected edge type name"));
5318                            }
5319                            let type_name = self.get_identifier_name();
5320                            self.advance();
5321                            alterations.push(GraphTypeAlteration::DropEdgeType(type_name));
5322                        }
5323                        _ => return Err(self.error("Expected NODE or EDGE after DROP")),
5324                    }
5325                }
5326                _ => break,
5327            }
5328        }
5329
5330        if alterations.is_empty() {
5331            return Err(self.error("Expected ADD or DROP alteration"));
5332        }
5333
5334        let span = Some(SourceSpan::new(span_start, self.current.span.end, 1, 1));
5335        Ok(Statement::Schema(SchemaStatement::AlterGraphType(
5336            AlterGraphTypeStatement {
5337                name,
5338                alterations,
5339                span,
5340            },
5341        )))
5342    }
5343
5344    fn parse_property_definitions(&mut self) -> Result<Vec<PropertyDefinition>> {
5345        self.expect(TokenKind::LParen)?;
5346
5347        let mut defs = Vec::new();
5348
5349        if self.current.kind != TokenKind::RParen {
5350            loop {
5351                if !self.is_identifier() {
5352                    return Err(self.error("Expected property name"));
5353                }
5354                let name = self.get_identifier_name();
5355                self.advance();
5356
5357                if !self.is_identifier() {
5358                    return Err(self.error("Expected type name"));
5359                }
5360                let data_type = self.get_identifier_name();
5361                self.advance();
5362
5363                let nullable = if self.current.kind == TokenKind::Not {
5364                    self.advance();
5365                    if self.current.kind != TokenKind::Null {
5366                        return Err(self.error("Expected NULL after NOT"));
5367                    }
5368                    self.advance();
5369                    false
5370                } else {
5371                    true
5372                };
5373
5374                // Optional DEFAULT <literal>
5375                let default_value = if self.is_identifier()
5376                    && self.get_identifier_name().eq_ignore_ascii_case("DEFAULT")
5377                {
5378                    self.advance();
5379                    let lit = match self.current.kind {
5380                        TokenKind::String
5381                        | TokenKind::Integer
5382                        | TokenKind::Float
5383                        | TokenKind::True
5384                        | TokenKind::False
5385                        | TokenKind::Null => self.current.text.clone(),
5386                        _ => return Err(self.error("Expected literal value after DEFAULT")),
5387                    };
5388                    self.advance();
5389                    Some(lit)
5390                } else {
5391                    None
5392                };
5393
5394                defs.push(PropertyDefinition {
5395                    name,
5396                    data_type,
5397                    nullable,
5398                    default_value,
5399                });
5400
5401                if self.current.kind != TokenKind::Comma {
5402                    break;
5403                }
5404                self.advance();
5405            }
5406        }
5407
5408        self.expect(TokenKind::RParen)?;
5409        Ok(defs)
5410    }
5411
5412    /// Parses property definitions inside braces: `{ name TYPE [NOT NULL], ... }`.
5413    ///
5414    /// Used by pattern-form graph type syntax where properties use `{}` instead of `()`.
5415    fn parse_property_definitions_braces(&mut self) -> Result<Vec<PropertyDefinition>> {
5416        self.expect(TokenKind::LBrace)?;
5417
5418        let mut defs = Vec::new();
5419
5420        if self.current.kind != TokenKind::RBrace {
5421            loop {
5422                if !self.is_identifier() {
5423                    return Err(self.error("Expected property name"));
5424                }
5425                let name = self.get_identifier_name();
5426                self.advance();
5427
5428                if !self.is_identifier() {
5429                    return Err(self.error("Expected type name"));
5430                }
5431                let data_type = self.get_identifier_name();
5432                self.advance();
5433
5434                let nullable = if self.current.kind == TokenKind::Not {
5435                    self.advance();
5436                    if self.current.kind != TokenKind::Null {
5437                        return Err(self.error("Expected NULL after NOT"));
5438                    }
5439                    self.advance();
5440                    false
5441                } else {
5442                    true
5443                };
5444
5445                // Optional DEFAULT <literal>
5446                let default_value = if self.is_identifier()
5447                    && self.get_identifier_name().eq_ignore_ascii_case("DEFAULT")
5448                {
5449                    self.advance();
5450                    let lit = match self.current.kind {
5451                        TokenKind::String
5452                        | TokenKind::Integer
5453                        | TokenKind::Float
5454                        | TokenKind::True
5455                        | TokenKind::False
5456                        | TokenKind::Null => self.current.text.clone(),
5457                        _ => return Err(self.error("Expected literal value after DEFAULT")),
5458                    };
5459                    self.advance();
5460                    Some(lit)
5461                } else {
5462                    None
5463                };
5464
5465                defs.push(PropertyDefinition {
5466                    name,
5467                    data_type,
5468                    nullable,
5469                    default_value,
5470                });
5471
5472                if self.current.kind != TokenKind::Comma {
5473                    break;
5474                }
5475                self.advance();
5476            }
5477        }
5478
5479        self.expect(TokenKind::RBrace)?;
5480        Ok(defs)
5481    }
5482
5483    /// Parses a SHOW statement.
5484    ///
5485    /// ```text
5486    /// SHOW CONSTRAINTS
5487    /// SHOW INDEXES
5488    /// SHOW NODE TYPES
5489    /// SHOW EDGE TYPES
5490    /// SHOW GRAPH TYPES
5491    /// SHOW GRAPH TYPE <name>
5492    /// ```
5493    fn parse_show(&mut self) -> Result<SchemaStatement> {
5494        self.advance(); // consume SHOW
5495
5496        if !self.is_identifier()
5497            && self.current.kind != TokenKind::Node
5498            && self.current.kind != TokenKind::Edge
5499            && self.current.kind != TokenKind::Index
5500        {
5501            return Err(self.error(
5502                "Expected CONSTRAINTS, INDEXES, NODE TYPES, EDGE TYPES, GRAPHS, GRAPH TYPES, or GRAPH TYPE <name> after SHOW",
5503            ));
5504        }
5505
5506        match self.current.kind {
5507            TokenKind::Node => {
5508                // SHOW NODE TYPES
5509                self.advance();
5510                if self.current.kind != TokenKind::Type
5511                    && !(self.is_identifier()
5512                        && self.get_identifier_name().eq_ignore_ascii_case("TYPES"))
5513                {
5514                    return Err(self.error("Expected TYPES after SHOW NODE"));
5515                }
5516                self.advance();
5517                Ok(SchemaStatement::ShowNodeTypes)
5518            }
5519            TokenKind::Edge => {
5520                // SHOW EDGE TYPES
5521                self.advance();
5522                if self.current.kind != TokenKind::Type
5523                    && !(self.is_identifier()
5524                        && self.get_identifier_name().eq_ignore_ascii_case("TYPES"))
5525                {
5526                    return Err(self.error("Expected TYPES after SHOW EDGE"));
5527                }
5528                self.advance();
5529                Ok(SchemaStatement::ShowEdgeTypes)
5530            }
5531            TokenKind::Index => {
5532                // SHOW INDEXES (INDEX is a keyword token)
5533                self.advance();
5534                // Allow optional plural "ES" as a separate token won't happen,
5535                // but the keyword is INDEX. Accept both SHOW INDEX and SHOW INDEXES.
5536                Ok(SchemaStatement::ShowIndexes)
5537            }
5538            _ => {
5539                let name = self.get_identifier_name();
5540                match name.to_uppercase().as_str() {
5541                    "CONSTRAINTS" => {
5542                        self.advance();
5543                        Ok(SchemaStatement::ShowConstraints)
5544                    }
5545                    "INDEXES" => {
5546                        self.advance();
5547                        Ok(SchemaStatement::ShowIndexes)
5548                    }
5549                    "GRAPHS" => {
5550                        self.advance();
5551                        Ok(SchemaStatement::ShowGraphs)
5552                    }
5553                    "SCHEMAS" => {
5554                        self.advance();
5555                        Ok(SchemaStatement::ShowSchemas)
5556                    }
5557                    "GRAPH" => {
5558                        self.advance();
5559                        // SHOW GRAPH TYPES or SHOW GRAPH TYPE <name>
5560                        if self.current.kind == TokenKind::Type {
5561                            self.advance();
5562                            // SHOW GRAPH TYPE <name> (singular)
5563                            if !self.is_identifier() {
5564                                return Err(self.error("Expected graph type name after SHOW GRAPH TYPE"));
5565                            }
5566                            let type_name = self.get_identifier_name();
5567                            self.advance();
5568                            Ok(SchemaStatement::ShowGraphType(type_name))
5569                        } else if self.is_identifier()
5570                            && self.get_identifier_name().eq_ignore_ascii_case("TYPES")
5571                        {
5572                            // SHOW GRAPH TYPES (plural)
5573                            self.advance();
5574                            Ok(SchemaStatement::ShowGraphTypes)
5575                        } else {
5576                            Err(self.error("Expected TYPE <name> or TYPES after SHOW GRAPH"))
5577                        }
5578                    }
5579                    _ => Err(self.error(
5580                        "Expected CONSTRAINTS, INDEXES, NODE TYPES, EDGE TYPES, GRAPHS, GRAPH TYPES, or GRAPH TYPE <name> after SHOW",
5581                    )),
5582                }
5583            }
5584        }
5585    }
5586
5587    fn advance(&mut self) {
5588        if let Some(peeked) = self.peeked.take() {
5589            self.current = peeked;
5590            // Shift peeked_second into peeked
5591            self.peeked = self.peeked_second.take();
5592        } else {
5593            self.current = self.lexer.next_token();
5594        }
5595    }
5596
5597    fn expect(&mut self, kind: TokenKind) -> Result<()> {
5598        if self.current.kind == kind {
5599            self.advance();
5600            Ok(())
5601        } else {
5602            Err(self.error(&format!("Expected {:?}", kind)))
5603        }
5604    }
5605
5606    fn peek_kind(&mut self) -> TokenKind {
5607        if self.peeked.is_none() {
5608            self.peeked = Some(self.lexer.next_token());
5609        }
5610        self.peeked
5611            .as_ref()
5612            .expect("peeked token was just populated")
5613            .kind
5614    }
5615
5616    /// Peeks at the token after the next token (two-token lookahead).
5617    fn peek_second_kind(&mut self) -> TokenKind {
5618        // Ensure first peeked is populated
5619        let _ = self.peek_kind();
5620        if self.peeked_second.is_none() {
5621            self.peeked_second = Some(self.lexer.next_token());
5622        }
5623        self.peeked_second
5624            .as_ref()
5625            .expect("peeked_second token was just populated")
5626            .kind
5627    }
5628
5629    /// Returns the uppercased text of the peeked token.
5630    /// Must call `peek_kind()` first.
5631    fn peek_text_upper(&self) -> String {
5632        self.peeked
5633            .as_ref()
5634            .map(|t| t.text.to_uppercase())
5635            .unwrap_or_default()
5636    }
5637
5638    /// Checks whether CREATE is followed by [PROPERTY] GRAPH (for graph instances, not GRAPH TYPE).
5639    ///
5640    /// Returns true for `CREATE GRAPH <name>` and `CREATE PROPERTY GRAPH <name>`,
5641    /// but false for `CREATE GRAPH TYPE <name>` (which is schema DDL).
5642    fn peek_is_graph_instance_keyword(&mut self) -> bool {
5643        let pk = self.peek_kind();
5644        if pk != TokenKind::Identifier {
5645            return false;
5646        }
5647        let text = self.peek_text_upper();
5648        if text == "PROPERTY" {
5649            return true; // CREATE PROPERTY GRAPH ...
5650        }
5651        if text == "GRAPH" {
5652            // Need to check the token after GRAPH. If it's TYPE, this is GRAPH TYPE (schema).
5653            // Use a temporary lexer to peek 2 tokens ahead from the current source position.
5654            let peeked_token = self
5655                .peeked
5656                .as_ref()
5657                .expect("peek_kind guarantees peeked is Some");
5658            let remaining = &self.source[peeked_token.span.end..];
5659            let mut temp_lexer = Lexer::new(remaining);
5660            let next_after_graph = temp_lexer.next_token();
5661            // If it's TYPE, this is CREATE GRAPH TYPE, not a graph instance
5662            return next_after_graph.kind != TokenKind::Type;
5663        }
5664        false
5665    }
5666
5667    /// Parses `CREATE [OR REPLACE] PROCEDURE name(params) RETURNS (cols) AS { body }`.
5668    fn parse_create_procedure(&mut self, or_replace: bool) -> Result<SchemaStatement> {
5669        let if_not_exists = self.try_parse_if_not_exists();
5670
5671        if !self.is_identifier() {
5672            return Err(self.error("Expected procedure name"));
5673        }
5674        let name = self.get_identifier_name();
5675        self.advance();
5676
5677        // Parse parameter list
5678        self.expect(TokenKind::LParen)?;
5679        let mut params = Vec::new();
5680        if self.current.kind != TokenKind::RParen {
5681            loop {
5682                if !self.is_identifier() {
5683                    return Err(self.error("Expected parameter name"));
5684                }
5685                let param_name = self.get_identifier_name();
5686                self.advance();
5687
5688                if !self.is_identifier() {
5689                    return Err(self.error("Expected parameter type"));
5690                }
5691                let param_type = self.get_identifier_name().to_uppercase();
5692                self.advance();
5693
5694                params.push(ProcedureParam {
5695                    name: param_name,
5696                    param_type,
5697                });
5698
5699                if self.current.kind != TokenKind::Comma {
5700                    break;
5701                }
5702                self.advance();
5703            }
5704        }
5705        self.expect(TokenKind::RParen)?;
5706
5707        // Parse RETURNS (col1 type, ...)
5708        let mut returns = Vec::new();
5709        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("RETURNS") {
5710            self.advance();
5711            self.expect(TokenKind::LParen)?;
5712            if self.current.kind != TokenKind::RParen {
5713                loop {
5714                    if !self.is_identifier() {
5715                        return Err(self.error("Expected return column name"));
5716                    }
5717                    let col_name = self.get_identifier_name();
5718                    self.advance();
5719
5720                    if !self.is_identifier() {
5721                        return Err(self.error("Expected return column type"));
5722                    }
5723                    let col_type = self.get_identifier_name().to_uppercase();
5724                    self.advance();
5725
5726                    returns.push(ProcedureReturn {
5727                        name: col_name,
5728                        return_type: col_type,
5729                    });
5730
5731                    if self.current.kind != TokenKind::Comma {
5732                        break;
5733                    }
5734                    self.advance();
5735                }
5736            }
5737            self.expect(TokenKind::RParen)?;
5738        }
5739
5740        // Expect AS (TokenKind::As is a keyword, not a contextual identifier)
5741        if self.current.kind == TokenKind::As {
5742            self.advance();
5743        } else {
5744            return Err(self.error("Expected AS before procedure body"));
5745        }
5746
5747        // Parse body: { ... } with brace nesting
5748        self.expect(TokenKind::LBrace)?;
5749        let body_start = self.current.span.start;
5750        let mut depth = 1u32;
5751        while depth > 0 && self.current.kind != TokenKind::Eof {
5752            if self.current.kind == TokenKind::LBrace {
5753                depth += 1;
5754            } else if self.current.kind == TokenKind::RBrace {
5755                depth -= 1;
5756                if depth == 0 {
5757                    break;
5758                }
5759            }
5760            self.advance();
5761        }
5762        let body_end = self.current.span.start;
5763        let body = self.source[body_start..body_end].trim().to_string();
5764        self.expect(TokenKind::RBrace)?;
5765
5766        Ok(SchemaStatement::CreateProcedure(CreateProcedureStatement {
5767            name,
5768            params,
5769            returns,
5770            body,
5771            if_not_exists,
5772            or_replace,
5773            span: None,
5774        }))
5775    }
5776
5777    /// Parses `CREATE [PROPERTY] GRAPH [IF NOT EXISTS] <name>`.
5778    fn parse_create_graph(&mut self) -> Result<SessionCommand> {
5779        self.expect(TokenKind::Create)?;
5780
5781        // Skip optional PROPERTY keyword
5782        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("PROPERTY") {
5783            self.advance();
5784        }
5785
5786        // Expect GRAPH
5787        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("GRAPH") {
5788            return Err(self.error("Expected GRAPH after CREATE"));
5789        }
5790        self.advance();
5791
5792        // Optional IF NOT EXISTS
5793        let if_not_exists = if self.is_identifier()
5794            && self.get_identifier_name().eq_ignore_ascii_case("IF")
5795        {
5796            self.advance();
5797            if !(self.current.kind == TokenKind::Not
5798                || (self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("NOT")))
5799            {
5800                return Err(self.error("Expected NOT after IF"));
5801            }
5802            self.advance();
5803            if self.current.kind != TokenKind::Exists
5804                && (!self.is_identifier()
5805                    || !self.get_identifier_name().eq_ignore_ascii_case("EXISTS"))
5806            {
5807                return Err(self.error("Expected EXISTS after IF NOT"));
5808            }
5809            self.advance();
5810            true
5811        } else {
5812            false
5813        };
5814
5815        // Parse graph name
5816        if !self.is_identifier() {
5817            return Err(self.error("Expected graph name"));
5818        }
5819        let name = self.get_identifier_name();
5820        self.advance();
5821
5822        // Optional TYPED type_name or [TYPED] ANY [[PROPERTY] GRAPH] (open graph type)
5823        let mut open = false;
5824        let typed = if self.is_identifier()
5825            && self.get_identifier_name().eq_ignore_ascii_case("TYPED")
5826        {
5827            self.advance();
5828            // Check for ANY (open graph type): TYPED ANY [[PROPERTY] GRAPH]
5829            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("ANY") {
5830                self.advance();
5831                // Consume optional PROPERTY
5832                if self.is_identifier()
5833                    && self.get_identifier_name().eq_ignore_ascii_case("PROPERTY")
5834                {
5835                    self.advance();
5836                }
5837                // Consume optional GRAPH
5838                if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("GRAPH")
5839                {
5840                    self.advance();
5841                }
5842                open = true;
5843                None // ANY GRAPH = open/schema-free (no type binding)
5844            } else if self.is_identifier() {
5845                let type_name = self.get_identifier_name();
5846                self.advance();
5847                Some(type_name)
5848            } else {
5849                return Err(self.error("Expected graph type name or ANY after TYPED"));
5850            }
5851        } else if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("ANY") {
5852            // ANY [[PROPERTY] GRAPH] without TYPED prefix
5853            self.advance();
5854            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("PROPERTY") {
5855                self.advance();
5856            }
5857            if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("GRAPH") {
5858                self.advance();
5859            }
5860            open = true;
5861            None // open graph
5862        } else {
5863            None
5864        };
5865
5866        // Optional LIKE source_graph (LIKE is a keyword token, not an identifier)
5867        let like_graph = if self.current.kind == TokenKind::Like {
5868            self.advance();
5869            if !self.is_identifier() {
5870                return Err(self.error("Expected graph name after LIKE"));
5871            }
5872            let source = self.get_identifier_name();
5873            self.advance();
5874            Some(source)
5875        } else {
5876            None
5877        };
5878
5879        // Optional AS COPY OF source_graph
5880        let copy_of = if self.current.kind == TokenKind::As {
5881            self.advance();
5882            if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("COPY") {
5883                return Err(self.error("Expected COPY after AS"));
5884            }
5885            self.advance();
5886            if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("OF") {
5887                return Err(self.error("Expected OF after COPY"));
5888            }
5889            self.advance();
5890            if !self.is_identifier() {
5891                return Err(self.error("Expected graph name after AS COPY OF"));
5892            }
5893            let source = self.get_identifier_name();
5894            self.advance();
5895            Some(source)
5896        } else {
5897            None
5898        };
5899
5900        Ok(SessionCommand::CreateGraph {
5901            name,
5902            if_not_exists,
5903            typed,
5904            like_graph,
5905            copy_of,
5906            open,
5907        })
5908    }
5909
5910    /// Parses `DROP [PROPERTY] GRAPH [IF EXISTS] <name>`.
5911    /// Assumes DROP has already been consumed.
5912    fn parse_drop_graph_body(&mut self) -> Result<SessionCommand> {
5913        // Skip optional PROPERTY keyword
5914        if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("PROPERTY") {
5915            self.advance();
5916        }
5917
5918        // Expect GRAPH
5919        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("GRAPH") {
5920            return Err(
5921                self.error("Expected GRAPH, NODE TYPE, EDGE TYPE, INDEX, or CONSTRAINT after DROP")
5922            );
5923        }
5924        self.advance();
5925
5926        // Optional IF EXISTS
5927        let if_exists = self.try_parse_if_exists();
5928
5929        // Parse graph name
5930        if !self.is_identifier() {
5931            return Err(self.error("Expected graph name"));
5932        }
5933        let name = self.get_identifier_name();
5934        self.advance();
5935
5936        Ok(SessionCommand::DropGraph { name, if_exists })
5937    }
5938
5939    /// Parses `USE GRAPH <name>`.
5940    fn parse_use_graph(&mut self) -> Result<SessionCommand> {
5941        self.advance(); // consume USE
5942
5943        // Expect GRAPH
5944        if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("GRAPH") {
5945            return Err(self.error("Expected GRAPH after USE"));
5946        }
5947        self.advance();
5948
5949        // Parse graph name
5950        if !self.is_identifier() {
5951            return Err(self.error("Expected graph name"));
5952        }
5953        let name = self.get_identifier_name();
5954        self.advance();
5955
5956        Ok(SessionCommand::UseGraph(name))
5957    }
5958
5959    /// Parses SESSION commands: SET, RESET, CLOSE.
5960    fn parse_session_command(&mut self) -> Result<SessionCommand> {
5961        self.advance(); // consume SESSION
5962
5963        if !self.is_identifier() {
5964            return Err(self.error("Expected SET, RESET, or CLOSE after SESSION"));
5965        }
5966
5967        let action = self.get_identifier_name();
5968        match action.to_uppercase().as_str() {
5969            "SET" => {
5970                self.advance(); // consume SET
5971                self.parse_session_set()
5972            }
5973            "RESET" => {
5974                self.advance(); // consume RESET
5975                // ISO/IEC 39075 Section 7.2: SESSION RESET [ALL CHARACTERISTICS | SCHEMA | GRAPH | TIME ZONE | PARAMETERS]
5976                self.parse_session_reset()
5977            }
5978            "CLOSE" => {
5979                self.advance(); // consume CLOSE
5980                Ok(SessionCommand::SessionClose)
5981            }
5982            _ => Err(self.error("Expected SET, RESET, or CLOSE after SESSION")),
5983        }
5984    }
5985
5986    /// Parses SESSION SET variants: GRAPH, TIME ZONE, PARAMETER.
5987    fn parse_session_set(&mut self) -> Result<SessionCommand> {
5988        if !self.is_identifier() {
5989            return Err(self.error("Expected GRAPH, TIME, SCHEMA, or PARAMETER after SESSION SET"));
5990        }
5991
5992        let keyword = self.get_identifier_name();
5993        match keyword.to_uppercase().as_str() {
5994            "GRAPH" => {
5995                self.advance(); // consume GRAPH
5996                if !self.is_identifier() {
5997                    return Err(self.error("Expected graph name"));
5998                }
5999                let name = self.get_identifier_name();
6000                self.advance();
6001                Ok(SessionCommand::SessionSetGraph(name))
6002            }
6003            "TIME" => {
6004                self.advance(); // consume TIME
6005                // Expect ZONE
6006                if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("ZONE")
6007                {
6008                    return Err(self.error("Expected ZONE after TIME"));
6009                }
6010                self.advance();
6011                // Expect timezone string
6012                if self.current.kind != TokenKind::String {
6013                    return Err(self.error("Expected timezone string after TIME ZONE"));
6014                }
6015                let tz = self.current.text[1..self.current.text.len() - 1].to_string();
6016                self.advance();
6017                Ok(SessionCommand::SessionSetTimeZone(tz))
6018            }
6019            "SCHEMA" => {
6020                self.advance(); // consume SCHEMA
6021                if !self.is_identifier() {
6022                    return Err(self.error("Expected schema name"));
6023                }
6024                let name = self.get_identifier_name();
6025                self.advance();
6026                // ISO/IEC 39075 Section 7.1 GR1: session schema is independent from session graph
6027                Ok(SessionCommand::SessionSetSchema(name))
6028            }
6029            "PARAMETER" => {
6030                self.advance(); // consume PARAMETER
6031                // Expect $name or identifier
6032                let param_name = if self.current.kind == TokenKind::Parameter {
6033                    let name = self.current.text[1..].to_string();
6034                    self.advance();
6035                    name
6036                } else if self.is_identifier() {
6037                    let name = self.get_identifier_name();
6038                    self.advance();
6039                    name
6040                } else {
6041                    return Err(self.error("Expected parameter name"));
6042                };
6043                // Expect =
6044                self.expect(TokenKind::Eq)?;
6045                // Parse value expression
6046                let value = self.parse_expression()?;
6047                Ok(SessionCommand::SessionSetParameter(param_name, value))
6048            }
6049            _ => Err(self.error("Expected GRAPH, TIME, SCHEMA, or PARAMETER after SESSION SET")),
6050        }
6051    }
6052
6053    /// Parses SESSION RESET targets per ISO/IEC 39075 Section 7.2.
6054    ///
6055    /// `SESSION RESET` (bare) = reset all characteristics.
6056    /// `SESSION RESET ALL [CHARACTERISTICS | PARAMETERS]` = reset all.
6057    /// `SESSION RESET SCHEMA` = reset session schema only.
6058    /// `SESSION RESET [PROPERTY] GRAPH` = reset session graph only.
6059    /// `SESSION RESET TIME ZONE` = reset time zone only.
6060    /// `SESSION RESET [ALL] PARAMETERS` = reset parameters only.
6061    fn parse_session_reset(&mut self) -> Result<SessionCommand> {
6062        use SessionResetTarget as T;
6063
6064        // Bare SESSION RESET (no arguments) = reset all per Section 7.2 SR2b
6065        if self.current.kind == TokenKind::Eof {
6066            return Ok(SessionCommand::SessionReset(T::All));
6067        }
6068
6069        // ALL [CHARACTERISTICS | PARAMETERS]
6070        if self.current.kind == TokenKind::All {
6071            self.advance();
6072            if self.is_identifier() {
6073                let kw = self.get_identifier_name().to_uppercase();
6074                if kw == "PARAMETERS" {
6075                    self.advance();
6076                    return Ok(SessionCommand::SessionReset(T::Parameters));
6077                }
6078                if kw == "CHARACTERISTICS" {
6079                    self.advance();
6080                }
6081            }
6082            return Ok(SessionCommand::SessionReset(T::All));
6083        }
6084
6085        if !self.is_identifier() {
6086            return Err(
6087                self.error("Expected SCHEMA, GRAPH, TIME, PARAMETERS, or ALL after SESSION RESET")
6088            );
6089        }
6090
6091        let kw = self.get_identifier_name().to_uppercase();
6092        match kw.as_str() {
6093            "SCHEMA" => {
6094                self.advance();
6095                Ok(SessionCommand::SessionReset(T::Schema))
6096            }
6097            "GRAPH" | "PROPERTY" => {
6098                self.advance();
6099                // Skip optional GRAPH after PROPERTY
6100                if kw == "PROPERTY"
6101                    && self.is_identifier()
6102                    && self.get_identifier_name().eq_ignore_ascii_case("GRAPH")
6103                {
6104                    self.advance();
6105                }
6106                Ok(SessionCommand::SessionReset(T::Graph))
6107            }
6108            "TIME" => {
6109                self.advance();
6110                if self.is_identifier() && self.get_identifier_name().eq_ignore_ascii_case("ZONE") {
6111                    self.advance();
6112                }
6113                Ok(SessionCommand::SessionReset(T::TimeZone))
6114            }
6115            "PARAMETERS" => {
6116                self.advance();
6117                Ok(SessionCommand::SessionReset(T::Parameters))
6118            }
6119            "CHARACTERISTICS" => {
6120                self.advance();
6121                Ok(SessionCommand::SessionReset(T::All))
6122            }
6123            _ => {
6124                Err(self
6125                    .error("Expected SCHEMA, GRAPH, TIME, PARAMETERS, or ALL after SESSION RESET"))
6126            }
6127        }
6128    }
6129
6130    /// Parses `START TRANSACTION [READ ONLY | READ WRITE] [ISOLATION LEVEL ...]`.
6131    fn parse_start_transaction(&mut self) -> Result<SessionCommand> {
6132        self.advance(); // consume START
6133        if !self.is_identifier()
6134            || !self
6135                .get_identifier_name()
6136                .eq_ignore_ascii_case("TRANSACTION")
6137        {
6138            return Err(self.error("Expected TRANSACTION after START"));
6139        }
6140        self.advance(); // consume TRANSACTION
6141
6142        let mut read_only = false;
6143        let mut isolation_level = None;
6144
6145        // Parse optional characteristics (can appear in either order)
6146        for _ in 0..2 {
6147            if !self.is_identifier() {
6148                break;
6149            }
6150            let kw = self.get_identifier_name().to_uppercase();
6151            match kw.as_str() {
6152                "READ" => {
6153                    self.advance(); // consume READ
6154                    if !self.is_identifier() {
6155                        return Err(self.error("Expected ONLY or WRITE after READ"));
6156                    }
6157                    let mode = self.get_identifier_name().to_uppercase();
6158                    match mode.as_str() {
6159                        "ONLY" => {
6160                            self.advance();
6161                            read_only = true;
6162                        }
6163                        "WRITE" | "COMMITTED" if mode == "WRITE" => {
6164                            self.advance();
6165                            read_only = false;
6166                        }
6167                        _ => return Err(self.error("Expected ONLY or WRITE after READ")),
6168                    }
6169                }
6170                "ISOLATION" => {
6171                    self.advance(); // consume ISOLATION
6172                    if !self.is_identifier()
6173                        || !self.get_identifier_name().eq_ignore_ascii_case("LEVEL")
6174                    {
6175                        return Err(self.error("Expected LEVEL after ISOLATION"));
6176                    }
6177                    self.advance(); // consume LEVEL
6178                    isolation_level = Some(self.parse_isolation_level_name()?);
6179                }
6180                _ => break,
6181            }
6182        }
6183
6184        Ok(SessionCommand::StartTransaction {
6185            read_only,
6186            isolation_level,
6187        })
6188    }
6189
6190    /// Parses an isolation level name: READ COMMITTED, SNAPSHOT [ISOLATION],
6191    /// REPEATABLE READ, or SERIALIZABLE.
6192    fn parse_isolation_level_name(&mut self) -> Result<TransactionIsolationLevel> {
6193        if !self.is_identifier() {
6194            return Err(self.error("Expected isolation level name"));
6195        }
6196        let name = self.get_identifier_name().to_uppercase();
6197        match name.as_str() {
6198            "READ" => {
6199                self.advance();
6200                if !self.is_identifier()
6201                    || !self.get_identifier_name().eq_ignore_ascii_case("COMMITTED")
6202                {
6203                    return Err(self.error("Expected COMMITTED after READ"));
6204                }
6205                self.advance();
6206                Ok(TransactionIsolationLevel::ReadCommitted)
6207            }
6208            "SNAPSHOT" => {
6209                self.advance();
6210                // Optional "ISOLATION" suffix
6211                if self.is_identifier()
6212                    && self.get_identifier_name().eq_ignore_ascii_case("ISOLATION")
6213                {
6214                    self.advance();
6215                }
6216                Ok(TransactionIsolationLevel::SnapshotIsolation)
6217            }
6218            "REPEATABLE" => {
6219                self.advance();
6220                if !self.is_identifier() || !self.get_identifier_name().eq_ignore_ascii_case("READ")
6221                {
6222                    return Err(self.error("Expected READ after REPEATABLE"));
6223                }
6224                self.advance();
6225                Ok(TransactionIsolationLevel::SnapshotIsolation)
6226            }
6227            "SERIALIZABLE" => {
6228                self.advance();
6229                Ok(TransactionIsolationLevel::Serializable)
6230            }
6231            _ => Err(self.error(&format!("Unknown isolation level: {name}"))),
6232        }
6233    }
6234
6235    fn error(&self, message: &str) -> Error {
6236        Error::Query(
6237            QueryError::new(QueryErrorKind::Syntax, message)
6238                .with_span(self.current.span)
6239                .with_source(self.source.to_string()),
6240        )
6241    }
6242}
6243
6244#[cfg(test)]
6245mod tests {
6246    use super::*;
6247
6248    #[test]
6249    fn test_parse_simple_match() {
6250        let mut parser = Parser::new("MATCH (n) RETURN n");
6251        let result = parser.parse();
6252        assert!(result.is_ok());
6253
6254        let stmt = result.unwrap();
6255        assert!(matches!(stmt, Statement::Query(_)));
6256    }
6257
6258    #[test]
6259    fn test_parse_match_with_label() {
6260        let mut parser = Parser::new("MATCH (n:Person) RETURN n");
6261        let result = parser.parse().unwrap();
6262        if let Statement::Query(query) = result {
6263            assert_eq!(query.match_clauses.len(), 1);
6264            if let Pattern::Node(node) = &query.match_clauses[0].patterns[0].pattern {
6265                assert_eq!(node.variable, Some("n".to_string()));
6266                assert_eq!(node.labels, vec!["Person".to_string()]);
6267            } else {
6268                panic!("Expected node pattern");
6269            }
6270        } else {
6271            panic!("Expected Query statement");
6272        }
6273    }
6274
6275    #[test]
6276    fn test_parse_match_with_where() {
6277        let mut parser = Parser::new("MATCH (n:Person) WHERE n.age > 30 RETURN n");
6278        let result = parser.parse().unwrap();
6279        if let Statement::Query(query) = result {
6280            assert!(
6281                query.where_clause.is_some(),
6282                "WHERE clause should be parsed"
6283            );
6284            let where_clause = query.where_clause.as_ref().unwrap();
6285            if let Expression::Binary { op, .. } = &where_clause.expression {
6286                assert_eq!(*op, BinaryOp::Gt);
6287            } else {
6288                panic!("Expected binary expression in WHERE clause");
6289            }
6290        } else {
6291            panic!("Expected Query statement");
6292        }
6293    }
6294
6295    #[test]
6296    fn test_parse_path_pattern() {
6297        let mut parser = Parser::new("MATCH (a)-[:KNOWS]->(b) RETURN a, b");
6298        let result = parser.parse().unwrap();
6299        if let Statement::Query(query) = result {
6300            if let Pattern::Path(path) = &query.match_clauses[0].patterns[0].pattern {
6301                assert_eq!(path.source.variable, Some("a".to_string()));
6302                assert_eq!(path.edges.len(), 1);
6303                assert_eq!(path.edges[0].types, vec!["KNOWS".to_string()]);
6304                assert_eq!(
6305                    path.edges[0].direction,
6306                    EdgeDirection::Outgoing,
6307                    "Arrow should point outward"
6308                );
6309                assert_eq!(path.edges[0].target.variable, Some("b".to_string()));
6310            } else {
6311                panic!("Expected path pattern");
6312            }
6313        } else {
6314            panic!("Expected Query statement");
6315        }
6316    }
6317
6318    #[test]
6319    fn test_parse_insert() {
6320        let mut parser = Parser::new("INSERT (n:Person {name: 'Alix'})");
6321        let result = parser.parse().unwrap();
6322        if let Statement::DataModification(DataModificationStatement::Insert(insert)) = result {
6323            assert_eq!(insert.patterns.len(), 1);
6324            if let Pattern::Node(node) = &insert.patterns[0] {
6325                assert_eq!(node.labels, vec!["Person".to_string()]);
6326                assert_eq!(node.properties.len(), 1);
6327                assert_eq!(node.properties[0].0, "name");
6328            } else {
6329                panic!("Expected node pattern");
6330            }
6331        } else {
6332            panic!("Expected Insert statement");
6333        }
6334    }
6335
6336    #[test]
6337    fn test_parse_optional_match() {
6338        let mut parser =
6339            Parser::new("MATCH (a:Person) OPTIONAL MATCH (a)-[:KNOWS]->(b) RETURN a, b");
6340        let result = parser.parse();
6341        assert!(result.is_ok());
6342
6343        if let Statement::Query(query) = result.unwrap() {
6344            assert_eq!(query.match_clauses.len(), 2);
6345            assert!(!query.match_clauses[0].optional);
6346            assert!(query.match_clauses[1].optional);
6347        } else {
6348            panic!("Expected Query statement");
6349        }
6350    }
6351
6352    #[test]
6353    fn test_parse_with_clause() {
6354        let mut parser =
6355            Parser::new("MATCH (n:Person) WITH n.name AS name, n.age AS age RETURN name, age");
6356        let result = parser.parse();
6357        assert!(result.is_ok());
6358
6359        if let Statement::Query(query) = result.unwrap() {
6360            assert_eq!(query.with_clauses.len(), 1);
6361            assert_eq!(query.with_clauses[0].items.len(), 2);
6362        } else {
6363            panic!("Expected Query statement");
6364        }
6365    }
6366
6367    #[test]
6368    fn test_parse_order_by() {
6369        let mut parser = Parser::new("MATCH (n:Person) RETURN n.name ORDER BY n.age DESC");
6370        let result = parser.parse();
6371        assert!(result.is_ok());
6372
6373        if let Statement::Query(query) = result.unwrap() {
6374            let order_by = query.return_clause.order_by.as_ref().unwrap();
6375            assert_eq!(order_by.items.len(), 1);
6376            assert_eq!(order_by.items[0].order, SortOrder::Desc);
6377        } else {
6378            panic!("Expected Query statement");
6379        }
6380    }
6381
6382    #[test]
6383    fn test_parse_limit_skip() {
6384        let mut parser = Parser::new("MATCH (n) RETURN n SKIP 10 LIMIT 5");
6385        let result = parser.parse();
6386        assert!(result.is_ok());
6387
6388        if let Statement::Query(query) = result.unwrap() {
6389            assert!(query.return_clause.skip.is_some());
6390            assert!(query.return_clause.limit.is_some());
6391        } else {
6392            panic!("Expected Query statement");
6393        }
6394    }
6395
6396    #[test]
6397    fn test_parse_aggregation() {
6398        let mut parser = Parser::new("MATCH (n:Person) RETURN count(n), avg(n.age)");
6399        let result = parser.parse();
6400        assert!(result.is_ok());
6401
6402        if let Statement::Query(query) = result.unwrap() {
6403            assert_eq!(query.return_clause.items.len(), 2);
6404            // Check that function calls are parsed
6405            if let Expression::FunctionCall { name, .. } = &query.return_clause.items[0].expression
6406            {
6407                assert_eq!(name, "count");
6408            } else {
6409                panic!("Expected function call");
6410            }
6411        } else {
6412            panic!("Expected Query statement");
6413        }
6414    }
6415
6416    #[test]
6417    fn test_parse_with_parameter() {
6418        let mut parser = Parser::new("MATCH (n:Person) WHERE n.age > $min_age RETURN n");
6419        let result = parser.parse();
6420        assert!(result.is_ok());
6421
6422        if let Statement::Query(query) = result.unwrap() {
6423            // Check that the WHERE clause contains a parameter
6424            let where_clause = query.where_clause.as_ref().expect("Expected WHERE clause");
6425            if let Expression::Binary { right, .. } = &where_clause.expression {
6426                if let Expression::Parameter(name) = right.as_ref() {
6427                    assert_eq!(name, "min_age");
6428                } else {
6429                    panic!("Expected parameter, got {:?}", right);
6430                }
6431            } else {
6432                panic!("Expected binary expression in WHERE clause");
6433            }
6434        } else {
6435            panic!("Expected Query statement");
6436        }
6437    }
6438
6439    #[test]
6440    fn test_parse_insert_with_parameter() {
6441        let mut parser = Parser::new("INSERT (n:Person {name: $name, age: $age})");
6442        let result = parser.parse();
6443        assert!(result.is_ok());
6444
6445        if let Statement::DataModification(DataModificationStatement::Insert(insert)) =
6446            result.unwrap()
6447        {
6448            if let Pattern::Node(node) = &insert.patterns[0] {
6449                assert_eq!(node.properties.len(), 2);
6450                // Check first property is a parameter
6451                if let Expression::Parameter(name) = &node.properties[0].1 {
6452                    assert_eq!(name, "name");
6453                } else {
6454                    panic!("Expected parameter for name property");
6455                }
6456            } else {
6457                panic!("Expected node pattern");
6458            }
6459        } else {
6460            panic!("Expected Insert statement");
6461        }
6462    }
6463
6464    #[test]
6465    fn test_parse_variable_length_path() {
6466        let mut parser = Parser::new("MATCH (a)-[:KNOWS*1..3]->(b) RETURN a, b");
6467        let result = parser.parse();
6468        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6469
6470        if let Statement::Query(query) = result.unwrap() {
6471            if let Pattern::Path(path) = &query.match_clauses[0].patterns[0].pattern {
6472                let edge = &path.edges[0];
6473                assert_eq!(edge.min_hops, Some(1));
6474                assert_eq!(edge.max_hops, Some(3));
6475            } else {
6476                panic!("Expected path pattern");
6477            }
6478        } else {
6479            panic!("Expected Query statement");
6480        }
6481    }
6482
6483    #[test]
6484    fn test_parse_variable_length_path_unbounded() {
6485        let mut parser = Parser::new("MATCH (a)-[:KNOWS*]->(b) RETURN a, b");
6486        let result = parser.parse();
6487        assert!(result.is_ok());
6488
6489        if let Statement::Query(query) = result.unwrap() {
6490            if let Pattern::Path(path) = &query.match_clauses[0].patterns[0].pattern {
6491                let edge = &path.edges[0];
6492                assert_eq!(edge.min_hops, Some(1)); // default min is 1
6493                assert_eq!(edge.max_hops, None); // unbounded max
6494            } else {
6495                panic!("Expected path pattern");
6496            }
6497        } else {
6498            panic!("Expected Query statement");
6499        }
6500    }
6501
6502    #[test]
6503    fn test_parse_variable_length_path_exact() {
6504        let mut parser = Parser::new("MATCH (a)-[:KNOWS*2]->(b) RETURN a, b");
6505        let result = parser.parse();
6506        assert!(result.is_ok());
6507
6508        if let Statement::Query(query) = result.unwrap() {
6509            if let Pattern::Path(path) = &query.match_clauses[0].patterns[0].pattern {
6510                let edge = &path.edges[0];
6511                assert_eq!(edge.min_hops, Some(2));
6512                assert_eq!(edge.max_hops, Some(2)); // exact means min == max
6513            } else {
6514                panic!("Expected path pattern");
6515            }
6516        } else {
6517            panic!("Expected Query statement");
6518        }
6519    }
6520
6521    #[test]
6522    fn test_parse_variable_length_path_with_properties() {
6523        // Test variable-length path with node properties and labels
6524        let query = "MATCH (start:Node {name: 'a'})-[:NEXT*1..3]->(end:Node) RETURN end.name";
6525        let mut parser = Parser::new(query);
6526        let result = parser.parse();
6527        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6528
6529        if let Statement::Query(query) = result.unwrap() {
6530            if let Pattern::Path(path) = &query.match_clauses[0].patterns[0].pattern {
6531                let edge = &path.edges[0];
6532                assert_eq!(edge.min_hops, Some(1));
6533                assert_eq!(edge.max_hops, Some(3));
6534                // Verify source and target patterns
6535                assert_eq!(path.source.variable, Some("start".to_string()));
6536                assert_eq!(path.source.labels, vec!["Node".to_string()]);
6537                assert_eq!(edge.target.variable, Some("end".to_string()));
6538                assert_eq!(edge.target.labels, vec!["Node".to_string()]);
6539            } else {
6540                panic!("Expected path pattern");
6541            }
6542        } else {
6543            panic!("Expected Query statement");
6544        }
6545    }
6546
6547    #[test]
6548    fn test_reserved_keywords_as_identifiers() {
6549        // Test that reserved keywords can be used as variable names
6550        let queries = [
6551            ("MATCH (end:Node) RETURN end", "end"),
6552            ("MATCH (node:Person) RETURN node", "node"),
6553            ("MATCH (type:Category) RETURN type", "type"),
6554            ("MATCH (case:Test) RETURN case", "case"),
6555        ];
6556
6557        for (query, expected_var) in queries {
6558            let mut parser = Parser::new(query);
6559            let result = parser.parse();
6560            assert!(
6561                result.is_ok(),
6562                "Parse error for '{}': {:?}",
6563                expected_var,
6564                result.err()
6565            );
6566
6567            if let Statement::Query(q) = result.unwrap()
6568                && let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern
6569            {
6570                assert_eq!(node.variable, Some(expected_var.to_string()));
6571            }
6572        }
6573    }
6574
6575    #[test]
6576    fn test_parse_quoted_identifier_label() {
6577        let mut parser = Parser::new("MATCH (n:`rdf:type`) RETURN n");
6578        let result = parser.parse();
6579        assert!(result.is_ok());
6580
6581        if let Statement::Query(query) = result.unwrap() {
6582            if let Pattern::Node(node) = &query.match_clauses[0].patterns[0].pattern {
6583                assert_eq!(node.labels[0], "rdf:type");
6584            } else {
6585                panic!("Expected node pattern");
6586            }
6587        } else {
6588            panic!("Expected Query statement");
6589        }
6590    }
6591
6592    #[test]
6593    fn test_parse_unwind() {
6594        let mut parser = Parser::new("UNWIND [1, 2, 3] AS x RETURN x");
6595        let result = parser.parse();
6596        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6597
6598        if let Statement::Query(query) = result.unwrap() {
6599            assert_eq!(query.unwind_clauses.len(), 1);
6600            assert_eq!(query.unwind_clauses[0].alias, "x");
6601        } else {
6602            panic!("Expected Query statement");
6603        }
6604    }
6605
6606    #[test]
6607    fn test_parse_merge() {
6608        let mut parser = Parser::new("MERGE (n:Person {name: 'Alix'}) RETURN n");
6609        let result = parser.parse();
6610        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6611
6612        if let Statement::Query(query) = result.unwrap() {
6613            assert_eq!(query.merge_clauses.len(), 1);
6614            if let Pattern::Node(node) = &query.merge_clauses[0].pattern {
6615                assert_eq!(node.labels[0], "Person");
6616            } else {
6617                panic!("Expected node pattern in MERGE");
6618            }
6619        } else {
6620            panic!("Expected Query statement");
6621        }
6622    }
6623
6624    #[test]
6625    fn test_parse_merge_on_create() {
6626        let mut parser =
6627            Parser::new("MERGE (n:Person {name: 'Alix'}) ON CREATE SET n.created = true RETURN n");
6628        let result = parser.parse();
6629        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6630
6631        if let Statement::Query(query) = result.unwrap() {
6632            assert_eq!(query.merge_clauses.len(), 1);
6633            let merge = &query.merge_clauses[0];
6634            assert!(merge.on_create.is_some());
6635            assert_eq!(merge.on_create.as_ref().unwrap().len(), 1);
6636        } else {
6637            panic!("Expected Query statement");
6638        }
6639    }
6640
6641    #[test]
6642    fn test_parse_remove_label() {
6643        let mut parser = Parser::new("MATCH (n:Person) REMOVE n:Employee RETURN n");
6644        let result = parser.parse();
6645        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6646
6647        if let Statement::Query(query) = result.unwrap() {
6648            assert_eq!(query.remove_clauses.len(), 1);
6649            assert_eq!(query.remove_clauses[0].label_operations.len(), 1);
6650            assert_eq!(query.remove_clauses[0].label_operations[0].variable, "n");
6651            assert_eq!(
6652                query.remove_clauses[0].label_operations[0].labels,
6653                vec!["Employee"]
6654            );
6655        } else {
6656            panic!("Expected Query statement");
6657        }
6658    }
6659
6660    #[test]
6661    fn test_parse_remove_property() {
6662        let mut parser = Parser::new("MATCH (n:Person) REMOVE n.age RETURN n");
6663        let result = parser.parse();
6664        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6665
6666        if let Statement::Query(query) = result.unwrap() {
6667            assert_eq!(query.remove_clauses.len(), 1);
6668            assert_eq!(query.remove_clauses[0].property_removals.len(), 1);
6669            assert_eq!(query.remove_clauses[0].property_removals[0].0, "n");
6670            assert_eq!(query.remove_clauses[0].property_removals[0].1, "age");
6671        } else {
6672            panic!("Expected Query statement");
6673        }
6674    }
6675
6676    #[test]
6677    fn test_parse_remove_multiple() {
6678        let mut parser =
6679            Parser::new("MATCH (n:Person) REMOVE n:Employee, n.age, n:Contractor RETURN n");
6680        let result = parser.parse();
6681        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6682
6683        if let Statement::Query(query) = result.unwrap() {
6684            assert_eq!(query.remove_clauses.len(), 1);
6685            let remove = &query.remove_clauses[0];
6686            // Two label operations (Employee, Contractor) and one property removal (age)
6687            assert_eq!(remove.label_operations.len(), 2);
6688            assert_eq!(remove.property_removals.len(), 1);
6689        } else {
6690            panic!("Expected Query statement");
6691        }
6692    }
6693
6694    #[test]
6695    fn test_parse_vector_function_call() {
6696        let mut parser = Parser::new("MATCH (n) RETURN vector([0.1, 0.2, 0.3])");
6697        let result = parser.parse();
6698        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6699
6700        if let Statement::Query(query) = result.unwrap() {
6701            assert_eq!(query.return_clause.items.len(), 1);
6702            if let Expression::FunctionCall { name, args, .. } =
6703                &query.return_clause.items[0].expression
6704            {
6705                assert_eq!(name, "vector");
6706                assert_eq!(args.len(), 1);
6707                // The argument should be a list
6708                if let Expression::List(elements) = &args[0] {
6709                    assert_eq!(elements.len(), 3);
6710                } else {
6711                    panic!("Expected list argument, got {:?}", args[0]);
6712                }
6713            } else {
6714                panic!("Expected function call");
6715            }
6716        } else {
6717            panic!("Expected Query statement");
6718        }
6719    }
6720
6721    #[test]
6722    fn test_parse_cosine_similarity() {
6723        let mut parser =
6724            Parser::new("MATCH (n) WHERE cosine_similarity(n.embedding, $query) > 0.8 RETURN n");
6725        let result = parser.parse();
6726        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6727
6728        if let Statement::Query(query) = result.unwrap() {
6729            let where_clause = query.where_clause.as_ref().expect("Expected WHERE clause");
6730            if let Expression::Binary { left, .. } = &where_clause.expression {
6731                if let Expression::FunctionCall { name, args, .. } = left.as_ref() {
6732                    assert_eq!(name, "cosine_similarity");
6733                    assert_eq!(args.len(), 2);
6734                } else {
6735                    panic!("Expected function call, got {:?}", left);
6736                }
6737            } else {
6738                panic!("Expected binary expression");
6739            }
6740        } else {
6741            panic!("Expected Query statement");
6742        }
6743    }
6744
6745    #[test]
6746    fn test_parse_euclidean_distance() {
6747        let mut parser =
6748            Parser::new("MATCH (n) RETURN euclidean_distance(n.embedding, [1.0, 2.0]) AS dist");
6749        let result = parser.parse();
6750        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6751
6752        if let Statement::Query(query) = result.unwrap() {
6753            assert_eq!(query.return_clause.items.len(), 1);
6754            if let Expression::FunctionCall { name, args, .. } =
6755                &query.return_clause.items[0].expression
6756            {
6757                assert_eq!(name, "euclidean_distance");
6758                assert_eq!(args.len(), 2);
6759            } else {
6760                panic!("Expected function call");
6761            }
6762        } else {
6763            panic!("Expected Query statement");
6764        }
6765    }
6766
6767    #[test]
6768    fn test_parse_create_vector_index() {
6769        let mut parser = Parser::new("CREATE VECTOR INDEX movie_embeddings ON :Movie(embedding)");
6770        let result = parser.parse();
6771        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6772
6773        if let Statement::Schema(SchemaStatement::CreateVectorIndex(stmt)) = result.unwrap() {
6774            assert_eq!(stmt.name, "movie_embeddings");
6775            assert_eq!(stmt.node_label, "Movie");
6776            assert_eq!(stmt.property, "embedding");
6777            assert!(stmt.dimensions.is_none());
6778            assert!(stmt.metric.is_none());
6779        } else {
6780            panic!("Expected CreateVectorIndex statement");
6781        }
6782    }
6783
6784    #[test]
6785    fn test_parse_create_vector_index_with_options() {
6786        let mut parser = Parser::new(
6787            "CREATE VECTOR INDEX embeddings ON :Document(vec) DIMENSION 384 METRIC 'cosine'",
6788        );
6789        let result = parser.parse();
6790        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6791
6792        if let Statement::Schema(SchemaStatement::CreateVectorIndex(stmt)) = result.unwrap() {
6793            assert_eq!(stmt.name, "embeddings");
6794            assert_eq!(stmt.node_label, "Document");
6795            assert_eq!(stmt.property, "vec");
6796            assert_eq!(stmt.dimensions, Some(384));
6797            assert_eq!(stmt.metric, Some("cosine".to_string()));
6798        } else {
6799            panic!("Expected CreateVectorIndex statement");
6800        }
6801    }
6802
6803    #[test]
6804    fn test_in_operator_with_list() {
6805        let mut parser =
6806            Parser::new("MATCH (n:Person) WHERE n.name IN ['Alix', 'Gus'] RETURN n.name");
6807        let result = parser.parse();
6808        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6809
6810        if let Statement::Query(q) = result.unwrap() {
6811            let where_clause = q.where_clause.expect("Expected WHERE clause");
6812            if let WhereClause {
6813                expression: Expression::Binary { op, right, .. },
6814                ..
6815            } = where_clause
6816            {
6817                assert_eq!(op, BinaryOp::In);
6818                assert!(matches!(right.as_ref(), Expression::List(elems) if elems.len() == 2));
6819            } else {
6820                panic!("Expected Binary IN expression");
6821            }
6822        } else {
6823            panic!("Expected Query statement");
6824        }
6825    }
6826
6827    #[test]
6828    fn test_in_operator_with_integers() {
6829        let mut parser = Parser::new("MATCH (n:Item) WHERE n.status IN [1, 2, 3] RETURN n");
6830        let result = parser.parse();
6831        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6832    }
6833
6834    #[test]
6835    fn test_string_escape_single_quotes() {
6836        let mut parser = Parser::new(r#"MATCH (n) WHERE n.name = 'O\'Brien' RETURN n"#);
6837        let result = parser.parse();
6838        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6839
6840        if let Statement::Query(q) = result.unwrap() {
6841            let where_clause = q.where_clause.expect("Expected WHERE clause");
6842            if let WhereClause {
6843                expression: Expression::Binary { right, .. },
6844                ..
6845            } = where_clause
6846            {
6847                if let Expression::Literal(Literal::String(s)) = right.as_ref() {
6848                    assert_eq!(s, "O'Brien");
6849                } else {
6850                    panic!("Expected string literal");
6851                }
6852            }
6853        }
6854    }
6855
6856    #[test]
6857    fn test_string_escape_sequences() {
6858        let mut parser = Parser::new(r#"MATCH (n) WHERE n.text = 'line1\nline2' RETURN n"#);
6859        let result = parser.parse();
6860        assert!(result.is_ok(), "Parse error: {:?}", result.err());
6861
6862        if let Statement::Query(q) = result.unwrap() {
6863            let where_clause = q.where_clause.expect("Expected WHERE clause");
6864            if let WhereClause {
6865                expression: Expression::Binary { right, .. },
6866                ..
6867            } = where_clause
6868            {
6869                if let Expression::Literal(Literal::String(s)) = right.as_ref() {
6870                    assert_eq!(s, "line1\nline2");
6871                } else {
6872                    panic!("Expected string literal");
6873                }
6874            }
6875        }
6876    }
6877
6878    // ==================== Error/Negative Cases ====================
6879
6880    #[test]
6881    fn test_parse_error_empty_input() {
6882        let mut parser = Parser::new("");
6883        let result = parser.parse();
6884        assert!(result.is_err(), "Empty input should fail");
6885    }
6886
6887    #[test]
6888    fn test_parse_error_just_match() {
6889        let mut parser = Parser::new("MATCH");
6890        let result = parser.parse();
6891        assert!(result.is_err(), "MATCH alone should fail");
6892    }
6893
6894    #[test]
6895    fn test_parse_error_unclosed_node_pattern() {
6896        let mut parser = Parser::new("MATCH (n:Person RETURN n");
6897        let result = parser.parse();
6898        assert!(result.is_err(), "Unclosed node pattern should fail");
6899    }
6900
6901    #[test]
6902    fn test_parse_error_unclosed_edge_pattern() {
6903        let mut parser = Parser::new("MATCH (a)-[:KNOWS->(b) RETURN a");
6904        let result = parser.parse();
6905        assert!(result.is_err(), "Unclosed edge pattern should fail");
6906    }
6907
6908    #[test]
6909    fn test_parse_error_missing_return() {
6910        let mut parser = Parser::new("MATCH (n:Person) WHERE n.age > 25");
6911        let result = parser.parse();
6912        assert!(
6913            result.is_err(),
6914            "Query without RETURN or mutation should fail"
6915        );
6916    }
6917
6918    #[test]
6919    fn test_parse_error_double_where() {
6920        let mut parser = Parser::new("MATCH (n) WHERE n.a = 1 WHERE n.b = 2 RETURN n");
6921        let result = parser.parse();
6922        assert!(result.is_err(), "Double WHERE should fail");
6923    }
6924
6925    #[test]
6926    fn test_parse_error_invalid_literal() {
6927        let mut parser = Parser::new("MATCH (n) WHERE n.x = @invalid RETURN n");
6928        let result = parser.parse();
6929        assert!(result.is_err(), "Invalid literal should fail");
6930    }
6931
6932    #[test]
6933    fn test_parse_error_unclosed_string() {
6934        let mut parser = Parser::new("MATCH (n) WHERE n.name = 'hello RETURN n");
6935        let result = parser.parse();
6936        assert!(result.is_err(), "Unclosed string should fail");
6937    }
6938
6939    #[test]
6940    fn test_parse_error_unclosed_property_map() {
6941        let mut parser = Parser::new("MATCH (n:Person {name: 'Alix') RETURN n");
6942        let result = parser.parse();
6943        assert!(result.is_err(), "Unclosed property map should fail");
6944    }
6945
6946    #[test]
6947    fn test_parse_error_return_only() {
6948        let mut parser = Parser::new("RETURN RETURN");
6949        let result = parser.parse();
6950        assert!(result.is_err(), "RETURN RETURN should fail");
6951    }
6952
6953    #[test]
6954    fn test_parse_error_insert_without_pattern() {
6955        let mut parser = Parser::new("INSERT RETURN n");
6956        let result = parser.parse();
6957        assert!(result.is_err(), "INSERT without pattern should fail");
6958    }
6959
6960    // ==================== 0.5.13 Features ====================
6961
6962    // --- Comments ---
6963
6964    #[test]
6965    fn test_parse_with_line_comment() {
6966        let mut parser = Parser::new("MATCH (n) -- find all nodes\nRETURN n");
6967        let result = parser.parse();
6968        assert!(
6969            result.is_ok(),
6970            "Line comment should be skipped: {:?}",
6971            result.err()
6972        );
6973    }
6974
6975    #[test]
6976    fn test_parse_with_block_comment() {
6977        let mut parser = Parser::new("MATCH /* nodes */ (n:Person) RETURN n");
6978        let result = parser.parse();
6979        assert!(
6980            result.is_ok(),
6981            "Block comment should be skipped: {:?}",
6982            result.err()
6983        );
6984    }
6985
6986    // --- XOR operator ---
6987
6988    #[test]
6989    fn test_parse_xor_expression() {
6990        let mut parser = Parser::new("MATCH (n) WHERE n.a = 1 XOR n.b = 2 RETURN n");
6991        let result = parser.parse();
6992        assert!(result.is_ok(), "XOR should parse: {:?}", result.err());
6993
6994        if let Statement::Query(q) = result.unwrap() {
6995            let where_clause = q.where_clause.expect("Expected WHERE clause");
6996            if let Expression::Binary { op, .. } = &where_clause.expression {
6997                assert_eq!(*op, BinaryOp::Xor);
6998            } else {
6999                panic!("Expected binary XOR expression");
7000            }
7001        } else {
7002            panic!("Expected Query statement");
7003        }
7004    }
7005
7006    // --- ISO Path Quantifiers {m,n} ---
7007
7008    #[test]
7009    fn test_parse_iso_path_quantifier_range() {
7010        let mut parser = Parser::new("MATCH (a)-[:KNOWS{2,5}]->(b) RETURN a, b");
7011        let result = parser.parse();
7012        assert!(
7013            result.is_ok(),
7014            "ISO {{m,n}} quantifier should parse: {:?}",
7015            result.err()
7016        );
7017
7018        if let Statement::Query(q) = result.unwrap() {
7019            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
7020                assert_eq!(path.edges[0].min_hops, Some(2));
7021                assert_eq!(path.edges[0].max_hops, Some(5));
7022            } else {
7023                panic!("Expected path pattern");
7024            }
7025        } else {
7026            panic!("Expected Query statement");
7027        }
7028    }
7029
7030    #[test]
7031    fn test_parse_iso_path_quantifier_exact() {
7032        let mut parser = Parser::new("MATCH (a)-[:KNOWS{3}]->(b) RETURN a, b");
7033        let result = parser.parse();
7034        assert!(
7035            result.is_ok(),
7036            "ISO {{n}} quantifier should parse: {:?}",
7037            result.err()
7038        );
7039
7040        if let Statement::Query(q) = result.unwrap() {
7041            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
7042                assert_eq!(path.edges[0].min_hops, Some(3));
7043                assert_eq!(path.edges[0].max_hops, Some(3));
7044            } else {
7045                panic!("Expected path pattern");
7046            }
7047        } else {
7048            panic!("Expected Query statement");
7049        }
7050    }
7051
7052    #[test]
7053    fn test_parse_iso_path_quantifier_lower_only() {
7054        let mut parser = Parser::new("MATCH (a)-[:KNOWS{2,}]->(b) RETURN a, b");
7055        let result = parser.parse();
7056        assert!(
7057            result.is_ok(),
7058            "ISO {{m,}} quantifier should parse: {:?}",
7059            result.err()
7060        );
7061
7062        if let Statement::Query(q) = result.unwrap() {
7063            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
7064                assert_eq!(path.edges[0].min_hops, Some(2));
7065                assert_eq!(path.edges[0].max_hops, None);
7066            } else {
7067                panic!("Expected path pattern");
7068            }
7069        } else {
7070            panic!("Expected Query statement");
7071        }
7072    }
7073
7074    // --- List Access list[i] ---
7075
7076    #[test]
7077    fn test_parse_list_index_access() {
7078        let mut parser = Parser::new("MATCH (n) RETURN [1, 2, 3][0]");
7079        let result = parser.parse();
7080        assert!(
7081            result.is_ok(),
7082            "List index access should parse: {:?}",
7083            result.err()
7084        );
7085
7086        if let Statement::Query(q) = result.unwrap() {
7087            if let Expression::IndexAccess { .. } = &q.return_clause.items[0].expression {
7088                // IndexAccess parsed
7089            } else {
7090                panic!(
7091                    "Expected IndexAccess expression, got {:?}",
7092                    q.return_clause.items[0].expression
7093                );
7094            }
7095        } else {
7096            panic!("Expected Query statement");
7097        }
7098    }
7099
7100    // --- CAST expressions ---
7101
7102    #[test]
7103    fn test_parse_cast_to_integer() {
7104        let mut parser = Parser::new("MATCH (n) RETURN CAST('42' AS INTEGER)");
7105        let result = parser.parse();
7106        assert!(
7107            result.is_ok(),
7108            "CAST AS INTEGER should parse: {:?}",
7109            result.err()
7110        );
7111
7112        if let Statement::Query(q) = result.unwrap() {
7113            if let Expression::FunctionCall { name, .. } = &q.return_clause.items[0].expression {
7114                assert_eq!(name, "toInteger");
7115            } else {
7116                panic!("Expected function call from CAST");
7117            }
7118        } else {
7119            panic!("Expected Query statement");
7120        }
7121    }
7122
7123    #[test]
7124    fn test_parse_cast_to_float() {
7125        let mut parser = Parser::new("MATCH (n) RETURN CAST(n.val AS FLOAT)");
7126        let result = parser.parse();
7127        assert!(
7128            result.is_ok(),
7129            "CAST AS FLOAT should parse: {:?}",
7130            result.err()
7131        );
7132
7133        if let Statement::Query(q) = result.unwrap() {
7134            if let Expression::FunctionCall { name, .. } = &q.return_clause.items[0].expression {
7135                assert_eq!(name, "toFloat");
7136            } else {
7137                panic!("Expected function call from CAST");
7138            }
7139        } else {
7140            panic!("Expected Query statement");
7141        }
7142    }
7143
7144    #[test]
7145    fn test_parse_cast_to_string() {
7146        let mut parser = Parser::new("MATCH (n) RETURN CAST(42 AS STRING)");
7147        let result = parser.parse();
7148        assert!(
7149            result.is_ok(),
7150            "CAST AS STRING should parse: {:?}",
7151            result.err()
7152        );
7153
7154        if let Statement::Query(q) = result.unwrap() {
7155            if let Expression::FunctionCall { name, .. } = &q.return_clause.items[0].expression {
7156                assert_eq!(name, "toString");
7157            } else {
7158                panic!("Expected function call from CAST");
7159            }
7160        } else {
7161            panic!("Expected Query statement");
7162        }
7163    }
7164
7165    #[test]
7166    fn test_parse_cast_to_boolean() {
7167        let mut parser = Parser::new("MATCH (n) RETURN CAST('true' AS BOOLEAN)");
7168        let result = parser.parse();
7169        assert!(
7170            result.is_ok(),
7171            "CAST AS BOOLEAN should parse: {:?}",
7172            result.err()
7173        );
7174
7175        if let Statement::Query(q) = result.unwrap() {
7176            if let Expression::FunctionCall { name, .. } = &q.return_clause.items[0].expression {
7177                assert_eq!(name, "toBoolean");
7178            } else {
7179                panic!("Expected function call from CAST");
7180            }
7181        } else {
7182            panic!("Expected Query statement");
7183        }
7184    }
7185
7186    // --- OFFSET as SKIP alias ---
7187
7188    #[test]
7189    fn test_parse_offset_as_skip_alias() {
7190        let mut parser = Parser::new("MATCH (n) RETURN n OFFSET 10 LIMIT 5");
7191        let result = parser.parse();
7192        assert!(
7193            result.is_ok(),
7194            "OFFSET should parse as SKIP alias: {:?}",
7195            result.err()
7196        );
7197
7198        if let Statement::Query(q) = result.unwrap() {
7199            assert!(q.return_clause.skip.is_some());
7200            assert!(q.return_clause.limit.is_some());
7201        } else {
7202            panic!("Expected Query statement");
7203        }
7204    }
7205
7206    // --- Label Expressions (IS syntax) ---
7207
7208    #[test]
7209    fn test_parse_is_label_single() {
7210        let mut parser = Parser::new("MATCH (n IS Person) RETURN n");
7211        let result = parser.parse();
7212        assert!(result.is_ok(), "IS label should parse: {:?}", result.err());
7213
7214        if let Statement::Query(q) = result.unwrap() {
7215            if let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern {
7216                match &node.label_expression {
7217                    Some(LabelExpression::Label(name)) => assert_eq!(name, "Person"),
7218                    other => panic!("Expected Label(Person), got {:?}", other),
7219                }
7220            } else {
7221                panic!("Expected node pattern");
7222            }
7223        } else {
7224            panic!("Expected Query statement");
7225        }
7226    }
7227
7228    #[test]
7229    fn test_parse_is_label_disjunction() {
7230        let mut parser = Parser::new("MATCH (n IS Person | Company) RETURN n");
7231        let result = parser.parse();
7232        assert!(
7233            result.is_ok(),
7234            "IS label disjunction should parse: {:?}",
7235            result.err()
7236        );
7237
7238        if let Statement::Query(q) = result.unwrap() {
7239            if let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern {
7240                assert!(matches!(
7241                    &node.label_expression,
7242                    Some(LabelExpression::Disjunction(_))
7243                ));
7244            } else {
7245                panic!("Expected node pattern");
7246            }
7247        } else {
7248            panic!("Expected Query statement");
7249        }
7250    }
7251
7252    #[test]
7253    fn test_parse_is_label_conjunction() {
7254        let mut parser = Parser::new("MATCH (n IS Person & Employee) RETURN n");
7255        let result = parser.parse();
7256        assert!(
7257            result.is_ok(),
7258            "IS label conjunction should parse: {:?}",
7259            result.err()
7260        );
7261
7262        if let Statement::Query(q) = result.unwrap() {
7263            if let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern {
7264                assert!(matches!(
7265                    &node.label_expression,
7266                    Some(LabelExpression::Conjunction(_))
7267                ));
7268            } else {
7269                panic!("Expected node pattern");
7270            }
7271        } else {
7272            panic!("Expected Query statement");
7273        }
7274    }
7275
7276    #[test]
7277    fn test_parse_is_label_negation() {
7278        let mut parser = Parser::new("MATCH (n IS !Inactive) RETURN n");
7279        let result = parser.parse();
7280        assert!(
7281            result.is_ok(),
7282            "IS label negation should parse: {:?}",
7283            result.err()
7284        );
7285
7286        if let Statement::Query(q) = result.unwrap() {
7287            if let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern {
7288                assert!(matches!(
7289                    &node.label_expression,
7290                    Some(LabelExpression::Negation(_))
7291                ));
7292            } else {
7293                panic!("Expected node pattern");
7294            }
7295        } else {
7296            panic!("Expected Query statement");
7297        }
7298    }
7299
7300    #[test]
7301    fn test_parse_is_label_wildcard() {
7302        let mut parser = Parser::new("MATCH (n IS %) RETURN n");
7303        let result = parser.parse();
7304        assert!(
7305            result.is_ok(),
7306            "IS wildcard should parse: {:?}",
7307            result.err()
7308        );
7309
7310        if let Statement::Query(q) = result.unwrap() {
7311            if let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern {
7312                assert!(matches!(
7313                    &node.label_expression,
7314                    Some(LabelExpression::Wildcard)
7315                ));
7316            } else {
7317                panic!("Expected node pattern");
7318            }
7319        } else {
7320            panic!("Expected Query statement");
7321        }
7322    }
7323
7324    #[test]
7325    fn test_parse_is_label_complex() {
7326        // (Person | Company) & !Inactive
7327        let mut parser = Parser::new("MATCH (n IS (Person | Company) & !Inactive) RETURN n");
7328        let result = parser.parse();
7329        assert!(
7330            result.is_ok(),
7331            "Complex label expression should parse: {:?}",
7332            result.err()
7333        );
7334
7335        if let Statement::Query(q) = result.unwrap() {
7336            if let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern {
7337                assert!(node.label_expression.is_some());
7338            } else {
7339                panic!("Expected node pattern");
7340            }
7341        } else {
7342            panic!("Expected Query statement");
7343        }
7344    }
7345
7346    #[test]
7347    fn test_parse_is_label_on_edge_colon_syntax() {
7348        // IS on edges is not yet wired; use colon syntax instead
7349        let mut parser = Parser::new("MATCH (a)-[e:KNOWS]->(b) RETURN a, b");
7350        let result = parser.parse();
7351        assert!(
7352            result.is_ok(),
7353            "Edge colon syntax should parse: {:?}",
7354            result.err()
7355        );
7356    }
7357
7358    // --- Path Modes ---
7359
7360    #[test]
7361    fn test_parse_path_mode_walk() {
7362        let mut parser = Parser::new("MATCH WALK (a)-[:KNOWS*]->(b) RETURN a, b");
7363        let result = parser.parse();
7364        assert!(result.is_ok(), "WALK mode should parse: {:?}", result.err());
7365
7366        if let Statement::Query(q) = result.unwrap() {
7367            assert_eq!(q.match_clauses[0].path_mode, Some(PathMode::Walk));
7368        } else {
7369            panic!("Expected Query statement");
7370        }
7371    }
7372
7373    #[test]
7374    fn test_parse_path_mode_trail() {
7375        let mut parser = Parser::new("MATCH TRAIL (a)-[:KNOWS*]->(b) RETURN a, b");
7376        let result = parser.parse();
7377        assert!(
7378            result.is_ok(),
7379            "TRAIL mode should parse: {:?}",
7380            result.err()
7381        );
7382
7383        if let Statement::Query(q) = result.unwrap() {
7384            assert_eq!(q.match_clauses[0].path_mode, Some(PathMode::Trail));
7385        } else {
7386            panic!("Expected Query statement");
7387        }
7388    }
7389
7390    #[test]
7391    fn test_parse_path_mode_simple() {
7392        let mut parser = Parser::new("MATCH SIMPLE (a)-[:KNOWS*]->(b) RETURN a, b");
7393        let result = parser.parse();
7394        assert!(
7395            result.is_ok(),
7396            "SIMPLE mode should parse: {:?}",
7397            result.err()
7398        );
7399
7400        if let Statement::Query(q) = result.unwrap() {
7401            assert_eq!(q.match_clauses[0].path_mode, Some(PathMode::Simple));
7402        } else {
7403            panic!("Expected Query statement");
7404        }
7405    }
7406
7407    #[test]
7408    fn test_parse_path_mode_acyclic() {
7409        let mut parser = Parser::new("MATCH ACYCLIC (a)-[:KNOWS*]->(b) RETURN a, b");
7410        let result = parser.parse();
7411        assert!(
7412            result.is_ok(),
7413            "ACYCLIC mode should parse: {:?}",
7414            result.err()
7415        );
7416
7417        if let Statement::Query(q) = result.unwrap() {
7418            assert_eq!(q.match_clauses[0].path_mode, Some(PathMode::Acyclic));
7419        } else {
7420            panic!("Expected Query statement");
7421        }
7422    }
7423
7424    #[test]
7425    fn test_parse_no_path_mode_default() {
7426        let mut parser = Parser::new("MATCH (a)-[:KNOWS*]->(b) RETURN a, b");
7427        let result = parser.parse();
7428        assert!(result.is_ok());
7429
7430        if let Statement::Query(q) = result.unwrap() {
7431            assert_eq!(q.match_clauses[0].path_mode, None);
7432        } else {
7433            panic!("Expected Query statement");
7434        }
7435    }
7436
7437    // --- Composite Queries ---
7438
7439    #[test]
7440    fn test_parse_union() {
7441        let mut parser =
7442            Parser::new("MATCH (n:Person) RETURN n.name UNION MATCH (n:Company) RETURN n.name");
7443        let result = parser.parse();
7444        assert!(result.is_ok(), "UNION should parse: {:?}", result.err());
7445
7446        if let Statement::CompositeQuery { op, .. } = result.unwrap() {
7447            assert_eq!(op, CompositeOp::Union);
7448        } else {
7449            panic!("Expected CompositeQuery");
7450        }
7451    }
7452
7453    #[test]
7454    fn test_parse_union_all() {
7455        let mut parser =
7456            Parser::new("MATCH (n:Person) RETURN n.name UNION ALL MATCH (n:Company) RETURN n.name");
7457        let result = parser.parse();
7458        assert!(result.is_ok(), "UNION ALL should parse: {:?}", result.err());
7459
7460        if let Statement::CompositeQuery { op, .. } = result.unwrap() {
7461            assert_eq!(op, CompositeOp::UnionAll);
7462        } else {
7463            panic!("Expected CompositeQuery");
7464        }
7465    }
7466
7467    #[test]
7468    fn test_parse_except() {
7469        let mut parser =
7470            Parser::new("MATCH (n:Person) RETURN n.name EXCEPT MATCH (n:Employee) RETURN n.name");
7471        let result = parser.parse();
7472        assert!(result.is_ok(), "EXCEPT should parse: {:?}", result.err());
7473
7474        if let Statement::CompositeQuery { op, .. } = result.unwrap() {
7475            assert_eq!(op, CompositeOp::Except);
7476        } else {
7477            panic!("Expected CompositeQuery");
7478        }
7479    }
7480
7481    #[test]
7482    fn test_parse_intersect() {
7483        let mut parser = Parser::new(
7484            "MATCH (n:Person) RETURN n.name INTERSECT MATCH (n:Employee) RETURN n.name",
7485        );
7486        let result = parser.parse();
7487        assert!(result.is_ok(), "INTERSECT should parse: {:?}", result.err());
7488
7489        if let Statement::CompositeQuery { op, .. } = result.unwrap() {
7490            assert_eq!(op, CompositeOp::Intersect);
7491        } else {
7492            panic!("Expected CompositeQuery");
7493        }
7494    }
7495
7496    #[test]
7497    fn test_parse_otherwise() {
7498        let mut parser =
7499            Parser::new("MATCH (n:Person) RETURN n.name OTHERWISE MATCH (n:Company) RETURN n.name");
7500        let result = parser.parse();
7501        assert!(result.is_ok(), "OTHERWISE should parse: {:?}", result.err());
7502
7503        if let Statement::CompositeQuery { op, .. } = result.unwrap() {
7504            assert_eq!(op, CompositeOp::Otherwise);
7505        } else {
7506            panic!("Expected CompositeQuery");
7507        }
7508    }
7509
7510    // --- FILTER statement ---
7511
7512    #[test]
7513    fn test_parse_filter_as_where_synonym() {
7514        let mut parser = Parser::new("MATCH (n:Person) FILTER n.age > 25 RETURN n");
7515        let result = parser.parse();
7516        assert!(
7517            result.is_ok(),
7518            "FILTER should parse as WHERE synonym: {:?}",
7519            result.err()
7520        );
7521
7522        if let Statement::Query(q) = result.unwrap() {
7523            assert!(q.where_clause.is_some());
7524        } else {
7525            panic!("Expected Query statement");
7526        }
7527    }
7528
7529    // --- GROUP BY ---
7530
7531    #[test]
7532    fn test_parse_group_by() {
7533        let mut parser = Parser::new("MATCH (n:Person) RETURN n.city, count(n) GROUP BY n.city");
7534        let result = parser.parse();
7535        assert!(result.is_ok(), "GROUP BY should parse: {:?}", result.err());
7536
7537        if let Statement::Query(q) = result.unwrap() {
7538            assert_eq!(q.return_clause.group_by.len(), 1);
7539            if let Expression::PropertyAccess { property, .. } = &q.return_clause.group_by[0] {
7540                assert_eq!(property, "city");
7541            } else {
7542                panic!("Expected property access in GROUP BY");
7543            }
7544        } else {
7545            panic!("Expected Query statement");
7546        }
7547    }
7548
7549    #[test]
7550    fn test_parse_group_by_multiple() {
7551        let mut parser =
7552            Parser::new("MATCH (n:Person) RETURN n.city, n.age, count(n) GROUP BY n.city, n.age");
7553        let result = parser.parse();
7554        assert!(
7555            result.is_ok(),
7556            "Multiple GROUP BY should parse: {:?}",
7557            result.err()
7558        );
7559
7560        if let Statement::Query(q) = result.unwrap() {
7561            assert_eq!(q.return_clause.group_by.len(), 2);
7562        } else {
7563            panic!("Expected Query statement");
7564        }
7565    }
7566
7567    // --- ELEMENT_ID function ---
7568
7569    #[test]
7570    fn test_parse_element_id_function() {
7571        let mut parser = Parser::new("MATCH (n) RETURN element_id(n)");
7572        let result = parser.parse();
7573        assert!(
7574            result.is_ok(),
7575            "element_id should parse: {:?}",
7576            result.err()
7577        );
7578
7579        if let Statement::Query(q) = result.unwrap() {
7580            if let Expression::FunctionCall { name, args, .. } =
7581                &q.return_clause.items[0].expression
7582            {
7583                assert_eq!(name, "element_id");
7584                assert_eq!(args.len(), 1);
7585            } else {
7586                panic!("Expected function call");
7587            }
7588        } else {
7589            panic!("Expected Query statement");
7590        }
7591    }
7592
7593    // --- Error Cases for New Features ---
7594
7595    #[test]
7596    fn test_parse_error_cast_missing_as() {
7597        let mut parser = Parser::new("MATCH (n) RETURN CAST(42 INTEGER)");
7598        let result = parser.parse();
7599        assert!(result.is_err(), "CAST without AS should fail");
7600    }
7601
7602    #[test]
7603    fn test_parse_error_cast_invalid_type() {
7604        let mut parser = Parser::new("MATCH (n) RETURN CAST(42 AS VECTOR)");
7605        let result = parser.parse();
7606        assert!(result.is_err(), "CAST to unsupported type should fail");
7607    }
7608
7609    #[test]
7610    fn test_parse_error_group_by_without_expressions() {
7611        let mut parser = Parser::new("MATCH (n) RETURN n GROUP BY");
7612        let result = parser.parse();
7613        assert!(result.is_err(), "GROUP BY without expressions should fail");
7614    }
7615
7616    #[test]
7617    fn test_parse_hex_integer_literal() {
7618        let mut parser = Parser::new("MATCH (n) RETURN 0xFF");
7619        let result = parser.parse();
7620        assert!(
7621            result.is_ok(),
7622            "Hex literal should parse: {:?}",
7623            result.err()
7624        );
7625        if let Statement::Query(q) = result.unwrap() {
7626            let item = &q.return_clause.items[0];
7627            if let Expression::Literal(Literal::Integer(val)) = &item.expression {
7628                assert_eq!(*val, 255, "0xFF should parse to 255");
7629            } else {
7630                panic!("Expected integer literal");
7631            }
7632        }
7633    }
7634
7635    #[test]
7636    fn test_parse_octal_integer_literal() {
7637        let mut parser = Parser::new("MATCH (n) RETURN 0o77");
7638        let result = parser.parse();
7639        assert!(
7640            result.is_ok(),
7641            "Octal literal should parse: {:?}",
7642            result.err()
7643        );
7644        if let Statement::Query(q) = result.unwrap() {
7645            let item = &q.return_clause.items[0];
7646            if let Expression::Literal(Literal::Integer(val)) = &item.expression {
7647                assert_eq!(*val, 63, "0o77 should parse to 63");
7648            } else {
7649                panic!("Expected integer literal");
7650            }
7651        }
7652    }
7653
7654    #[test]
7655    fn test_parse_scientific_float_literal() {
7656        let mut parser = Parser::new("MATCH (n) RETURN 1.5e10");
7657        let result = parser.parse();
7658        assert!(
7659            result.is_ok(),
7660            "Scientific literal should parse: {:?}",
7661            result.err()
7662        );
7663        if let Statement::Query(q) = result.unwrap() {
7664            let item = &q.return_clause.items[0];
7665            if let Expression::Literal(Literal::Float(val)) = &item.expression {
7666                assert!((val - 1.5e10).abs() < 1.0, "1.5e10 should parse correctly");
7667            } else {
7668                panic!("Expected float literal");
7669            }
7670        }
7671    }
7672
7673    /// Helper to extract edges from the first match pattern.
7674    fn get_first_path_edges(stmt: &Statement) -> &[EdgePattern] {
7675        if let Statement::Query(q) = stmt
7676            && let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern
7677        {
7678            return &path.edges;
7679        }
7680        panic!("Expected query with path pattern");
7681    }
7682
7683    #[test]
7684    fn test_parse_edge_type_pipe_alternatives() {
7685        let mut parser = Parser::new("MATCH (a)-[:KNOWS|LIKES|FOLLOWS]->(b) RETURN a, b");
7686        let result = parser.parse().expect("Edge type pipe should parse");
7687        let edges = get_first_path_edges(&result);
7688        assert_eq!(edges.len(), 1);
7689        assert_eq!(edges[0].types, vec!["KNOWS", "LIKES", "FOLLOWS"]);
7690    }
7691
7692    #[test]
7693    fn test_parse_edge_type_pipe_with_variable() {
7694        let mut parser = Parser::new("MATCH (a)-[r:KNOWS|LIKES]->(b) RETURN r");
7695        let result = parser
7696            .parse()
7697            .expect("Edge type pipe with var should parse");
7698        let edges = get_first_path_edges(&result);
7699        assert_eq!(edges[0].variable, Some("r".to_string()));
7700        assert_eq!(edges[0].types, vec!["KNOWS", "LIKES"]);
7701    }
7702
7703    #[test]
7704    fn test_parse_tilde_undirected_edge() {
7705        let mut parser = Parser::new("MATCH (a)~[e:KNOWS]~(b) RETURN a, b");
7706        let result = parser.parse().expect("Tilde edge should parse");
7707        let edges = get_first_path_edges(&result);
7708        assert_eq!(edges.len(), 1);
7709        assert_eq!(edges[0].variable, Some("e".to_string()));
7710        assert_eq!(edges[0].types, vec!["KNOWS"]);
7711        assert_eq!(edges[0].direction, EdgeDirection::Undirected);
7712    }
7713
7714    #[test]
7715    fn test_parse_tilde_simple() {
7716        let mut parser = Parser::new("MATCH (a)~(b) RETURN a");
7717        let result = parser.parse().expect("Simple tilde should parse");
7718        let edges = get_first_path_edges(&result);
7719        assert_eq!(edges[0].direction, EdgeDirection::Undirected);
7720        assert!(edges[0].variable.is_none());
7721        assert!(edges[0].types.is_empty());
7722    }
7723
7724    #[test]
7725    fn test_parse_tilde_with_pipe_types() {
7726        let mut parser = Parser::new("MATCH (a)~[:KNOWS|LIKES]~(b) RETURN a");
7727        let result = parser.parse().expect("Tilde with pipe types should parse");
7728        let edges = get_first_path_edges(&result);
7729        assert_eq!(edges[0].types, vec!["KNOWS", "LIKES"]);
7730        assert_eq!(edges[0].direction, EdgeDirection::Undirected);
7731    }
7732
7733    // ==================== shorthand arrow edges ====================
7734
7735    #[test]
7736    fn test_parse_shorthand_outgoing_arrow() {
7737        // --> shorthand: directed outgoing, no brackets
7738        let mut parser = Parser::new("MATCH (a)-->(b) RETURN b");
7739        let result = parser.parse().expect("Shorthand --> should parse");
7740        let edges = get_first_path_edges(&result);
7741        assert_eq!(edges.len(), 1);
7742        assert_eq!(edges[0].direction, EdgeDirection::Outgoing);
7743        assert!(edges[0].variable.is_none());
7744        assert!(edges[0].types.is_empty());
7745    }
7746
7747    #[test]
7748    fn test_parse_shorthand_incoming_arrow() {
7749        // <-- shorthand: directed incoming, no brackets
7750        let mut parser = Parser::new("MATCH (a)<--(b) RETURN a");
7751        let result = parser.parse().expect("Shorthand <-- should parse");
7752        let edges = get_first_path_edges(&result);
7753        assert_eq!(edges.len(), 1);
7754        assert_eq!(edges[0].direction, EdgeDirection::Incoming);
7755        assert!(edges[0].variable.is_none());
7756        assert!(edges[0].types.is_empty());
7757    }
7758
7759    #[test]
7760    fn test_parse_shorthand_arrow_chain() {
7761        // Chained shorthand arrows: (a)-->(b)-->(c)
7762        let mut parser = Parser::new("MATCH (a)-->(b)-->(c) RETURN c");
7763        let result = parser.parse().expect("Chained --> should parse");
7764        let edges = get_first_path_edges(&result);
7765        assert_eq!(edges.len(), 2);
7766        assert_eq!(edges[0].direction, EdgeDirection::Outgoing);
7767        assert_eq!(edges[1].direction, EdgeDirection::Outgoing);
7768    }
7769
7770    #[test]
7771    fn test_parse_shorthand_mixed_directions() {
7772        // Mixed: (a)<--(b)-->(c)
7773        let mut parser = Parser::new("MATCH (a)<--(b)-->(c) RETURN c");
7774        let result = parser.parse().expect("Mixed <-- and --> should parse");
7775        let edges = get_first_path_edges(&result);
7776        assert_eq!(edges.len(), 2);
7777        assert_eq!(edges[0].direction, EdgeDirection::Incoming);
7778        assert_eq!(edges[1].direction, EdgeDirection::Outgoing);
7779    }
7780
7781    #[test]
7782    fn test_parse_shorthand_undirected_still_works() {
7783        // -- (undirected) must still work
7784        let mut parser = Parser::new("MATCH (a)--(b) RETURN b");
7785        let result = parser.parse().expect("Undirected -- should still parse");
7786        let edges = get_first_path_edges(&result);
7787        assert_eq!(edges[0].direction, EdgeDirection::Undirected);
7788    }
7789
7790    // ==================== unescape_string ====================
7791
7792    #[test]
7793    fn test_unescape_string_newline() {
7794        assert_eq!(unescape_string(r"hello\nworld"), "hello\nworld");
7795    }
7796
7797    #[test]
7798    fn test_unescape_string_carriage_return() {
7799        assert_eq!(unescape_string(r"line\rend"), "line\rend");
7800    }
7801
7802    #[test]
7803    fn test_unescape_string_tab() {
7804        assert_eq!(unescape_string(r"col1\tcol2"), "col1\tcol2");
7805    }
7806
7807    #[test]
7808    fn test_unescape_string_backslash() {
7809        assert_eq!(unescape_string(r"path\\to"), "path\\to");
7810    }
7811
7812    #[test]
7813    fn test_unescape_string_single_quote() {
7814        assert_eq!(unescape_string(r"it\'s"), "it's");
7815    }
7816
7817    #[test]
7818    fn test_unescape_string_double_quote() {
7819        assert_eq!(unescape_string(r#"say\"hello\""#), "say\"hello\"");
7820    }
7821
7822    #[test]
7823    fn test_unescape_string_unknown_escape() {
7824        // Unknown escapes are kept as-is (backslash + char)
7825        assert_eq!(unescape_string(r"\z"), "\\z");
7826    }
7827
7828    #[test]
7829    fn test_unescape_string_trailing_backslash() {
7830        // Trailing backslash with no following char is kept
7831        assert_eq!(unescape_string("trailing\\"), "trailing\\");
7832    }
7833
7834    // ==================== DDL / Session Commands ====================
7835
7836    #[test]
7837    fn test_parse_create_graph() {
7838        let mut parser = Parser::new("CREATE GRAPH mydb");
7839        let result = parser.parse();
7840        assert!(
7841            result.is_ok(),
7842            "CREATE GRAPH should parse: {:?}",
7843            result.err()
7844        );
7845
7846        if let Statement::SessionCommand(SessionCommand::CreateGraph {
7847            name,
7848            if_not_exists,
7849            ..
7850        }) = result.unwrap()
7851        {
7852            assert_eq!(name, "mydb");
7853            assert!(!if_not_exists);
7854        } else {
7855            panic!("Expected CreateGraph session command");
7856        }
7857    }
7858
7859    #[test]
7860    fn test_parse_create_graph_if_not_exists() {
7861        let mut parser = Parser::new("CREATE GRAPH IF NOT EXISTS mydb");
7862        let result = parser.parse();
7863        assert!(
7864            result.is_ok(),
7865            "CREATE GRAPH IF NOT EXISTS should parse: {:?}",
7866            result.err()
7867        );
7868
7869        if let Statement::SessionCommand(SessionCommand::CreateGraph {
7870            name,
7871            if_not_exists,
7872            ..
7873        }) = result.unwrap()
7874        {
7875            assert_eq!(name, "mydb");
7876            assert!(if_not_exists);
7877        } else {
7878            panic!("Expected CreateGraph session command");
7879        }
7880    }
7881
7882    #[test]
7883    fn test_parse_create_property_graph() {
7884        let mut parser = Parser::new("CREATE PROPERTY GRAPH pg1");
7885        let result = parser.parse();
7886        assert!(
7887            result.is_ok(),
7888            "CREATE PROPERTY GRAPH should parse: {:?}",
7889            result.err()
7890        );
7891
7892        if let Statement::SessionCommand(SessionCommand::CreateGraph {
7893            name,
7894            if_not_exists,
7895            ..
7896        }) = result.unwrap()
7897        {
7898            assert_eq!(name, "pg1");
7899            assert!(!if_not_exists);
7900        } else {
7901            panic!("Expected CreateGraph session command");
7902        }
7903    }
7904
7905    #[test]
7906    fn test_parse_drop_graph() {
7907        let mut parser = Parser::new("DROP GRAPH mydb");
7908        let result = parser.parse();
7909        assert!(
7910            result.is_ok(),
7911            "DROP GRAPH should parse: {:?}",
7912            result.err()
7913        );
7914
7915        if let Statement::SessionCommand(SessionCommand::DropGraph { name, if_exists }) =
7916            result.unwrap()
7917        {
7918            assert_eq!(name, "mydb");
7919            assert!(!if_exists);
7920        } else {
7921            panic!("Expected DropGraph session command");
7922        }
7923    }
7924
7925    #[test]
7926    fn test_parse_drop_graph_if_exists() {
7927        let mut parser = Parser::new("DROP GRAPH IF EXISTS mydb");
7928        let result = parser.parse();
7929        assert!(
7930            result.is_ok(),
7931            "DROP GRAPH IF EXISTS should parse: {:?}",
7932            result.err()
7933        );
7934
7935        if let Statement::SessionCommand(SessionCommand::DropGraph { name, if_exists }) =
7936            result.unwrap()
7937        {
7938            assert_eq!(name, "mydb");
7939            assert!(if_exists);
7940        } else {
7941            panic!("Expected DropGraph session command");
7942        }
7943    }
7944
7945    #[test]
7946    fn test_parse_drop_property_graph() {
7947        let mut parser = Parser::new("DROP PROPERTY GRAPH pg1");
7948        let result = parser.parse();
7949        assert!(
7950            result.is_ok(),
7951            "DROP PROPERTY GRAPH should parse: {:?}",
7952            result.err()
7953        );
7954
7955        if let Statement::SessionCommand(SessionCommand::DropGraph { name, if_exists }) =
7956            result.unwrap()
7957        {
7958            assert_eq!(name, "pg1");
7959            assert!(!if_exists);
7960        } else {
7961            panic!("Expected DropGraph session command");
7962        }
7963    }
7964
7965    #[test]
7966    fn test_parse_use_graph() {
7967        let mut parser = Parser::new("USE GRAPH workspace");
7968        let result = parser.parse();
7969        assert!(result.is_ok(), "USE GRAPH should parse: {:?}", result.err());
7970
7971        if let Statement::SessionCommand(SessionCommand::UseGraph(name)) = result.unwrap() {
7972            assert_eq!(name, "workspace");
7973        } else {
7974            panic!("Expected UseGraph session command");
7975        }
7976    }
7977
7978    #[test]
7979    fn test_parse_session_set_graph() {
7980        let mut parser = Parser::new("SESSION SET GRAPH analytics");
7981        let result = parser.parse();
7982        assert!(
7983            result.is_ok(),
7984            "SESSION SET GRAPH should parse: {:?}",
7985            result.err()
7986        );
7987
7988        if let Statement::SessionCommand(SessionCommand::SessionSetGraph(name)) = result.unwrap() {
7989            assert_eq!(name, "analytics");
7990        } else {
7991            panic!("Expected SessionSetGraph session command");
7992        }
7993    }
7994
7995    #[test]
7996    fn test_parse_session_set_time_zone() {
7997        let mut parser = Parser::new("SESSION SET TIME ZONE 'UTC+5'");
7998        let result = parser.parse();
7999        assert!(
8000            result.is_ok(),
8001            "SESSION SET TIME ZONE should parse: {:?}",
8002            result.err()
8003        );
8004
8005        if let Statement::SessionCommand(SessionCommand::SessionSetTimeZone(tz)) = result.unwrap() {
8006            assert_eq!(tz, "UTC+5");
8007        } else {
8008            panic!("Expected SessionSetTimeZone session command");
8009        }
8010    }
8011
8012    #[test]
8013    fn test_parse_session_set_schema() {
8014        // ISO/IEC 39075 Section 7.1 GR1: SESSION SET SCHEMA is independent from SESSION SET GRAPH
8015        let mut parser = Parser::new("SESSION SET SCHEMA myschema");
8016        let result = parser.parse();
8017        assert!(
8018            result.is_ok(),
8019            "SESSION SET SCHEMA should parse: {:?}",
8020            result.err()
8021        );
8022
8023        if let Statement::SessionCommand(SessionCommand::SessionSetSchema(name)) = result.unwrap() {
8024            assert_eq!(name, "myschema");
8025        } else {
8026            panic!("Expected SessionSetSchema session command");
8027        }
8028    }
8029
8030    #[test]
8031    fn test_parse_session_set_parameter() {
8032        let mut parser = Parser::new("SESSION SET PARAMETER timeout = 30");
8033        let result = parser.parse();
8034        assert!(
8035            result.is_ok(),
8036            "SESSION SET PARAMETER should parse: {:?}",
8037            result.err()
8038        );
8039
8040        if let Statement::SessionCommand(SessionCommand::SessionSetParameter(name, _value)) =
8041            result.unwrap()
8042        {
8043            assert_eq!(name, "timeout");
8044        } else {
8045            panic!("Expected SessionSetParameter session command");
8046        }
8047    }
8048
8049    #[test]
8050    fn test_parse_session_reset() {
8051        // Bare SESSION RESET = reset all characteristics (Section 7.2 SR2b)
8052        let mut parser = Parser::new("SESSION RESET");
8053        let result = parser.parse();
8054        assert!(
8055            result.is_ok(),
8056            "SESSION RESET should parse: {:?}",
8057            result.err()
8058        );
8059
8060        assert!(matches!(
8061            result.unwrap(),
8062            Statement::SessionCommand(SessionCommand::SessionReset(SessionResetTarget::All))
8063        ));
8064    }
8065
8066    #[test]
8067    fn test_parse_session_reset_all() {
8068        let mut parser = Parser::new("SESSION RESET ALL");
8069        let result = parser.parse();
8070        assert!(
8071            result.is_ok(),
8072            "SESSION RESET ALL should parse: {:?}",
8073            result.err()
8074        );
8075
8076        assert!(matches!(
8077            result.unwrap(),
8078            Statement::SessionCommand(SessionCommand::SessionReset(SessionResetTarget::All))
8079        ));
8080    }
8081
8082    #[test]
8083    fn test_parse_session_reset_schema() {
8084        // ISO/IEC 39075 Section 7.2 GR1: reset session schema independently
8085        let mut parser = Parser::new("SESSION RESET SCHEMA");
8086        let result = parser.parse();
8087        assert!(
8088            result.is_ok(),
8089            "SESSION RESET SCHEMA should parse: {:?}",
8090            result.err()
8091        );
8092
8093        assert!(matches!(
8094            result.unwrap(),
8095            Statement::SessionCommand(SessionCommand::SessionReset(SessionResetTarget::Schema))
8096        ));
8097    }
8098
8099    #[test]
8100    fn test_parse_session_reset_graph() {
8101        // ISO/IEC 39075 Section 7.2 GR2: reset session graph independently
8102        let mut parser = Parser::new("SESSION RESET GRAPH");
8103        let result = parser.parse();
8104        assert!(
8105            result.is_ok(),
8106            "SESSION RESET GRAPH should parse: {:?}",
8107            result.err()
8108        );
8109
8110        assert!(matches!(
8111            result.unwrap(),
8112            Statement::SessionCommand(SessionCommand::SessionReset(SessionResetTarget::Graph))
8113        ));
8114    }
8115
8116    #[test]
8117    fn test_parse_session_reset_property_graph() {
8118        // SESSION RESET PROPERTY GRAPH (Section 7.2)
8119        let mut parser = Parser::new("SESSION RESET PROPERTY GRAPH");
8120        let result = parser.parse();
8121        assert!(
8122            result.is_ok(),
8123            "SESSION RESET PROPERTY GRAPH should parse: {:?}",
8124            result.err()
8125        );
8126
8127        assert!(matches!(
8128            result.unwrap(),
8129            Statement::SessionCommand(SessionCommand::SessionReset(SessionResetTarget::Graph))
8130        ));
8131    }
8132
8133    #[test]
8134    fn test_parse_session_close() {
8135        let mut parser = Parser::new("SESSION CLOSE");
8136        let result = parser.parse();
8137        assert!(
8138            result.is_ok(),
8139            "SESSION CLOSE should parse: {:?}",
8140            result.err()
8141        );
8142
8143        assert!(matches!(
8144            result.unwrap(),
8145            Statement::SessionCommand(SessionCommand::SessionClose)
8146        ));
8147    }
8148
8149    #[test]
8150    fn test_parse_start_transaction() {
8151        let mut parser = Parser::new("START TRANSACTION");
8152        let result = parser.parse();
8153        assert!(
8154            result.is_ok(),
8155            "START TRANSACTION should parse: {:?}",
8156            result.err()
8157        );
8158        match result.unwrap() {
8159            Statement::SessionCommand(SessionCommand::StartTransaction {
8160                read_only,
8161                isolation_level,
8162            }) => {
8163                assert!(!read_only);
8164                assert!(isolation_level.is_none());
8165            }
8166            other => panic!("Expected StartTransaction, got {other:?}"),
8167        }
8168    }
8169
8170    #[test]
8171    fn test_parse_start_transaction_read_only() {
8172        let mut parser = Parser::new("START TRANSACTION READ ONLY");
8173        let result = parser.parse().unwrap();
8174        match result {
8175            Statement::SessionCommand(SessionCommand::StartTransaction {
8176                read_only,
8177                isolation_level,
8178            }) => {
8179                assert!(read_only);
8180                assert!(isolation_level.is_none());
8181            }
8182            other => panic!("Expected StartTransaction READ ONLY, got {other:?}"),
8183        }
8184    }
8185
8186    #[test]
8187    fn test_parse_start_transaction_isolation_level() {
8188        let mut parser = Parser::new("START TRANSACTION ISOLATION LEVEL SERIALIZABLE");
8189        let result = parser.parse().unwrap();
8190        match result {
8191            Statement::SessionCommand(SessionCommand::StartTransaction {
8192                read_only,
8193                isolation_level,
8194            }) => {
8195                assert!(!read_only);
8196                assert_eq!(
8197                    isolation_level,
8198                    Some(TransactionIsolationLevel::Serializable)
8199                );
8200            }
8201            other => panic!("Expected StartTransaction with isolation, got {other:?}"),
8202        }
8203    }
8204
8205    #[test]
8206    fn test_parse_start_transaction_read_only_with_isolation() {
8207        let mut parser = Parser::new("START TRANSACTION READ ONLY ISOLATION LEVEL READ COMMITTED");
8208        let result = parser.parse().unwrap();
8209        match result {
8210            Statement::SessionCommand(SessionCommand::StartTransaction {
8211                read_only,
8212                isolation_level,
8213            }) => {
8214                assert!(read_only);
8215                assert_eq!(
8216                    isolation_level,
8217                    Some(TransactionIsolationLevel::ReadCommitted)
8218                );
8219            }
8220            other => panic!("Expected StartTransaction READ ONLY + isolation, got {other:?}"),
8221        }
8222    }
8223
8224    #[test]
8225    fn test_parse_commit() {
8226        let mut parser = Parser::new("COMMIT");
8227        let result = parser.parse();
8228        assert!(result.is_ok(), "COMMIT should parse: {:?}", result.err());
8229
8230        assert!(matches!(
8231            result.unwrap(),
8232            Statement::SessionCommand(SessionCommand::Commit)
8233        ));
8234    }
8235
8236    #[test]
8237    fn test_parse_rollback() {
8238        let mut parser = Parser::new("ROLLBACK");
8239        let result = parser.parse();
8240        assert!(result.is_ok(), "ROLLBACK should parse: {:?}", result.err());
8241
8242        assert!(matches!(
8243            result.unwrap(),
8244            Statement::SessionCommand(SessionCommand::Rollback)
8245        ));
8246    }
8247
8248    // ==================== Edge WHERE Clause ====================
8249
8250    #[test]
8251    fn test_parse_edge_where_clause() {
8252        let mut parser = Parser::new("MATCH (a)-[e:KNOWS WHERE e.since >= 2020]->(b) RETURN a, b");
8253        let result = parser.parse();
8254        assert!(
8255            result.is_ok(),
8256            "Edge WHERE clause should parse: {:?}",
8257            result.err()
8258        );
8259
8260        let stmt = result.unwrap();
8261        let edges = get_first_path_edges(&stmt);
8262        assert_eq!(edges.len(), 1);
8263        assert_eq!(edges[0].variable, Some("e".to_string()));
8264        assert_eq!(edges[0].types, vec!["KNOWS"]);
8265        assert!(
8266            edges[0].where_clause.is_some(),
8267            "Edge where_clause should be Some"
8268        );
8269    }
8270
8271    // ==================== Path Quantifier Disambiguation ====================
8272
8273    #[test]
8274    fn test_parse_path_quantifier_vs_property_map() {
8275        // {1,3} after an edge type is a quantifier (min/max hops)
8276        let mut parser = Parser::new("MATCH (a)-[:KNOWS{1,3}]->(b) RETURN a, b");
8277        let result = parser.parse();
8278        assert!(
8279            result.is_ok(),
8280            "{{1,3}} quantifier should parse: {:?}",
8281            result.err()
8282        );
8283
8284        if let Statement::Query(q) = result.unwrap() {
8285            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
8286                assert_eq!(path.edges[0].min_hops, Some(1));
8287                assert_eq!(path.edges[0].max_hops, Some(3));
8288            } else {
8289                panic!("Expected path pattern");
8290            }
8291        } else {
8292            panic!("Expected Query statement");
8293        }
8294
8295        // {since: 2020} inside a node pattern is a property map, not a quantifier
8296        let mut parser2 = Parser::new("MATCH (n:Person {since: 2020}) RETURN n");
8297        let result2 = parser2.parse();
8298        assert!(
8299            result2.is_ok(),
8300            "Property map should parse: {:?}",
8301            result2.err()
8302        );
8303
8304        if let Statement::Query(q) = result2.unwrap() {
8305            if let Pattern::Node(node) = &q.match_clauses[0].patterns[0].pattern {
8306                assert_eq!(node.properties.len(), 1);
8307                assert_eq!(node.properties[0].0, "since");
8308            } else {
8309                panic!("Expected node pattern");
8310            }
8311        } else {
8312            panic!("Expected Query statement");
8313        }
8314    }
8315
8316    // ==================== NEXT Composition ====================
8317
8318    #[test]
8319    fn test_parse_next_composition() {
8320        let mut parser =
8321            Parser::new("MATCH (n:Person) RETURN n.name NEXT MATCH (m:Company) RETURN m.name");
8322        let result = parser.parse();
8323        assert!(
8324            result.is_ok(),
8325            "NEXT composition should parse: {:?}",
8326            result.err()
8327        );
8328
8329        if let Statement::CompositeQuery { op, .. } = result.unwrap() {
8330            assert_eq!(op, CompositeOp::Next);
8331        } else {
8332            panic!("Expected CompositeQuery with Next op");
8333        }
8334    }
8335
8336    // ==================== FINISH Statement ====================
8337
8338    #[test]
8339    fn test_parse_finish_statement() {
8340        let mut parser = Parser::new("MATCH (n) FINISH");
8341        let result = parser.parse();
8342        assert!(result.is_ok(), "FINISH should parse: {:?}", result.err());
8343
8344        if let Statement::Query(q) = result.unwrap() {
8345            assert!(q.return_clause.is_finish, "Expected is_finish to be true");
8346            assert!(
8347                q.return_clause.items.is_empty(),
8348                "FINISH should have no return items"
8349            );
8350        } else {
8351            panic!("Expected Query statement");
8352        }
8353    }
8354
8355    // ==================== SELECT Statement ====================
8356
8357    #[test]
8358    fn test_parse_select_statement() {
8359        let mut parser = Parser::new("MATCH (n:Person) SELECT n.name");
8360        let result = parser.parse();
8361        assert!(result.is_ok(), "SELECT should parse: {:?}", result.err());
8362
8363        if let Statement::Query(q) = result.unwrap() {
8364            assert!(!q.return_clause.is_finish);
8365            assert_eq!(q.return_clause.items.len(), 1);
8366        } else {
8367            panic!("Expected Query statement");
8368        }
8369    }
8370
8371    // ==================== Error Cases for New Commands ====================
8372
8373    #[test]
8374    fn test_parse_error_drop_nothing() {
8375        let mut parser = Parser::new("DROP NOTHING");
8376        let result = parser.parse();
8377        assert!(result.is_err(), "DROP NOTHING should fail");
8378    }
8379
8380    #[test]
8381    fn test_parse_error_session_destroy() {
8382        let mut parser = Parser::new("SESSION DESTROY");
8383        let result = parser.parse();
8384        assert!(result.is_err(), "SESSION DESTROY should fail");
8385    }
8386
8387    #[test]
8388    fn test_parse_error_start_something() {
8389        let mut parser = Parser::new("START SOMETHING");
8390        let result = parser.parse();
8391        assert!(result.is_err(), "START SOMETHING should fail");
8392    }
8393
8394    #[test]
8395    fn test_parse_error_use_something() {
8396        let mut parser = Parser::new("USE SOMETHING");
8397        let result = parser.parse();
8398        assert!(result.is_err(), "USE SOMETHING should fail");
8399    }
8400
8401    // -------------------------------------------------------------------
8402    // ISO GQL Conformance: NULLS FIRST/LAST (GA03)
8403    // -------------------------------------------------------------------
8404
8405    #[test]
8406    fn test_parse_order_by_nulls_first() {
8407        let mut parser =
8408            Parser::new("MATCH (n:Person) RETURN n.name ORDER BY n.age ASC NULLS FIRST");
8409        let stmt = parser.parse().unwrap();
8410        if let Statement::Query(q) = stmt {
8411            let order = q.return_clause.order_by.unwrap();
8412            assert_eq!(order.items[0].nulls, Some(NullsOrdering::First));
8413        } else {
8414            panic!("Expected query");
8415        }
8416    }
8417
8418    #[test]
8419    fn test_parse_order_by_nulls_last() {
8420        let mut parser =
8421            Parser::new("MATCH (n:Person) RETURN n.name ORDER BY n.age DESC NULLS LAST");
8422        let stmt = parser.parse().unwrap();
8423        if let Statement::Query(q) = stmt {
8424            let order = q.return_clause.order_by.unwrap();
8425            assert_eq!(order.items[0].nulls, Some(NullsOrdering::Last));
8426        } else {
8427            panic!("Expected query");
8428        }
8429    }
8430
8431    #[test]
8432    fn test_parse_order_by_no_nulls_clause() {
8433        let mut parser = Parser::new("MATCH (n:Person) RETURN n.name ORDER BY n.age ASC");
8434        let stmt = parser.parse().unwrap();
8435        if let Statement::Query(q) = stmt {
8436            let order = q.return_clause.order_by.unwrap();
8437            assert_eq!(order.items[0].nulls, None);
8438        } else {
8439            panic!("Expected query");
8440        }
8441    }
8442
8443    // -------------------------------------------------------------------
8444    // ISO GQL Conformance: NULLIF / COALESCE keyword syntax
8445    // -------------------------------------------------------------------
8446
8447    #[test]
8448    fn test_parse_nullif() {
8449        let mut parser = Parser::new("MATCH (n:Person) RETURN NULLIF(n.age, 30) AS val");
8450        let stmt = parser.parse().unwrap();
8451        if let Statement::Query(q) = stmt {
8452            match &q.return_clause.items[0].expression {
8453                Expression::FunctionCall { name, args, .. } => {
8454                    assert_eq!(name, "nullif");
8455                    assert_eq!(args.len(), 2);
8456                }
8457                other => panic!("Expected FunctionCall, got {other:?}"),
8458            }
8459        } else {
8460            panic!("Expected query");
8461        }
8462    }
8463
8464    #[test]
8465    fn test_parse_coalesce() {
8466        let mut parser =
8467            Parser::new("MATCH (n:Person) RETURN COALESCE(null, n.name, 'default') AS val");
8468        let stmt = parser.parse().unwrap();
8469        if let Statement::Query(q) = stmt {
8470            match &q.return_clause.items[0].expression {
8471                Expression::FunctionCall { name, args, .. } => {
8472                    assert_eq!(name, "coalesce");
8473                    assert_eq!(args.len(), 3);
8474                }
8475                other => panic!("Expected FunctionCall, got {other:?}"),
8476            }
8477        } else {
8478            panic!("Expected query");
8479        }
8480    }
8481
8482    // -------------------------------------------------------------------
8483    // ISO GQL Conformance: IS [NFC|NFD|NFKC|NFKD] NORMALIZED
8484    // -------------------------------------------------------------------
8485
8486    #[test]
8487    fn test_parse_is_nfc_normalized() {
8488        let mut parser = Parser::new("MATCH (n:Person) RETURN n.name IS NFC NORMALIZED AS norm");
8489        let stmt = parser.parse().unwrap();
8490        if let Statement::Query(q) = stmt {
8491            match &q.return_clause.items[0].expression {
8492                Expression::FunctionCall { name, args, .. } => {
8493                    assert_eq!(name, "isNormalized");
8494                    assert_eq!(args.len(), 2);
8495                    // Second arg should be the form string "NFC"
8496                    match &args[1] {
8497                        Expression::Literal(Literal::String(s)) => assert_eq!(s, "NFC"),
8498                        other => panic!("Expected string literal, got {other:?}"),
8499                    }
8500                }
8501                other => panic!("Expected FunctionCall, got {other:?}"),
8502            }
8503        } else {
8504            panic!("Expected query");
8505        }
8506    }
8507
8508    #[test]
8509    fn test_parse_is_not_nfkd_normalized() {
8510        let mut parser =
8511            Parser::new("MATCH (n:Person) RETURN n.name IS NOT NFKD NORMALIZED AS norm");
8512        let stmt = parser.parse().unwrap();
8513        if let Statement::Query(q) = stmt {
8514            match &q.return_clause.items[0].expression {
8515                Expression::Unary { op, operand } => {
8516                    assert_eq!(*op, UnaryOp::Not);
8517                    match operand.as_ref() {
8518                        Expression::FunctionCall { name, args, .. } => {
8519                            assert_eq!(name, "isNormalized");
8520                            match &args[1] {
8521                                Expression::Literal(Literal::String(s)) => {
8522                                    assert_eq!(s, "NFKD");
8523                                }
8524                                other => panic!("Expected string literal, got {other:?}"),
8525                            }
8526                        }
8527                        other => panic!("Expected FunctionCall, got {other:?}"),
8528                    }
8529                }
8530                other => panic!("Expected Unary NOT, got {other:?}"),
8531            }
8532        } else {
8533            panic!("Expected query");
8534        }
8535    }
8536
8537    #[test]
8538    fn test_parse_is_normalized_default_form() {
8539        let mut parser = Parser::new("MATCH (n:Person) RETURN n.name IS NORMALIZED AS norm");
8540        let stmt = parser.parse().unwrap();
8541        if let Statement::Query(q) = stmt {
8542            match &q.return_clause.items[0].expression {
8543                Expression::FunctionCall { name, args, .. } => {
8544                    assert_eq!(name, "isNormalized");
8545                    assert_eq!(args.len(), 2);
8546                    match &args[1] {
8547                        Expression::Literal(Literal::String(s)) => assert_eq!(s, "NFC"),
8548                        other => panic!("Expected string literal NFC, got {other:?}"),
8549                    }
8550                }
8551                other => panic!("Expected FunctionCall, got {other:?}"),
8552            }
8553        } else {
8554            panic!("Expected query");
8555        }
8556    }
8557
8558    // --- Group 4: Parenthesized Path Enhancements ---
8559
8560    #[test]
8561    fn test_parse_parenthesized_path_mode_prefix() {
8562        // G049: Path mode prefix inside parenthesized pattern
8563        let mut parser = Parser::new("MATCH (TRAIL (a)-[e]->(b)){2,5} RETURN a, b");
8564        let result = parser.parse();
8565        assert!(
8566            result.is_ok(),
8567            "Parenthesized path with mode prefix should parse: {:?}",
8568            result.err()
8569        );
8570
8571        if let Statement::Query(q) = result.unwrap() {
8572            let pat = &q.match_clauses[0].patterns[0].pattern;
8573            if let Pattern::Quantified {
8574                min,
8575                max,
8576                path_mode,
8577                ..
8578            } = pat
8579            {
8580                assert_eq!(*min, 2);
8581                assert_eq!(*max, Some(5));
8582                assert_eq!(*path_mode, Some(PathMode::Trail));
8583            } else {
8584                panic!("Expected Quantified pattern, got {pat:?}");
8585            }
8586        } else {
8587            panic!("Expected Query statement");
8588        }
8589    }
8590
8591    #[test]
8592    fn test_parse_parenthesized_where_clause() {
8593        // G050: WHERE clause inside parenthesized pattern
8594        let mut parser = Parser::new("MATCH ((a)-[e]->(b) WHERE e.weight > 5){1,3} RETURN a, b");
8595        let result = parser.parse();
8596        assert!(
8597            result.is_ok(),
8598            "Parenthesized path with WHERE should parse: {:?}",
8599            result.err()
8600        );
8601
8602        if let Statement::Query(q) = result.unwrap() {
8603            let pat = &q.match_clauses[0].patterns[0].pattern;
8604            if let Pattern::Quantified {
8605                min,
8606                max,
8607                where_clause,
8608                ..
8609            } = pat
8610            {
8611                assert_eq!(*min, 1);
8612                assert_eq!(*max, Some(3));
8613                assert!(where_clause.is_some(), "WHERE clause should be present");
8614            } else {
8615                panic!("Expected Quantified pattern, got {pat:?}");
8616            }
8617        } else {
8618            panic!("Expected Query statement");
8619        }
8620    }
8621
8622    #[test]
8623    fn test_parse_parenthesized_all_features() {
8624        // All three: path mode + WHERE + quantifier
8625        let mut parser =
8626            Parser::new("MATCH (ACYCLIC (a)-[e]->(b) WHERE e.active = true){2,4} RETURN a, b");
8627        let result = parser.parse();
8628        assert!(
8629            result.is_ok(),
8630            "Full parenthesized path should parse: {:?}",
8631            result.err()
8632        );
8633
8634        if let Statement::Query(q) = result.unwrap() {
8635            let pat = &q.match_clauses[0].patterns[0].pattern;
8636            if let Pattern::Quantified {
8637                min,
8638                max,
8639                path_mode,
8640                where_clause,
8641                subpath_var,
8642                ..
8643            } = pat
8644            {
8645                assert_eq!(*min, 2);
8646                assert_eq!(*max, Some(4));
8647                assert_eq!(*path_mode, Some(PathMode::Acyclic));
8648                assert!(where_clause.is_some());
8649                assert!(subpath_var.is_none());
8650            } else {
8651                panic!("Expected Quantified pattern, got {pat:?}");
8652            }
8653        } else {
8654            panic!("Expected Query statement");
8655        }
8656    }
8657
8658    // --- Group 5: Simplified Path Patterns ---
8659
8660    #[test]
8661    fn test_parse_simplified_outgoing() {
8662        // G080: -/:KNOWS/-> desugars to -[:KNOWS]->
8663        let mut parser = Parser::new("MATCH (a:Person)-/:KNOWS/->(b:Person) RETURN b.name");
8664        let result = parser.parse();
8665        assert!(
8666            result.is_ok(),
8667            "Simplified outgoing path should parse: {:?}",
8668            result.err()
8669        );
8670
8671        if let Statement::Query(q) = result.unwrap() {
8672            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
8673                assert_eq!(path.edges.len(), 1);
8674                assert_eq!(path.edges[0].types, vec!["KNOWS"]);
8675                assert_eq!(path.edges[0].direction, EdgeDirection::Outgoing);
8676            } else {
8677                panic!("Expected Path pattern");
8678            }
8679        } else {
8680            panic!("Expected Query");
8681        }
8682    }
8683
8684    #[test]
8685    fn test_parse_simplified_incoming() {
8686        // G080: <-/:KNOWS/- desugars to <-[:KNOWS]-
8687        let mut parser = Parser::new("MATCH (a:Person)<-/:KNOWS/-(b:Person) RETURN b.name");
8688        let result = parser.parse();
8689        assert!(
8690            result.is_ok(),
8691            "Simplified incoming path should parse: {:?}",
8692            result.err()
8693        );
8694
8695        if let Statement::Query(q) = result.unwrap() {
8696            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
8697                assert_eq!(path.edges.len(), 1);
8698                assert_eq!(path.edges[0].types, vec!["KNOWS"]);
8699                assert_eq!(path.edges[0].direction, EdgeDirection::Incoming);
8700            } else {
8701                panic!("Expected Path pattern");
8702            }
8703        } else {
8704            panic!("Expected Query");
8705        }
8706    }
8707
8708    #[test]
8709    fn test_parse_simplified_undirected() {
8710        // G080: -/:KNOWS/- desugars to -[:KNOWS]-
8711        let mut parser = Parser::new("MATCH (a:Person)-/:KNOWS/-(b:Person) RETURN b.name");
8712        let result = parser.parse();
8713        assert!(
8714            result.is_ok(),
8715            "Simplified undirected path should parse: {:?}",
8716            result.err()
8717        );
8718
8719        if let Statement::Query(q) = result.unwrap() {
8720            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
8721                assert_eq!(path.edges.len(), 1);
8722                assert_eq!(path.edges[0].types, vec!["KNOWS"]);
8723                assert_eq!(path.edges[0].direction, EdgeDirection::Undirected);
8724            } else {
8725                panic!("Expected Path pattern");
8726            }
8727        } else {
8728            panic!("Expected Query");
8729        }
8730    }
8731
8732    #[test]
8733    fn test_parse_simplified_multi_label() {
8734        // G039: -/:KNOWS|WORKS_WITH/-> with multiple label alternatives
8735        let mut parser =
8736            Parser::new("MATCH (a:Person)-/:KNOWS|WORKS_WITH/->(b:Person) RETURN b.name");
8737        let result = parser.parse();
8738        assert!(
8739            result.is_ok(),
8740            "Simplified multi-label path should parse: {:?}",
8741            result.err()
8742        );
8743
8744        if let Statement::Query(q) = result.unwrap() {
8745            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
8746                assert_eq!(path.edges[0].types, vec!["KNOWS", "WORKS_WITH"]);
8747                assert_eq!(path.edges[0].direction, EdgeDirection::Outgoing);
8748            } else {
8749                panic!("Expected Path pattern");
8750            }
8751        } else {
8752            panic!("Expected Query");
8753        }
8754    }
8755
8756    #[test]
8757    fn test_parse_simplified_tilde() {
8758        // G080: ~/:KNOWS/~ desugars to ~[:KNOWS]~
8759        let mut parser = Parser::new("MATCH (a:Person)~/:KNOWS/~(b:Person) RETURN b.name");
8760        let result = parser.parse();
8761        assert!(
8762            result.is_ok(),
8763            "Simplified tilde path should parse: {:?}",
8764            result.err()
8765        );
8766
8767        if let Statement::Query(q) = result.unwrap() {
8768            if let Pattern::Path(path) = &q.match_clauses[0].patterns[0].pattern {
8769                assert_eq!(path.edges[0].types, vec!["KNOWS"]);
8770                assert_eq!(path.edges[0].direction, EdgeDirection::Undirected);
8771            } else {
8772                panic!("Expected Path pattern");
8773            }
8774        } else {
8775            panic!("Expected Query");
8776        }
8777    }
8778
8779    // --- Group 6: Multiset Alternation ---
8780
8781    #[test]
8782    fn test_parse_multiset_alternation() {
8783        // G030: |+| operator creates MultisetUnion
8784        let mut parser = Parser::new(
8785            "MATCH ((a)-[:KNOWS]->(b) |+| (a)-[:WORKS_WITH]->(b)) RETURN a.name, b.name",
8786        );
8787        let result = parser.parse();
8788        assert!(
8789            result.is_ok(),
8790            "Multiset alternation should parse: {:?}",
8791            result.err()
8792        );
8793
8794        if let Statement::Query(q) = result.unwrap() {
8795            let pattern = &q.match_clauses[0].patterns[0].pattern;
8796            assert!(
8797                matches!(pattern, Pattern::MultisetUnion(_)),
8798                "Expected MultisetUnion pattern, got {:?}",
8799                pattern
8800            );
8801            if let Pattern::MultisetUnion(alternatives) = pattern {
8802                assert_eq!(alternatives.len(), 2);
8803            }
8804        } else {
8805            panic!("Expected Query");
8806        }
8807    }
8808
8809    #[test]
8810    fn test_parse_set_alternation() {
8811        // Set union uses | and produces Pattern::Union
8812        let mut parser =
8813            Parser::new("MATCH ((a)-[:KNOWS]->(b) | (a)-[:WORKS_WITH]->(b)) RETURN a.name");
8814        let result = parser.parse();
8815        assert!(
8816            result.is_ok(),
8817            "Set alternation should parse: {:?}",
8818            result.err()
8819        );
8820
8821        if let Statement::Query(q) = result.unwrap() {
8822            let pattern = &q.match_clauses[0].patterns[0].pattern;
8823            assert!(
8824                matches!(pattern, Pattern::Union(_)),
8825                "Expected Union pattern, got {:?}",
8826                pattern
8827            );
8828        } else {
8829            panic!("Expected Query");
8830        }
8831    }
8832
8833    #[test]
8834    fn test_parse_delete_variable() {
8835        // Basic DELETE with variable (existing behavior)
8836        let mut parser = Parser::new("MATCH (n:Person) DELETE n");
8837        let result = parser.parse();
8838        assert!(
8839            result.is_ok(),
8840            "DELETE variable should parse: {:?}",
8841            result.err()
8842        );
8843        if let Statement::Query(q) = result.unwrap() {
8844            assert_eq!(q.delete_clauses.len(), 1);
8845            assert_eq!(q.delete_clauses[0].targets.len(), 1);
8846            assert!(
8847                matches!(&q.delete_clauses[0].targets[0], DeleteTarget::Variable(name) if name == "n"),
8848                "Expected Variable target"
8849            );
8850        } else {
8851            panic!("Expected Query");
8852        }
8853    }
8854
8855    #[test]
8856    fn test_parse_delete_expression() {
8857        // GD04: DELETE with property access expression
8858        let mut parser = Parser::new("MATCH (n:Person) DELETE n.friend");
8859        let result = parser.parse();
8860        assert!(
8861            result.is_ok(),
8862            "DELETE expression should parse: {:?}",
8863            result.err()
8864        );
8865        if let Statement::Query(q) = result.unwrap() {
8866            assert_eq!(q.delete_clauses.len(), 1);
8867            assert_eq!(q.delete_clauses[0].targets.len(), 1);
8868            assert!(
8869                matches!(&q.delete_clauses[0].targets[0], DeleteTarget::Expression(_)),
8870                "Expected Expression target, got {:?}",
8871                q.delete_clauses[0].targets[0]
8872            );
8873        } else {
8874            panic!("Expected Query");
8875        }
8876    }
8877
8878    #[test]
8879    fn test_parse_delete_multiple_mixed_targets() {
8880        // GD04: DELETE with both variable and expression targets
8881        let mut parser = Parser::new("MATCH (n:Person)-[r:KNOWS]->(m) DELETE n, r");
8882        let result = parser.parse();
8883        assert!(
8884            result.is_ok(),
8885            "DELETE mixed targets should parse: {:?}",
8886            result.err()
8887        );
8888        if let Statement::Query(q) = result.unwrap() {
8889            assert_eq!(q.delete_clauses[0].targets.len(), 2);
8890            assert!(matches!(
8891                &q.delete_clauses[0].targets[0],
8892                DeleteTarget::Variable(name) if name == "n"
8893            ));
8894            assert!(matches!(
8895                &q.delete_clauses[0].targets[1],
8896                DeleteTarget::Variable(name) if name == "r"
8897            ));
8898        } else {
8899            panic!("Expected Query");
8900        }
8901    }
8902
8903    #[test]
8904    fn test_parse_detach_delete_expression() {
8905        // GD04: DETACH DELETE with expression
8906        let mut parser = Parser::new("MATCH (n:Person) DETACH DELETE n");
8907        let result = parser.parse();
8908        assert!(
8909            result.is_ok(),
8910            "DETACH DELETE should parse: {:?}",
8911            result.err()
8912        );
8913        if let Statement::Query(q) = result.unwrap() {
8914            assert!(q.delete_clauses[0].detach);
8915            assert_eq!(q.delete_clauses[0].targets.len(), 1);
8916        } else {
8917            panic!("Expected Query");
8918        }
8919    }
8920
8921    // =========================================================================
8922    // Group 13: Graph Type Advanced Features (GG03, GG04, GG21)
8923    // =========================================================================
8924
8925    #[test]
8926    fn test_parse_create_graph_type_iso_syntax() {
8927        let mut parser = Parser::new(
8928            "CREATE GRAPH TYPE social (\
8929                NODE TYPE Person (name STRING NOT NULL, age INTEGER),\
8930                EDGE TYPE KNOWS (since INTEGER)\
8931            )",
8932        );
8933        let result = parser.parse();
8934        assert!(result.is_ok(), "Failed to parse ISO graph type: {result:?}");
8935        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
8936            assert_eq!(stmt.name, "social");
8937            assert_eq!(stmt.inline_types.len(), 2);
8938            assert!(stmt.node_types.contains(&"Person".to_string()));
8939            assert!(stmt.edge_types.contains(&"KNOWS".to_string()));
8940        } else {
8941            panic!("Expected CreateGraphType");
8942        }
8943    }
8944
8945    #[test]
8946    fn test_parse_create_graph_type_like() {
8947        let mut parser = Parser::new("CREATE GRAPH TYPE cloned LIKE original_graph");
8948        let result = parser.parse();
8949        assert!(result.is_ok(), "Failed to parse LIKE: {result:?}");
8950        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
8951            assert_eq!(stmt.name, "cloned");
8952            assert_eq!(stmt.like_graph, Some("original_graph".to_string()));
8953        } else {
8954            panic!("Expected CreateGraphType");
8955        }
8956    }
8957
8958    #[test]
8959    fn test_parse_create_graph_type_key_labels() {
8960        let mut parser = Parser::new(
8961            "CREATE GRAPH TYPE keyed (\
8962                NODE TYPE Person KEY (PersonLabel, NamedEntity) (name STRING NOT NULL)\
8963            )",
8964        );
8965        let result = parser.parse();
8966        assert!(result.is_ok(), "Failed to parse key labels: {result:?}");
8967        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
8968            assert_eq!(stmt.inline_types.len(), 1);
8969            match &stmt.inline_types[0] {
8970                InlineElementType::Node { key_labels, .. } => {
8971                    assert_eq!(key_labels.len(), 2);
8972                    assert_eq!(key_labels[0], "PersonLabel");
8973                    assert_eq!(key_labels[1], "NamedEntity");
8974                }
8975                _ => panic!("Expected Node"),
8976            }
8977        } else {
8978            panic!("Expected CreateGraphType");
8979        }
8980    }
8981
8982    // ==================== EXISTS bare pattern ====================
8983
8984    #[test]
8985    fn test_parse_exists_with_match() {
8986        // EXISTS with explicit MATCH (should already work)
8987        let mut parser = Parser::new("MATCH (n) WHERE EXISTS { MATCH (n)-[:KNOWS]->() } RETURN n");
8988        let result = parser.parse();
8989        assert!(result.is_ok(), "EXISTS with MATCH should parse: {result:?}");
8990    }
8991
8992    #[test]
8993    fn test_parse_exists_bare_pattern() {
8994        // Bare pattern without MATCH keyword
8995        let mut parser = Parser::new("MATCH (n) WHERE EXISTS { (n)-[:KNOWS]->() } RETURN n");
8996        let result = parser.parse();
8997        assert!(
8998            result.is_ok(),
8999            "EXISTS bare pattern should parse: {result:?}"
9000        );
9001    }
9002
9003    #[test]
9004    fn test_parse_exists_bare_pattern_with_where() {
9005        // Bare pattern with WHERE inside EXISTS
9006        let mut parser = Parser::new(
9007            "MATCH (a), (b) WHERE NOT EXISTS { (a)-[r]->(b) WHERE type(r) = 'KNOWS' } RETURN a",
9008        );
9009        let result = parser.parse();
9010        assert!(
9011            result.is_ok(),
9012            "EXISTS bare pattern with WHERE should parse: {result:?}"
9013        );
9014    }
9015
9016    // ==================== Pattern-form graph type syntax ====================
9017
9018    #[test]
9019    fn test_parse_graph_type_pattern_form_simple() {
9020        let mut parser = Parser::new(
9021            "CREATE GRAPH TYPE social (\
9022                (:Person {name STRING NOT NULL})-[:KNOWS {since INTEGER}]->(:Person)\
9023            )",
9024        );
9025        let result = parser.parse();
9026        assert!(
9027            result.is_ok(),
9028            "Pattern-form graph type should parse: {result:?}"
9029        );
9030        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
9031            assert_eq!(stmt.name, "social");
9032            assert!(stmt.node_types.contains(&"Person".to_string()));
9033            assert!(stmt.edge_types.contains(&"KNOWS".to_string()));
9034            // Should have Person node type and KNOWS edge type
9035            let node_count = stmt
9036                .inline_types
9037                .iter()
9038                .filter(|t| matches!(t, InlineElementType::Node { .. }))
9039                .count();
9040            let edge_count = stmt
9041                .inline_types
9042                .iter()
9043                .filter(|t| matches!(t, InlineElementType::Edge { .. }))
9044                .count();
9045            assert_eq!(
9046                node_count, 1,
9047                "Should have 1 node type (Person, deduplicated)"
9048            );
9049            assert_eq!(edge_count, 1, "Should have 1 edge type (KNOWS)");
9050            // Check KNOWS edge has source/target
9051            for t in &stmt.inline_types {
9052                if let InlineElementType::Edge {
9053                    name,
9054                    source_node_types,
9055                    target_node_types,
9056                    ..
9057                } = t
9058                {
9059                    assert_eq!(name, "KNOWS");
9060                    assert_eq!(source_node_types, &["Person"]);
9061                    assert_eq!(target_node_types, &["Person"]);
9062                }
9063            }
9064        } else {
9065            panic!("Expected CreateGraphType");
9066        }
9067    }
9068
9069    #[test]
9070    fn test_parse_graph_type_pattern_form_multiple_patterns() {
9071        let mut parser = Parser::new(
9072            "CREATE GRAPH TYPE social (\
9073                (:Person {name STRING NOT NULL})-[:KNOWS {since INTEGER}]->(:Person),\
9074                (:Person)-[:LIVES_IN]->(:City)\
9075            )",
9076        );
9077        let result = parser.parse();
9078        assert!(
9079            result.is_ok(),
9080            "Multiple pattern-form entries should parse: {result:?}"
9081        );
9082        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
9083            assert_eq!(stmt.name, "social");
9084            assert!(stmt.node_types.contains(&"Person".to_string()));
9085            assert!(stmt.node_types.contains(&"City".to_string()));
9086            assert!(stmt.edge_types.contains(&"KNOWS".to_string()));
9087            assert!(stmt.edge_types.contains(&"LIVES_IN".to_string()));
9088            // Person should appear only once despite being in two patterns
9089            let node_count = stmt
9090                .inline_types
9091                .iter()
9092                .filter(|t| matches!(t, InlineElementType::Node { .. }))
9093                .count();
9094            assert_eq!(node_count, 2, "Should have 2 node types (Person, City)");
9095        } else {
9096            panic!("Expected CreateGraphType");
9097        }
9098    }
9099
9100    #[test]
9101    fn test_parse_graph_type_pattern_form_standalone_node() {
9102        let mut parser = Parser::new(
9103            "CREATE GRAPH TYPE basic_nodes (\
9104                (:Person {name STRING})\
9105            )",
9106        );
9107        let result = parser.parse();
9108        assert!(
9109            result.is_ok(),
9110            "Standalone node pattern should parse: {result:?}"
9111        );
9112        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
9113            assert_eq!(stmt.inline_types.len(), 1);
9114            assert!(matches!(
9115                &stmt.inline_types[0],
9116                InlineElementType::Node { name, .. } if name == "Person"
9117            ));
9118        } else {
9119            panic!("Expected CreateGraphType");
9120        }
9121    }
9122
9123    #[test]
9124    fn test_parse_graph_type_pattern_form_no_props() {
9125        let mut parser = Parser::new(
9126            "CREATE GRAPH TYPE bare (\
9127                (:Person)-[:KNOWS]->(:Person)\
9128            )",
9129        );
9130        let result = parser.parse();
9131        assert!(
9132            result.is_ok(),
9133            "Pattern without properties should parse: {result:?}"
9134        );
9135        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
9136            // Node should have no properties
9137            for t in &stmt.inline_types {
9138                if let InlineElementType::Node { properties, .. } = t {
9139                    assert!(properties.is_empty());
9140                }
9141                if let InlineElementType::Edge { properties, .. } = t {
9142                    assert!(properties.is_empty());
9143                }
9144            }
9145        } else {
9146            panic!("Expected CreateGraphType");
9147        }
9148    }
9149
9150    #[test]
9151    fn test_parse_graph_type_pattern_form_backward_edge() {
9152        let mut parser = Parser::new(
9153            "CREATE GRAPH TYPE rev (\
9154                (:City)<-[:LIVES_IN]-(:Person)\
9155            )",
9156        );
9157        let result = parser.parse();
9158        assert!(
9159            result.is_ok(),
9160            "Backward edge pattern should parse: {result:?}"
9161        );
9162        if let Statement::Schema(SchemaStatement::CreateGraphType(stmt)) = result.unwrap() {
9163            for t in &stmt.inline_types {
9164                if let InlineElementType::Edge {
9165                    name,
9166                    source_node_types,
9167                    target_node_types,
9168                    ..
9169                } = t
9170                {
9171                    assert_eq!(name, "LIVES_IN");
9172                    // Backward: source is Person (right side), target is City (left side)
9173                    assert_eq!(source_node_types, &["Person"]);
9174                    assert_eq!(target_node_types, &["City"]);
9175                }
9176            }
9177        } else {
9178            panic!("Expected CreateGraphType");
9179        }
9180    }
9181
9182    // ==================== SHOW commands ====================
9183
9184    #[test]
9185    fn test_parse_show_constraints() {
9186        let mut parser = Parser::new("SHOW CONSTRAINTS");
9187        let result = parser.parse();
9188        assert!(result.is_ok(), "SHOW CONSTRAINTS should parse: {result:?}");
9189        assert!(matches!(
9190            result.unwrap(),
9191            Statement::Schema(SchemaStatement::ShowConstraints)
9192        ));
9193    }
9194
9195    #[test]
9196    fn test_parse_show_indexes() {
9197        let mut parser = Parser::new("SHOW INDEXES");
9198        let result = parser.parse();
9199        assert!(result.is_ok(), "SHOW INDEXES should parse: {result:?}");
9200        assert!(matches!(
9201            result.unwrap(),
9202            Statement::Schema(SchemaStatement::ShowIndexes)
9203        ));
9204    }
9205
9206    #[test]
9207    fn test_parse_show_index_singular() {
9208        // INDEX is a keyword token, so SHOW INDEX should also work
9209        let mut parser = Parser::new("SHOW INDEX");
9210        let result = parser.parse();
9211        assert!(result.is_ok(), "SHOW INDEX should parse: {result:?}");
9212        assert!(matches!(
9213            result.unwrap(),
9214            Statement::Schema(SchemaStatement::ShowIndexes)
9215        ));
9216    }
9217
9218    #[test]
9219    fn test_parse_show_node_types() {
9220        let mut parser = Parser::new("SHOW NODE TYPES");
9221        let result = parser.parse();
9222        assert!(result.is_ok(), "SHOW NODE TYPES should parse: {result:?}");
9223        assert!(matches!(
9224            result.unwrap(),
9225            Statement::Schema(SchemaStatement::ShowNodeTypes)
9226        ));
9227    }
9228
9229    #[test]
9230    fn test_parse_show_edge_types() {
9231        let mut parser = Parser::new("SHOW EDGE TYPES");
9232        let result = parser.parse();
9233        assert!(result.is_ok(), "SHOW EDGE TYPES should parse: {result:?}");
9234        assert!(matches!(
9235            result.unwrap(),
9236            Statement::Schema(SchemaStatement::ShowEdgeTypes)
9237        ));
9238    }
9239
9240    #[test]
9241    fn test_parse_show_graph_types() {
9242        let mut parser = Parser::new("SHOW GRAPH TYPES");
9243        let result = parser.parse();
9244        assert!(result.is_ok(), "SHOW GRAPH TYPES should parse: {result:?}");
9245        assert!(matches!(
9246            result.unwrap(),
9247            Statement::Schema(SchemaStatement::ShowGraphTypes)
9248        ));
9249    }
9250
9251    #[test]
9252    fn test_parse_show_graphs() {
9253        let mut parser = Parser::new("SHOW GRAPHS");
9254        let result = parser.parse();
9255        assert!(result.is_ok(), "SHOW GRAPHS should parse: {result:?}");
9256        assert!(matches!(
9257            result.unwrap(),
9258            Statement::Schema(SchemaStatement::ShowGraphs)
9259        ));
9260    }
9261
9262    #[test]
9263    fn test_parse_show_graph_type_named() {
9264        let mut parser = Parser::new("SHOW GRAPH TYPE social");
9265        let result = parser.parse();
9266        assert!(
9267            result.is_ok(),
9268            "SHOW GRAPH TYPE <name> should parse: {result:?}"
9269        );
9270        if let Statement::Schema(SchemaStatement::ShowGraphType(name)) = result.unwrap() {
9271            assert_eq!(name, "social");
9272        } else {
9273            panic!("Expected ShowGraphType");
9274        }
9275    }
9276
9277    // --- LOAD DATA ---
9278
9279    #[test]
9280    fn test_parse_load_data_csv() {
9281        let mut parser = Parser::new(
9282            "LOAD DATA FROM 'people.csv' FORMAT CSV WITH HEADERS AS row RETURN row.name",
9283        );
9284        let result = parser.parse();
9285        assert!(result.is_ok(), "LOAD DATA CSV parse failed: {result:?}");
9286        if let Statement::Query(query) = result.unwrap() {
9287            assert!(!query.ordered_clauses.is_empty());
9288            assert!(matches!(query.ordered_clauses[0], QueryClause::LoadData(_)));
9289            if let QueryClause::LoadData(ref ld) = query.ordered_clauses[0] {
9290                assert_eq!(ld.path, "people.csv");
9291                assert_eq!(ld.format, LoadFormat::Csv);
9292                assert!(ld.with_headers);
9293                assert_eq!(ld.variable, "row");
9294            }
9295        } else {
9296            panic!("Expected Query statement");
9297        }
9298    }
9299
9300    #[test]
9301    fn test_parse_load_data_csv_no_headers() {
9302        let mut parser = Parser::new("LOAD DATA FROM 'data.csv' FORMAT CSV AS r RETURN r[0]");
9303        let result = parser.parse();
9304        assert!(
9305            result.is_ok(),
9306            "LOAD DATA CSV no headers parse failed: {result:?}"
9307        );
9308        if let Statement::Query(query) = result.unwrap()
9309            && let QueryClause::LoadData(ref ld) = query.ordered_clauses[0]
9310        {
9311            assert!(!ld.with_headers);
9312            assert_eq!(ld.variable, "r");
9313        }
9314    }
9315
9316    #[test]
9317    fn test_parse_load_data_jsonl() {
9318        let mut parser =
9319            Parser::new("LOAD DATA FROM 'events.jsonl' FORMAT JSONL AS row RETURN row.title");
9320        let result = parser.parse();
9321        assert!(result.is_ok(), "LOAD DATA JSONL parse failed: {result:?}");
9322        if let Statement::Query(query) = result.unwrap()
9323            && let QueryClause::LoadData(ref ld) = query.ordered_clauses[0]
9324        {
9325            assert_eq!(ld.format, LoadFormat::Jsonl);
9326            assert_eq!(ld.path, "events.jsonl");
9327        }
9328    }
9329
9330    #[test]
9331    fn test_parse_load_data_ndjson() {
9332        let mut parser =
9333            Parser::new("LOAD DATA FROM 'data.ndjson' FORMAT NDJSON AS row RETURN row");
9334        let result = parser.parse();
9335        assert!(
9336            result.is_ok(),
9337            "LOAD DATA NDJSON alias parse failed: {result:?}"
9338        );
9339        if let Statement::Query(query) = result.unwrap()
9340            && let QueryClause::LoadData(ref ld) = query.ordered_clauses[0]
9341        {
9342            assert_eq!(ld.format, LoadFormat::Jsonl);
9343        }
9344    }
9345
9346    #[test]
9347    fn test_parse_load_data_parquet() {
9348        let mut parser =
9349            Parser::new("LOAD DATA FROM 'data.parquet' FORMAT PARQUET AS row RETURN row.id");
9350        let result = parser.parse();
9351        assert!(result.is_ok(), "LOAD DATA PARQUET parse failed: {result:?}");
9352        if let Statement::Query(query) = result.unwrap()
9353            && let QueryClause::LoadData(ref ld) = query.ordered_clauses[0]
9354        {
9355            assert_eq!(ld.format, LoadFormat::Parquet);
9356        }
9357    }
9358
9359    #[test]
9360    fn test_parse_load_csv_compat() {
9361        // Cypher-compatible LOAD CSV syntax in GQL parser
9362        let mut parser =
9363            Parser::new("LOAD CSV WITH HEADERS FROM 'file.csv' AS row RETURN row.name");
9364        let result = parser.parse();
9365        assert!(result.is_ok(), "LOAD CSV compat parse failed: {result:?}");
9366        if let Statement::Query(query) = result.unwrap()
9367            && let QueryClause::LoadData(ref ld) = query.ordered_clauses[0]
9368        {
9369            assert_eq!(ld.format, LoadFormat::Csv);
9370            assert!(ld.with_headers);
9371            assert_eq!(ld.path, "file.csv");
9372        }
9373    }
9374
9375    #[test]
9376    fn test_parse_load_data_with_fieldterminator() {
9377        let mut parser = Parser::new(
9378            "LOAD DATA FROM 'data.tsv' FORMAT CSV WITH HEADERS AS row FIELDTERMINATOR '\\t' RETURN row",
9379        );
9380        let result = parser.parse();
9381        assert!(
9382            result.is_ok(),
9383            "LOAD DATA with FIELDTERMINATOR parse failed: {result:?}"
9384        );
9385        if let Statement::Query(query) = result.unwrap()
9386            && let QueryClause::LoadData(ref ld) = query.ordered_clauses[0]
9387        {
9388            assert_eq!(ld.field_terminator, Some('\t'));
9389        }
9390    }
9391
9392    #[test]
9393    fn test_parse_load_data_with_insert() {
9394        let mut parser = Parser::new(
9395            "LOAD DATA FROM 'people.csv' FORMAT CSV WITH HEADERS AS row INSERT (:Person {name: row.name})",
9396        );
9397        let result = parser.parse();
9398        assert!(
9399            result.is_ok(),
9400            "LOAD DATA + INSERT parse failed: {result:?}"
9401        );
9402    }
9403
9404    #[test]
9405    fn test_parse_load_data_bad_format() {
9406        let mut parser = Parser::new("LOAD DATA FROM 'data.xml' FORMAT XML AS row RETURN row");
9407        let result = parser.parse();
9408        assert!(result.is_err(), "Should fail with unknown format XML");
9409    }
9410
9411    // --- T2-11: GQL keyword case-insensitivity ---
9412
9413    #[test]
9414    fn test_parse_lowercase_keywords() {
9415        // Lowercase GQL keywords should parse identically to uppercase
9416        let upper = Parser::new("MATCH (n:Person) WHERE n.age > 30 RETURN n.name")
9417            .parse()
9418            .unwrap();
9419        let lower = Parser::new("match (n:Person) where n.age > 30 return n.name")
9420            .parse()
9421            .unwrap();
9422
9423        // Both should be Query statements with the same structure
9424        let (Statement::Query(q_upper), Statement::Query(q_lower)) = (&upper, &lower) else {
9425            panic!("Expected Query statements");
9426        };
9427        assert_eq!(q_upper.match_clauses.len(), q_lower.match_clauses.len());
9428        assert!(q_upper.where_clause.is_some());
9429        assert!(q_lower.where_clause.is_some());
9430        assert_eq!(
9431            q_upper.return_clause.items.len(),
9432            q_lower.return_clause.items.len()
9433        );
9434    }
9435
9436    #[test]
9437    fn test_parse_mixed_case_keywords() {
9438        let result = Parser::new("Match (n:Person) Return n").parse();
9439        assert!(
9440            result.is_ok(),
9441            "Mixed-case keywords should parse: {result:?}"
9442        );
9443    }
9444
9445    // --- T2-12: Temporal literal parsing ---
9446
9447    #[test]
9448    fn test_parse_date_literal() {
9449        let mut parser = Parser::new("RETURN DATE '2024-01-15'");
9450        let result = parser.parse().unwrap();
9451        if let Statement::Query(query) = result {
9452            if let Expression::Literal(Literal::Date(s)) = &query.return_clause.items[0].expression
9453            {
9454                assert_eq!(s, "2024-01-15");
9455            } else {
9456                panic!(
9457                    "Expected Date literal, got: {:?}",
9458                    query.return_clause.items[0].expression
9459                );
9460            }
9461        } else {
9462            panic!("Expected Query statement");
9463        }
9464    }
9465
9466    #[test]
9467    fn test_parse_time_literal() {
9468        let mut parser = Parser::new("RETURN TIME '10:30:00'");
9469        let result = parser.parse().unwrap();
9470        if let Statement::Query(query) = result {
9471            if let Expression::Literal(Literal::Time(s)) = &query.return_clause.items[0].expression
9472            {
9473                assert_eq!(s, "10:30:00");
9474            } else {
9475                panic!(
9476                    "Expected Time literal, got: {:?}",
9477                    query.return_clause.items[0].expression
9478                );
9479            }
9480        } else {
9481            panic!("Expected Query statement");
9482        }
9483    }
9484
9485    #[test]
9486    fn test_parse_duration_literal() {
9487        let mut parser = Parser::new("RETURN DURATION 'P1Y2M'");
9488        let result = parser.parse().unwrap();
9489        if let Statement::Query(query) = result {
9490            if let Expression::Literal(Literal::Duration(s)) =
9491                &query.return_clause.items[0].expression
9492            {
9493                assert_eq!(s, "P1Y2M");
9494            } else {
9495                panic!(
9496                    "Expected Duration literal, got: {:?}",
9497                    query.return_clause.items[0].expression
9498                );
9499            }
9500        } else {
9501            panic!("Expected Query statement");
9502        }
9503    }
9504
9505    #[test]
9506    fn test_parse_datetime_literal() {
9507        let mut parser = Parser::new("RETURN DATETIME '2024-01-15T14:30:00'");
9508        let result = parser.parse().unwrap();
9509        if let Statement::Query(query) = result {
9510            if let Expression::Literal(Literal::Datetime(s)) =
9511                &query.return_clause.items[0].expression
9512            {
9513                assert_eq!(s, "2024-01-15T14:30:00");
9514            } else {
9515                panic!(
9516                    "Expected Datetime literal, got: {:?}",
9517                    query.return_clause.items[0].expression
9518                );
9519            }
9520        } else {
9521            panic!("Expected Query statement");
9522        }
9523    }
9524
9525    #[test]
9526    fn test_parse_zoned_datetime_literal() {
9527        let mut parser = Parser::new("RETURN ZONED DATETIME '2024-01-15T14:30:00+05:30'");
9528        let result = parser.parse().unwrap();
9529        if let Statement::Query(query) = result {
9530            if let Expression::Literal(Literal::ZonedDatetime(s)) =
9531                &query.return_clause.items[0].expression
9532            {
9533                assert_eq!(s, "2024-01-15T14:30:00+05:30");
9534            } else {
9535                panic!(
9536                    "Expected ZonedDatetime literal, got: {:?}",
9537                    query.return_clause.items[0].expression
9538                );
9539            }
9540        } else {
9541            panic!("Expected Query statement");
9542        }
9543    }
9544
9545    #[test]
9546    fn test_parse_zoned_time_literal() {
9547        let mut parser = Parser::new("RETURN ZONED TIME '14:30:00+01:00'");
9548        let result = parser.parse().unwrap();
9549        if let Statement::Query(query) = result {
9550            if let Expression::Literal(Literal::ZonedTime(s)) =
9551                &query.return_clause.items[0].expression
9552            {
9553                assert_eq!(s, "14:30:00+01:00");
9554            } else {
9555                panic!(
9556                    "Expected ZonedTime literal, got: {:?}",
9557                    query.return_clause.items[0].expression
9558                );
9559            }
9560        } else {
9561            panic!("Expected Query statement");
9562        }
9563    }
9564}