use sqlx::PgPool;
use uuid::Uuid;
use crate::error::Post3Error;
use crate::models::BucketRow;
pub struct BucketsRepository<'a> {
db: &'a PgPool,
}
impl<'a> BucketsRepository<'a> {
pub fn new(db: &'a PgPool) -> Self {
Self { db }
}
pub async fn create(&self, name: &str) -> Result<BucketRow, Post3Error> {
let existing = self.get_by_name(name).await?;
if existing.is_some() {
return Err(Post3Error::BucketAlreadyExists(name.to_string()));
}
let row = sqlx::query_as::<_, BucketRow>(
"INSERT INTO buckets (name) VALUES ($1) RETURNING *",
)
.bind(name)
.fetch_one(self.db)
.await?;
Ok(row)
}
pub async fn get_by_name(&self, name: &str) -> Result<Option<BucketRow>, Post3Error> {
let row =
sqlx::query_as::<_, BucketRow>("SELECT * FROM buckets WHERE name = $1")
.bind(name)
.fetch_optional(self.db)
.await?;
Ok(row)
}
pub async fn list(&self) -> Result<Vec<BucketRow>, Post3Error> {
let rows = sqlx::query_as::<_, BucketRow>(
"SELECT * FROM buckets ORDER BY created_at ASC",
)
.fetch_all(self.db)
.await?;
Ok(rows)
}
pub async fn delete(&self, name: &str) -> Result<(), Post3Error> {
let bucket = self
.get_by_name(name)
.await?
.ok_or_else(|| Post3Error::BucketNotFound(name.to_string()))?;
if !self.is_empty(bucket.id).await? {
return Err(Post3Error::BucketNotEmpty(name.to_string()));
}
sqlx::query("DELETE FROM buckets WHERE id = $1")
.bind(bucket.id)
.execute(self.db)
.await?;
Ok(())
}
pub async fn is_empty(&self, bucket_id: Uuid) -> Result<bool, Post3Error> {
let count: (i64,) = sqlx::query_as(
"SELECT COUNT(*) FROM objects WHERE bucket_id = $1",
)
.bind(bucket_id)
.fetch_one(self.db)
.await?;
Ok(count.0 == 0)
}
}