earthmc 2.0.5

Async client for interacting with the EarthMC API
Documentation
use derive_builder::Builder;
use serde::Serialize;
use uuid::Uuid;

#[derive(Clone, Serialize)]
pub(crate) struct Query<D>
where
    D: Serialize + ?Sized,
{
    query: D,
}

impl<D: Serialize + Sized> From<D> for Query<D> {
    fn from(value: D) -> Self {
        Self { query: value }
    }
}

#[derive(Serialize, Clone)]
#[serde(untagged)]
pub enum StrOrUuid {
    Str(String),
    Uid(Uuid),
}

impl From<&str> for StrOrUuid {
    fn from(s: &str) -> Self {
        StrOrUuid::Str(s.to_string())
    }
}

impl From<String> for StrOrUuid {
    fn from(s: String) -> Self {
        StrOrUuid::Str(s)
    }
}

impl From<Uuid> for StrOrUuid {
    fn from(u: Uuid) -> Self {
        StrOrUuid::Uid(u)
    }
}

/// An API query that looks up by UUID.
#[derive(Clone, Serialize, Builder)]
#[serde(transparent)]
#[builder(pattern = "owned")]
pub struct UuidQuery {
    #[builder(default)]
    values: Vec<Uuid>,
}

impl From<Uuid> for UuidQuery {
    fn from(value: Uuid) -> Self {
        Self {
            values: vec![value],
        }
    }
}

impl From<Vec<Uuid>> for UuidQuery {
    fn from(values: Vec<Uuid>) -> Self {
        Self { values }
    }
}

impl<const N: usize> From<[Uuid; N]> for UuidQuery {
    fn from(values: [Uuid; N]) -> Self {
        Self {
            values: values.into(),
        }
    }
}

impl UuidQueryBuilder {
    pub fn insert(mut self, single: Uuid) -> Self {
        self.values.get_or_insert_with(Vec::new).push(single);
        self
    }

    pub fn insert_many<I>(mut self, values: I) -> Self
    where
        I: IntoIterator<Item = Uuid>,
    {
        self.values.get_or_insert_with(Vec::new).extend(values);
        self
    }
}

/// An API query that looks up by either UUIDs or names.
#[derive(Clone, Serialize, Builder)]
#[serde(transparent)]
#[builder(pattern = "owned")]
pub struct SimpleQuery {
    #[builder(default)]
    values: Vec<StrOrUuid>,
}

impl SimpleQueryBuilder {
    pub fn insert<T: Into<StrOrUuid>>(mut self, single: T) -> Self {
        self.values.get_or_insert_with(Vec::new).push(single.into());
        self
    }

    pub fn insert_many<I, T>(mut self, values: I) -> Self
    where
        I: IntoIterator<Item = T>,
        T: Into<StrOrUuid>,
    {
        self.values
            .get_or_insert_with(Vec::new)
            .extend(values.into_iter().map(Into::into));
        self
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use serde_json::json;
    use uuid::Uuid;

    use super::{Query, UuidQuery};

    #[test]
    fn uuid_query_serializes_as_query_array() {
        let uuid =
            Uuid::from_str("751de3e0-42f1-4da0-bf62-40d1f5096e50").unwrap();
        let query: Query<UuidQuery> = UuidQuery::from(uuid).into();

        assert_eq!(
            serde_json::to_value(query).unwrap(),
            json!({
                "query": ["751de3e0-42f1-4da0-bf62-40d1f5096e50"]
            })
        );
    }

    #[test]
    fn uuid_query_can_be_built_from_vec() {
        let uuid =
            Uuid::from_str("751de3e0-42f1-4da0-bf62-40d1f5096e50").unwrap();
        let query: Query<UuidQuery> = UuidQuery::from(vec![uuid]).into();

        assert_eq!(
            serde_json::to_value(query).unwrap(),
            json!({
                "query": ["751de3e0-42f1-4da0-bf62-40d1f5096e50"]
            })
        );
    }
}