105 lines
3.8 KiB
Rust
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))
|
|
}
|