sql_cli/query_plan/
transformer_adapters.rs

1//! Adapter wrappers for existing transformers to implement ASTTransformer trait
2//!
3//! This module provides wrappers around our existing transformation code
4//! (CTEHoister, ExpressionLifter, etc.) so they can be used in the pipeline.
5
6use super::pipeline::ASTTransformer;
7use super::{CTEHoister, ExpressionLifter, InOperatorLifter};
8use crate::sql::parser::ast::SelectStatement;
9use anyhow::Result;
10
11/// Wrapper for CTEHoister
12pub struct CTEHoisterTransformer;
13
14impl CTEHoisterTransformer {
15    pub fn new() -> Self {
16        Self
17    }
18}
19
20impl Default for CTEHoisterTransformer {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl ASTTransformer for CTEHoisterTransformer {
27    fn name(&self) -> &str {
28        "CTEHoister"
29    }
30
31    fn description(&self) -> &str {
32        "Hoists nested WITH clauses to top level for efficient execution"
33    }
34
35    fn transform(&mut self, stmt: SelectStatement) -> Result<SelectStatement> {
36        Ok(CTEHoister::hoist_ctes(stmt))
37    }
38}
39
40/// Wrapper for ExpressionLifter
41pub struct ExpressionLifterTransformer {
42    lifter: ExpressionLifter,
43}
44
45impl ExpressionLifterTransformer {
46    pub fn new() -> Self {
47        Self {
48            lifter: ExpressionLifter::new(),
49        }
50    }
51}
52
53impl Default for ExpressionLifterTransformer {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59impl ASTTransformer for ExpressionLifterTransformer {
60    fn name(&self) -> &str {
61        "ExpressionLifter"
62    }
63
64    fn description(&self) -> &str {
65        "Lifts window functions and column alias dependencies to CTEs"
66    }
67
68    fn transform(&mut self, mut stmt: SelectStatement) -> Result<SelectStatement> {
69        let lifted_ctes = self.lifter.lift_expressions(&mut stmt);
70
71        if !lifted_ctes.is_empty() {
72            tracing::info!("ExpressionLifter generated {} CTE(s)", lifted_ctes.len());
73        }
74
75        Ok(stmt)
76    }
77}
78
79/// Wrapper for InOperatorLifter
80pub struct InOperatorLifterTransformer {
81    lifter: InOperatorLifter,
82}
83
84impl InOperatorLifterTransformer {
85    pub fn new() -> Self {
86        Self {
87            lifter: InOperatorLifter::new(),
88        }
89    }
90}
91
92impl Default for InOperatorLifterTransformer {
93    fn default() -> Self {
94        Self::new()
95    }
96}
97
98impl ASTTransformer for InOperatorLifterTransformer {
99    fn name(&self) -> &str {
100        "InOperatorLifter"
101    }
102
103    fn description(&self) -> &str {
104        "Optimizes IN expressions with large value lists by lifting to CTEs"
105    }
106
107    fn transform(&mut self, mut stmt: SelectStatement) -> Result<SelectStatement> {
108        if self.lifter.rewrite_query(&mut stmt) {
109            tracing::info!("InOperatorLifter applied - query rewritten with CTEs");
110        }
111        Ok(stmt)
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_cte_hoister_transformer() {
121        let mut transformer = CTEHoisterTransformer::new();
122        assert_eq!(transformer.name(), "CTEHoister");
123        assert!(transformer.enabled());
124
125        let stmt = SelectStatement::default();
126        let result = transformer.transform(stmt);
127        assert!(result.is_ok());
128    }
129
130    #[test]
131    fn test_expression_lifter_transformer() {
132        let mut transformer = ExpressionLifterTransformer::new();
133        assert_eq!(transformer.name(), "ExpressionLifter");
134
135        let stmt = SelectStatement::default();
136        let result = transformer.transform(stmt);
137        assert!(result.is_ok());
138    }
139
140    #[test]
141    fn test_in_operator_lifter_transformer() {
142        let mut transformer = InOperatorLifterTransformer::new();
143        assert_eq!(transformer.name(), "InOperatorLifter");
144
145        let stmt = SelectStatement::default();
146        let result = transformer.transform(stmt);
147        assert!(result.is_ok());
148    }
149}