//! Translation implementations for array and map access functions

use crate::{utils::hamelin_array_index_to_sql_with_negatives, TranslationRegistry};
use hamelin_lib::{
    func::defs::{GetArray, GetMap},
    sql::expression::apply::FunctionCallApply,
};

/// Register all access function translations.
pub fn register(registry: &mut TranslationRegistry) {
    // get(array, index) -> element_at(array, safe_index)
    // Use element_at instead of array[index] subscript syntax because subscript throws
    // an error on out-of-bounds access while element_at returns NULL (which matches Hamelin semantics).
    // Hamelin uses 0-based indexing with negative index support, SQL uses 1-based.
    // The index conversion in hamelin_array_index_to_sql_with_negatives guards against
    // out-of-bounds negative indices by returning NULL for converted values < 1.
    registry.register::<GetArray>(|_, mut bindings| {
        let array = bindings.take_by_name("array")?;
        let index = bindings.take_by_name("index")?;
        let sql_index = hamelin_array_index_to_sql_with_negatives(index.sql, array.sql.clone());
        Ok(FunctionCallApply::with_two("element_at", array.sql, sql_index).into())
    });

    // get(map, key) -> element_at(map, key)
    // Use element_at instead of map[key] subscript syntax because subscript throws
    // an error for missing keys while element_at returns NULL (which matches Hamelin semantics)
    registry.register::<GetMap>(|_, mut bindings| {
        let map = bindings.take_by_name("map")?;
        let key = bindings.take_by_name("key")?;
        Ok(FunctionCallApply::with_two("element_at", map.sql, key.sql).into())
    });
}
