mod link;
mod read;
mod remove;
mod update;
mod write;
use std::sync::Arc;
use reqwest::Method;
use reduct_base::error::ErrorCode;
use reduct_base::msg::bucket_api::{BucketInfo, BucketSettings, FullBucketInfo, QuotaType};
use reduct_base::msg::entry_api::{EntryInfo, RenameEntry};
use crate::client::Result;
use crate::http_client::HttpClient;
pub struct Bucket {
pub(crate) name: String,
pub(crate) http_client: Arc<HttpClient>,
}
pub struct BucketBuilder {
name: String,
exist_ok: bool,
settings: BucketSettings,
http_client: Arc<HttpClient>,
}
impl BucketBuilder {
pub(crate) fn new(name: String, http_client: Arc<HttpClient>) -> Self {
Self {
name,
exist_ok: false,
settings: BucketSettings::default(),
http_client,
}
}
pub fn exist_ok(mut self, exist_ok: bool) -> Self {
self.exist_ok = exist_ok;
self
}
pub fn quota_type(mut self, quota_type: QuotaType) -> Self {
self.settings.quota_type = Some(quota_type);
self
}
pub fn quota_size(mut self, quota_size: u64) -> Self {
self.settings.quota_size = Some(quota_size);
self
}
pub fn max_block_size(mut self, max_block_size: u64) -> Self {
self.settings.max_block_size = Some(max_block_size);
self
}
pub fn max_block_records(mut self, max_block_records: u64) -> Self {
self.settings.max_block_records = Some(max_block_records);
self
}
pub fn settings(mut self, settings: BucketSettings) -> Self {
self.settings = settings;
self
}
pub async fn send(self) -> Result<Bucket> {
let result = self
.http_client
.send_json(Method::POST, &format!("/b/{}", self.name), self.settings)
.await;
match result {
Ok(_) => {}
Err(e) => {
if !(self.exist_ok && e.status() == ErrorCode::Conflict) {
return Err(e);
}
}
}
Ok(Bucket {
name: self.name.clone(),
http_client: Arc::clone(&self.http_client),
})
}
}
impl Bucket {
pub fn name(&self) -> &str {
&self.name
}
pub fn server_url(&self) -> &str {
&self.http_client.url()
}
pub async fn remove(&self) -> Result<()> {
let request = self
.http_client
.request(Method::DELETE, &format!("/b/{}", self.name));
self.http_client.send_request(request).await?;
Ok(())
}
pub async fn settings(&self) -> Result<BucketSettings> {
Ok(self.full_info().await?.settings)
}
pub async fn set_settings(&self, settings: BucketSettings) -> Result<()> {
self.http_client
.send_json::<BucketSettings>(Method::PUT, &format!("/b/{}", self.name), settings)
.await
}
pub async fn full_info(&self) -> Result<FullBucketInfo> {
self.http_client
.send_and_receive_json::<(), FullBucketInfo>(
Method::GET,
&format!("/b/{}", self.name),
None,
)
.await
}
pub async fn info(&self) -> Result<BucketInfo> {
Ok(self.full_info().await?.info)
}
pub async fn entries(&self) -> Result<Vec<EntryInfo>> {
Ok(self.full_info().await?.entries)
}
pub async fn rename_entry(&self, entry: &str, new_name: &str) -> Result<()> {
self.http_client
.send_json(
Method::PUT,
&format!("/b/{}/{}/rename", self.name, entry),
RenameEntry {
new_name: new_name.to_string(),
},
)
.await
}
pub async fn rename(&mut self, new_name: &str) -> Result<()> {
self.http_client
.send_json(
Method::PUT,
&format!("/b/{}/rename", self.name),
RenameEntry {
new_name: new_name.to_string(),
},
)
.await?;
self.name = new_name.to_string();
Ok(())
}
}
#[cfg(test)]
mod tests {
use rstest::{fixture, rstest};
use reduct_base::error::ErrorCode;
use crate::client::tests::{bucket_settings, client};
use crate::client::ReductClient;
use super::*;
#[rstest]
#[tokio::test]
async fn test_bucket_full_info(#[future] bucket: Bucket) {
let bucket = bucket.await;
let FullBucketInfo {
info,
settings,
entries,
} = bucket.full_info().await.unwrap();
assert_eq!(info, bucket.info().await.unwrap());
assert_eq!(settings, bucket.settings().await.unwrap());
assert_eq!(entries, bucket.entries().await.unwrap());
}
#[rstest]
#[tokio::test]
async fn test_bucket_settings(#[future] bucket: Bucket, bucket_settings: BucketSettings) {
let bucket = bucket.await;
let settings = bucket.settings().await.unwrap();
assert_eq!(settings, bucket_settings);
let new_settings = BucketSettings {
quota_size: Some(100),
..BucketSettings::default()
};
bucket.set_settings(new_settings.clone()).await.unwrap();
assert_eq!(
bucket.settings().await.unwrap(),
BucketSettings {
quota_size: new_settings.quota_size,
..bucket_settings
}
);
}
#[rstest]
#[tokio::test]
async fn test_bucket_remove(#[future] bucket: Bucket) {
let bucket = bucket.await;
bucket.remove().await.unwrap();
assert_eq!(
bucket.info().await.err().unwrap().status,
ErrorCode::NotFound
);
}
#[rstest]
#[tokio::test]
async fn test_bucket_rename_entry(#[future] bucket: Bucket) {
let bucket = bucket.await;
bucket.rename_entry("entry-1", "new-entry-1").await.unwrap();
let entries = bucket.entries().await.unwrap();
assert!(entries.iter().any(|entry| entry.name == "new-entry-1"));
}
#[rstest]
#[tokio::test]
async fn test_bucket_rename(#[future] bucket: Bucket) {
let mut bucket = bucket.await;
bucket.rename("new-bucket").await.unwrap();
assert_eq!(bucket.name(), "new-bucket");
assert!(bucket.info().await.is_ok());
}
#[fixture]
pub async fn bucket(#[future] client: ReductClient) -> Bucket {
client.await.get_bucket("test-bucket-1").await.unwrap()
}
}