Skip to main content

oak_sql/builder/
mod.rs

1use crate::{SqlElementType, SqlLanguage, SqlParser, ast, ast::*, lexer::token_type::SqlTokenType};
2use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, OakError, Parser, Range, RedNode, RedTree, SourceText, TextEdit, builder::BuildOutput, source::Source};
3use std::sync::Arc;
4
5mod build_expression_tree;
6
7/// AST builder for SQL.
8///
9/// This builder is responsible for converting the generic syntax tree (green/red trees)
10/// into a strongly-typed SQL Abstract Syntax Tree (AST). It implements the [`Builder`]
11/// trait, allowing it to be used within the Oak incremental parsing framework.
12///
13/// # Usage
14///
15/// ```rust
16/// use oak_core::{Builder, source::SourceText};
17/// use oak_sql::{SqlBuilder, SqlLanguage};
18///
19/// let config = SqlLanguage::default();
20/// let builder = SqlBuilder::new(&config);
21/// // ... use builder to build AST from source
22/// ```
23#[derive(Clone)]
24pub struct SqlBuilder<'config> {
25    config: &'config SqlLanguage,
26}
27
28impl<'config> SqlBuilder<'config> {
29    /// Creates a new `SqlBuilder` with the specified language configuration.
30    pub fn new(config: &'config SqlLanguage) -> Self {
31        Self { config }
32    }
33}
34
35impl<'config> Builder<SqlLanguage> for SqlBuilder<'config> {
36    /// Builds the SQL AST from the source text and edits.
37    ///
38    /// This is the main entry point for the builder. It performs the following steps:
39    /// 1. Initializes a [`SqlParser`] with the current configuration.
40    /// 2. Executes the parser to produce a [`RedTree`] (Concrete Syntax Tree).
41    /// 3. Converts the resulting green tree into a typed [`SqlRoot`] AST.
42    /// 4. Handles incremental updates by passing `edits` to the parser.
43    ///
44    /// # Examples
45    ///
46    /// ```rust
47    /// use oak_core::{Builder, ParseSession, source::SourceText};
48    /// use oak_sql::{SqlBuilder, SqlLanguage};
49    ///
50    /// let config = SqlLanguage::default();
51    /// let builder = SqlBuilder::new(&config);
52    /// let mut cache = ParseSession::default();
53    /// let source = "SELECT * FROM users";
54    /// let output = builder.build(&source, &[], &mut cache);
55    ///
56    /// if let Ok(root) = output.result {
57    ///     assert_eq!(root.statements.len(), 1);
58    /// }
59    /// ```
60    ///
61    /// # Errors
62    ///
63    /// Returns an error if parsing fails or if the CST cannot be lowered to a valid AST.
64    fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], cache: &'a mut impl BuilderCache<SqlLanguage>) -> BuildOutput<SqlLanguage> {
65        let parser = SqlParser::new(self.config);
66        let parse_result = parser.parse(source, edits, cache);
67        let OakDiagnostics { result, diagnostics } = parse_result;
68
69        match result {
70            Ok(green_tree) => {
71                let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
72                match self.build_root(green_tree, &source_text) {
73                    Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics },
74                    Err(build_error) => {
75                        let mut diagnostics = diagnostics;
76                        diagnostics.push(build_error.clone());
77                        OakDiagnostics { result: Err(build_error), diagnostics }
78                    }
79                }
80            }
81            Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics },
82        }
83    }
84}
85
86impl<'config> SqlBuilder<'config> {
87    /// Builds the root SQL AST node from a green tree.
88    ///
89    /// This method performs the "lowering" phase where it traverses the untyped [`GreenNode`]
90    /// tree and constructs a structured [`SqlRoot`]. It maps each top-level child node
91    /// to its corresponding SQL statement type (SELECT, INSERT, etc.).
92    pub(crate) fn build_root<'a>(&self, green_tree: &'a GreenNode<'a, SqlLanguage>, source: &SourceText) -> Result<SqlRoot, OakError> {
93        let root_node = RedNode::new(green_tree, 0);
94        let mut statements = Vec::new();
95
96        for child in root_node.children() {
97            if let RedTree::Node(n) = child {
98                let res = match n.green.kind {
99                    SqlElementType::SelectStatement => self.build_select_statement(n, source).map(SqlStatement::Select),
100                    SqlElementType::InsertStatement => self.build_insert_statement(n, source).map(SqlStatement::Insert),
101                    SqlElementType::UpdateStatement => self.build_update_statement(n, source).map(SqlStatement::Update),
102                    SqlElementType::DeleteStatement => self.build_delete_statement(n, source).map(SqlStatement::Delete),
103                    SqlElementType::CreateStatement => self.build_create_statement(n, source).map(SqlStatement::Create),
104                    SqlElementType::DropStatement => self.build_drop_statement(n, source).map(SqlStatement::Drop),
105                    SqlElementType::AlterStatement => self.build_alter_statement(n, source).map(SqlStatement::Alter),
106                    _ => continue,
107                };
108
109                match res {
110                    Ok(stmt) => statements.push(stmt),
111                    Err(e) => {
112                        statements.push(SqlStatement::Error { message: Arc::from(e.to_string()), span: n.span() });
113                    }
114                }
115            }
116        }
117
118        Ok(SqlRoot { statements, span: root_node.span() })
119    }
120
121    /// Builds a `SELECT` statement AST node.
122    fn build_select_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<SelectStatement, OakError> {
123        let mut items = Vec::new();
124        let mut from = None;
125        let mut joins = Vec::new();
126        let mut expr = None;
127        let mut group_by = None;
128        let mut having = None;
129        let mut order_by = None;
130        let mut limit = None;
131
132        let mut where_found = false;
133
134        for child in node.children() {
135            match child {
136                RedTree::Node(n) => match n.green.kind {
137                    SqlElementType::SelectItem => items.push(self.build_select_item(n, source)?),
138                    SqlElementType::TableName => from = Some(self.build_table_name(n, source)?),
139                    SqlElementType::JoinClause => joins.push(self.build_join_clause(n, source)?),
140                    SqlElementType::GroupByClause => group_by = Some(self.build_group_by_clause(n, source)?),
141                    SqlElementType::HavingClause => having = Some(self.build_having_clause(n, source)?),
142                    SqlElementType::OrderByClause => order_by = Some(self.build_order_by_clause(n, source)?),
143                    SqlElementType::LimitClause => limit = Some(self.build_limit_clause(n, source)?),
144                    SqlElementType::Expression => {
145                        if where_found && expr.is_none() {
146                            expr = Some(self.build_expression(n, source)?);
147                        }
148                    }
149                    _ => {}
150                },
151                RedTree::Leaf(t) => {
152                    if t.kind == SqlTokenType::Where {
153                        where_found = true;
154                    }
155                }
156            }
157        }
158
159        Ok(SelectStatement { items, from, joins, expr, group_by, having, order_by, limit, span: node.span() })
160    }
161
162    /// Builds a select item (column or expression) for a `SELECT` statement.
163    fn build_select_item<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<SelectItem, OakError> {
164        let mut expr = None;
165        let mut alias = None;
166        let mut is_star = false;
167
168        for child in node.children() {
169            match child {
170                RedTree::Leaf(t) => match t.kind {
171                    SqlTokenType::Star => is_star = true,
172                    SqlTokenType::Identifier_ => {
173                        if expr.is_none() {
174                            expr = Some(Expression::Identifier(Identifier { name: self.get_text(t.span.clone(), source), span: t.span.clone() }));
175                        }
176                        else {
177                            alias = Some(Identifier { name: self.get_text(t.span.clone(), source), span: t.span.clone() });
178                        }
179                    }
180                    _ => {}
181                },
182                RedTree::Node(n) => match n.green.kind {
183                    SqlElementType::Expression => expr = Some(self.build_expression(n, source)?),
184                    SqlElementType::Identifier => {
185                        if expr.is_none() {
186                            expr = Some(Expression::Identifier(self.build_identifier(n, source)?));
187                        }
188                        else {
189                            alias = Some(self.build_identifier(n, source)?);
190                        }
191                    }
192                    SqlElementType::Alias => alias = Some(self.build_identifier(n, source)?),
193                    _ => {}
194                },
195            }
196        }
197
198        if is_star { Ok(SelectItem::Star { span: node.span() }) } else { Ok(SelectItem::Expression { expr: expr.ok_or_else(|| OakError::custom_error("Missing expression in select item"))?, alias, span: node.span() }) }
199    }
200
201    /// Builds an `INSERT` statement AST node.
202    fn build_insert_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<InsertStatement, OakError> {
203        let mut table_name = None;
204        let mut columns = Vec::new();
205        let mut values = Vec::new();
206
207        for child in node.children() {
208            if let RedTree::Node(n) = child {
209                match n.green.kind {
210                    SqlElementType::TableName => table_name = Some(self.build_table_name(n, source)?),
211                    SqlElementType::ColumnName => {
212                        for sub in n.children() {
213                            match sub {
214                                RedTree::Node(sn) if sn.green.kind == SqlElementType::Identifier => {
215                                    columns.push(self.build_identifier(sn, source)?);
216                                }
217                                RedTree::Leaf(st) if st.kind == SqlTokenType::Identifier_ => {
218                                    columns.push(Identifier { name: self.get_text(st.span.clone(), source), span: st.span.clone() });
219                                }
220                                _ => {}
221                            }
222                        }
223                    }
224                    SqlElementType::ValueList => {
225                        self.collect_expressions(n, source, &mut values)?;
226                    }
227                    _ => {}
228                }
229            }
230        }
231
232        Ok(InsertStatement { table_name: table_name.ok_or_else(|| OakError::custom_error("Missing table name in INSERT"))?, columns, values, span: node.span() })
233    }
234
235    /// Collects expressions from a node into a vector.
236    fn collect_expressions<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText, out: &mut Vec<Expression>) -> Result<(), OakError> {
237        for child in node.children() {
238            if let RedTree::Node(n) = child {
239                match n.green.kind {
240                    SqlElementType::Expression => out.push(self.build_expression(n, source)?),
241                    SqlElementType::Identifier => out.push(Expression::Identifier(self.build_identifier(n, source)?)),
242                    SqlElementType::ValueList => self.collect_expressions(n, source, out)?,
243                    _ => {}
244                }
245            }
246        }
247        Ok(())
248    }
249
250    /// Builds an `UPDATE` statement AST node.
251    fn build_update_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<UpdateStatement, OakError> {
252        let mut table_name: Option<TableName> = None;
253        let mut assignments = Vec::new();
254        let mut selection = None;
255
256        for child in node.children() {
257            match child {
258                RedTree::Leaf(t) => match t.kind {
259                    SqlTokenType::Set => {}
260                    SqlTokenType::Identifier_ => {
261                        if table_name.is_none() {
262                            let ident = Identifier { name: self.get_text(t.span.clone(), source), span: t.span.clone() };
263                            table_name = Some(TableName { name: ident, span: t.span.clone() });
264                        }
265                    }
266                    _ => {}
267                },
268                RedTree::Node(n) => match n.green.kind {
269                    SqlElementType::TableName => table_name = Some(self.build_table_name(n, source)?),
270                    SqlElementType::Assignment => assignments.push(self.build_assignment(n, source)?),
271                    SqlElementType::Expression => selection = Some(self.build_expression(n, source)?),
272                    _ => {}
273                },
274            }
275        }
276
277        Ok(UpdateStatement { table_name: table_name.ok_or_else(|| OakError::custom_error("Missing table name in UPDATE"))?, assignments, selection, span: node.span() })
278    }
279
280    /// Builds an assignment (column = expression) for an `UPDATE` statement.
281    fn build_assignment<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<Assignment, OakError> {
282        let mut column = None;
283        let mut value = None;
284
285        for child in node.children() {
286            if let RedTree::Node(n) = child {
287                match n.green.kind {
288                    SqlElementType::ColumnName => column = Some(self.build_identifier(n, source)?),
289                    SqlElementType::Expression => value = Some(self.build_expression(n, source)?),
290                    _ => {}
291                }
292            }
293        }
294
295        Ok(Assignment { column: column.ok_or_else(|| OakError::custom_error("Missing column in assignment"))?, value: value.ok_or_else(|| OakError::custom_error("Missing value in assignment"))?, span: node.span() })
296    }
297
298    /// Builds a `DELETE` statement AST node.
299    fn build_delete_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<DeleteStatement, OakError> {
300        let mut table_name = None;
301        let mut selection = None;
302
303        for child in node.children() {
304            match child {
305                RedTree::Leaf(t) => {
306                    if t.kind == SqlTokenType::From {
307                        // skip
308                    }
309                }
310                RedTree::Node(n) => match n.green.kind {
311                    SqlElementType::TableName => table_name = Some(self.build_table_name(n, source)?),
312                    SqlElementType::Expression => selection = Some(self.build_expression(n, source)?),
313                    _ => {}
314                },
315            }
316        }
317
318        Ok(DeleteStatement { table_name: table_name.ok_or_else(|| OakError::custom_error("Missing table name in DELETE"))?, selection, span: node.span() })
319    }
320
321    /// Builds a `CREATE` statement AST node.
322    fn build_create_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<CreateStatement, OakError> {
323        let mut object_type = CreateObjectType::Table;
324        let mut name = None;
325        let mut if_not_exists = false;
326        let mut columns = Vec::new();
327        let mut query = None;
328        let mut table_name = None;
329        let mut index_columns = Vec::new();
330        let mut unique = false;
331
332        for child in node.children() {
333            match child {
334                RedTree::Leaf(t) => match t.kind {
335                    SqlTokenType::Table => object_type = CreateObjectType::Table,
336                    SqlTokenType::View => object_type = CreateObjectType::View,
337                    SqlTokenType::Index => object_type = CreateObjectType::Index,
338                    SqlTokenType::Database => object_type = CreateObjectType::Database,
339                    SqlTokenType::Exists => if_not_exists = true,
340                    SqlTokenType::Unique => unique = true,
341                    _ => {
342                        if object_type == CreateObjectType::Index && name.is_some() && table_name.is_some() && t.kind == SqlTokenType::Identifier_ {
343                            index_columns.push(ast::Identifier { name: self.get_text(t.span.clone(), source), span: t.span.clone() });
344                        }
345                    }
346                },
347                RedTree::Node(n) => match n.green.kind {
348                    SqlElementType::TableName => {
349                        if object_type == CreateObjectType::Index && name.is_some() {
350                            table_name = Some(self.build_table_name(n, source)?);
351                        }
352                        else {
353                            name = Some(self.build_identifier(n, source)?);
354                        }
355                    }
356                    SqlElementType::Identifier => {
357                        if object_type == CreateObjectType::Index && name.is_some() && table_name.is_none() {
358                            table_name = Some(ast::TableName { name: self.build_identifier(n, source)?, span: n.span() });
359                        }
360                        else if name.is_none() {
361                            name = Some(self.build_identifier(n, source)?);
362                        }
363                        else if object_type == CreateObjectType::Index {
364                            index_columns.push(self.build_identifier(n, source)?);
365                        }
366                    }
367                    SqlElementType::ColumnDefinition => {
368                        columns.push(self.build_column_definition(n, source)?);
369                    }
370                    SqlElementType::SelectStatement => {
371                        query = Some(self.build_select_statement(n, source)?);
372                    }
373                    _ => {}
374                },
375            }
376        }
377
378        let body = match object_type {
379            CreateObjectType::Table => CreateBody::Table { columns, span: node.span() },
380            CreateObjectType::View => CreateBody::View { query: Box::new(query.ok_or_else(|| OakError::custom_error("Missing query in CREATE VIEW"))?), span: node.span() },
381            CreateObjectType::Index => CreateBody::Index { table_name: table_name.ok_or_else(|| OakError::custom_error("Missing table name in CREATE INDEX"))?, columns: index_columns, unique, span: node.span() },
382            CreateObjectType::Database => CreateBody::Database { span: node.span() },
383        };
384
385        let result = CreateStatement { object_type, name: name.ok_or_else(|| OakError::custom_error("Missing name in CREATE"))?, if_not_exists, body, span: node.span() };
386        Ok(result)
387    }
388
389    fn build_column_definition<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<ColumnDefinition, OakError> {
390        let mut name = None;
391        let mut data_type_str = String::new();
392        let mut constraints = Vec::new();
393
394        // Use a flag to track if we are currently parsing the data type
395        let mut parsing_data_type = false;
396
397        for child in node.children() {
398            match child {
399                RedTree::Node(n) => match n.green.kind {
400                    SqlElementType::ColumnName | SqlElementType::Identifier => {
401                        if name.is_none() {
402                            name = Some(self.build_identifier(n, source)?);
403                            parsing_data_type = true;
404                        }
405                        else if parsing_data_type {
406                            if !data_type_str.is_empty() {
407                                data_type_str.push(' ');
408                            }
409                            data_type_str.push_str(self.get_text(n.span(), source).trim());
410                        }
411                    }
412                    _ => {}
413                },
414                RedTree::Leaf(t) => {
415                    match t.kind {
416                        SqlTokenType::Primary => {
417                            constraints.push(ColumnConstraint::PrimaryKey { span: t.span.clone() });
418                            parsing_data_type = false;
419                        }
420                        SqlTokenType::Key => {
421                            // Part of PRIMARY KEY, stop parsing data type if we haven't already
422                            parsing_data_type = false;
423                        }
424                        SqlTokenType::Not => {
425                            constraints.push(ColumnConstraint::NotNull { span: t.span.clone() });
426                            parsing_data_type = false;
427                        }
428                        SqlTokenType::Null => {
429                            // Check if NOT NULL was just added
430                            let mut is_not_null = false;
431                            if let Some(ColumnConstraint::NotNull { .. }) = constraints.last() {
432                                is_not_null = true;
433                            }
434
435                            if !is_not_null {
436                                constraints.push(ColumnConstraint::Nullable { span: t.span.clone() });
437                            }
438                            parsing_data_type = false;
439                        }
440                        SqlTokenType::Unique => {
441                            constraints.push(ColumnConstraint::Unique { span: t.span.clone() });
442                            parsing_data_type = false;
443                        }
444                        SqlTokenType::AutoIncrement => {
445                            constraints.push(ColumnConstraint::AutoIncrement { span: t.span.clone() });
446                            parsing_data_type = false;
447                        }
448                        SqlTokenType::Default => {
449                            parsing_data_type = false;
450                            // The expression follows Default token in column definition
451                            if let Some(expr_node) = self.find_next_node_in_parent(node.clone(), SqlElementType::Expression, t.span.end) {
452                                constraints.push(ColumnConstraint::Default(self.build_expression(expr_node, source)?, t.span.clone()));
453                            }
454                        }
455                        SqlTokenType::Check => {
456                            parsing_data_type = false;
457                            // The expression follows Check token in column definition
458                            if let Some(expr_node) = self.find_next_node_in_parent(node.clone(), SqlElementType::Expression, t.span.end) {
459                                constraints.push(ColumnConstraint::Check(self.build_expression(expr_node, source)?, t.span.clone()));
460                            }
461                        }
462                        _ if parsing_data_type => {
463                            if !data_type_str.is_empty() {
464                                data_type_str.push(' ');
465                            }
466                            data_type_str.push_str(self.get_text(t.span.clone(), source).trim());
467                        }
468                        _ => {}
469                    }
470                }
471            }
472        }
473
474        Ok(ColumnDefinition { name: name.ok_or_else(|| OakError::custom_error("Missing name in column definition"))?, data_type: Arc::from(data_type_str), constraints, span: node.span() })
475    }
476
477    /// Helper to find the next node of a specific kind after a certain position
478    fn find_next_node_in_parent<'a>(&self, parent: RedNode<'a, SqlLanguage>, kind: SqlElementType, after_pos: usize) -> Option<RedNode<'a, SqlLanguage>> {
479        for child in parent.children() {
480            if let RedTree::Node(n) = child {
481                if n.green.kind == kind && n.span().start >= after_pos {
482                    return Some(n);
483                }
484            }
485        }
486        None
487    }
488
489    fn build_drop_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<DropStatement, OakError> {
490        let mut object_type = DropObjectType::Table;
491        let mut name = None;
492        let mut if_exists = false;
493
494        for child in node.children() {
495            match child {
496                RedTree::Leaf(t) => match t.kind {
497                    SqlTokenType::Table => object_type = DropObjectType::Table,
498                    SqlTokenType::View => object_type = DropObjectType::View,
499                    SqlTokenType::Index => object_type = DropObjectType::Index,
500                    SqlTokenType::Database => object_type = DropObjectType::Database,
501                    SqlTokenType::Exists => if_exists = true,
502                    _ => {}
503                },
504                RedTree::Node(n) => {
505                    if n.green.kind == SqlElementType::TableName || n.green.kind == SqlElementType::Identifier {
506                        name = Some(self.build_identifier(n, source)?);
507                    }
508                }
509            }
510        }
511
512        let result = DropStatement { object_type, name: name.ok_or_else(|| OakError::custom_error("Missing name in DROP"))?, if_exists, span: node.span() };
513        Ok(result)
514    }
515
516    fn build_alter_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<AlterStatement, OakError> {
517        let mut table_name = None;
518        let mut action = None;
519
520        for child in node.children() {
521            if let RedTree::Node(n) = child {
522                if n.green.kind == SqlElementType::TableName {
523                    table_name = Some(self.build_table_name(n, source)?);
524                }
525                else if n.green.kind == SqlElementType::AlterAction {
526                    action = Some(self.build_alter_action(n, source)?);
527                }
528            }
529        }
530
531        let result = AlterStatement { table_name: table_name.ok_or_else(|| OakError::custom_error("Missing table name in ALTER"))?, action, span: node.span() };
532        Ok(result)
533    }
534
535    fn build_alter_action<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<ast::AlterAction, OakError> {
536        use SqlTokenType::*;
537        let mut is_add = false;
538        let mut is_drop = false;
539        let mut is_rename = false;
540        let mut identifier: Option<ast::Identifier> = None;
541        let mut data_type_tokens = Vec::new();
542
543        for child in node.children() {
544            match child {
545                RedTree::Leaf(t) => match t.kind {
546                    Add => is_add = true,
547                    Drop => is_drop = true,
548                    Rename => is_rename = true,
549                    Identifier_ => {
550                        if identifier.is_none() {
551                            identifier = Some(ast::Identifier { name: self.get_text(t.span.clone(), source), span: t.span.clone() });
552                        }
553                        else if is_add {
554                            data_type_tokens.push(t.span.clone());
555                        }
556                    }
557                    LeftParen | RightParen | NumberLiteral | Comma | Int | Integer | Varchar | Char | Text | Date | Time | Timestamp | Decimal | Float | Double | Boolean => {
558                        if is_add && identifier.is_some() {
559                            data_type_tokens.push(t.span.clone());
560                        }
561                    }
562                    _ => {}
563                },
564                RedTree::Node(n) if n.green.kind == SqlElementType::Identifier => {
565                    identifier = Some(self.build_identifier(n, source)?);
566                }
567                _ => {}
568            }
569        }
570
571        let data_type = if data_type_tokens.is_empty() {
572            None
573        }
574        else {
575            let start = data_type_tokens[0].start;
576            let end = data_type_tokens.last().unwrap().end;
577            Some(self.get_text(Range { start, end }, source))
578        };
579
580        if is_add {
581            Ok(ast::AlterAction::AddColumn { name: identifier.ok_or_else(|| OakError::custom_error("Missing column name in ALTER TABLE ADD"))?, data_type, span: node.span() })
582        }
583        else if is_drop {
584            Ok(ast::AlterAction::DropColumn { name: identifier.ok_or_else(|| OakError::custom_error("Missing column name in ALTER TABLE DROP"))?, span: node.span() })
585        }
586        else if is_rename {
587            Ok(ast::AlterAction::RenameTo { new_name: identifier.ok_or_else(|| OakError::custom_error("Missing new name in ALTER TABLE RENAME"))?, span: node.span() })
588        }
589        else {
590            Err(OakError::custom_error("Unknown ALTER action"))
591        }
592    }
593
594    fn build_table_name<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<TableName, OakError> {
595        let mut name = None;
596        for child in node.children() {
597            match child {
598                RedTree::Leaf(t) if t.kind == SqlTokenType::Identifier_ => {
599                    name = Some(Identifier { name: self.get_text(t.span.clone(), source), span: t.span.clone() });
600                }
601                RedTree::Node(n) if n.green.kind == SqlElementType::Identifier => {
602                    name = Some(self.build_identifier(n, source)?);
603                }
604                _ => {}
605            }
606        }
607        Ok(TableName { name: name.ok_or_else(|| OakError::custom_error("Missing table name"))?, span: node.span() })
608    }
609
610    fn build_identifier<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<Identifier, OakError> {
611        Ok(Identifier { name: self.get_text(node.span(), source), span: node.span() })
612    }
613
614    fn build_join_clause<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<JoinClause, OakError> {
615        let mut join_type = JoinType::Inner;
616        let mut table = None;
617        let mut on = None;
618
619        for child in node.children() {
620            match child {
621                RedTree::Leaf(t) => match t.kind {
622                    SqlTokenType::Inner => join_type = JoinType::Inner,
623                    SqlTokenType::Left => join_type = JoinType::Left,
624                    SqlTokenType::Right => join_type = JoinType::Right,
625                    SqlTokenType::Full => join_type = JoinType::Full,
626                    _ => {}
627                },
628                RedTree::Node(n) => match n.green.kind {
629                    SqlElementType::TableName => table = Some(self.build_table_name(n, source)?),
630                    SqlElementType::Expression => on = Some(self.build_expression(n, source)?),
631                    _ => {}
632                },
633            }
634        }
635
636        Ok(JoinClause { join_type, table: table.ok_or_else(|| OakError::custom_error("Missing table in JOIN"))?, on, span: node.span() })
637    }
638
639    fn build_group_by_clause<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<GroupByClause, OakError> {
640        let mut columns = Vec::new();
641        for child in node.children() {
642            if let RedTree::Node(n) = child {
643                if n.green.kind == SqlElementType::Expression {
644                    columns.push(self.build_expression(n, source)?);
645                }
646            }
647        }
648        Ok(GroupByClause { columns, span: node.span() })
649    }
650
651    fn build_having_clause<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<HavingClause, OakError> {
652        let mut condition = None;
653        for child in node.children() {
654            if let RedTree::Node(n) = child {
655                if n.green.kind == SqlElementType::Expression {
656                    condition = Some(self.build_expression(n, source)?);
657                }
658            }
659        }
660        Ok(HavingClause { condition: condition.ok_or_else(|| OakError::custom_error("Missing condition in HAVING"))?, span: node.span() })
661    }
662
663    fn build_order_by_clause<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<OrderByClause, OakError> {
664        let mut items = Vec::new();
665        let mut current_expr: Option<(Expression, Range<usize>)> = None;
666
667        for child in node.children() {
668            match child {
669                RedTree::Node(n) => {
670                    if n.green.kind == SqlElementType::Expression {
671                        if let Some((expr, span)) = current_expr.take() {
672                            items.push(OrderByItem { expr, direction: OrderDirection::Asc, span });
673                        }
674                        current_expr = Some((self.build_expression(n.clone(), source)?, n.span()));
675                    }
676                }
677                RedTree::Leaf(t) => match t.kind {
678                    SqlTokenType::Asc => {
679                        if let Some((expr, span)) = current_expr.take() {
680                            let total_span = Range { start: span.start, end: t.span.end };
681                            items.push(OrderByItem { expr, direction: OrderDirection::Asc, span: total_span });
682                        }
683                    }
684                    SqlTokenType::Desc => {
685                        if let Some((expr, span)) = current_expr.take() {
686                            let total_span = Range { start: span.start, end: t.span.end };
687                            items.push(OrderByItem { expr, direction: OrderDirection::Desc, span: total_span });
688                        }
689                    }
690                    _ => {}
691                },
692            }
693        }
694
695        if let Some((expr, span)) = current_expr {
696            items.push(OrderByItem { expr, direction: OrderDirection::Asc, span });
697        }
698
699        Ok(OrderByClause { items, span: node.span() })
700    }
701
702    fn build_limit_clause<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<LimitClause, OakError> {
703        let mut limit = None;
704        let mut offset = None;
705
706        for child in node.children() {
707            if let RedTree::Leaf(t) = child {
708                if t.kind == SqlTokenType::NumberLiteral {
709                    let expr = Expression::Literal(Literal::Number(self.get_text(t.span.clone(), source), t.span.clone()));
710                    if limit.is_none() {
711                        limit = Some(expr);
712                    }
713                    else {
714                        offset = Some(expr);
715                    }
716                }
717            }
718            else if let RedTree::Node(n) = child {
719                if n.green.kind == SqlElementType::Expression {
720                    let expr = self.build_expression(n, source)?;
721                    if limit.is_none() {
722                        limit = Some(expr);
723                    }
724                    else {
725                        offset = Some(expr);
726                    }
727                }
728            }
729        }
730
731        Ok(LimitClause { limit: limit.ok_or_else(|| OakError::custom_error("Missing limit value"))?, offset, span: node.span() })
732    }
733
734    fn build_statement<'a>(&self, node: RedNode<'a, SqlLanguage>, source: &SourceText) -> Result<SqlStatement, OakError> {
735        match node.green.kind {
736            SqlElementType::SelectStatement => Ok(SqlStatement::Select(self.build_select_statement(node, source)?)),
737            SqlElementType::InsertStatement => Ok(SqlStatement::Insert(self.build_insert_statement(node, source)?)),
738            SqlElementType::UpdateStatement => Ok(SqlStatement::Update(self.build_update_statement(node, source)?)),
739            SqlElementType::DeleteStatement => Ok(SqlStatement::Delete(self.build_delete_statement(node, source)?)),
740            SqlElementType::CreateStatement => Ok(SqlStatement::Create(self.build_create_statement(node, source)?)),
741            SqlElementType::DropStatement => Ok(SqlStatement::Drop(self.build_drop_statement(node, source)?)),
742            SqlElementType::AlterStatement => Ok(SqlStatement::Alter(self.build_alter_statement(node, source)?)),
743            _ => Err(OakError::custom_error("Unknown statement type")),
744        }
745    }
746
747    fn get_text(&self, span: core::range::Range<usize>, source: &SourceText) -> Arc<str> {
748        Arc::from(source.get_text_in(span))
749    }
750
751    fn map_unary_op(&self, kind: SqlTokenType) -> Option<UnaryOperator> {
752        match kind {
753            SqlTokenType::Plus => Some(UnaryOperator::Plus),
754            SqlTokenType::Minus => Some(UnaryOperator::Minus),
755            SqlTokenType::Not => Some(UnaryOperator::Not),
756            _ => None,
757        }
758    }
759
760    fn map_binary_op(&self, kind: SqlTokenType) -> Option<BinaryOperator> {
761        match kind {
762            SqlTokenType::Plus => Some(BinaryOperator::Plus),
763            SqlTokenType::Minus => Some(BinaryOperator::Minus),
764            SqlTokenType::Star => Some(BinaryOperator::Star),
765            SqlTokenType::Slash => Some(BinaryOperator::Slash),
766            SqlTokenType::Equal => Some(BinaryOperator::Equal),
767            SqlTokenType::NotEqual => Some(BinaryOperator::NotEqual),
768            SqlTokenType::Less => Some(BinaryOperator::Less),
769            SqlTokenType::LessEqual => Some(BinaryOperator::LessEqual),
770            SqlTokenType::Greater => Some(BinaryOperator::Greater),
771            SqlTokenType::GreaterEqual => Some(BinaryOperator::GreaterEqual),
772            SqlTokenType::And => Some(BinaryOperator::And),
773            SqlTokenType::Or => Some(BinaryOperator::Or),
774            _ => None,
775        }
776    }
777}