hamelin_legacy 0.3.10

Legacy AST translation code for Hamelin (to be deprecated)
Documentation
use std::rc::Rc;

use crate::ast::expression::HamelinExpression;
use crate::ast::QueryTranslationContext;
use crate::translation::sql_query_helpers::add_filter_condition;
use crate::translation::PendingQuery;

use hamelin_lib::antlr::hamelinparser::{WithinCommandContext, WithinCommandContextAttrs};
use hamelin_lib::err::{TranslationError, TranslationErrors};
use hamelin_lib::sql::expression::identifier::SimpleIdentifier;
use hamelin_lib::sql::expression::literal::ColumnReference;
use hamelin_lib::types::Type;
use hamelin_sql::range_builder::RangeBuilder;
use hamelin_sql::utils::{
    interval_range_to_timestamp_range, interval_to_range, timestamp_to_range, within_range,
    within_range_expr,
};

pub fn translate(
    ctx: &WithinCommandContext<'static>,
    previous: &PendingQuery,
    // TODO: Can't put pipeline here like all the others.
    //       It is invoked from outside pipeline, which is a hack.
    translation_context: Rc<QueryTranslationContext>,
) -> Result<PendingQuery, TranslationErrors> {
    let exp_tree = TranslationErrors::expect(ctx, ctx.expression())?;
    let exp = HamelinExpression::new(
        exp_tree.clone(),
        translation_context.default_expression_translation_context(&previous.env),
    );
    let translation = exp.translate()?;
    if let Err(e) = previous
        .env
        .lookup(&SimpleIdentifier::new("timestamp").into())
    {
        let e = TranslationError::msg(
            ctx,
            "Cannot use WITHIN here. The environment is missing the timestamp column.",
        )
        .with_source(e)
        .single();

        return Err(e);
    }

    let col_ref = ColumnReference::new(SimpleIdentifier::new("timestamp").into()).into();

    let res = match translation.typ {
        Type::Timestamp => PendingQuery::new(
            add_filter_condition(
                &previous.query,
                within_range(col_ref, timestamp_to_range(translation.sql)),
                &previous.env,
            ),
            previous.env.clone(),
        ),
        Type::Interval | Type::CalendarInterval => PendingQuery::new(
            add_filter_condition(
                &previous.query,
                within_range(col_ref, interval_to_range(translation.sql)),
                &previous.env,
            ),
            previous.env.clone(),
        ),
        Type::Range(r) => match r.of.as_ref() {
            Type::Interval | Type::CalendarInterval => PendingQuery::new(
                add_filter_condition(
                    &previous.query,
                    within_range(col_ref, interval_range_to_timestamp_range(translation.sql)),
                    &previous.env,
                ),
                previous.env.clone(),
            ),

            Type::Timestamp => PendingQuery::new(
                add_filter_condition(
                    &previous.query,
                    RangeBuilder::from_literal(translation.sql.clone())
                        .map(|r| within_range(col_ref.clone(), r))
                        .unwrap_or_else(|| within_range_expr(col_ref, translation.sql)),
                    &previous.env,
                ),
                previous.env.clone(),
            ),
            t => {
                return Err(TranslationError::msg(
                    ctx,
                    "WITHIN range must be of timestamp or interval",
                )
                .with_context(exp_tree.as_ref(), &format!("found: {}", t))
                .single())
            }
        },
        t => {
            return Err(
                TranslationError::msg(ctx, "WITHIN must be range, timestamp, or interval")
                    .with_context(exp_tree.as_ref(), &format!("found: {}", t))
                    .single(),
            )
        }
    };

    Ok(res)
}