use {
super::ExprNode,
crate::{
ast::Expr,
parse_sql::parse_comma_separated_exprs,
plan::ExprPlan,
result::Result,
translate::{NO_PARAMS, translate_expr},
},
std::borrow::Cow,
};
#[derive(Clone, Debug)]
pub enum ExprList<'a> {
Text(Cow<'a, str>),
Exprs(Cow<'a, [ExprNode<'a>]>),
}
impl<'a> From<&'a str> for ExprList<'a> {
fn from(exprs: &'a str) -> Self {
ExprList::Text(Cow::Borrowed(exprs))
}
}
impl From<String> for ExprList<'_> {
fn from(exprs: String) -> Self {
ExprList::Text(Cow::from(exprs))
}
}
impl<'a, T: Into<ExprNode<'a>>> From<Vec<T>> for ExprList<'a> {
fn from(exprs: Vec<T>) -> Self {
ExprList::Exprs(Cow::Owned(exprs.into_iter().map(Into::into).collect()))
}
}
impl<'a, T: Into<ExprNode<'a>> + Copy> From<&'a Vec<T>> for ExprList<'a> {
fn from(exprs: &'a Vec<T>) -> Self {
exprs.as_slice().into()
}
}
impl<'a, T: Into<ExprNode<'a>> + Copy> From<&'a [T]> for ExprList<'a> {
fn from(exprs: &'a [T]) -> Self {
ExprList::Exprs(Cow::Owned(exprs.iter().map(|&v| v.into()).collect()))
}
}
impl<'a> From<&'a [ExprNode<'a>]> for ExprList<'a> {
fn from(exprs: &'a [ExprNode<'a>]) -> Self {
ExprList::Exprs(Cow::Borrowed(exprs))
}
}
impl ExprList<'_> {
pub(super) fn build_exprs_plan(self) -> Result<Vec<ExprPlan>> {
match self {
ExprList::Text(exprs) => parse_comma_separated_exprs(exprs)?
.iter()
.map(|expr| translate_expr(expr, NO_PARAMS).map(Into::into))
.collect::<Result<Vec<_>>>(),
ExprList::Exprs(exprs) => {
let exprs = exprs.into_owned();
exprs
.into_iter()
.map(ExprNode::build_expr_plan)
.collect::<Result<Vec<_>>>()
}
}
}
pub(super) fn build_exprs(self) -> Result<Vec<Expr>> {
match self {
ExprList::Text(exprs) => parse_comma_separated_exprs(exprs)?
.iter()
.map(|expr| translate_expr(expr, NO_PARAMS))
.collect::<Result<Vec<_>>>(),
ExprList::Exprs(exprs) => exprs
.into_owned()
.into_iter()
.map(ExprNode::build_expr)
.collect::<Result<Vec<_>>>(),
}
}
}
#[cfg(test)]
mod tests {
use {
super::ExprList,
crate::{
parse_sql::parse_comma_separated_exprs,
plan::ExprPlan,
query_builder::col,
result::Result,
translate::{NO_PARAMS, translate_expr},
},
pretty_assertions::assert_eq,
};
fn test(actual: ExprList, expected: &str) {
let parsed = parse_comma_separated_exprs(expected).expect(expected);
let expected = parsed
.iter()
.map(|expr| translate_expr(expr, NO_PARAMS).map(ExprPlan::from))
.collect::<Result<Vec<ExprPlan>>>();
assert_eq!(actual.build_exprs_plan(), expected);
}
#[test]
fn into_expr_list() {
let actual: ExprList = "1, a * 2, b".into();
let expected = "1, a * 2, b";
test(actual, expected);
let actual: ExprList = String::from("'hello' || 'world', col1").into();
let expected = "'hello' || 'world', col1";
test(actual, expected);
let actual: ExprList = vec!["id", "name"].into();
let expected = "id, name";
test(actual, expected);
let actual: ExprList = vec![col("id"), col("name")].into();
let expected = "id, name";
test(actual, expected);
let actual = vec!["id", "name"];
let actual: ExprList = (&actual).into();
let expected = "id, name";
test(actual, expected);
let actual = vec!["rate / 10", "col1"];
let actual: ExprList = actual.as_slice().into();
let expected = "rate / 10, col1";
test(actual, expected);
let actual = vec![col("id"), col("name")];
let actual: ExprList = actual.as_slice().into();
let expected = "id, name";
test(actual, expected);
}
}