Skip to content

Commit

Permalink
Implement timezones endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
reubenwong97 committed Oct 21, 2023
1 parent c1fe598 commit c9af585
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "marketstack"
version = "0.0.6"
version = "0.0.7"
edition = "2021"
license = "MIT"
description = "Rust bindings for Marketstack REST API"
Expand Down
1 change: 1 addition & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub mod dividends;
pub mod eod;
pub mod paged;
pub mod splits;
pub mod timezones;

pub use self::client::AsyncClient;
pub use self::client::Client;
Expand Down
112 changes: 112 additions & 0 deletions src/api/timezones.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//! Implementation of the `timezones` API endpoint.
//!
//! This endpoint is used to lookup the timezones supported by Marketstack.

use derive_builder::Builder;

use crate::api::paged::PaginationError;
use crate::api::{endpoint_prelude::*, ApiError};

/// Query for `timezones`.
#[derive(Debug, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct Timezones {
/// Pagination limit for API request.
#[builder(setter(name = "_limit"), default)]
limit: Option<PageLimit>,
/// Pagination offset value for API request.
#[builder(default)]
offset: Option<u64>,
}

impl Timezones {
/// Create a builder for this endpoint.
pub fn builder() -> TimezonesBuilder {
TimezonesBuilder::default()
}
}

impl TimezonesBuilder {
/// Limit the number of results returned.
pub fn limit(&mut self, limit: u16) -> Result<&mut Self, ApiError<PaginationError>> {
let new = self;
new.limit = Some(Some(PageLimit::new(limit)?));
Ok(new)
}
}

impl Endpoint for Timezones {
fn method(&self) -> Method {
Method::GET
}

fn endpoint(&self) -> Cow<'static, str> {
"timezones".into()
}

fn parameters(&self) -> QueryParams {
let mut params = QueryParams::default();

params
.push_opt("limit", self.limit.clone())
.push_opt("offset", self.offset);

params
}
}

#[cfg(test)]
mod tests {

use crate::api::timezones::Timezones;
use crate::api::{self, Query};
use crate::test::client::{ExpectedUrl, SingleTestClient};

#[test]
fn timezones_defaults_are_sufficient() {
Timezones::builder().build().unwrap();
}

#[test]
fn timezones_endpoint() {
let endpoint = ExpectedUrl::builder()
.endpoint("timezones")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");

let endpoint = Timezones::builder().build().unwrap();
api::ignore(endpoint).query(&client).unwrap();
}

#[test]
fn timezones_limit() {
let endpoint = ExpectedUrl::builder()
.endpoint("timezones")
.add_query_params(&[("limit", "50")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");

let endpoint = Timezones::builder().limit(50).unwrap().build().unwrap();
api::ignore(endpoint).query(&client).unwrap();
}

#[test]
fn timezones_over_limit() {
assert!(Timezones::builder().limit(9999).is_err());
}

#[test]
fn timezones_offset() {
let endpoint = ExpectedUrl::builder()
.endpoint("timezones")
.add_query_params(&[("offset", "2")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");

let endpoint = Timezones::builder().offset(2).build().unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
}
56 changes: 55 additions & 1 deletion src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,31 @@ pub struct CurrenciesData {
pub data: Vec<CurrenciesDataItem>,
}

/// Rust representation of single data item from Marketstack `timezones` response.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TimezonesDataItem {
/// Name of the given timezone.
pub timezone: String,
/// Abbreviation of the given timezone.
pub abbr: String,
/// Summer time abbreviation of the given timezone.
pub abbr_dst: String,
}

/// Rust representation of the JSON response from `timezones` marketstack endpoint.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TimezonesData {
/// Corresponds to pagination entry from JSON response from marketstack.
pub pagination: PaginationInfo,
/// Corresponds to data entry from JSON response from marketstack.
pub data: Vec<TimezonesDataItem>,
}

#[cfg(test)]
mod tests {
use chrono::NaiveDate;

use crate::{CurrenciesData, DividendsData, EodData, SplitsData};
use crate::{CurrenciesData, DividendsData, EodData, SplitsData, TimezonesData};

#[test]
fn test_deserialize_eod() {
Expand Down Expand Up @@ -298,4 +318,38 @@ mod tests {
assert_eq!(currencies_data.data[0].symbol, "$");
assert_eq!(currencies_data.data[0].name, "US Dollar");
}

#[test]
fn test_deserialize_timezones() {
let json_data = r#"{
"pagination": {
"limit": 3,
"offset": 0,
"count": 3,
"total": 57
},
"data": [
{
"timezone": "America/New_York",
"abbr": "EST",
"abbr_dst": "EDT"
},
{
"timezone": "America/Argentina/Buenos_Aires",
"abbr": "-03",
"abbr_dst": "-03"
},
{
"timezone": "Europe/Vienna",
"abbr": "CET",
"abbr_dst": "CEST"
}
]
}"#;

let timezones_data: TimezonesData = serde_json::from_str(json_data).unwrap();
assert_eq!(timezones_data.data[0].timezone, "America/New_York");
assert_eq!(timezones_data.data[0].abbr, "EST");
assert_eq!(timezones_data.data[0].abbr_dst, "EDT");
}
}
44 changes: 44 additions & 0 deletions tests/timezones.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use marketstack::api::{timezones, AsyncQuery, Query};
use marketstack::{AsyncMarketstack, Marketstack, TimezonesData};

mod setup;

#[test]
#[ignore]
fn test_timezones() {
let api_key = setup::setup_key();
let client = Marketstack::new_insecure("api.marketstack.com", api_key).unwrap();

let endpoint = timezones::Timezones::builder()
.limit(3)
.unwrap()
.build()
.unwrap();
let timezones_result: TimezonesData = endpoint.query(&client).unwrap();

assert_eq!(timezones_result.pagination.limit, 3);
assert_eq!(timezones_result.pagination.offset, 0);

assert_eq!(timezones_result.data.len(), 3);
}

#[tokio::test]
#[ignore]
async fn test_async_timezones() {
let api_key = setup::setup_key();
let client = AsyncMarketstack::new_insecure("api.marketstack.com", api_key)
.await
.unwrap();

let endpoint = timezones::Timezones::builder()
.limit(3)
.unwrap()
.build()
.unwrap();
let timezones_result: TimezonesData = endpoint.query_async(&client).await.unwrap();

assert_eq!(timezones_result.pagination.limit, 3);
assert_eq!(timezones_result.pagination.offset, 0);

assert_eq!(timezones_result.data.len(), 3);
}

0 comments on commit c9af585

Please sign in to comment.