use crate::expression::core::Expression;
use crate::traits::expressive::ExpressiveEnum;
pub trait Flatten<T> {
fn flatten(&self, expr: &T) -> T;
fn resolve_deferred(&self, expr: &T) -> T;
fn flatten_nested(&self, expr: &T) -> T;
}
#[derive(Debug, Clone)]
pub struct ExpressionFlattener;
impl ExpressionFlattener {
pub fn new() -> Self {
Self
}
}
impl Default for ExpressionFlattener {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone> Flatten<Expression<T>> for ExpressionFlattener {
fn flatten(&self, expr: &Expression<T>) -> Expression<T> {
let resolved = self.resolve_deferred(expr);
self.flatten_nested(&resolved)
}
fn resolve_deferred(&self, expr: &Expression<T>) -> Expression<T> {
expr.clone()
}
fn flatten_nested(&self, expr: &Expression<T>) -> Expression<T> {
let mut result = expr.clone();
loop {
let mut final_template = String::new();
let mut final_params = Vec::new();
let mut had_nested = false;
let template_parts = result.template.split("{}");
let mut template_iter = template_parts.into_iter();
final_template.push_str(template_iter.next().unwrap_or(""));
for param in &result.parameters {
match param {
ExpressiveEnum::Nested(nested_expr) => {
had_nested = true;
final_template.push_str(&nested_expr.template);
final_params.extend(nested_expr.parameters.clone());
}
other => {
final_template.push_str("{}");
final_params.push(other.clone());
}
}
final_template.push_str(template_iter.next().unwrap_or(""));
}
result = Expression {
template: final_template,
parameters: final_params,
};
if !had_nested {
break;
}
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::expr_as;
#[test]
fn test_flatten_nested_expressions() {
let flattener = ExpressionFlattener::new();
let nested_expr = expr_as!(String, "Hello {}", "world");
let main_expr = expr_as!(String, "select {}", (nested_expr));
let flattened = flattener.flatten(&main_expr);
assert_eq!(flattened.template, "select Hello {}");
assert_eq!(flattened.parameters.len(), 1);
}
#[test]
fn test_multiple_nested_expressions() {
let flattener = ExpressionFlattener::new();
let greeting = expr_as!(String, "Hello {}", "John");
let farewell = expr_as!(String, "Goodbye {}", "Jane");
let main_expr = expr_as!(String, "{} and {}", (greeting), (farewell));
let flattened = flattener.flatten(&main_expr);
assert_eq!(flattened.template, "Hello {} and Goodbye {}");
assert_eq!(flattened.parameters.len(), 2);
}
#[test]
fn test_mixed_parameters() {
let flattener = ExpressionFlattener::new();
let nested = expr_as!(String, "count({})", "*");
let main_expr = expr_as!(
String,
"SELECT {} FROM users WHERE age > {}",
(nested),
"25"
);
let flattened = flattener.flatten(&main_expr);
assert_eq!(
flattened.template,
"SELECT count({}) FROM users WHERE age > {}"
);
assert_eq!(flattened.parameters.len(), 2);
}
}