qail_core/transformer/clauses/
mod.rs1use sqlparser::ast::{Expr, OrderByExpr, Select, SelectItem, TableFactor};
4
5use crate::transformer::traits::*;
6
7pub fn extract_table(select: &Select) -> Result<String, ExtractError> {
9 select
10 .from
11 .first()
12 .map(|f| extract_table_from_factor(&f.relation))
13 .transpose()?
14 .ok_or_else(|| ExtractError {
15 message: "No FROM clause found".to_string(),
16 })
17}
18
19pub fn extract_table_from_factor(factor: &TableFactor) -> Result<String, ExtractError> {
21 match factor {
22 TableFactor::Table { name, .. } => Ok(name.to_string()),
23 _ => Err(ExtractError {
24 message: "Complex table expression not supported".to_string(),
25 }),
26 }
27}
28
29pub fn extract_columns(select: &Select) -> Vec<String> {
31 select
32 .projection
33 .iter()
34 .map(|item| match item {
35 SelectItem::UnnamedExpr(expr) => expr_to_string(expr),
36 SelectItem::ExprWithAlias { alias, .. } => alias.value.clone(),
37 SelectItem::Wildcard(_) => "*".to_string(),
38 SelectItem::QualifiedWildcard(name, _) => format!("{}.*", name),
39 })
40 .collect()
41}
42
43pub fn extract_filter(expr: &Expr) -> Result<FilterData, ExtractError> {
45 match expr {
46 Expr::BinaryOp { left, op, right } => {
47 let column = expr_to_string(left);
48 let operator = match op {
49 sqlparser::ast::BinaryOperator::Eq => "Operator::Eq",
50 sqlparser::ast::BinaryOperator::NotEq => "Operator::NotEq",
51 sqlparser::ast::BinaryOperator::Lt => "Operator::Lt",
52 sqlparser::ast::BinaryOperator::LtEq => "Operator::LtEq",
53 sqlparser::ast::BinaryOperator::Gt => "Operator::Gt",
54 sqlparser::ast::BinaryOperator::GtEq => "Operator::GtEq",
55 _ => "Operator::Eq",
56 };
57 let value = expr_to_value(right);
58
59 Ok(FilterData {
60 column,
61 operator: operator.to_string(),
62 value,
63 })
64 }
65 _ => Err(ExtractError {
66 message: "Complex filter expression not supported".to_string(),
67 }),
68 }
69}
70
71pub fn extract_order_by(exprs: &[OrderByExpr]) -> Vec<OrderByData> {
73 exprs
74 .iter()
75 .map(|o| OrderByData {
76 column: expr_to_string(&o.expr),
77 descending: o.options.asc == Some(false),
78 })
79 .collect()
80}
81
82pub fn extract_limit(expr: &Expr) -> Option<u64> {
84 match expr {
85 Expr::Value(value_with_span) => {
86 let s = value_with_span.to_string();
87 s.parse().ok()
88 }
89 _ => None,
90 }
91}
92
93pub fn expr_to_string(expr: &Expr) -> String {
95 match expr {
96 Expr::Identifier(ident) => ident.value.clone(),
97 Expr::CompoundIdentifier(parts) => parts.iter().map(|i| i.value.clone()).collect::<Vec<_>>().join("."),
98 _ => expr.to_string(),
99 }
100}
101
102pub fn expr_to_value(expr: &Expr) -> ValueData {
104 match expr {
105 Expr::Value(v) => {
106 let s = v.to_string();
107 if let Some(stripped) = s.strip_prefix('$')
108 && let Ok(n) = stripped.parse::<usize>()
109 {
110 return ValueData::Param(n);
111 }
112 if s == "NULL" {
113 ValueData::Null
114 } else {
115 ValueData::Literal(s)
116 }
117 }
118 Expr::Identifier(ident) => ValueData::Column(ident.value.clone()),
119 _ => ValueData::Literal(expr.to_string()),
120 }
121}