139 lines
4.3 KiB
Rust
139 lines
4.3 KiB
Rust
use std::{fmt, sync::OnceLock, time::Duration};
|
|
use std::fmt::Display;
|
|
use chrono::{DateTime, Utc};
|
|
use redis::{aio::MultiplexedConnection as RedisConnection, Client as RedisClient, RedisResult};
|
|
use sqlx::{postgres::PgPoolOptions, Pool, Postgres};
|
|
use crate::error::SirenResult;
|
|
|
|
pub mod condition;
|
|
pub mod events;
|
|
mod executable_query;
|
|
pub mod guilds;
|
|
pub mod insert;
|
|
pub mod messages;
|
|
pub mod query;
|
|
pub mod update;
|
|
pub use executable_query::ExecutableQuery;
|
|
|
|
static POOL: OnceLock<Pool<Postgres>> = OnceLock::new();
|
|
static REDIS: OnceLock<RedisClient> = OnceLock::new();
|
|
|
|
pub async fn initialize() -> SirenResult<()> {
|
|
log::info!("Initializing database...");
|
|
let db_user = std::env::var("DATABASE_USER").unwrap_or("siren".to_string());
|
|
let db_password = std::env::var("DATABASE_PASSWORD").expect("DATABASE_PASSWORD must be set");
|
|
let db_host: String = std::env::var("DATABASE_HOST").expect("DATABASE_HOST must be set");
|
|
let db_port = std::env::var("DATABASE_PORT").unwrap_or("5432".to_string());
|
|
let db_name = std::env::var("DATABASE_NAME").unwrap_or("siren".to_string());
|
|
|
|
// Setup Postgres pool connection
|
|
let pool = PgPoolOptions::new()
|
|
.max_connections(5)
|
|
.acquire_timeout(Duration::from_secs(30))
|
|
.connect(&format!(
|
|
"postgres://{}:{}@{}:{}/{}",
|
|
db_user, db_password, db_host, db_port, db_name
|
|
))
|
|
.await?;
|
|
match POOL.set(pool) {
|
|
Ok(_) => {}
|
|
Err(_) => {
|
|
log::warn!("Database pool already initialized");
|
|
}
|
|
}
|
|
|
|
// Setup Redis connection
|
|
let redis = {
|
|
let host = std::env::var("REDIS_HOST").unwrap_or("localhost".to_string());
|
|
let port = std::env::var("REDIS_PORT").unwrap_or("6379".to_string());
|
|
let url = format!("redis://{}:{}", host, port);
|
|
RedisClient::open(url).expect("Failed to create redis client")
|
|
};
|
|
match REDIS.set(redis) {
|
|
Ok(_) => {}
|
|
Err(_) => {
|
|
log::warn!("Redis client already initialized");
|
|
}
|
|
}
|
|
|
|
// Run migrations
|
|
match run_migrations().await {
|
|
Ok(_) => log::debug!("Successfully ran migrations"),
|
|
Err(e) => log::error!("Failed to run migrations: {}", e),
|
|
}
|
|
|
|
log::info!("Database initialized");
|
|
Ok(())
|
|
}
|
|
|
|
pub fn pool() -> &'static Pool<Postgres> {
|
|
POOL.get().unwrap()
|
|
}
|
|
|
|
fn redis() -> &'static RedisClient {
|
|
REDIS.get().unwrap()
|
|
}
|
|
|
|
pub fn redis_connection() -> RedisResult<redis::Connection> {
|
|
let conn = redis().get_connection()?;
|
|
Ok(conn)
|
|
}
|
|
|
|
pub async fn redis_async_connection() -> RedisResult<RedisConnection> {
|
|
let conn = redis().get_multiplexed_async_connection().await?;
|
|
Ok(conn)
|
|
}
|
|
|
|
async fn run_migrations() -> SirenResult<()> {
|
|
log::debug!("Running migrations");
|
|
let pool = pool();
|
|
sqlx::migrate!().run(pool).await?;
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Value {
|
|
Int(i32),
|
|
OptionalInt(Option<i32>),
|
|
BigInt(i64),
|
|
OptionalBigInt(Option<i64>),
|
|
Float(f32),
|
|
OptionalFloat(Option<f32>),
|
|
Double(f64),
|
|
OptionalDouble(Option<f64>),
|
|
Bool(bool),
|
|
OptionalBool(Option<bool>),
|
|
Text(String),
|
|
OptionalText(Option<String>),
|
|
DateTime(DateTime<Utc>),
|
|
OptionalDateTime(Option<DateTime<Utc>>),
|
|
}
|
|
|
|
impl Display for Value {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Value::Int(n) => write!(f, "{}", n),
|
|
Value::OptionalInt(Some(n)) => write!(f, "{}", n),
|
|
Value::OptionalInt(None) => write!(f, "NULL"),
|
|
Value::BigInt(n) => write!(f, "{}", n),
|
|
Value::OptionalBigInt(Some(n)) => write!(f, "{}", n),
|
|
Value::OptionalBigInt(None) => write!(f, "NULL"),
|
|
Value::Float(n) => write!(f, "{}", n),
|
|
Value::OptionalFloat(Some(n)) => write!(f, "{}", n),
|
|
Value::OptionalFloat(None) => write!(f, "NULL"),
|
|
Value::Double(n) => write!(f, "{}", n),
|
|
Value::OptionalDouble(Some(n)) => write!(f, "{}", n),
|
|
Value::OptionalDouble(None) => write!(f, "NULL"),
|
|
Value::Bool(n) => write!(f, "{}", n),
|
|
Value::OptionalBool(Some(n)) => write!(f, "{}", n),
|
|
Value::OptionalBool(None) => write!(f, "NULL"),
|
|
Value::Text(s) => write!(f, "'{}'", s.replace("'", "''")),
|
|
Value::OptionalText(Some(s)) => write!(f, "'{}'", s.replace("'", "''")),
|
|
Value::OptionalText(None) => write!(f, "NULL"),
|
|
Value::DateTime(n) => write!(f, "{}", n),
|
|
Value::OptionalDateTime(Some(n)) => write!(f, "{}", n),
|
|
Value::OptionalDateTime(None) => write!(f, "NULL"),
|
|
}
|
|
}
|
|
}
|