tipi-lang/src/builtins/globals.rs

105 lines
3.8 KiB
Rust

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<FunctionMap> = 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<Value>, args: Vec<Value>) -> Result<Value, RuntimeError> {
print(_self_val, args)?;
println!();
Ok(Value::Void)
}
fn print(_self_val: RefMut<Value>, args: Vec<Value>) -> Result<Value, RuntimeError> {
for arg in args {
print!("{}", arg);
}
Ok(Value::Void)
}
fn now(_self_val: RefMut<Value>, _args: Vec<Value>) -> Result<Value, RuntimeError> {
Ok(Value::DateTime(Box::new(chrono::Utc::now())))
}
fn sql(_self_val: RefMut<Value>, args: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value, Value> = 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))
}