diff --git a/Cargo.lock b/Cargo.lock index 533ae07..0414b3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,6 +163,29 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bb8" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457d7ed3f888dfd2c7af56d4975cade43c622f74bdcddfed6d4352f57acc6310" +dependencies = [ + "futures-util", + "parking_lot", + "portable-atomic", + "tokio", +] + +[[package]] +name = "bb8-postgres" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e570e6557cd0f88d28d32afa76644873271a70dc22656df565b2021c4036aa9c" +dependencies = [ + "bb8", + "tokio", + "tokio-postgres", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1255,6 +1278,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "portable-atomic" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" + [[package]] name = "postgres" version = "0.19.12" @@ -1352,16 +1381,6 @@ dependencies = [ "scheduled-thread-pool", ] -[[package]] -name = "r2d2_postgres" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd4b47636dbca581cd057e2f27a5d39be741ea4f85fd3c29e415c55f71c7595" -dependencies = [ - "postgres", - "r2d2", -] - [[package]] name = "rand" version = "0.9.2" @@ -1924,6 +1943,8 @@ version = "0.1.0" dependencies = [ "arc-swap", "axum", + "bb8", + "bb8-postgres", "chrono", "clap", "dotenv", @@ -1932,12 +1953,12 @@ dependencies = [ "notify", "postgres", "r2d2", - "r2d2_postgres", "regex", "reqwest", "serde", "thiserror", "tokio", + "tokio-postgres", "tower", "tower-http", "tower-livereload", diff --git a/Cargo.toml b/Cargo.toml index 3113685..7adeaed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ axum = "0.8.6" log4rs = "1.4.0" serde = { version = "1.0.228", features = ["derive"] } tokio = { version = "1.47", features = ["full"] } +tokio-postgres = "0.7" chrono = "0.4" dotenv = "0.15.0" reqwest = { version = "0.12", features = ["json", "multipart"] } @@ -27,4 +28,5 @@ arc-swap = "1.7.1" regex = "1.12.2" r2d2 = "0.8.10" postgres = { version = "0.19", features = ["with-chrono-0_4"] } -r2d2_postgres = "0.18.2" \ No newline at end of file +bb8 = "0.9" +bb8-postgres = "0.9" \ No newline at end of file diff --git a/src/builtins/globals.rs b/src/builtins/globals.rs index 0a3a806..db89e3e 100644 --- a/src/builtins/globals.rs +++ b/src/builtins/globals.rs @@ -1,28 +1,14 @@ -use crate::builtins::{FunctionMap, Signature, add}; +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::{Value, string}; -use r2d2_postgres::PostgresConnectionManager; -use r2d2_postgres::postgres::NoTls; -use r2d2_postgres::postgres::types::Type; +use crate::value::{string, Value}; use std::cell::RefMut; use std::collections::HashMap; use std::sync::LazyLock; - -pub(crate) static DB_POOL: LazyLock>> = - LazyLock::new(|| { - let manager = PostgresConnectionManager::new( - "host=localhost user=postgres dbname=postgres password=boompje".parse().unwrap(), - NoTls, - ); - - r2d2::Pool::builder() - .max_size(15) - .build(manager) - .expect("Failed to create pool") - }); +use tokio_postgres::types::Type; +use crate::DB_POOL; pub(crate) static GLOBAL_FUNCTIONS: LazyLock = LazyLock::new(|| { let mut global_functions: FunctionMap = HashMap::new(); @@ -72,42 +58,48 @@ fn now(_self_val: RefMut, _args: Vec) -> Result, args: Vec) -> Result { - let mut conn = DB_POOL.get().unwrap(); - let result = conn.query(&args[0].to_string(), &[]).unwrap(); - let mut columns = vec![]; + 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)) + if let Some(first_row) = result.first() { + let retrieved_columns = first_row.columns(); + for column in retrieved_columns { + columns.push((column.name(), column.type_())); } - &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)); - } - Ok(Value::List(rows)) + 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)) } diff --git a/src/lib.rs b/src/lib.rs index 3ef8583..a7c27a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,9 @@ use crate::compiler::ast_pass::{Expression, Statement}; use crate::errors::CompilerErrorAtLine; use crate::symbol_builder::Symbol; use std::collections::HashMap; +use std::sync::OnceLock; +use bb8_postgres::PostgresConnectionManager; +use tokio_postgres::NoTls; mod builtins; pub mod compiler; @@ -20,4 +23,6 @@ pub(crate) type Stmt = Result; pub(crate) type AsmRegistry = HashMap; pub const TIPI_EXT: &str = ".tp"; -pub const DATE_FORMAT_TIMEZONE: &str = "%Y-%m-%d %H:%M:%S%.3f %z"; \ No newline at end of file +pub const DATE_FORMAT_TIMEZONE: &str = "%Y-%m-%d %H:%M:%S%.3f %z"; + +pub static DB_POOL: OnceLock>> = OnceLock::new(); diff --git a/src/main.rs b/src/main.rs index 02541e9..301a8ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,15 +3,18 @@ use axum::extract::{Request, State}; use axum::http::StatusCode; use axum::routing::any; use axum::{Json, Router}; +use bb8_postgres::PostgresConnectionManager; use clap::Parser; use log::info; use std::collections::HashMap; use std::fs; -use std::sync::Arc; +use std::sync::{Arc, LazyLock, OnceLock}; use tipi_lang::compiler::assembly_pass::AsmChunk; use tipi_lang::compiler::{compile_sourcedir, map_underlying, run}; use tipi_lang::errors::TipiLangError; use tipi_lang::vm::interpret_async; +use tokio_postgres::NoTls; +use tipi_lang::DB_POOL; /// A simple CLI tool to greet users #[derive(Parser, Debug)] @@ -31,6 +34,16 @@ struct Args { #[tokio::main] async fn main() -> Result<(), TipiLangError> { + //TODO make configurable + let manager = + PostgresConnectionManager::new_from_stringlike("host=localhost user=postgres password=boompje", NoTls) + .unwrap(); + let pool = bb8::Pool::builder() + .build(manager) + .await + .expect("cannot create the the database connection pool"); + let _ = DB_POOL.set(pool); + tracing_subscriber::fmt::init(); let args = Args::parse(); if let Some(file) = args.file {