use std::time::{Duration, SystemTime}; use rocket::futures::lock::Mutex; use tokio_postgres::{Client, Error, Statement}; use crate::GlobalState; pub const STATEMENT_GET_LINK: usize = 0; pub const STATEMENT_ADD_LINK: usize = 1; pub const STATEMENT_ADD_TEMP_LINK: usize = 2; pub const STATEMENT_DELETE_EXPIRED: usize = 3; pub const N_STATEMENTS: usize = 4; pub async fn get_link(state: &Mutex, link: &str) -> Result, Error> { let lock = state.lock().await; Ok(lock .db_client .query_opt(&lock.statements[STATEMENT_GET_LINK], &[&link]) .await? .map(|row| row.get(0))) } pub async fn add_link(state: &Mutex, link: &str, url: &str) -> Result<(), Error> { let lock = state.lock().await; lock.db_client .execute(&lock.statements[STATEMENT_ADD_LINK], &[&link, &url]) .await?; Ok(()) } pub async fn add_temporary_link( state: &Mutex, link: &str, url: &str, ttl: u64, ) -> Result<(), Error> { let time = SystemTime::now() + Duration::from_secs(ttl); let lock = state.lock().await; lock.db_client .execute( &lock.statements[STATEMENT_ADD_TEMP_LINK], &[&link, &url, &time], ) .await?; Ok(()) } pub async fn delete_expired_links(state: &Mutex) -> Result<(), Error> { let lock = state.lock().await; lock.db_client .execute(&lock.statements[STATEMENT_DELETE_EXPIRED], &[]) .await?; Ok(()) } pub async fn prepare_statements(db: &Client) -> Result<[Statement; N_STATEMENTS], Error> { Ok([ db.prepare("SELECT url FROM links WHERE id = $1").await?, db.prepare("INSERT INTO links (id, url) VALUES ($1, $2)") .await?, db.prepare("INSERT INTO links (id, url, valid_until) VALUES ($1, $2, $3)") .await?, db.prepare("DELETE FROM links WHERE valid_until < NOW()") .await?, ]) } pub async fn prepare_tables(db: &Client) -> Result<(), Error> { db.execute("CREATE TABLE IF NOT EXISTS links (id TEXT PRIMARY KEY, url TEXT NOT NULL, valid_until TIMESTAMP NOT NULL)", &[]).await?; Ok(()) }