stellar-client 0.1.2

A client interface to the stellar Horizon API
Documentation
//! Contains endpoints for assets and related information to specific assets.
use super::{Body, Cursor, Direction, IntoRequest, Limit, Order, Records};
use error::Result;
use http::{Request, Uri};
use resources::Asset;
use std::str::FromStr;
use uri::{self, TryFromUri, UriWrap};

/// Represents the all assets end point for the stellar horizon server. The endpoint
/// will return all assets filtered by a myriad of different query params.
///
/// <https://www.stellar.org/developers/horizon/reference/endpoints/assets-all.html>
///
/// ## Example
///
/// ```
/// use stellar_client::sync::Client;
/// use stellar_client::endpoint::asset;
///
/// let client      = Client::horizon_test().unwrap();
/// let endpoint    = asset::All::default();
/// let records     = client.request(endpoint).unwrap();
/// #
/// # assert!(records.records().len() > 0);
/// ```
#[derive(Debug, Default, Clone)]
pub struct All {
    code: Option<String>,
    issuer: Option<String>,
    cursor: Option<String>,
    order: Option<Direction>,
    limit: Option<u32>,
}

impl_cursor!(All);
impl_limit!(All);
impl_order!(All);

impl All {
    /// Fetches all records for a given asset code.
    ///
    /// ## Example
    ///
    /// ```
    /// use stellar_client::sync::Client;
    /// use stellar_client::endpoint::asset;
    ///
    /// let client      = Client::horizon_test().unwrap();
    /// let endpoint    = asset::All::default().with_asset_code("USD");
    /// let records     = client.request(endpoint).unwrap();
    /// #
    /// # assert!(records.records().len() > 0);
    /// # assert_eq!(records.records()[0].code(), "USD");
    /// ```
    pub fn with_asset_code(mut self, code: &str) -> Self {
        self.code = Some(code.to_string());
        self
    }

    /// Fetches all records for a given asset issuer.
    ///
    /// ## Example
    ///
    /// ```
    /// use stellar_client::sync::Client;
    /// use stellar_client::endpoint::asset;
    ///
    /// let client = Client::horizon_test().unwrap();
    /// # let endpoint = asset::All::default().with_asset_code("USD");
    /// # let records = client.request(endpoint).unwrap();
    /// # let issuer = records.records()[0].issuer();
    /// let endpoint = asset::All::default().with_asset_issuer(issuer);
    /// let records = client.request(endpoint).unwrap();
    /// #
    /// # assert!(records.records().len() > 0);
    /// # assert_eq!(records.records()[0].issuer(), issuer);
    /// ```
    pub fn with_asset_issuer(mut self, issuer: &str) -> Self {
        self.issuer = Some(issuer.to_string());
        self
    }

    fn has_query(&self) -> bool {
        self.code.is_some()
            || self.issuer.is_some()
            || self.order.is_some()
            || self.cursor.is_some()
            || self.limit.is_some()
    }
}

impl IntoRequest for All {
    type Response = Records<Asset>;

    fn into_request(self, host: &str) -> Result<Request<Body>> {
        let mut uri = format!("{}/assets", host);

        if self.has_query() {
            uri.push_str("?");
            if let Some(code) = self.code {
                uri.push_str(&format!("asset_code={}&", code));
            }

            if let Some(issuer) = self.issuer {
                uri.push_str(&format!("asset_issuer={}&", issuer));
            }

            if let Some(order) = self.order {
                uri.push_str(&format!("order={}&", order.to_string()));
            }

            if let Some(cursor) = self.cursor {
                uri.push_str(&format!("cursor={}&", cursor));
            }

            if let Some(limit) = self.limit {
                uri.push_str(&format!("limit={}", limit));
            }
        }

        let uri = Uri::from_str(&uri)?;
        let request = Request::get(uri).body(Body::None)?;
        Ok(request)
    }
}

impl TryFromUri for All {
    fn try_from_wrap(wrap: &UriWrap) -> ::std::result::Result<All, uri::Error> {
        let params = wrap.params();
        Ok(All {
            code: params.get_parse("asset_code").ok(),
            issuer: params.get_parse("asset_issuer").ok(),
            cursor: params.get_parse("cursor").ok(),
            order: params.get_parse("order").ok(),
            limit: params.get_parse("limit").ok(),
        })
    }
}

#[cfg(test)]
mod all_assets_tests {
    use super::*;

    #[test]
    fn it_leaves_off_the_params_if_not_specified() {
        let ep = All::default();
        let req = ep.into_request("https://www.google.com").unwrap();
        assert_eq!(req.uri().path(), "/assets");
        assert_eq!(req.uri().query(), None);
    }

    #[test]
    fn it_puts_the_query_params_on_the_uri() {
        let ep = All::default()
            .with_asset_code("CODE")
            .with_asset_issuer("ISSUER")
            .with_cursor("CURSOR")
            .with_limit(123)
            .with_order(Direction::Desc);
        let req = ep.into_request("https://www.google.com").unwrap();
        assert_eq!(req.uri().path(), "/assets");
        assert_eq!(
            req.uri().query(),
            Some("asset_code=CODE&asset_issuer=ISSUER&order=desc&cursor=CURSOR&limit=123")
        );
    }

    #[test]
    fn it_parses_the_query_params_on_the_uri() {
        let uri: Uri =
            "/path?asset_code=CODE&asset_issuer=ISSUER&order=desc&cursor=CURSOR&limit=123"
                .parse()
                .unwrap();
        let ep = All::try_from(&uri).unwrap();
        assert_eq!(ep.code, Some("CODE".to_string()));
        assert_eq!(ep.issuer, Some("ISSUER".to_string()));
        assert_eq!(ep.limit, Some(123));
        assert_eq!(ep.cursor, Some("CURSOR".to_string()));
        assert_eq!(ep.order, Some(Direction::Desc));
    }
}