post3 0.1.0

Pluggable S3-compatible object storage — core library with PostgreSQL and filesystem backends
Documentation
use sqlx::PgPool;
use uuid::Uuid;

use crate::error::Post3Error;
use crate::models::{UploadPartInfo, UploadPartRow};

pub struct UploadPartsRepository;

impl UploadPartsRepository {
    pub async fn upsert(
        db: &PgPool,
        upload_id: Uuid,
        part_number: i32,
        data: &[u8],
        size: i64,
        etag: &str,
    ) -> Result<(), Post3Error> {
        sqlx::query(
            "INSERT INTO upload_parts (upload_id, part_number, data, size, etag) \
             VALUES ($1, $2, $3, $4, $5) \
             ON CONFLICT (upload_id, part_number) DO UPDATE \
             SET data = EXCLUDED.data, size = EXCLUDED.size, \
                 etag = EXCLUDED.etag, created_at = NOW()",
        )
        .bind(upload_id)
        .bind(part_number)
        .bind(data)
        .bind(size)
        .bind(etag)
        .execute(db)
        .await?;

        Ok(())
    }

    pub async fn list_info(
        db: &PgPool,
        upload_id: Uuid,
        part_number_marker: Option<i32>,
        max_parts: i64,
    ) -> Result<Vec<UploadPartInfo>, Post3Error> {
        let rows = if let Some(marker) = part_number_marker {
            sqlx::query_as::<_, UploadPartInfo>(
                "SELECT part_number, size, etag, created_at \
                 FROM upload_parts \
                 WHERE upload_id = $1 AND part_number > $2 \
                 ORDER BY part_number ASC LIMIT $3",
            )
            .bind(upload_id)
            .bind(marker)
            .bind(max_parts)
            .fetch_all(db)
            .await?
        } else {
            sqlx::query_as::<_, UploadPartInfo>(
                "SELECT part_number, size, etag, created_at \
                 FROM upload_parts \
                 WHERE upload_id = $1 \
                 ORDER BY part_number ASC LIMIT $2",
            )
            .bind(upload_id)
            .bind(max_parts)
            .fetch_all(db)
            .await?
        };

        Ok(rows)
    }

    pub async fn get_ordered_by_numbers(
        db: &PgPool,
        upload_id: Uuid,
        part_numbers: &[i32],
    ) -> Result<Vec<UploadPartRow>, Post3Error> {
        // Fetch the requested parts in order
        let rows = sqlx::query_as::<_, UploadPartRow>(
            "SELECT * FROM upload_parts \
             WHERE upload_id = $1 AND part_number = ANY($2) \
             ORDER BY part_number ASC",
        )
        .bind(upload_id)
        .bind(part_numbers)
        .fetch_all(db)
        .await?;

        Ok(rows)
    }
}