diff --git a/src/api/eod.rs b/src/api/eod.rs index 46dbbc1..97e0cc4 100644 --- a/src/api/eod.rs +++ b/src/api/eod.rs @@ -6,3 +6,7 @@ #![allow(clippy::module_inception)] mod eod; + +pub use eod::Eod; +pub use eod::EodBuilder; +pub use eod::EodBuilderError; diff --git a/src/api/eod/eod.rs b/src/api/eod/eod.rs index a64f9f6..3b232a6 100644 --- a/src/api/eod/eod.rs +++ b/src/api/eod/eod.rs @@ -10,14 +10,13 @@ use derive_builder::Builder; use crate::api::common::SortOrder; use crate::api::endpoint_prelude::*; -use crate::api::ParamValue; /// Query for eod. #[derive(Debug, Builder, Clone)] #[builder(setter(strip_option))] pub struct Eod<'a> { /// Search for eod for a symbol. - #[builder(setter(into), default)] + #[builder(setter(name = "_symbols"), default)] symbols: BTreeSet>, /// Exchange to filer symbol by. #[builder(setter(into), default)] @@ -40,11 +39,23 @@ impl<'a> Eod<'a> { } impl<'a> EodBuilder<'a> { - pub fn search_symbols(&mut self, iter: I) -> &mut Self + /// Search the given symbol. + pub fn symbol(&mut self, symbol: &'a str) -> &mut Self { + self.symbols + .get_or_insert_with(BTreeSet::new) + .insert(symbol.into()); + self + } + + /// Search the given symbols. + pub fn symbols(&mut self, iter: I) -> &mut Self where - I: Iterator>, + I: Iterator, + V: Into>, { - self.symbols.get_or_insert_with(BTreeSet::new).extend(iter); + self.symbols + .get_or_insert_with(BTreeSet::new) + .extend(iter.map(|v| v.into())); self } } @@ -62,5 +73,132 @@ impl<'a> Endpoint for Eod<'a> { let mut params = QueryParams::default(); params + .extend(self.symbols.iter().map(|value| ("symbols", value))) + .push_opt("exchange", self.exchange.as_ref()) + .push_opt("sort", self.sort) + .push_opt("date_from", self.date_from) + .push_opt("date_to", self.date_to); + + params + } +} + +impl<'a> Pageable for Eod<'a> { + fn use_keyset_pagination(&self) -> bool { + false + } +} + +#[cfg(test)] +mod tests { + use std::borrow::BorrowMut; + + use chrono::NaiveDate; + + use crate::api::common::SortOrder; + use crate::api::eod::Eod; + use crate::api::{self, endpoint_prelude, Query}; + use crate::test::client::{ExpectedUrl, SingleTestClient}; + + #[test] + fn defaults_are_sufficient() { + Eod::builder().build().unwrap(); + } + + #[test] + fn endpoint() { + let endpoint = ExpectedUrl::builder().endpoint("eod").build().unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = Eod::builder().build().unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn endpoint_symbol() { + let endpoint = ExpectedUrl::builder() + .endpoint("eod") + .add_query_params(&[("symbols", "AAPL")]) + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = Eod::builder().symbol("AAPL").build().unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn endpoint_symbols() { + let endpoint = ExpectedUrl::builder() + .endpoint("eod") + .add_query_params(&[("symbols", "AAPL"), ("symbols", "GOOG")]) + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = Eod::builder() + .symbol("AAPL") + .symbols(["AAPL", "GOOG"].iter().copied()) + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn endpoint_exchange() { + let endpoint = ExpectedUrl::builder() + .endpoint("eod") + .add_query_params(&[("exchange", "NYSE")]) + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = Eod::builder().exchange("NYSE").build().unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn endpoint_sort() { + let endpoint = ExpectedUrl::builder() + .endpoint("eod") + .add_query_params(&[("sort", "ASC")]) + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = Eod::builder().sort(SortOrder::Ascending).build().unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn date_from() { + let endpoint = ExpectedUrl::builder() + .endpoint("eod") + .add_query_params(&[("date_from", "2020-01-01")]) + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = Eod::builder() + .date_from(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap()) + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn date_to() { + let endpoint = ExpectedUrl::builder() + .endpoint("eod") + .add_query_params(&[("date_to", "2020-01-01")]) + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = Eod::builder() + .date_to(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap()) + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); } } diff --git a/src/api/raw.rs b/src/api/raw.rs index 82d3eb2..7ef5941 100644 --- a/src/api/raw.rs +++ b/src/api/raw.rs @@ -89,8 +89,8 @@ mod tests { use http::StatusCode; use serde_json::json; + use crate::api::endpoint_prelude::*; use crate::api::{self, ApiError, AsyncQuery, Query}; - use crate::api::{endpoint, endpoint_prelude::*}; use crate::test::client::{ExpectedUrl, SingleTestClient}; struct Dummy;