use std::any::TypeId;
use std::sync::Arc;
use anyhow::bail;
use crate::func::def::{FunctionDef, ParameterBinding, ParameterBindingProvider, Parameters};
use crate::func::utils::must_be_same_type;
use crate::tree::ast::expression::{Expression, ExpressionKind};
use crate::tree::typed_ast::context::ExpressionTranslationContext;
use crate::tree::typed_ast::expression::TypedExpression;
use crate::types::array::Array;
use crate::types::map::Map;
use crate::types::matcher::{
AnyMatcher, ArrayMatcher, BaseMatcher, ExactMatcher, MapKeyMatcher, MapMatcher, TupleMatcher,
};
use crate::types::tuple::Tuple;
use crate::types::{Type, STRING, UNKNOWN, VARIANT};
#[derive(Default, Clone)]
pub struct MapFromArrays;
impl FunctionDef for MapFromArrays {
fn name(&self) -> &'static str {
"map"
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("keys", ArrayMatcher::of(MapKeyMatcher::default()))
.with("values", ArrayMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let keys = match bindings.get_by_index(0)?.typ() {
Type::Array(array) => array,
_ => bail!("checked by type"),
};
let values = match bindings.get_by_index(1)?.typ() {
Type::Array(array) => array,
_ => bail!("checked by type"),
};
Ok(Map::new(
keys.element_type.as_ref().clone(),
values.element_type.as_ref().clone(),
)
.into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct MapFromPairs;
impl FunctionDef for MapFromPairs {
fn name(&self) -> &'static str {
"map"
}
fn parameters(&self) -> Parameters {
Parameters::new().with(
"elements",
ArrayMatcher::of(TupleMatcher::of(
MapKeyMatcher::default(),
AnyMatcher::default(),
)),
)
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
if let Type::Array(array) = bindings.get_by_index(0)?.typ() {
if let Type::Tuple(Tuple { elements }) = array.element_type.as_ref() {
return Ok(Map::new(
elements
.get(0)
.ok_or_else(|| anyhow::anyhow!("checked by type"))?
.as_ref()
.clone(),
elements
.get(1)
.ok_or_else(|| anyhow::anyhow!("checked by type"))?
.as_ref()
.clone(),
)
.into());
}
};
bail!("checked by type");
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct MapEmpty;
impl FunctionDef for MapEmpty {
fn name(&self) -> &'static str {
"map"
}
fn return_type(&self, _bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
Ok(Map::new(UNKNOWN.into(), UNKNOWN.into()).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct MapFromKeyValue;
impl FunctionDef for MapFromKeyValue {
fn name(&self) -> &'static str {
"map"
}
fn parameters(&self) -> Parameters {
Parameters::new().with_var_args(TupleMatcher::of(
MapKeyMatcher::default(),
AnyMatcher::default(),
))
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let tuples: Vec<_> = bindings
.iter()
.map(|t| match t.typ() {
Type::Tuple(tup) => Ok(tup.clone()),
other => bail!("Expected tuple type, got: {other}"),
})
.collect::<anyhow::Result<_>>()?;
let key_type = must_be_same_type(tuples.iter().map(|tup| tup.elements[0].as_ref()))?;
let value_type = must_be_same_type(tuples.iter().map(|tup| tup.elements[1].as_ref()))?;
Ok(Map::new(key_type.clone(), value_type.clone()).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct MapKeys;
impl FunctionDef for MapKeys {
fn name(&self) -> &'static str {
"map_keys"
}
fn parameters(&self) -> Parameters {
Parameters::new().with("map", MapMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let key_type = match bindings.get_by_index(0)?.typ() {
Type::Map(m) => m.key_type.as_ref(),
_ => bail!("expected map type"),
};
Ok(Array::new(key_type.clone()).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct MapValues;
impl FunctionDef for MapValues {
fn name(&self) -> &'static str {
"map_values"
}
fn parameters(&self) -> Parameters {
Parameters::new().with("map", MapMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let value_type = match bindings.get_by_index(0)?.typ() {
Type::Map(m) => m.value_type.as_ref(),
_ => bail!("expected map type"),
};
Ok(Array::new(value_type.clone()).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct TransformValues;
impl FunctionDef for TransformValues {
fn name(&self) -> &'static str {
"transform_values"
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("map", AnyMatcher)
.with("lambda", AnyMatcher)
}
fn custom_bind(
&self,
ast_binding: &ParameterBinding<Arc<Expression>>,
ctx: &mut ExpressionTranslationContext,
) -> anyhow::Result<Option<ParameterBinding<Arc<TypedExpression>>>> {
let map_ast = ast_binding.get_by_name("map")?.clone();
let typed_map = Arc::new(TypedExpression::from_ast_with_context(map_ast, ctx));
let value_type = match typed_map.resolved_type.as_ref() {
Type::Map(m) => m.value_type.clone(),
other => bail!("Expected map type, got {}", other),
};
let lambda_ast = ast_binding.get_by_name("lambda")?.clone();
let ExpressionKind::Lambda(lambda) = &lambda_ast.kind else {
bail!("Expected lambda expression");
};
let lambda_with_hints = lambda.with_param_types(&[value_type])?;
let lambda_expr = Expression {
kind: lambda_with_hints.into(),
span: lambda_ast.span.clone(),
};
let typed_lambda = Arc::new(TypedExpression::from_ast_with_context(
Arc::new(lambda_expr),
ctx,
));
Ok(Some(ParameterBinding::from_named([
("map".to_string(), typed_map),
("lambda".to_string(), typed_lambda),
])))
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let map_type = bindings.get_by_name("map")?.typ().clone();
let key_type = match &map_type {
Type::Map(m) => m.key_type.as_ref().clone(),
Type::Unknown => return Ok(Type::Unknown),
other => bail!("Expected map type for 'map', got {}", other),
};
let lambda_arg = bindings.get_by_name("lambda")?;
let return_type = match lambda_arg.typ() {
Type::Function(f) => f.return_type.as_ref().clone(),
Type::Unknown => Type::Unknown,
other => bail!("Expected function type for lambda, got {}", other),
};
Ok(Map::new(key_type, return_type).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct MapVariantGetValues;
impl FunctionDef for MapVariantGetValues {
fn name(&self) -> &'static str {
"map_variant_get_values"
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with(
"map",
MapMatcher::of(BaseMatcher, ExactMatcher::of(VARIANT)),
)
.with("path", ExactMatcher::of(STRING))
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let key_type = match bindings.get_by_name("map")?.typ() {
Type::Map(m) => m.key_type.as_ref().clone(),
_ => bail!("expected map type"),
};
Ok(Map::new(key_type, VARIANT).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct MapVariantToJsonValues;
impl FunctionDef for MapVariantToJsonValues {
fn name(&self) -> &'static str {
"map_variant_to_json_values"
}
fn parameters(&self) -> Parameters {
Parameters::new().with(
"map",
MapMatcher::of(BaseMatcher, ExactMatcher::of(VARIANT)),
)
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let key_type = match bindings.get_by_name("map")?.typ() {
Type::Map(m) => m.key_type.as_ref().clone(),
_ => bail!("expected map type"),
};
Ok(Map::new(key_type, STRING).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}