use crate::builtins::{add, FunctionMap, Signature}; use crate::compiler::ast_pass::Parameter; use crate::compiler::tokens::TokenType; use crate::compiler::tokens::TokenType::{DateTime, ListType, StringType, Void}; use crate::errors::RuntimeError; use crate::value::{string, Value}; use std::cell::RefMut; use std::collections::HashMap; use std::sync::LazyLock; use tokio_postgres::types::Type; use crate::DB_POOL; pub(crate) static GLOBAL_FUNCTIONS: LazyLock = LazyLock::new(|| { let mut global_functions: FunctionMap = HashMap::new(); let functions = &mut global_functions; add(functions, "now", Signature::new(vec![], DateTime, now)); add( functions, "print", Signature::new(vec![Parameter::new("text", StringType)], Void, print), ); add( functions, "println", Signature::new(vec![Parameter::new("text", StringType)], Void, println), ); add( functions, "sql", Signature::new( vec![ Parameter::new("query", StringType), Parameter::varargs(TokenType::Any), ], ListType, sql, ), ); global_functions }); fn println(_self_val: RefMut, args: Vec) -> Result { print(_self_val, args)?; println!(); Ok(Value::Void) } fn print(_self_val: RefMut, args: Vec) -> Result { for arg in args { print!("{}", arg); } Ok(Value::Void) } fn now(_self_val: RefMut, _args: Vec) -> Result { Ok(Value::DateTime(Box::new(chrono::Utc::now()))) } fn sql(_self_val: RefMut, args: Vec) -> Result { let result = tokio::task::block_in_place(|| { tokio::runtime::Handle::current().block_on(async { let mut conn = DB_POOL.get().unwrap().get().await.unwrap(); let result = conn.query(&args[0].to_string(), &[]).await.unwrap(); let mut columns = vec![]; if let Some(first_row) = result.first() { let retrieved_columns = first_row.columns(); for column in retrieved_columns { columns.push((column.name(), column.type_())); } } let mut rows = vec![]; for result_row in &result { let mut row: HashMap = HashMap::new(); for (index, column) in result_row.columns().iter().enumerate() { let column_name = columns.get(index).unwrap().0; let column_type = columns.get(index).unwrap().1; let value = match column_type { &Type::BOOL => Value::Bool(result_row.get(index)), &Type::INT2 | &Type::INT4 => Value::I32(result_row.get(index)), &Type::INT8 => Value::I64(result_row.get(index)), &Type::FLOAT4 => Value::F32(result_row.get(index)), &Type::FLOAT8 | &Type::NUMERIC => Value::F64(result_row.get(index)), &Type::CHAR | &Type::VARCHAR | &Type::TEXT | &Type::BPCHAR | &Type::NAME => { Value::String(result_row.get(index)) } &Type::TIMESTAMP | &Type::TIMESTAMPTZ => { Value::DateTime(Box::new(result_row.get(index))) } &Type::UUID => Value::Uuid(result_row.get(index)), _ => unimplemented!("database type {:?}", column_type), }; row.insert(string(column_name), value); } rows.push(Value::Map(row)); } rows }) }); Ok(Value::List(result)) }