use std::rc::Rc;
use crate::ast::expression::HamelinExpression;
use crate::ast::pipeline::HamelinPipeline;
use crate::env::Environment;
use crate::translation::{PendingStatement, PendingStatementResult};
use hamelin_lib::antlr::hamelinparser::{
ExpressionQueryContextAttrs, QueryContextAll, StandaloneQueryContextAttrs,
WithQueryContextAttrs,
};
use hamelin_lib::err::TranslationError;
use hamelin_lib::sql::query::cte::CTE;
use hamelin_lib::sql::query::dml::DML;
use hamelin_lib::sql::query::projection::Binding;
use hamelin_lib::sql::query::SQLQuery;
use hamelin_lib::sql::statement::Statement;
use hamelin_lib::types::struct_type::Struct;
use super::QueryTranslationContext;
use hamelin_lib::sql::expression::identifier::HamelinSimpleIdentifier;
pub struct HamelinQuery {
pub tree: Rc<QueryContextAll<'static>>,
pub context: Rc<QueryTranslationContext>,
}
impl HamelinQuery {
pub fn new(tree: Rc<QueryContextAll<'static>>, context: Rc<QueryTranslationContext>) -> Self {
Self { tree, context }
}
pub fn translate(&self) -> PendingStatementResult {
match self.tree.as_ref() {
QueryContextAll::WithQueryContext(ctx) => {
let mut cte = CTE::default();
let mut env = Environment::default();
let mut pending = PendingStatementResult::default();
for (ident_ctx, pipeline_ctx) in ctx
.simpleIdentifier_all()
.into_iter()
.zip(ctx.pipeline_all().into_iter())
{
let maybe_ident = HamelinSimpleIdentifier::new(ident_ctx).to_sql();
let mut pipeline = HamelinPipeline::new(
pipeline_ctx.clone(),
env.clone(),
self.context.clone(),
);
if let Some(within) = self.context.within.clone() {
pipeline = pipeline.add_within_if_none_present(within);
}
let translation = pending.recover(pipeline.translate());
match (maybe_ident, translation.statement) {
(Ok(i), Statement::SQLQuery(sql)) => {
cte = cte.with(i.clone(), sql);
env = env.with_binding(i.into(), translation.env.fields.into());
}
(_, Statement::DML(_)) => {
pending.add_error(TranslationError::msg(
pipeline_ctx.as_ref(),
"DML not allowed in CTE pipeline.",
));
}
(Err(e), _) => {
pending.add_errors(e);
}
}
}
if let Some(pipeline_ctx) = ctx.pipeline_all().last() {
let mut pipeline =
HamelinPipeline::new(pipeline_ctx.clone(), env, self.context.clone());
if let Some(within) = self.context.within.clone() {
pipeline = pipeline.add_within_if_none_present(within);
}
let mut translation = pending.recover(pipeline.translate());
translation = match &translation.statement {
Statement::SQLQuery(q) => match cte.merge(q.cte.clone()) {
Ok(merged_cte) => PendingStatement::new_query(
q.clone().cte(merged_cte),
translation.env,
),
Err(e) => {
pending.add_error(TranslationError::msg(
pipeline_ctx.as_ref(),
&e.to_string(),
));
translation
}
},
Statement::DML(DML::Insert(i)) => match cte.merge(i.query.cte.clone()) {
Ok(merged_cte) => {
let mut i = i.clone();
i.query = i.query.clone().cte(merged_cte);
PendingStatement::new_dml(i.into(), translation.env)
}
Err(e) => {
pending.add_error(TranslationError::msg(
pipeline_ctx.as_ref(),
&e.to_string(),
));
translation
}
},
Statement::DML(DML::Merge(m)) => match cte.merge(m.query.cte.clone()) {
Ok(merged_cte) => {
let mut m = m.clone();
m.query = m.query.clone().cte(merged_cte);
PendingStatement::new_dml(m.into(), translation.env)
}
Err(e) => {
pending.add_error(TranslationError::msg(
pipeline_ctx.as_ref(),
&e.to_string(),
));
translation
}
},
};
pending.translation = translation
}
pending
}
QueryContextAll::StandaloneQueryContext(ctx) => ctx
.pipeline()
.map(|ctx| {
let mut p =
HamelinPipeline::new(ctx, Environment::default(), self.context.clone());
if let Some(within) = self.context.within.clone() {
p = p.add_within_if_none_present(within);
}
p.translate()
})
.unwrap_or_default(),
QueryContextAll::ExpressionQueryContext(ctx) => ctx
.expression()
.map(|ectx| {
let env = Environment::default();
let expression = HamelinExpression::new(
ectx,
self.context.default_expression_translation_context(&env),
);
match expression.translate() {
Ok(exp) => {
let typ = Struct::default().with("result".parse().unwrap(), exp.typ);
let pending_statement = PendingStatement::new_query(
SQLQuery::default().select(vec![Binding::new(
"result".parse().unwrap(),
exp.sql,
)
.into()]),
Environment::new(typ),
);
PendingStatementResult::default().with_translation(pending_statement)
}
Err(e) => PendingStatementResult::default().with_errors(e),
}
})
.unwrap_or_default(),
QueryContextAll::Error(ctx) => PendingStatementResult::default()
.with_error(TranslationError::msg(ctx, "parse error")),
}
}
}