hamelin_legacy 0.4.0

Legacy AST translation code for Hamelin (to be deprecated)
Documentation
use hamelin_lib::{
    antlr::hamelinparser::{UnnestCommandContext, UnnestCommandContextAttrs},
    err::{TranslationError, TranslationErrors},
    sql::{
        expression::{identifier::SimpleIdentifier, literal::BooleanLiteral},
        query::{
            projection::{Binding, ColumnProjection},
            Join, JoinClause, JoinType, SQLQuery, SubQuery, TableAlias, TableExpression,
            TableFunctionApply,
        },
    },
    types::Type,
};

use crate::env::Environment;
use crate::translation::PendingQuery;
use crate::{
    ast::{expression::HamelinExpression, pipeline::HamelinPipeline},
    translation::sql_query_helpers::prepend_projections,
};

pub fn translate(
    ctx: &UnnestCommandContext<'static>,
    pipeline: &HamelinPipeline,
    previous_command: &PendingQuery,
) -> Result<PendingQuery, TranslationErrors> {
    let expression_ctx = TranslationErrors::expect(ctx, ctx.expression())?;
    let expression = HamelinExpression::new(
        expression_ctx.clone(),
        pipeline
            .context
            .default_expression_translation_context(&previous_command.env),
    );
    let expression_translation = expression.translate()?;

    let left_alias = SimpleIdentifier::new("_left");
    let right_alias = SimpleIdentifier::new("_right");

    let left_sql = previous_command.query.clone();
    let left_query = SubQuery::new(left_sql.clone().into()).alias(left_alias.clone().into());

    match expression_translation.typ {
        Type::Array(array) => match array.element_type.as_ref() {
            Type::Struct(srct) => {
                let right_env = Environment::new(srct.clone());
                let merged_env = previous_command.env.clone().prepend_overwrite(&right_env);

                let unnest = TableFunctionApply::new("unnest".to_string())
                    .with_argument(expression_translation.sql.clone())
                    .with_alias(TableAlias::new(right_alias.clone().into()));

                let from: TableExpression = if left_sql == SQLQuery::default() {
                    unnest.into()
                } else {
                    Join::new(left_query.into())
                        .with_clause(JoinClause {
                            table: unnest.into(),
                            join_type: JoinType::LEFT,
                            condition: Some(BooleanLiteral::new(true).into()),
                        })
                        .into()
                };

                let query = SQLQuery::default().from(from).select(
                    merged_env
                        .get_column_projections()
                        .into_iter()
                        .map(|cp| {
                            if right_env.lookup(&cp.identifier).is_ok() {
                                ColumnProjection::new(
                                    cp.identifier
                                        .prefix_from_simples(&[right_alias.clone()])
                                        .into(),
                                )
                                .into()
                            } else {
                                ColumnProjection::new(
                                    cp.identifier
                                        .prefix_from_simples(&[left_alias.clone()])
                                        .into(),
                                )
                                .into()
                            }
                        })
                        .collect(),
                );

                Ok(PendingQuery::new(query, merged_env))
            }
            t => {
                return Err(TranslationError::msg(
                    expression_ctx.as_ref(),
                    &format!(
                    "Unsupported type {} for unnest command. Must be struct or array-of-struct.",
                    t
                ),
                )
                .single())
            }
        },
        Type::Struct(srct) => {
            let right_env = Environment::new(srct.clone());
            let prev_sql = previous_command.query.clone();
            let prev_env = previous_command.env.clone();
            let merged_env = prev_env.prepend_overwrite(&right_env);

            let query = prepend_projections(
                &prev_sql,
                srct.fields
                    .iter()
                    .map(|(k, _)| {
                        Binding::new(
                            k.clone(),
                            expression_translation.sql.clone().dot(k.clone().into()),
                        )
                        .into()
                    })
                    .collect(),
                &merged_env,
            );

            Ok(PendingQuery::new(query, merged_env))
        }
        t => {
            return Err(TranslationError::msg(
                expression_ctx.as_ref(),
                &format!(
                    "Unsupported type {} for unnest command. Must be struct or array-of-struct.",
                    t
                ),
            )
            .single())
        }
    }
}