Parse a GQL query or statement into an AST Document
(input: &str)
| 93 | |
| 94 | /// Parse a GQL query or statement into an AST Document |
| 95 | pub fn parse_query(input: &str) -> Result<Document, ParserError> { |
| 96 | // Debug: Print query text if it contains GROUP BY |
| 97 | if input.contains("GROUP BY") { |
| 98 | log::debug!( |
| 99 | "PARSER: Parsing query with GROUP BY: {}", |
| 100 | input.trim().split('\n').collect::<Vec<_>>().join(" ") |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | // First tokenize the input |
| 105 | let mut tokens = tokenize(input).map_err(ParserError::LexerError)?; |
| 106 | |
| 107 | // Filter out SQL-style comments at the parser level |
| 108 | tokens = filter_sql_comments(tokens); |
| 109 | |
| 110 | // Debug: Check if GROUP BY tokens exist |
| 111 | if input.contains("GROUP BY") { |
| 112 | let has_group_token = tokens.iter().any(|t| matches!(t, Token::Group)); |
| 113 | let has_by_token = tokens.iter().any(|t| matches!(t, Token::By)); |
| 114 | log::debug!( |
| 115 | "PARSER: Token stream has GROUP={}, BY={}", |
| 116 | has_group_token, |
| 117 | has_by_token |
| 118 | ); |
| 119 | } |
| 120 | |
| 121 | // Check for invalid DELETE SCHEMA and DELETE GRAPH patterns before parsing |
| 122 | if tokens.len() >= 2 { |
| 123 | match (&tokens[0], &tokens[1]) { |
| 124 | (Token::Delete, Token::Schema) => { |
| 125 | return Err(ParserError::InvalidDeleteSchema); |
| 126 | } |
| 127 | (Token::Delete, Token::Graph) => { |
| 128 | return Err(ParserError::InvalidDeleteGraph); |
| 129 | } |
| 130 | _ => {} |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | // Check for incomplete set operations (trailing keywords without right-hand side) |
| 135 | // Look for set operation keywords followed by EOF or at the end |
| 136 | for i in 0..tokens.len() { |
| 137 | match &tokens[i] { |
| 138 | Token::Union => { |
| 139 | // Check if this is followed by EOF or is the last meaningful token |
| 140 | if i + 1 >= tokens.len() || matches!(tokens.get(i + 1), Some(Token::Eof) | None) { |
| 141 | return Err(ParserError::IncompleteUnion); |
| 142 | } |
| 143 | } |
| 144 | Token::Except => { |
| 145 | if i + 1 >= tokens.len() || matches!(tokens.get(i + 1), Some(Token::Eof) | None) { |
| 146 | return Err(ParserError::IncompleteExcept); |
| 147 | } |
| 148 | } |
| 149 | Token::Intersect => { |
| 150 | if i + 1 >= tokens.len() || matches!(tokens.get(i + 1), Some(Token::Eof) | None) { |
| 151 | return Err(ParserError::IncompleteIntersect); |
| 152 | } |