use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::error::Result;
use crate::http::HttpClient;
use crate::models::{FieldDefinition, FieldType, FieldValidationResult};
use crate::pagination::Page;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateFieldBody {
#[serde(rename = "type")]
pub kind: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub regex: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_required: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
}
impl CreateFieldBody {
pub fn new<K, N>(kind: K, name: N) -> Self
where
K: Into<String>,
N: Into<String>,
{
Self {
kind: kind.into(),
name: name.into(),
regex: None,
is_required: None,
is_active: None,
}
}
pub fn regex<S: Into<String>>(mut self, regex: S) -> Self {
self.regex = Some(regex.into());
self
}
pub fn required(mut self, required: bool) -> Self {
self.is_required = Some(required);
self
}
pub fn active(mut self, active: bool) -> Self {
self.is_active = Some(active);
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UpdateFieldBody {
#[serde(skip_serializing_if = "Option::is_none", rename = "type")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regex: Option<Option<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_required: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
}
impl UpdateFieldBody {
pub fn new() -> Self {
Self::default()
}
pub fn kind<S: Into<String>>(mut self, kind: S) -> Self {
self.kind = Some(kind.into());
self
}
pub fn name<S: Into<String>>(mut self, name: S) -> Self {
self.name = Some(name.into());
self
}
pub fn regex<S: Into<String>>(mut self, regex: S) -> Self {
self.regex = Some(Some(regex.into()));
self
}
pub fn clear_regex(mut self) -> Self {
self.regex = Some(None);
self
}
pub fn required(mut self, required: bool) -> Self {
self.is_required = Some(required);
self
}
pub fn active(mut self, active: bool) -> Self {
self.is_active = Some(active);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidateFieldEntry {
pub field_id: String,
pub value: serde_json::Value,
}
impl ValidateFieldEntry {
pub fn new<S: Into<String>>(field_id: S, value: impl Into<serde_json::Value>) -> Self {
Self {
field_id: field_id.into(),
value: value.into(),
}
}
}
#[derive(Debug)]
pub struct ListFieldsRequest<'a> {
http: &'a HttpClient,
account_id: &'a str,
page: Option<u32>,
per_page: Option<u32>,
search: Option<String>,
sort: Option<String>,
include_inactive: Option<bool>,
include_standard: Option<bool>,
}
impl<'a> ListFieldsRequest<'a> {
pub fn page(mut self, page: u32) -> Self {
self.page = Some(page);
self
}
pub fn per_page(mut self, per_page: u32) -> Self {
self.per_page = Some(per_page);
self
}
pub fn search<S: Into<String>>(mut self, search: S) -> Self {
self.search = Some(search.into());
self
}
pub fn sort<S: Into<String>>(mut self, sort: S) -> Self {
self.sort = Some(sort.into());
self
}
pub fn include_inactive(mut self, value: bool) -> Self {
self.include_inactive = Some(value);
self
}
pub fn include_standard(mut self, value: bool) -> Self {
self.include_standard = Some(value);
self
}
pub async fn send(self) -> Result<Page<FieldDefinition>> {
let path = format!("accounts/{}/fields", self.account_id);
let mut req = self.http.request(Method::GET, &path)?;
let mut q: Vec<(&str, String)> = Vec::new();
if let Some(v) = self.page {
q.push(("page", v.to_string()));
}
if let Some(v) = self.per_page {
q.push(("per-page", v.to_string()));
}
if let Some(v) = self.search {
q.push(("search", v));
}
if let Some(v) = self.sort {
q.push(("sort", v));
}
if let Some(v) = self.include_inactive {
q.push(("include_inactive", v.to_string()));
}
if let Some(v) = self.include_standard {
q.push(("include_standard", v.to_string()));
}
if !q.is_empty() {
req = req.query(&q);
}
self.http.send_paged(req).await
}
}
#[derive(Debug)]
pub struct FieldsApi<'a> {
http: &'a HttpClient,
account_id: String,
}
impl<'a> FieldsApi<'a> {
pub(crate) fn new(http: &'a HttpClient, account_id: String) -> Self {
Self { http, account_id }
}
pub async fn create(&self, body: &CreateFieldBody) -> Result<FieldDefinition> {
let path = format!("accounts/{}/fields", self.account_id);
let req = self.http.request(Method::POST, &path)?.json(body);
self.http.send_envelope(req).await
}
pub fn list(&self) -> ListFieldsRequest<'_> {
ListFieldsRequest {
http: self.http,
account_id: &self.account_id,
page: None,
per_page: None,
search: None,
sort: None,
include_inactive: None,
include_standard: None,
}
}
pub async fn get<S: AsRef<str>>(&self, field_id: S) -> Result<FieldDefinition> {
let path = format!("accounts/{}/fields/{}", self.account_id, field_id.as_ref());
let req = self.http.request(Method::GET, &path)?;
self.http.send_envelope(req).await
}
pub async fn update<S: AsRef<str>>(
&self,
field_id: S,
body: &UpdateFieldBody,
) -> Result<FieldDefinition> {
let path = format!("accounts/{}/fields/{}", self.account_id, field_id.as_ref());
let req = self.http.request(Method::PUT, &path)?.json(body);
self.http.send_envelope(req).await
}
pub async fn delete<S: AsRef<str>>(&self, field_id: S) -> Result<()> {
let path = format!("accounts/{}/fields/{}", self.account_id, field_id.as_ref());
let req = self.http.request(Method::DELETE, &path)?;
self.http.send_no_content(req).await
}
pub async fn validate<S: AsRef<str>>(
&self,
field_id: S,
value: impl Into<serde_json::Value>,
) -> Result<FieldValidationResult> {
let path = format!(
"accounts/{}/fields/{}/validate",
self.account_id,
field_id.as_ref()
);
let req = self
.http
.request(Method::POST, &path)?
.json(&serde_json::json!({ "value": value.into() }));
self.http.send_envelope(req).await
}
pub async fn validate_multiple<I>(&self, entries: I) -> Result<Vec<FieldValidationResult>>
where
I: IntoIterator<Item = ValidateFieldEntry>,
{
let entries: Vec<ValidateFieldEntry> = entries.into_iter().collect();
let path = format!("accounts/{}/fields/validate-multiple", self.account_id);
let req = self.http.request(Method::POST, &path)?.json(&entries);
self.http.send_envelope(req).await
}
pub async fn list_types(&self) -> Result<Vec<FieldType>> {
let req = self.http.request(Method::GET, "field-types")?;
self.http.send_envelope(req).await
}
}