use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::Collection;
use crate::error::{BadRequestError, BadRequestResponse};
#[derive(Error, Debug)]
pub enum CreateError {
#[error("Failed to create record: {0:?}")]
BadRequest(Vec<BadRequestError>),
#[error("You are not allowed to perform this request.")]
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 mismatch 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),
}
#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CreateResponse {
pub collection_name: String,
pub collection_id: String,
pub id: String,
pub updated: String,
pub created: String,
}
impl Collection<'_> {
pub async fn create<T: Default + Serialize + Clone + Send>(
self,
record: T,
) -> Result<CreateResponse, CreateError> {
let endpoint = format!(
"{}/api/collections/{}/records",
self.client.base_url, self.name
);
let request = self
.client
.request_post_json(&endpoint, &record)
.send()
.await;
create_processing(request).await
}
pub async fn create_multipart(
self,
form: reqwest::multipart::Form,
) -> Result<CreateResponse, CreateError> {
let collection_name = self.name;
let endpoint = format!(
"{}/api/collections/{}/records",
self.client.base_url, collection_name
);
let request = self.client.request_post_form(&endpoint, form).send().await;
create_processing(request).await
}
}
async fn create_processing(
request: Result<reqwest::Response, reqwest::Error>,
) -> Result<CreateResponse, CreateError> {
match request {
Ok(response) => match response.status() {
reqwest::StatusCode::OK => {
let data = response.json::<CreateResponse>().await;
match data {
Ok(data) => Ok(data),
Err(error) => Err(CreateError::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(CreateError::BadRequest(errors))
}
Err(error) => Err(CreateError::ParseError(error.to_string())),
}
}
reqwest::StatusCode::FORBIDDEN => Err(CreateError::Forbidden),
reqwest::StatusCode::NOT_FOUND => Err(CreateError::NotFound),
_ => Err(CreateError::UnexpectedResponse(
response.status().to_string(),
)),
},
Err(error) => Err(CreateError::Unreachable(error.to_string())),
}
}