use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::error::{BadRequestError, BadRequestResponse};
use crate::{Collection, PocketBase};
#[derive(Error, Debug)]
pub enum UpdateError {
#[error("One or more fields were not validated : {0:?}")]
BadRequest(Vec<BadRequestError>),
#[error("The authorized record is not allowed to perform this action.")]
Forbidden,
#[error("The requested resource wasn't found. Missing collection context.")]
NotFound,
#[error("The communication with the PocketBase API failed: {0}")]
Unreachable(String),
#[error(
"Could not parse response into the expected data structure. It usually means that there is a missmatch between the provided Generic Type Parameter and your Collection definition: {0}"
)]
ParseError(String),
#[error("An unhandled status code was returned by the PocketBase API: {0}")]
UnexpectedResponse(String),
}
pub struct CollectionUpdateBuilder<'a, T: Send + Serialize + Deserialize<'a>> {
client: &'a PocketBase,
collection_name: &'a str,
record_id: &'a str,
data: T,
_marker: std::marker::PhantomData<T>,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct UpdateResponse {
pub collection_name: String,
pub collection_id: String,
pub id: String,
pub updated: String,
pub created: String,
}
impl<'a> Collection<'a> {
pub async fn update<T: Default + Serialize + Clone + Send>(
self,
record_id: &'a str,
record: T,
) -> Result<UpdateResponse, UpdateError> {
let collection_name = self.name;
let endpoint = format!(
"{}/api/collections/{}/records/{}",
self.client.base_url, collection_name, record_id
);
let request = self
.client
.request_patch_json(&endpoint, &record)
.send()
.await;
match request {
Ok(response) => match response.status() {
reqwest::StatusCode::OK => {
let data = response.json::<UpdateResponse>().await;
match data {
Ok(data) => Ok(data),
Err(error) => Err(UpdateError::ParseError(error.to_string())),
}
}
reqwest::StatusCode::BAD_REQUEST => {
let data = response.json::<BadRequestResponse>().await;
match data {
Ok(bad_response) => {
let mut errors: Vec<BadRequestError> = vec![];
for (error_name, error_data) in bad_response.data {
errors.push(BadRequestError {
name: error_name,
code: error_data.code,
message: error_data.message,
});
}
Err(UpdateError::BadRequest(errors))
}
Err(error) => Err(UpdateError::ParseError(error.to_string())),
}
}
reqwest::StatusCode::FORBIDDEN => Err(UpdateError::Forbidden),
reqwest::StatusCode::NOT_FOUND => Err(UpdateError::NotFound),
_ => Err(UpdateError::UnexpectedResponse(
response.status().to_string(),
)),
},
Err(error) => Err(UpdateError::Unreachable(error.to_string())),
}
}
}