use serde::{Deserialize, Serialize};
use super::{
shared::traits::{
builder::JQuantsBuilder,
pagination::{HasPaginationKey, MergePage, Paginatable},
},
JQuantsApiClient, JQuantsPlanClient,
};
#[derive(Clone, Serialize)]
pub struct TopixPricesBuilder {
#[serde(skip)]
client: JQuantsApiClient,
#[serde(skip_serializing_if = "Option::is_none")]
from: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pagination_key: Option<String>,
}
impl JQuantsBuilder<TopixPricesResponse> for TopixPricesBuilder {
async fn send(self) -> Result<TopixPricesResponse, crate::JQuantsError> {
self.send_ref().await
}
async fn send_ref(&self) -> Result<TopixPricesResponse, crate::JQuantsError> {
self.client.inner.get("indices/topix", self).await
}
}
impl Paginatable<TopixPricesResponse> for TopixPricesBuilder {
fn pagination_key(mut self, pagination_key: impl Into<String>) -> Self {
self.pagination_key = Some(pagination_key.into());
self
}
}
impl TopixPricesBuilder {
pub(crate) fn new(client: JQuantsApiClient) -> Self {
Self {
client,
from: None,
to: None,
date: None,
pagination_key: None,
}
}
pub fn from(mut self, from: impl Into<String>) -> Self {
self.from = Some(from.into());
self
}
pub fn to(mut self, to: impl Into<String>) -> Self {
self.to = Some(to.into());
self
}
pub fn date(mut self, date: impl Into<String>) -> Self {
self.date = Some(date.into());
self
}
}
pub trait TopixPricesApi: JQuantsPlanClient {
fn get_topix_prices(&self) -> TopixPricesBuilder {
TopixPricesBuilder::new(self.get_api_client().clone())
}
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct TopixPricesResponse {
pub topix: Vec<TopixPriceItem>,
pub pagination_key: Option<String>,
}
impl HasPaginationKey for TopixPricesResponse {
fn get_pagination_key(&self) -> Option<&str> {
self.pagination_key.as_deref()
}
}
impl MergePage for TopixPricesResponse {
fn merge_page(
page: Result<Vec<Self>, crate::JQuantsError>,
) -> Result<Self, crate::JQuantsError> {
let mut page = page?;
let mut merged = page.pop().unwrap();
for p in page {
merged.topix.extend(p.topix);
}
merged.pagination_key = None;
Ok(merged)
}
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct TopixPriceItem {
#[serde(rename = "Date")]
pub date: String,
#[serde(rename = "Open")]
pub open: f64,
#[serde(rename = "High")]
pub high: f64,
#[serde(rename = "Low")]
pub low: f64,
#[serde(rename = "Close")]
pub close: f64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deserialize_topix_prices_response() {
let json = r#"
{
"topix": [
{
"Date": "2022-06-28",
"Open": 1885.52,
"High": 1907.38,
"Low": 1885.32,
"Close": 1907.38
}
],
"pagination_key": "value1.value2."
}
"#;
let response: TopixPricesResponse = serde_json::from_str(json).unwrap();
let expected_response = TopixPricesResponse {
topix: vec![TopixPriceItem {
date: "2022-06-28".to_string(),
open: 1885.52,
high: 1907.38,
low: 1885.32,
close: 1907.38,
}],
pagination_key: Some("value1.value2.".to_string()),
};
pretty_assertions::assert_eq!(response, expected_response);
}
#[test]
fn test_deserialize_topix_prices_response_no_pagination_key() {
let json = r#"
{
"topix": [
{
"Date": "2022-06-28",
"Open": 1885.52,
"High": 1907.38,
"Low": 1885.32,
"Close": 1907.38
}
]
}
"#;
let response: TopixPricesResponse = serde_json::from_str(json).unwrap();
let expected_response = TopixPricesResponse {
topix: vec![TopixPriceItem {
date: "2022-06-28".to_string(),
open: 1885.52,
high: 1907.38,
low: 1885.32,
close: 1907.38,
}],
pagination_key: None,
};
pretty_assertions::assert_eq!(response, expected_response);
}
#[test]
fn test_deserialize_topix_prices_esponse_multiple_items() {
let json = r#"
{
"topix": [
{
"Date": "2022-06-27",
"Open": 1850.50,
"High": 1875.75,
"Low": 1845.00,
"Close": 1860.25
},
{
"Date": "2022-06-28",
"Open": 1885.52,
"High": 1907.38,
"Low": 1885.32,
"Close": 1907.38
}
],
"pagination_key": "value1.value2."
}
"#;
let response: TopixPricesResponse = serde_json::from_str(json).unwrap();
let expected_response = TopixPricesResponse {
topix: vec![
TopixPriceItem {
date: "2022-06-27".to_string(),
open: 1850.50,
high: 1875.75,
low: 1845.00,
close: 1860.25,
},
TopixPriceItem {
date: "2022-06-28".to_string(),
open: 1885.52,
high: 1907.38,
low: 1885.32,
close: 1907.38,
},
],
pagination_key: Some("value1.value2.".to_string()),
};
pretty_assertions::assert_eq!(response, expected_response);
}
#[test]
fn test_deserialize_topix_prices_response_no_data() {
let json = r#"
{
"topix": []
}
"#;
let response: TopixPricesResponse = serde_json::from_str(json).unwrap();
let expected_response = TopixPricesResponse {
topix: vec![],
pagination_key: None,
};
pretty_assertions::assert_eq!(response, expected_response);
}
}