use secrecy::SecretString; use sqlx::{query, query_as, Connection, SqliteConnection}; use crate::auth::UserToken; // TODO: allow configuring this via envar const DB_URI_DEFAULT: &str = "sqlite://sqlite.db"; pub trait Database { async fn get_token(&mut self, username: &str) -> Result; } #[derive(Debug)] pub struct SqliteDatabase { conn: SqliteConnection, } impl SqliteDatabase { pub async fn open() -> Self { let mut db = Self { conn: SqliteConnection::connect(DB_URI_DEFAULT) .await .expect("Failed to open SQLite database"), }; db.init().await; db } pub async fn init(&mut self) { query( "CREATE TABLE IF NOT EXISTS user_tokens ( id INTEGER PRIMARY KEY NOT NULL, username VARCHAR(255), token NCHAR(30), created DATETIME, valid BOOLEAN, );", ) .execute(&mut self.conn) .await .expect("Failed to initialize table user_tokens"); } } impl Database for SqliteDatabase { async fn get_token(&mut self, username: &str) -> Result { let row: (String,) = query_as( "SELECT token FROM user_tokens WHERE username = {username} AND valid = TRUE ORDER BY created DESC", ) .bind(username) .fetch_one(&mut self.conn) .await?; Ok(UserToken(SecretString::new(row.0))) } }