1use crate::ast::*;
17use aegis_common::{AegisError, DataType, Result};
18use sqlparser::ast as sp;
19use sqlparser::dialect::GenericDialect;
20use sqlparser::parser::Parser as SqlParser;
21
22pub struct Parser {
28 dialect: GenericDialect,
29}
30
31impl Parser {
32 pub fn new() -> Self {
33 Self {
34 dialect: GenericDialect {},
35 }
36 }
37
38 pub fn parse(&self, sql: &str) -> Result<Vec<Statement>> {
40 let ast = SqlParser::parse_sql(&self.dialect, sql)
41 .map_err(|e| AegisError::Parse(e.to_string()))?;
42
43 ast.into_iter().map(|stmt| self.convert_statement(stmt)).collect()
44 }
45
46 pub fn parse_single(&self, sql: &str) -> Result<Statement> {
48 let statements = self.parse(sql)?;
49 if statements.len() != 1 {
50 return Err(AegisError::Parse(format!(
51 "Expected 1 statement, got {}",
52 statements.len()
53 )));
54 }
55 Ok(statements.into_iter().next().expect("statements verified to have exactly 1 element"))
57 }
58
59 fn convert_statement(&self, stmt: sp::Statement) -> Result<Statement> {
60 match stmt {
61 sp::Statement::Query(query) => {
62 let select = self.convert_query(*query)?;
63 Ok(Statement::Select(select))
64 }
65 sp::Statement::Insert(insert) => {
66 let insert_stmt = self.convert_insert(insert)?;
67 Ok(Statement::Insert(insert_stmt))
68 }
69 sp::Statement::Update { table, assignments, from: _, selection, returning: _, .. } => {
70 let update_stmt = self.convert_update(table, assignments, selection)?;
71 Ok(Statement::Update(update_stmt))
72 }
73 sp::Statement::Delete(delete) => {
74 let delete_stmt = self.convert_delete(delete)?;
75 Ok(Statement::Delete(delete_stmt))
76 }
77 sp::Statement::CreateTable(create) => {
78 let create_stmt = self.convert_create_table(create)?;
79 Ok(Statement::CreateTable(create_stmt))
80 }
81 sp::Statement::Drop { object_type, if_exists, names, .. } => {
82 self.convert_drop(object_type, if_exists, names)
83 }
84 sp::Statement::CreateIndex(create) => {
85 let create_stmt = self.convert_create_index(create)?;
86 Ok(Statement::CreateIndex(create_stmt))
87 }
88 sp::Statement::AlterTable { name, operations, .. } => {
89 let alter_stmt = self.convert_alter_table(name, operations)?;
90 Ok(Statement::AlterTable(alter_stmt))
91 }
92 sp::Statement::StartTransaction { .. } => Ok(Statement::Begin),
93 sp::Statement::Commit { .. } => Ok(Statement::Commit),
94 sp::Statement::Rollback { .. } => Ok(Statement::Rollback),
95 _ => Err(AegisError::Parse(format!(
96 "Unsupported statement type: {:?}",
97 stmt
98 ))),
99 }
100 }
101
102 fn convert_query(&self, query: sp::Query) -> Result<SelectStatement> {
103 let body = match *query.body {
104 sp::SetExpr::Select(select) => select,
105 _ => return Err(AegisError::Parse("Unsupported query type".to_string())),
106 };
107
108 let columns = body
109 .projection
110 .into_iter()
111 .map(|item| self.convert_select_item(item))
112 .collect::<Result<Vec<_>>>()?;
113
114 let from = if !body.from.is_empty() {
115 Some(self.convert_from(&body.from)?)
116 } else {
117 None
118 };
119
120 let where_clause = body
121 .selection
122 .map(|expr| self.convert_expr(expr))
123 .transpose()?;
124
125 let group_by = match body.group_by {
126 sp::GroupByExpr::Expressions(exprs, _) => exprs
127 .into_iter()
128 .map(|e| self.convert_expr(e))
129 .collect::<Result<Vec<_>>>()?,
130 sp::GroupByExpr::All(_) => Vec::new(),
131 };
132
133 let having = body.having.map(|e| self.convert_expr(e)).transpose()?;
134
135 let order_by = query
136 .order_by
137 .map(|ob| {
138 ob.exprs
139 .into_iter()
140 .map(|item| self.convert_order_by_item(item))
141 .collect::<Result<Vec<_>>>()
142 })
143 .transpose()?
144 .unwrap_or_default();
145
146 let limit = query
147 .limit
148 .map(|e| self.extract_limit(e))
149 .transpose()?;
150
151 let offset = query
152 .offset
153 .map(|o| self.extract_limit(o.value))
154 .transpose()?;
155
156 Ok(SelectStatement {
157 distinct: body.distinct.is_some(),
158 columns,
159 from,
160 where_clause,
161 group_by,
162 having,
163 order_by,
164 limit,
165 offset,
166 })
167 }
168
169 fn convert_select_item(&self, item: sp::SelectItem) -> Result<SelectColumn> {
170 match item {
171 sp::SelectItem::UnnamedExpr(expr) => Ok(SelectColumn::Expression {
172 expr: self.convert_expr(expr)?,
173 alias: None,
174 }),
175 sp::SelectItem::ExprWithAlias { expr, alias } => Ok(SelectColumn::Expression {
176 expr: self.convert_expr(expr)?,
177 alias: Some(alias.value),
178 }),
179 sp::SelectItem::Wildcard(_) => Ok(SelectColumn::AllColumns),
180 sp::SelectItem::QualifiedWildcard(name, _) => {
181 Ok(SelectColumn::TableAllColumns(name.to_string()))
182 }
183 }
184 }
185
186 fn convert_from(&self, from: &[sp::TableWithJoins]) -> Result<FromClause> {
187 let first = from.first().ok_or_else(|| AegisError::Parse("Empty FROM".to_string()))?;
188
189 let source = self.convert_table_factor(&first.relation)?;
190
191 let mut joins = Vec::new();
192 for join in &first.joins {
193 joins.push(self.convert_join(join)?);
194 }
195
196 Ok(FromClause { source, joins })
197 }
198
199 fn convert_table_factor(&self, factor: &sp::TableFactor) -> Result<TableReference> {
200 match factor {
201 sp::TableFactor::Table { name, alias, .. } => Ok(TableReference::Table {
202 name: name.to_string(),
203 alias: alias.as_ref().map(|a| a.name.value.clone()),
204 }),
205 sp::TableFactor::Derived { subquery, alias, .. } => {
206 let alias_name = alias
207 .as_ref()
208 .map(|a| a.name.value.clone())
209 .ok_or_else(|| AegisError::Parse("Subquery requires alias".to_string()))?;
210 Ok(TableReference::Subquery {
211 query: Box::new(self.convert_query(*subquery.clone())?),
212 alias: alias_name,
213 })
214 }
215 _ => Err(AegisError::Parse("Unsupported table factor".to_string())),
216 }
217 }
218
219 fn convert_join(&self, join: &sp::Join) -> Result<JoinClause> {
220 let join_type = match &join.join_operator {
221 sp::JoinOperator::Inner(_) => JoinType::Inner,
222 sp::JoinOperator::LeftOuter(_) => JoinType::Left,
223 sp::JoinOperator::RightOuter(_) => JoinType::Right,
224 sp::JoinOperator::FullOuter(_) => JoinType::Full,
225 sp::JoinOperator::CrossJoin => JoinType::Cross,
226 _ => return Err(AegisError::Parse("Unsupported join type".to_string())),
227 };
228
229 let condition = match &join.join_operator {
230 sp::JoinOperator::Inner(c)
231 | sp::JoinOperator::LeftOuter(c)
232 | sp::JoinOperator::RightOuter(c)
233 | sp::JoinOperator::FullOuter(c) => match c {
234 sp::JoinConstraint::On(expr) => Some(self.convert_expr(expr.clone())?),
235 sp::JoinConstraint::None => None,
236 _ => return Err(AegisError::Parse("Unsupported join constraint".to_string())),
237 },
238 sp::JoinOperator::CrossJoin => None,
239 _ => None,
240 };
241
242 Ok(JoinClause {
243 join_type,
244 table: self.convert_table_factor(&join.relation)?,
245 condition,
246 })
247 }
248
249 fn convert_order_by_item(&self, item: sp::OrderByExpr) -> Result<OrderByItem> {
250 Ok(OrderByItem {
251 expression: self.convert_expr(item.expr)?,
252 ascending: item.asc.unwrap_or(true),
253 nulls_first: item.nulls_first,
254 })
255 }
256
257 fn convert_expr(&self, expr: sp::Expr) -> Result<Expression> {
258 match expr {
259 sp::Expr::Identifier(ident) => Ok(Expression::Column(ColumnRef {
260 table: None,
261 column: ident.value,
262 })),
263 sp::Expr::CompoundIdentifier(idents) => {
264 if idents.len() == 2 {
265 Ok(Expression::Column(ColumnRef {
266 table: Some(idents[0].value.clone()),
267 column: idents[1].value.clone(),
268 }))
269 } else {
270 Ok(Expression::Column(ColumnRef {
271 table: None,
272 column: idents.last().map(|i| i.value.clone()).unwrap_or_default(),
273 }))
274 }
275 }
276 sp::Expr::Value(value) => self.convert_value(value),
277 sp::Expr::BinaryOp { left, op, right } => Ok(Expression::BinaryOp {
278 left: Box::new(self.convert_expr(*left)?),
279 op: self.convert_binary_op(op)?,
280 right: Box::new(self.convert_expr(*right)?),
281 }),
282 sp::Expr::UnaryOp { op, expr } => Ok(Expression::UnaryOp {
283 op: self.convert_unary_op(op)?,
284 expr: Box::new(self.convert_expr(*expr)?),
285 }),
286 sp::Expr::Function(func) => {
287 let args = match func.args {
288 sp::FunctionArguments::List(list) => list
289 .args
290 .into_iter()
291 .filter_map(|arg| match arg {
292 sp::FunctionArg::Unnamed(sp::FunctionArgExpr::Expr(e)) => {
293 Some(self.convert_expr(e))
294 }
295 _ => None,
296 })
297 .collect::<Result<Vec<_>>>()?,
298 _ => Vec::new(),
299 };
300
301 Ok(Expression::Function {
302 name: func.name.to_string(),
303 args,
304 distinct: false,
305 })
306 }
307 sp::Expr::Nested(expr) => self.convert_expr(*expr),
308 sp::Expr::IsNull(expr) => Ok(Expression::IsNull {
309 expr: Box::new(self.convert_expr(*expr)?),
310 negated: false,
311 }),
312 sp::Expr::IsNotNull(expr) => Ok(Expression::IsNull {
313 expr: Box::new(self.convert_expr(*expr)?),
314 negated: true,
315 }),
316 sp::Expr::InList { expr, list, negated } => Ok(Expression::InList {
317 expr: Box::new(self.convert_expr(*expr)?),
318 list: list
319 .into_iter()
320 .map(|e| self.convert_expr(e))
321 .collect::<Result<Vec<_>>>()?,
322 negated,
323 }),
324 sp::Expr::Between { expr, low, high, negated } => Ok(Expression::Between {
325 expr: Box::new(self.convert_expr(*expr)?),
326 low: Box::new(self.convert_expr(*low)?),
327 high: Box::new(self.convert_expr(*high)?),
328 negated,
329 }),
330 sp::Expr::Like { expr, pattern, negated, .. } => Ok(Expression::Like {
331 expr: Box::new(self.convert_expr(*expr)?),
332 pattern: Box::new(self.convert_expr(*pattern)?),
333 negated,
334 }),
335 _ => Err(AegisError::Parse(format!(
336 "Unsupported expression: {:?}",
337 expr
338 ))),
339 }
340 }
341
342 fn convert_value(&self, value: sp::Value) -> Result<Expression> {
343 let literal = match value {
344 sp::Value::Null => Literal::Null,
345 sp::Value::Boolean(b) => Literal::Boolean(b),
346 sp::Value::Number(n, _) => {
347 if n.contains('.') {
348 Literal::Float(n.parse().map_err(|_| AegisError::Parse("Invalid float".to_string()))?)
349 } else {
350 Literal::Integer(n.parse().map_err(|_| AegisError::Parse("Invalid integer".to_string()))?)
351 }
352 }
353 sp::Value::SingleQuotedString(s) | sp::Value::DoubleQuotedString(s) => Literal::String(s),
354 _ => return Err(AegisError::Parse("Unsupported literal value".to_string())),
355 };
356 Ok(Expression::Literal(literal))
357 }
358
359 fn convert_binary_op(&self, op: sp::BinaryOperator) -> Result<BinaryOperator> {
360 match op {
361 sp::BinaryOperator::Plus => Ok(BinaryOperator::Add),
362 sp::BinaryOperator::Minus => Ok(BinaryOperator::Subtract),
363 sp::BinaryOperator::Multiply => Ok(BinaryOperator::Multiply),
364 sp::BinaryOperator::Divide => Ok(BinaryOperator::Divide),
365 sp::BinaryOperator::Modulo => Ok(BinaryOperator::Modulo),
366 sp::BinaryOperator::Eq => Ok(BinaryOperator::Equal),
367 sp::BinaryOperator::NotEq => Ok(BinaryOperator::NotEqual),
368 sp::BinaryOperator::Lt => Ok(BinaryOperator::LessThan),
369 sp::BinaryOperator::LtEq => Ok(BinaryOperator::LessThanOrEqual),
370 sp::BinaryOperator::Gt => Ok(BinaryOperator::GreaterThan),
371 sp::BinaryOperator::GtEq => Ok(BinaryOperator::GreaterThanOrEqual),
372 sp::BinaryOperator::And => Ok(BinaryOperator::And),
373 sp::BinaryOperator::Or => Ok(BinaryOperator::Or),
374 sp::BinaryOperator::StringConcat => Ok(BinaryOperator::Concat),
375 _ => Err(AegisError::Parse(format!("Unsupported operator: {:?}", op))),
376 }
377 }
378
379 fn convert_unary_op(&self, op: sp::UnaryOperator) -> Result<UnaryOperator> {
380 match op {
381 sp::UnaryOperator::Not => Ok(UnaryOperator::Not),
382 sp::UnaryOperator::Minus => Ok(UnaryOperator::Negative),
383 sp::UnaryOperator::Plus => Ok(UnaryOperator::Positive),
384 _ => Err(AegisError::Parse(format!("Unsupported unary operator: {:?}", op))),
385 }
386 }
387
388 fn convert_insert(&self, insert: sp::Insert) -> Result<InsertStatement> {
389 let table = insert.table_name.to_string();
390
391 let columns = if insert.columns.is_empty() {
392 None
393 } else {
394 Some(insert.columns.into_iter().map(|c| c.value).collect())
395 };
396
397 let source = match insert.source {
398 Some(query) => match *query.body {
399 sp::SetExpr::Values(values) => {
400 let rows = values
401 .rows
402 .into_iter()
403 .map(|row| {
404 row.into_iter()
405 .map(|e| self.convert_expr(e))
406 .collect::<Result<Vec<_>>>()
407 })
408 .collect::<Result<Vec<_>>>()?;
409 InsertSource::Values(rows)
410 }
411 _ => InsertSource::Query(Box::new(self.convert_query(*query)?)),
412 },
413 None => return Err(AegisError::Parse("INSERT missing values".to_string())),
414 };
415
416 Ok(InsertStatement {
417 table,
418 columns,
419 source,
420 })
421 }
422
423 fn convert_update(
424 &self,
425 table: sp::TableWithJoins,
426 assignments: Vec<sp::Assignment>,
427 selection: Option<sp::Expr>,
428 ) -> Result<UpdateStatement> {
429 let table_name = match &table.relation {
430 sp::TableFactor::Table { name, .. } => name.to_string(),
431 _ => return Err(AegisError::Parse("UPDATE requires table name".to_string())),
432 };
433
434 let assigns = assignments
435 .into_iter()
436 .map(|a| {
437 let column = match a.target {
438 sp::AssignmentTarget::ColumnName(names) => {
439 names.0.into_iter().map(|i| i.value).collect::<Vec<_>>().join(".")
440 }
441 sp::AssignmentTarget::Tuple(cols) => {
442 cols.into_iter()
443 .map(|c| c.to_string())
444 .collect::<Vec<_>>()
445 .join(", ")
446 }
447 };
448 Ok(Assignment {
449 column,
450 value: self.convert_expr(a.value)?,
451 })
452 })
453 .collect::<Result<Vec<_>>>()?;
454
455 let where_clause = selection.map(|e| self.convert_expr(e)).transpose()?;
456
457 Ok(UpdateStatement {
458 table: table_name,
459 assignments: assigns,
460 where_clause,
461 })
462 }
463
464 fn convert_delete(&self, delete: sp::Delete) -> Result<DeleteStatement> {
465 let table = match delete.from {
466 sp::FromTable::WithFromKeyword(tables) => {
467 tables.first()
468 .map(|t| match &t.relation {
469 sp::TableFactor::Table { name, .. } => name.to_string(),
470 _ => String::new(),
471 })
472 .ok_or_else(|| AegisError::Parse("DELETE missing table".to_string()))?
473 }
474 sp::FromTable::WithoutKeyword(tables) => {
475 tables.first()
476 .map(|t| match &t.relation {
477 sp::TableFactor::Table { name, .. } => name.to_string(),
478 _ => String::new(),
479 })
480 .ok_or_else(|| AegisError::Parse("DELETE missing table".to_string()))?
481 }
482 };
483
484 let where_clause = delete.selection.map(|e| self.convert_expr(e)).transpose()?;
485
486 Ok(DeleteStatement {
487 table,
488 where_clause,
489 })
490 }
491
492 fn convert_create_table(&self, create: sp::CreateTable) -> Result<CreateTableStatement> {
493 let columns = create
494 .columns
495 .into_iter()
496 .map(|col| {
497 Ok(ColumnDefinition {
498 name: col.name.value,
499 data_type: self.convert_data_type(&col.data_type)?,
500 nullable: !col.options.iter().any(|o| {
501 matches!(o.option, sp::ColumnOption::NotNull)
502 }),
503 default: col
504 .options
505 .iter()
506 .find_map(|o| match &o.option {
507 sp::ColumnOption::Default(e) => Some(self.convert_expr(e.clone())),
508 _ => None,
509 })
510 .transpose()?,
511 constraints: Vec::new(),
512 })
513 })
514 .collect::<Result<Vec<_>>>()?;
515
516 Ok(CreateTableStatement {
517 name: create.name.to_string(),
518 columns,
519 constraints: Vec::new(),
520 if_not_exists: create.if_not_exists,
521 })
522 }
523
524 fn convert_drop(
525 &self,
526 object_type: sp::ObjectType,
527 if_exists: bool,
528 names: Vec<sp::ObjectName>,
529 ) -> Result<Statement> {
530 let name = names
531 .first()
532 .map(|n| n.to_string())
533 .ok_or_else(|| AegisError::Parse("DROP missing name".to_string()))?;
534
535 match object_type {
536 sp::ObjectType::Table => Ok(Statement::DropTable(DropTableStatement {
537 name,
538 if_exists,
539 })),
540 sp::ObjectType::Index => Ok(Statement::DropIndex(DropIndexStatement {
541 name,
542 if_exists,
543 })),
544 _ => Err(AegisError::Parse(format!(
545 "Unsupported DROP object type: {:?}",
546 object_type
547 ))),
548 }
549 }
550
551 fn convert_create_index(&self, create: sp::CreateIndex) -> Result<CreateIndexStatement> {
552 let name = create
553 .name
554 .map(|n| n.to_string())
555 .ok_or_else(|| AegisError::Parse("CREATE INDEX missing name".to_string()))?;
556
557 let table = create.table_name.to_string();
558
559 let columns = create
560 .columns
561 .into_iter()
562 .map(|c| c.expr.to_string())
563 .collect();
564
565 Ok(CreateIndexStatement {
566 name,
567 table,
568 columns,
569 unique: create.unique,
570 if_not_exists: create.if_not_exists,
571 })
572 }
573
574 fn convert_alter_table(
575 &self,
576 name: sp::ObjectName,
577 operations: Vec<sp::AlterTableOperation>,
578 ) -> Result<AlterTableStatement> {
579 let ops = operations
580 .into_iter()
581 .map(|op| self.convert_alter_operation(op))
582 .collect::<Result<Vec<_>>>()?;
583
584 Ok(AlterTableStatement {
585 name: name.to_string(),
586 operations: ops,
587 })
588 }
589
590 fn convert_alter_operation(&self, op: sp::AlterTableOperation) -> Result<AlterTableOperation> {
591 match op {
592 sp::AlterTableOperation::AddColumn { column_def, .. } => {
593 let col = ColumnDefinition {
594 name: column_def.name.value.clone(),
595 data_type: self.convert_data_type(&column_def.data_type)?,
596 nullable: !column_def.options.iter().any(|o| {
597 matches!(o.option, sp::ColumnOption::NotNull)
598 }),
599 default: column_def
600 .options
601 .iter()
602 .find_map(|o| match &o.option {
603 sp::ColumnOption::Default(e) => Some(self.convert_expr(e.clone())),
604 _ => None,
605 })
606 .transpose()?,
607 constraints: Vec::new(),
608 };
609 Ok(AlterTableOperation::AddColumn(col))
610 }
611 sp::AlterTableOperation::DropColumn { column_name, if_exists, .. } => {
612 Ok(AlterTableOperation::DropColumn {
613 name: column_name.value,
614 if_exists,
615 })
616 }
617 sp::AlterTableOperation::RenameColumn { old_column_name, new_column_name } => {
618 Ok(AlterTableOperation::RenameColumn {
619 old_name: old_column_name.value,
620 new_name: new_column_name.value,
621 })
622 }
623 sp::AlterTableOperation::RenameTable { table_name } => {
624 Ok(AlterTableOperation::RenameTable {
625 new_name: table_name.to_string(),
626 })
627 }
628 sp::AlterTableOperation::AlterColumn { column_name, op } => {
629 match op {
630 sp::AlterColumnOperation::SetDataType { data_type, .. } => {
631 Ok(AlterTableOperation::AlterColumn {
632 name: column_name.value,
633 data_type: Some(self.convert_data_type(&data_type)?),
634 set_not_null: None,
635 set_default: None,
636 })
637 }
638 sp::AlterColumnOperation::SetNotNull => {
639 Ok(AlterTableOperation::AlterColumn {
640 name: column_name.value,
641 data_type: None,
642 set_not_null: Some(true),
643 set_default: None,
644 })
645 }
646 sp::AlterColumnOperation::DropNotNull => {
647 Ok(AlterTableOperation::AlterColumn {
648 name: column_name.value,
649 data_type: None,
650 set_not_null: Some(false),
651 set_default: None,
652 })
653 }
654 sp::AlterColumnOperation::SetDefault { value } => {
655 Ok(AlterTableOperation::AlterColumn {
656 name: column_name.value,
657 data_type: None,
658 set_not_null: None,
659 set_default: Some(Some(self.convert_expr(value)?)),
660 })
661 }
662 sp::AlterColumnOperation::DropDefault => {
663 Ok(AlterTableOperation::AlterColumn {
664 name: column_name.value,
665 data_type: None,
666 set_not_null: None,
667 set_default: Some(None),
668 })
669 }
670 _ => Err(AegisError::Parse(format!(
671 "Unsupported ALTER COLUMN operation: {:?}",
672 op
673 ))),
674 }
675 }
676 sp::AlterTableOperation::DropConstraint { name, .. } => {
677 Ok(AlterTableOperation::DropConstraint {
678 name: name.value,
679 })
680 }
681 _ => Err(AegisError::Parse(format!(
682 "Unsupported ALTER TABLE operation: {:?}",
683 op
684 ))),
685 }
686 }
687
688 fn convert_data_type(&self, dt: &sp::DataType) -> Result<DataType> {
689 match dt {
690 sp::DataType::Boolean => Ok(DataType::Boolean),
691 sp::DataType::TinyInt(_) => Ok(DataType::TinyInt),
692 sp::DataType::SmallInt(_) => Ok(DataType::SmallInt),
693 sp::DataType::Int(_) | sp::DataType::Integer(_) => Ok(DataType::Integer),
694 sp::DataType::BigInt(_) => Ok(DataType::BigInt),
695 sp::DataType::Real => Ok(DataType::Float),
696 sp::DataType::Float(_) | sp::DataType::Double | sp::DataType::DoublePrecision => {
697 Ok(DataType::Double)
698 }
699 sp::DataType::Decimal(info) | sp::DataType::Numeric(info) => {
700 let (precision, scale) = match info {
701 sp::ExactNumberInfo::PrecisionAndScale(p, s) => (*p as u8, *s as u8),
702 sp::ExactNumberInfo::Precision(p) => (*p as u8, 0),
703 sp::ExactNumberInfo::None => (18, 0),
704 };
705 Ok(DataType::Decimal { precision, scale })
706 }
707 sp::DataType::Char(len) => {
708 let size = len.as_ref().and_then(|l| {
709 match l {
710 sp::CharacterLength::IntegerLength { length, .. } => Some(*length as u16),
711 sp::CharacterLength::Max => None,
712 }
713 }).unwrap_or(1);
714 Ok(DataType::Char(size))
715 }
716 sp::DataType::Varchar(len) => {
717 let size = len.as_ref().and_then(|l| {
718 match l {
719 sp::CharacterLength::IntegerLength { length, .. } => Some(*length as u16),
720 sp::CharacterLength::Max => None,
721 }
722 }).unwrap_or(255);
723 Ok(DataType::Varchar(size))
724 }
725 sp::DataType::Text => Ok(DataType::Text),
726 sp::DataType::Blob(_) => Ok(DataType::Blob),
727 sp::DataType::Date => Ok(DataType::Date),
728 sp::DataType::Time(..) => Ok(DataType::Time),
729 sp::DataType::Timestamp(..) => Ok(DataType::Timestamp),
730 sp::DataType::JSON => Ok(DataType::Json),
731 sp::DataType::Uuid => Ok(DataType::Uuid),
732 _ => Err(AegisError::Parse(format!("Unsupported data type: {:?}", dt))),
733 }
734 }
735
736 fn extract_limit(&self, expr: sp::Expr) -> Result<u64> {
737 match expr {
738 sp::Expr::Value(sp::Value::Number(n, _)) => n
739 .parse()
740 .map_err(|_| AegisError::Parse("Invalid LIMIT value".to_string())),
741 _ => Err(AegisError::Parse("LIMIT must be a number".to_string())),
742 }
743 }
744}
745
746impl Default for Parser {
747 fn default() -> Self {
748 Self::new()
749 }
750}
751
752#[cfg(test)]
757mod tests {
758 use super::*;
759
760 #[test]
761 fn test_parse_simple_select() {
762 let parser = Parser::new();
763 let stmt = parser.parse_single("SELECT id, name FROM users").unwrap();
764
765 match stmt {
766 Statement::Select(select) => {
767 assert_eq!(select.columns.len(), 2);
768 assert!(select.from.is_some());
769 }
770 _ => panic!("Expected SELECT statement"),
771 }
772 }
773
774 #[test]
775 fn test_parse_select_with_where() {
776 let parser = Parser::new();
777 let stmt = parser
778 .parse_single("SELECT * FROM users WHERE age > 18")
779 .unwrap();
780
781 match stmt {
782 Statement::Select(select) => {
783 assert!(select.where_clause.is_some());
784 }
785 _ => panic!("Expected SELECT statement"),
786 }
787 }
788
789 #[test]
790 fn test_parse_select_with_join() {
791 let parser = Parser::new();
792 let stmt = parser
793 .parse_single("SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id")
794 .unwrap();
795
796 match stmt {
797 Statement::Select(select) => {
798 let from = select.from.unwrap();
799 assert_eq!(from.joins.len(), 1);
800 assert_eq!(from.joins[0].join_type, JoinType::Inner);
801 }
802 _ => panic!("Expected SELECT statement"),
803 }
804 }
805
806 #[test]
807 fn test_parse_insert() {
808 let parser = Parser::new();
809 let stmt = parser
810 .parse_single("INSERT INTO users (name, age) VALUES ('Alice', 25)")
811 .unwrap();
812
813 match stmt {
814 Statement::Insert(insert) => {
815 assert_eq!(insert.table, "users");
816 assert_eq!(insert.columns, Some(vec!["name".to_string(), "age".to_string()]));
817 }
818 _ => panic!("Expected INSERT statement"),
819 }
820 }
821
822 #[test]
823 fn test_parse_update() {
824 let parser = Parser::new();
825 let stmt = parser
826 .parse_single("UPDATE users SET age = 26 WHERE name = 'Alice'")
827 .unwrap();
828
829 match stmt {
830 Statement::Update(update) => {
831 assert_eq!(update.table, "users");
832 assert_eq!(update.assignments.len(), 1);
833 assert!(update.where_clause.is_some());
834 }
835 _ => panic!("Expected UPDATE statement"),
836 }
837 }
838
839 #[test]
840 fn test_parse_delete() {
841 let parser = Parser::new();
842 let stmt = parser
843 .parse_single("DELETE FROM users WHERE age < 18")
844 .unwrap();
845
846 match stmt {
847 Statement::Delete(delete) => {
848 assert_eq!(delete.table, "users");
849 assert!(delete.where_clause.is_some());
850 }
851 _ => panic!("Expected DELETE statement"),
852 }
853 }
854
855 #[test]
856 fn test_parse_create_table() {
857 let parser = Parser::new();
858 let stmt = parser
859 .parse_single(
860 "CREATE TABLE users (
861 id INTEGER NOT NULL,
862 name VARCHAR(255),
863 age INTEGER
864 )",
865 )
866 .unwrap();
867
868 match stmt {
869 Statement::CreateTable(create) => {
870 assert_eq!(create.name, "users");
871 assert_eq!(create.columns.len(), 3);
872 assert!(!create.columns[0].nullable);
873 assert!(create.columns[1].nullable);
874 }
875 _ => panic!("Expected CREATE TABLE statement"),
876 }
877 }
878
879 #[test]
880 fn test_parse_transaction_statements() {
881 let parser = Parser::new();
882
883 assert!(matches!(parser.parse_single("BEGIN").unwrap(), Statement::Begin));
884 assert!(matches!(parser.parse_single("COMMIT").unwrap(), Statement::Commit));
885 assert!(matches!(parser.parse_single("ROLLBACK").unwrap(), Statement::Rollback));
886 }
887}