hamelin_lib 0.10.4

Core library for Hamelin query language
Documentation
//! JSON functions

use std::any::TypeId;

use crate::func::def::{FunctionDef, ParameterBindingProvider, Parameters};
use crate::types::array::Array;
use crate::types::matcher::{AnyMatcher, ArrayMatcher, ExactMatcher};
use crate::types::struct_type::Struct;
use crate::types::{Type, STRING, VARIANT};

/// parse_json(json_string) - Parse JSON string to variant.
#[derive(Default, Clone)]
pub struct ParseJsonString;

impl FunctionDef for ParseJsonString {
    fn name(&self) -> &'static str {
        "parse_json"
    }

    fn parameters(&self) -> Parameters {
        Parameters::new().with("json", ExactMatcher::of(STRING))
    }

    fn return_type(&self, _bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
        Ok(VARIANT)
    }

    fn type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}

/// parse_json(variant) - Pass-through for already-parsed JSON.
#[derive(Default, Clone)]
pub struct ParseJsonVariant;

impl FunctionDef for ParseJsonVariant {
    fn name(&self) -> &'static str {
        "parse_json"
    }

    fn parameters(&self) -> Parameters {
        Parameters::new().with("json", ExactMatcher::of(VARIANT))
    }

    fn return_type(&self, _bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
        Ok(VARIANT)
    }

    fn type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}

/// to_json_string(variant) - Convert variant to JSON string.
#[derive(Default, Clone)]
pub struct ToJsonString;

impl FunctionDef for ToJsonString {
    fn name(&self) -> &'static str {
        "to_json_string"
    }

    fn parameters(&self) -> Parameters {
        Parameters::new().with("json", ExactMatcher::of(VARIANT))
    }

    fn return_type(&self, _bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
        Ok(STRING)
    }

    fn type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}

/// array_variant_to_json(array<variant>) - Convert every variant element of an
/// array to its JSON string.
///
/// **Internal-only.** Users write `to_json_string(arr)`, which broadcasts via
/// element-type substitution into `transform(arr, x -> to_json_string(x))`;
/// the `lower_transform` fast-path matcher rewrites that to a direct call
/// against this function. Backends translate this to a vectorized array
/// operator (DataFusion: `hamelin_array_variant_to_json` UDF; Trino/DuckDB:
/// `transform(arr, x -> json_format(x))`), avoiding the explode/reaggregate
/// pipeline that a per-row `to_json_string` would force.
#[derive(Default, Clone)]
pub struct ArrayVariantToJson;

impl FunctionDef for ArrayVariantToJson {
    fn name(&self) -> &'static str {
        "array_variant_to_json"
    }

    fn parameters(&self) -> Parameters {
        Parameters::new().with("array", ArrayMatcher::of(ExactMatcher::of(VARIANT)))
    }

    fn return_type(&self, _bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
        Ok(Array::new(STRING).into())
    }

    fn type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}

/// typeof(x) - Get the type of any expression.
#[derive(Default, Clone)]
pub struct Typeof;

impl FunctionDef for Typeof {
    fn name(&self) -> &'static str {
        "typeof"
    }

    fn parameters(&self) -> Parameters {
        Parameters::new().with("x", AnyMatcher::default())
    }

    fn return_type(&self, _bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
        Ok(Struct::default()
            .with_str("hamelin_type", STRING.into())
            .with_str("sql_type", STRING.into())
            .into())
    }

    fn type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}