use async_trait::async_trait;
use crate::path::Path;
use crate::{Error, MultipartId, PutMultipartOptions, PutPayload, PutResult, Result};
#[derive(Debug, Clone)]
pub struct PartId {
pub content_id: String,
}
#[async_trait]
pub trait MultipartStore: Send + Sync + 'static {
async fn create_multipart(&self, path: &Path) -> Result<MultipartId>;
async fn create_multipart_opts(
&self,
path: &Path,
opts: PutMultipartOptions,
) -> Result<MultipartId> {
let PutMultipartOptions {
tags,
attributes,
extensions: _,
} = opts;
if !tags.is_empty() || !attributes.is_empty() {
return Err(Error::NotSupported {
source: "create_multipart_opts with non-default options".into(),
});
}
self.create_multipart(path).await
}
async fn put_part(
&self,
path: &Path,
id: &MultipartId,
part_idx: usize,
data: PutPayload,
) -> Result<PartId>;
async fn complete_multipart(
&self,
path: &Path,
id: &MultipartId,
parts: Vec<PartId>,
) -> Result<PutResult>;
async fn abort_multipart(&self, path: &Path, id: &MultipartId) -> Result<()>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Extensions;
struct TestMultipartStore;
#[async_trait]
impl MultipartStore for TestMultipartStore {
async fn create_multipart(&self, _path: &Path) -> Result<MultipartId> {
Ok("test".into())
}
async fn put_part(
&self,
_path: &Path,
_id: &MultipartId,
_part_idx: usize,
_data: PutPayload,
) -> Result<PartId> {
unreachable!()
}
async fn complete_multipart(
&self,
_path: &Path,
_id: &MultipartId,
_parts: Vec<PartId>,
) -> Result<PutResult> {
unreachable!()
}
async fn abort_multipart(&self, _path: &Path, _id: &MultipartId) -> Result<()> {
unreachable!()
}
}
#[tokio::test]
async fn default_create_multipart_opts_ignores_extensions() {
let mut extensions = Extensions::new();
extensions.insert("extension");
let opts = PutMultipartOptions {
extensions,
..Default::default()
};
let id = TestMultipartStore
.create_multipart_opts(&Path::from("test"), opts)
.await
.unwrap();
assert_eq!(id, "test");
}
}