79 lines
2.0 KiB
Rust
79 lines
2.0 KiB
Rust
use derive_more::{Display, Error, From};
|
|
use sqlx::migrate::Migrator;
|
|
|
|
use crate::{config, entity};
|
|
|
|
static MIGRATOR: Migrator = sqlx::migrate!("./migrations");
|
|
|
|
#[derive(Clone)]
|
|
pub struct Database {
|
|
pool: sqlx::AnyPool,
|
|
}
|
|
|
|
impl Database {
|
|
pub async fn init() -> Result<Self> {
|
|
let config = config::config();
|
|
|
|
let pool = sqlx::any::AnyPoolOptions::new()
|
|
.max_connections(config.database.max_connections)
|
|
.connect(&config.database.url)
|
|
.await
|
|
.inspect_err(|e| tracing::error!("Could not connect to database: {e}"))?;
|
|
|
|
MIGRATOR.run(&pool).await?;
|
|
|
|
Ok(Self { pool })
|
|
}
|
|
|
|
pub async fn get_user_by_id(&self, id: entity::ShortId) -> Result<entity::User> {
|
|
let user = sqlx::query_as("SELECT * FROM users WHERE id = $1")
|
|
.bind(id)
|
|
.fetch_optional(&self.pool)
|
|
.await?
|
|
.ok_or(Error::UserDoesNotExists)?;
|
|
|
|
Ok(user)
|
|
}
|
|
|
|
pub async fn get_user_by_username(&self, username: &str) -> Result<entity::User> {
|
|
let user = sqlx::query_as("SELECT * FROM users WHERE username = $1")
|
|
.bind(username)
|
|
.fetch_optional(&self.pool)
|
|
.await?
|
|
.ok_or(Error::UserDoesNotExists)?;
|
|
|
|
Ok(user)
|
|
}
|
|
|
|
pub async fn create_user(&self, username: &str, password: &str) -> Result<entity::User> {
|
|
let user = self.get_user_by_username(username).await;
|
|
if user.is_ok() {
|
|
return Err(Error::UserAlreadyExists);
|
|
}
|
|
|
|
let id = sqlx::query_scalar(
|
|
"INSERT INTO users(username, password) VALUES ($1, $2) RETURNING id",
|
|
)
|
|
.bind(username)
|
|
.bind(password)
|
|
.fetch_one(&self.pool)
|
|
.await?;
|
|
|
|
let user = self.get_user_by_id(id).await?;
|
|
|
|
Ok(user)
|
|
}
|
|
}
|
|
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
#[derive(Debug, From, Error, Display)]
|
|
pub enum Error {
|
|
#[from]
|
|
Migrate(sqlx::migrate::MigrateError),
|
|
#[from]
|
|
Sqlx(sqlx::Error),
|
|
UserDoesNotExists,
|
|
UserAlreadyExists,
|
|
}
|