parcelwing 0.1.0

Official Rust SDK for the Parcel Wing API.
Documentation
use std::sync::Arc;

use crate::error::Error;
use crate::http::HttpClient;
use crate::types::{
    sort_order_to_string, topic_sort_by_to_string, DeletionResponse, ListResponse,
    ResourceResponse, Topic, TopicCreateRequest, TopicListParams, TopicUpdateRequest,
    TopicVisibility,
};

#[derive(Clone, Debug)]
pub struct TopicsResource {
    http: Arc<HttpClient>,
}

impl TopicsResource {
    pub(crate) fn new(http: Arc<HttpClient>) -> Self {
        Self { http }
    }

    pub async fn list(&self, params: TopicListParams) -> Result<ListResponse<Topic>, Error> {
        self.http
            .get("/api/topics", Some(topic_query(params)))
            .await
    }

    pub async fn create(&self, input: TopicCreateRequest) -> Result<Topic, Error> {
        let response: ResourceResponse<Topic> = self.http.post("/api/topics", &input).await?;
        Ok(response.data)
    }

    pub async fn get(&self, id: impl AsRef<str>) -> Result<Topic, Error> {
        let response: ResourceResponse<Topic> = self
            .http
            .get(&format!("/api/topics/{}", encode(id.as_ref())), None)
            .await?;
        Ok(response.data)
    }

    pub async fn update(
        &self,
        id: impl AsRef<str>,
        input: TopicUpdateRequest,
    ) -> Result<Topic, Error> {
        let response: ResourceResponse<Topic> = self
            .http
            .patch(&format!("/api/topics/{}", encode(id.as_ref())), &input)
            .await?;
        Ok(response.data)
    }

    pub async fn delete(&self, id: impl AsRef<str>) -> Result<DeletionResponse, Error> {
        self.http
            .delete(&format!("/api/topics/{}", encode(id.as_ref())))
            .await
    }
}

fn topic_query(params: TopicListParams) -> Vec<(&'static str, String)> {
    let mut query = Vec::new();
    if let Some(value) = params.page {
        query.push(("page", value.to_string()));
    }
    if let Some(value) = params.limit {
        query.push(("limit", value.to_string()));
    }
    if let Some(value) = params.search {
        query.push(("search", value));
    }
    if let Some(value) = params.active {
        query.push(("active", value.to_string()));
    }
    if let Some(value) = params.visibility {
        query.push(("visibility", topic_visibility_to_string(&value).to_string()));
    }
    if let Some(value) = params.sort_by {
        query.push(("sort_by", topic_sort_by_to_string(&value).to_string()));
    }
    if let Some(value) = params.sort_order {
        query.push(("sort_order", sort_order_to_string(&value).to_string()));
    }
    query
}

fn topic_visibility_to_string(value: &TopicVisibility) -> &'static str {
    match value {
        TopicVisibility::Public => "public",
        TopicVisibility::Private => "private",
    }
}

fn encode(value: &str) -> String {
    url::form_urlencoded::byte_serialize(value.as_bytes()).collect()
}