use std::sync::Arc;
use crate::value::Value;
use hamelin_lib::tree::ast::expression::{
BinaryLiteral, Expression, IntervalUnit, RowsLiteral, UnboundRangeLiteral,
};
use hamelin_lib::tree::ast::ops::{BinaryOp, UnaryPostfixOp, UnaryPrefixOp};
use hamelin_lib::tree::builder::{
boolean, call, decimal_from_parts, double, int, interval, lambda, null, pair, string,
struct_literal, ArrayLiteralBuilder, BinaryOperatorBuilder, ExpressionBuilder,
TupleLiteralBuilder, UnaryPostfixOperatorBuilder, UnaryPrefixOperatorBuilder,
};
use hamelin_lib::tree::options::ExpressionTypeCheckOptions;
use hamelin_lib::tree::typed_ast::expression::TypedExpression;
use hamelin_lib::type_check_expression;
impl From<Value> for Arc<TypedExpression> {
fn from(value: Value) -> Self {
Arc::new(TypedExpression::from(value))
}
}
impl From<Value> for TypedExpression {
fn from(value: Value) -> Self {
let ast = match value {
Value::Boolean(b) => boolean(b).build(),
Value::Int(i) => int(i).build(),
Value::Double(d) => double(d).build(),
Value::String(s) => string(s).build(),
Value::Binary(b) => Expression::from_kind(BinaryLiteral { value: b }),
Value::Rows(r) => Expression::from_kind(RowsLiteral { value: r }),
Value::Interval(duration) => {
let millis = duration.num_milliseconds();
interval(millis, IntervalUnit::Millisecond).build()
}
Value::CalendarInterval(months) => {
interval(months as i64, IntervalUnit::Month).build()
}
Value::Null => null().build(),
Value::Decimal(decimal) => {
let unscaled_digits = decimal.unscaled.abs().to_string().len() as u32;
let precision = unscaled_digits.max(decimal.scale as u32);
decimal_from_parts(decimal.unscaled, precision, decimal.scale as u32).build()
}
Value::Array(elements) => {
let mut builder = ArrayLiteralBuilder::new();
for elem in elements {
let typed_elem = TypedExpression::from(elem);
builder = builder.element(typed_elem.ast.as_ref().clone());
}
builder.build()
}
Value::Tuple(elements) => {
let mut builder = TupleLiteralBuilder::new();
for elem in elements {
let typed_elem = TypedExpression::from(elem);
builder = builder.element(typed_elem.ast.as_ref().clone());
}
builder.build()
}
Value::Struct(fields) => {
let mut builder = struct_literal();
for (sql_name, value) in fields {
let typed_expr = TypedExpression::from(value);
builder = builder.field(sql_name.name(), typed_expr.ast.as_ref().clone());
}
builder.build()
}
Value::Timestamp(ts) => {
let iso_string = ts.instant().to_rfc3339();
call("ts").arg(string(iso_string)).build()
}
Value::Map(map) => {
let mut array_builder = ArrayLiteralBuilder::new();
for (k, v) in map {
let key_expr = TypedExpression::from(k);
let val_expr = TypedExpression::from(v);
let pair_expr =
pair(key_expr.ast.as_ref().clone(), val_expr.ast.as_ref().clone());
array_builder = array_builder.element(pair_expr);
}
call("map").arg(array_builder).build()
}
Value::Range(range) => {
match (&range.lower, &range.upper) {
(Some(lower), Some(upper)) => {
let left_expr = TypedExpression::from(lower.clone());
let right_expr = TypedExpression::from(upper.clone());
BinaryOperatorBuilder::new(
BinaryOp::Range,
left_expr.ast.as_ref().clone(),
right_expr.ast.as_ref().clone(),
)
.build()
}
(Some(lower), None) => {
let operand_expr = TypedExpression::from(lower.clone());
UnaryPostfixOperatorBuilder::new(
UnaryPostfixOp::Range,
operand_expr.ast.as_ref().clone(),
)
.build()
}
(None, Some(upper)) => {
let operand_expr = TypedExpression::from(upper.clone());
UnaryPrefixOperatorBuilder::new(
UnaryPrefixOp::Range,
operand_expr.ast.as_ref().clone(),
)
.build()
}
(None, None) => {
Expression::from_kind(UnboundRangeLiteral {})
}
}
}
Value::Variant(json) => {
let json_string = json.to_string();
call("parse_json").arg(string(json_string)).build()
}
Value::Closure(closure) => {
closure
.lambda
.parameters
.iter()
.fold(lambda(), |b, param| {
b.param_with_type(param.name.name(), param.typ.clone())
})
.body(closure.lambda.body.ast.as_ref().clone())
.build()
}
Value::Unknown => null().build(),
};
type_check_expression(ast, ExpressionTypeCheckOptions::default()).output
}
}