use sqlx::{PgPool, Postgres, Transaction};
use uuid::Uuid;
use crate::error::Post3Error;
use crate::models::ObjectRow;
pub struct ObjectsRepository<'a> {
db: &'a PgPool,
}
impl<'a> ObjectsRepository<'a> {
pub fn new(db: &'a PgPool) -> Self {
Self { db }
}
pub async fn insert_in_tx(
tx: &mut Transaction<'_, Postgres>,
bucket_id: Uuid,
key: &str,
size: i64,
etag: &str,
content_type: &str,
) -> Result<ObjectRow, Post3Error> {
sqlx::query("DELETE FROM objects WHERE bucket_id = $1 AND key = $2")
.bind(bucket_id)
.bind(key)
.execute(&mut **tx)
.await?;
let row = sqlx::query_as::<_, ObjectRow>(
"INSERT INTO objects (bucket_id, key, size, etag, content_type) \
VALUES ($1, $2, $3, $4, $5) RETURNING *",
)
.bind(bucket_id)
.bind(key)
.bind(size)
.bind(etag)
.bind(content_type)
.fetch_one(&mut **tx)
.await?;
Ok(row)
}
pub async fn get(
&self,
bucket_id: Uuid,
key: &str,
) -> Result<Option<ObjectRow>, Post3Error> {
let row = sqlx::query_as::<_, ObjectRow>(
"SELECT * FROM objects WHERE bucket_id = $1 AND key = $2",
)
.bind(bucket_id)
.bind(key)
.fetch_optional(self.db)
.await?;
Ok(row)
}
pub async fn delete(
&self,
bucket_id: Uuid,
key: &str,
) -> Result<bool, Post3Error> {
let result =
sqlx::query("DELETE FROM objects WHERE bucket_id = $1 AND key = $2")
.bind(bucket_id)
.bind(key)
.execute(self.db)
.await?;
Ok(result.rows_affected() > 0)
}
pub async fn list(
&self,
bucket_id: Uuid,
prefix: Option<&str>,
start_after: Option<&str>,
max_keys: i64,
) -> Result<Vec<ObjectRow>, Post3Error> {
let rows = match (prefix, start_after) {
(Some(pfx), Some(after)) => {
let pattern = format!("{pfx}%");
sqlx::query_as::<_, ObjectRow>(
"SELECT * FROM objects \
WHERE bucket_id = $1 AND key LIKE $2 AND key > $3 \
ORDER BY key ASC LIMIT $4",
)
.bind(bucket_id)
.bind(pattern)
.bind(after)
.bind(max_keys)
.fetch_all(self.db)
.await?
}
(Some(pfx), None) => {
let pattern = format!("{pfx}%");
sqlx::query_as::<_, ObjectRow>(
"SELECT * FROM objects \
WHERE bucket_id = $1 AND key LIKE $2 \
ORDER BY key ASC LIMIT $3",
)
.bind(bucket_id)
.bind(pattern)
.bind(max_keys)
.fetch_all(self.db)
.await?
}
(None, Some(after)) => {
sqlx::query_as::<_, ObjectRow>(
"SELECT * FROM objects \
WHERE bucket_id = $1 AND key > $2 \
ORDER BY key ASC LIMIT $3",
)
.bind(bucket_id)
.bind(after)
.bind(max_keys)
.fetch_all(self.db)
.await?
}
(None, None) => {
sqlx::query_as::<_, ObjectRow>(
"SELECT * FROM objects \
WHERE bucket_id = $1 \
ORDER BY key ASC LIMIT $2",
)
.bind(bucket_id)
.bind(max_keys)
.fetch_all(self.db)
.await?
}
};
Ok(rows)
}
}