From a48cadbb507a0971c88ae62550d13731ec2d0d03 Mon Sep 17 00:00:00 2001 From: Eline Jorritsma Date: Tue, 21 Nov 2023 14:29:32 +0100 Subject: [PATCH] Refactor AllAssetsRequest, SingleAccountRequest --- src/accounts/single_account_request.rs | 68 ++++++------ src/assets/all_assets_request.rs | 104 ++++++++---------- .../all_claimable_balances_request.rs | 100 +++++++++-------- .../single_claimable_balance_request.rs | 14 ++- src/horizon_client/horizon_client.rs | 22 ++-- src/ledgers/ledgers_request.rs | 7 +- 6 files changed, 156 insertions(+), 159 deletions(-) diff --git a/src/accounts/single_account_request.rs b/src/accounts/single_account_request.rs index a36ce64..a0377d6 100644 --- a/src/accounts/single_account_request.rs +++ b/src/accounts/single_account_request.rs @@ -1,26 +1,50 @@ use crate::models::{is_public_key, Request}; -/// SingleAccountRequest is the request for the /accounts enpoint to get a single account. -/// [More Details](https://www.stellar.org/developers/horizon/reference/endpoints/accounts.html "Accounts") -pub struct SingleAccountRequest { +#[derive(Default, Clone)] +pub struct AccountId(String); +#[derive(Default, Clone)] +pub struct NoAccountId; + +/// SingleAccountRequest is the request for the /accounts endpoint to get a single account. +/// [More Details](https://developers.stellar.org/api/horizon/resources/retrieve-an-account "Accounts") +#[derive(Default)] +pub struct SingleAccountRequest { /// Account ID of the sponsor. Every account in the response will either be sponsored by the given account ID or have a subentry (trustline, offer, or data entry) which is sponsored by the given account ID. - account_id: Option, + account_id: I, } -impl Request for SingleAccountRequest { - fn new() -> Self { - SingleAccountRequest { account_id: None } +impl SingleAccountRequest { + pub fn new() -> Self { + SingleAccountRequest::default() } +} +impl SingleAccountRequest { + /// Sets the account ID of the account to get. + /// # Arguments + /// * `account_id` - The account ID of the account to get. + /// # Returns + /// The request object + /// [SingleAccountRequest](struct.SingleAccountRequest.html) + pub fn set_account_id(self, account_id: String) -> Result, String> { + if let Err(e) = is_public_key(&account_id) { + return Err(e.to_string()); + } + + Ok(SingleAccountRequest { + account_id: AccountId(account_id) + }) + } +} + +impl Request for SingleAccountRequest { fn get_path(&self) -> &str { "/accounts/" } fn get_query_parameters(&self) -> String { let mut query = String::new(); - if let Some(account_id) = &self.account_id { - query.push_str(&format!("{}", account_id)); - } + query.push_str(&format!("{}", self.account_id.0)); query.trim_end_matches('&').to_string() } @@ -33,28 +57,4 @@ impl Request for SingleAccountRequest { self.get_query_parameters() ) } - - fn validate(&self) -> Result<(), String> { - if let Some(account_id) = &self.account_id { - let is_valid = is_public_key(account_id); - if is_valid.is_err() { - return Err(is_valid.unwrap_err()); - } - } - - Ok(()) - } -} - -impl SingleAccountRequest { - /// Sets the account ID of the account to get. - /// # Arguments - /// * `account_id` - The account ID of the account to get. - /// # Returns - /// The request object - /// [SingleAccountRequest](struct.SingleAccountRequest.html) - pub fn set_account_id(&mut self, account_id: String) -> &mut Self { - self.account_id = Some(account_id); - self - } } diff --git a/src/assets/all_assets_request.rs b/src/assets/all_assets_request.rs index d523aee..8e0a84a 100644 --- a/src/assets/all_assets_request.rs +++ b/src/assets/all_assets_request.rs @@ -3,9 +3,9 @@ use crate::models::Request; use super::super::Order; // AllAssetsRequest is the request for the /assets endpoint -// [More Details] https://www.stellar.org/developers/horizon/reference/endpoints/assets-all.html "Assets" +// [More Details] https://developers.stellar.org/api/horizon/resources/list-all-assets "Assets" +#[derive(Default)] pub struct AllAssetsRequest { - /// The assets identifying code. For example, if the asset is a credit issued on the Stellar network, /// the code will be the asset’s code. If the asset is a native asset, the code will be XLM. asset_code: Option, @@ -24,17 +24,13 @@ pub struct AllAssetsRequest { order: Option, } -impl Request for AllAssetsRequest { - fn new() -> Self { - AllAssetsRequest { - asset_code: None, - asset_issuer: None, - cursor: None, - limit: None, - order: None, - } +impl AllAssetsRequest { + pub fn new() -> AllAssetsRequest { + AllAssetsRequest::default() } +} +impl Request for AllAssetsRequest { fn get_path(&self) -> &str { "/assets" } @@ -60,36 +56,6 @@ impl Request for AllAssetsRequest { query.trim_end_matches('&').to_string() } - fn validate(&self) -> Result<(), String> { - if let Some(asset_code) = &self.asset_code { - // TODO: implement full asset code regex - if asset_code.len() > 12 { - return Err("asset_code must be 12 characters or less".to_string()); - } - } - - if let Some(asset_issuer) = &self.asset_issuer { - // TODO: implement full asset issuer regex - if asset_issuer.len() != 56 { - return Err("asset_issuer must be 56 characters".to_string()); - } - } - - if let Some(limit) = &self.limit { - if *limit < 1 || *limit > 200 { - return Err("limit must be between 1 and 200".to_string()); - } - } - - if let Some(cursor) = &self.cursor { - if *cursor < 1 { - return Err("cursor must be greater than or equal to 1".to_string()); - } - } - - Ok(()) - } - fn build_url(&self, base_url: &str) -> String { format!( "{}{}?{}", @@ -107,9 +73,15 @@ impl AllAssetsRequest { /// # Returns /// The request object /// [AllAssetsRequest](struct.AllAssetsRequest.html) - pub fn set_asset_code(&mut self, asset_code: &str) -> &mut Self { - self.asset_code = Some(asset_code.to_owned()); - self + pub fn set_asset_code(self, asset_code: &str) -> Result { + if asset_code.len() > 12 { + return Err("asset_code must be 12 characters or less".to_string()); + } + + Ok(AllAssetsRequest { + asset_code: Some(asset_code.to_string()), + ..self + }) } /// Sets the asset issuer @@ -118,9 +90,15 @@ impl AllAssetsRequest { /// # Returns /// The request object /// [AllAssetsRequest](struct.AllAssetsRequest.html) - pub fn set_asset_issuer(&mut self, asset_issuer: &str) -> &mut Self { - self.asset_issuer = Some(asset_issuer.to_owned()); - self + pub fn set_asset_issuer(self, asset_issuer: &str) -> Result { + if asset_issuer.len() != 56 { + return Err("asset_issuer must be 56 characters".to_string()); + } + + Ok(AllAssetsRequest { + asset_issuer: Some(asset_issuer.to_string()), + ..self + }) } /// Sets the cursor @@ -129,9 +107,15 @@ impl AllAssetsRequest { /// # Returns /// The request object /// [AllAssetsRequest](struct.AllAssetsRequest.html) - pub fn set_cursor(&mut self, cursor: u32) -> &mut Self { - self.cursor = Some(cursor); - self + pub fn set_cursor(self, cursor: u32) -> Result { + if cursor < 1 { + return Err("cursor must be greater than or equal to 1".to_string()); + } + + Ok(AllAssetsRequest { + cursor: Some(cursor), + ..self + }) } /// Sets the limit @@ -140,9 +124,15 @@ impl AllAssetsRequest { /// # Returns /// The request object /// [AllAssetsRequest](struct.AllAssetsRequest.html) - pub fn set_limit(&mut self, limit: u32) -> &mut Self { - self.limit = Some(limit); - self + pub fn set_limit(self, limit: u32) -> Result { + if limit < 1 || limit > 200 { + return Err("limit must be between 1 and 200".to_string()); + } + + Ok(AllAssetsRequest { + limit: Some(limit), + ..self + }) } /// Sets the order @@ -151,8 +141,10 @@ impl AllAssetsRequest { /// # Returns /// The request object /// [AllAssetsRequest](struct.AllAssetsRequest.html) - pub fn set_order(&mut self, order: Order) -> &mut Self { - self.order = Some(order); - self + pub fn set_order(self, order: Order) -> AllAssetsRequest { + AllAssetsRequest { + order: Some(order), + ..self + } } } diff --git a/src/claimable_balances/all_claimable_balances_request.rs b/src/claimable_balances/all_claimable_balances_request.rs index f63ef90..b338770 100644 --- a/src/claimable_balances/all_claimable_balances_request.rs +++ b/src/claimable_balances/all_claimable_balances_request.rs @@ -35,45 +35,6 @@ impl AllClaimableBalancesRequest { } } -impl Request for AllClaimableBalancesRequest { - fn get_path(&self) -> &str { - "/claimable_balances/" - } - - fn get_query_parameters(&self) -> String { - let mut query = String::new(); - if let Some(sponsor) = &self.sponsor { - query.push_str(&format!("sponsor={}&", sponsor)); - } - if let Some(asset) = &self.asset { - query.push_str(&format!("asset={}&", asset)); - } - if let Some(claimant) = &self.claimant { - query.push_str(&format!("claimant={}&", claimant)); - } - if let Some(cursor) = &self.cursor { - query.push_str(&format!("cursor={}&", cursor)); - } - if let Some(limit) = &self.limit { - query.push_str(&format!("limit={}&", limit)); - } - if let Some(order) = &self.order { - query.push_str(&format!("order={}&", order)); - } - - query.trim_end_matches('&').to_string() - } - - fn build_url(&self, base_url: &str) -> String { - format!( - "{}{}?{}", - base_url, - self.get_path(), - self.get_query_parameters() - ) - } -} - impl AllClaimableBalancesRequest { /// Sets the sponsor for the request /// # Arguments @@ -132,11 +93,15 @@ impl AllClaimableBalancesRequest { /// # Returns /// The request object /// [AllClaimableBalancesRequest](struct.AllClaimableBalancesRequest.html) - pub fn set_cursor(self, cursor: u32) -> AllClaimableBalancesRequest { - AllClaimableBalancesRequest { + pub fn set_cursor(self, cursor: u32) -> Result { + if cursor < 1 { + return Err("cursor must be greater than or equal to 1".to_string()); + } + + Ok(AllClaimableBalancesRequest { cursor: Some(cursor), ..self - } + }) } /// Sets the limit for the request @@ -146,11 +111,15 @@ impl AllClaimableBalancesRequest { /// # Returns /// The request object /// [AllClaimableBalancesRequest](struct.AllClaimableBalancesRequest.html) - pub fn set_limit(self, limit: u32) -> AllClaimableBalancesRequest { - AllClaimableBalancesRequest { + pub fn set_limit(self, limit: u32) -> Result { + if limit < 1 || limit > 200 { + return Err("limit must be between 1 and 200".to_string()); + } + + Ok(AllClaimableBalancesRequest { limit: Some(limit), ..self - } + }) } /// Sets the order for the request @@ -166,4 +135,43 @@ impl AllClaimableBalancesRequest { ..self } } -} \ No newline at end of file +} + +impl Request for AllClaimableBalancesRequest { + fn get_path(&self) -> &str { + "/claimable_balances/" + } + + fn get_query_parameters(&self) -> String { + let mut query = String::new(); + if let Some(sponsor) = &self.sponsor { + query.push_str(&format!("sponsor={}&", sponsor)); + } + if let Some(asset) = &self.asset { + query.push_str(&format!("asset={}&", asset)); + } + if let Some(claimant) = &self.claimant { + query.push_str(&format!("claimant={}&", claimant)); + } + if let Some(cursor) = &self.cursor { + query.push_str(&format!("cursor={}&", cursor)); + } + if let Some(limit) = &self.limit { + query.push_str(&format!("limit={}&", limit)); + } + if let Some(order) = &self.order { + query.push_str(&format!("order={}&", order)); + } + + query.trim_end_matches('&').to_string() + } + + fn build_url(&self, base_url: &str) -> String { + format!( + "{}{}?{}", + base_url, + self.get_path(), + self.get_query_parameters() + ) + } +} diff --git a/src/claimable_balances/single_claimable_balance_request.rs b/src/claimable_balances/single_claimable_balance_request.rs index 9b723fb..f5e9ef6 100644 --- a/src/claimable_balances/single_claimable_balance_request.rs +++ b/src/claimable_balances/single_claimable_balance_request.rs @@ -2,9 +2,9 @@ use crate::models::*; #[derive(Default, Clone)] -pub struct Id(String); +pub struct ClaimableBalanceId(String); #[derive(Default, Clone)] -pub struct NoId; +pub struct NoClaimableBalanceId; /// SingleClaimableBalanceRequest is the struct that implements the type for the /claimable_balances endpoint to get a single claimable balance /// [More Details](https://developers.stellar.org/api/horizon/resources/retrieve-a-claimable-balance) "Single Claimable Balance") @@ -13,7 +13,7 @@ pub struct SingleClaimableBalanceRequest { claimable_balance_id: I, } -impl SingleClaimableBalanceRequest { +impl SingleClaimableBalanceRequest { pub fn new() -> Self { SingleClaimableBalanceRequest::default() } @@ -23,12 +23,14 @@ impl SingleClaimableBalanceRequest { pub fn set_claimable_balance_id( self, claimable_balance_id: String, - ) -> SingleClaimableBalanceRequest { - SingleClaimableBalanceRequest { claimable_balance_id: Id(claimable_balance_id) } + ) -> SingleClaimableBalanceRequest { + SingleClaimableBalanceRequest { + claimable_balance_id: ClaimableBalanceId(claimable_balance_id) + } } } -impl Request for SingleClaimableBalanceRequest { +impl Request for SingleClaimableBalanceRequest { fn get_path(&self) -> &str { "/claimable_balances/" } diff --git a/src/horizon_client/horizon_client.rs b/src/horizon_client/horizon_client.rs index fe07e58..9d7df86 100644 --- a/src/horizon_client/horizon_client.rs +++ b/src/horizon_client/horizon_client.rs @@ -5,7 +5,7 @@ use crate::{ assets::prelude::{AllAssetsRequest, AllAssetsResponse}, claimable_balances::prelude::{ AllClaimableBalancesRequest, AllClaimableBalancesResponse, SingleClaimableBalanceRequest, - SingleClaimableBalanceResponse, Id, + SingleClaimableBalanceResponse, ClaimableBalanceId, }, ledgers::{prelude::{ LedgersRequest, LedgersResponse, SingleLedgerRequest, SingleLedgerResponse, @@ -61,7 +61,7 @@ impl HorizonClient { /// [GET /accounts/{account_id}](https://www.stellar.org/developers/horizon/reference/endpoints/accounts-single.html) pub async fn get_single_account( &self, - request: &SingleAccountRequest, + request: &SingleAccountRequest, ) -> Result { self.get::(request).await } @@ -109,7 +109,7 @@ impl HorizonClient { /// [GET /claimable_balances/{claimable_balance_id}](https://www.stellar.org/developers/horizon/reference/endpoints/claimable_balances-single.html) pub async fn get_single_claimable_balance( &self, - request: &SingleClaimableBalanceRequest, + request: &SingleClaimableBalanceRequest, ) -> Result { self.get::(request).await } @@ -389,9 +389,9 @@ mod tests { HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap(); // construct request - let mut single_account_request = SingleAccountRequest::new(); - single_account_request - .set_account_id("GDQJUTQYK2MQX2VGDR2FYWLIYAQIEGXTQVTFEMGH2BEWFG4BRUY4CKI7".to_string()); + let mut single_account_request = SingleAccountRequest::new() + .set_account_id("GDQJUTQYK2MQX2VGDR2FYWLIYAQIEGXTQVTFEMGH2BEWFG4BRUY4CKI7".to_string()) + .unwrap(); let _single_account_response = horizon_client .get_single_account(&single_account_request) @@ -557,16 +557,14 @@ mod tests { } #[tokio::test] - async fn test_get_all_assests() { + async fn test_get_all_assets() { // Initialize horizon client let horizon_client = HorizonClient::new("https://horizon-testnet.stellar.org".to_string()).unwrap(); // construct request - let mut all_assets_request: AllAssetsRequest = AllAssetsRequest::new(); - all_assets_request - // .set_asset_issuer("GDQJUTQYK2MQX2VGDR2FYWLIYAQIEGXTQVTFEMGH2BEWFG4BRUY4CKI7") - .set_limit(1); + let mut all_assets_request: AllAssetsRequest = AllAssetsRequest::new() + .set_limit(1).unwrap(); let _all_assets_response = horizon_client.get_all_assets(&all_assets_request).await; @@ -1033,7 +1031,7 @@ mod tests { // construct request let mut all_claimable_balances_request = AllClaimableBalancesRequest::new() - .set_limit(2); + .set_limit(2).unwrap(); let _all_claimable_balances_response = horizon_client .get_all_claimable_balances(&all_claimable_balances_request) diff --git a/src/ledgers/ledgers_request.rs b/src/ledgers/ledgers_request.rs index de38992..7da7b97 100644 --- a/src/ledgers/ledgers_request.rs +++ b/src/ledgers/ledgers_request.rs @@ -79,11 +79,8 @@ impl LedgersRequest { /// The request object /// [AllAssetsRequest](struct.AllAssetsRequest.html) pub fn set_limit(self, limit: u32) -> Result { - if limit < 1 { - return Err("limit must be greater than or equal to 1".to_string()); - } - if limit > 200 { - return Err("limit must be less than or equal to 200".to_string()); + if limit < 1 || limit > 200 { + return Err("limit must be between 1 and 200".to_string()); } Ok(