use serde::{Deserialize, Serialize};
use crate::client::Client;
use crate::types::SymbolVariables;
const QUERY_RS_RATING_RI_PANEL: &str = include_str!("graphql/rs_rating_ri_panel.graphql");
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsRatingRiPanelResponse {
#[serde(default)]
pub market_data: Vec<RsRatingRiPanelItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsRatingRiPanelItem {
pub id: Option<String>,
pub origin_request: Option<RsRatingOriginRequest>,
pub ratings: Option<RsRatingRatings>,
pub pricing_statistics: Option<RsRatingPricingStatistics>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsRatingOriginRequest {
pub from_dialect: Option<String>,
pub symbol: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsRatingRatings {
#[serde(default)]
pub rs_rating: Vec<RsRatingSnapshot>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsRatingSnapshot {
pub letter_value: Option<String>,
pub period: Option<String>,
pub period_offset: Option<String>,
pub value: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsRatingPricingStatistics {
pub intraday_statistics: Option<RsRatingIntradayStatistics>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RsRatingIntradayStatistics {
pub rs_line_new_high: Option<bool>,
}
impl Client {
pub async fn rs_rating_ri_panel(
&self,
symbols: &[&str],
symbol_dialect_type: Option<&str>,
) -> crate::error::Result<RsRatingRiPanelResponse> {
self.graphql_operation(
"RSRatingRIPanel",
SymbolVariables::new(symbols, symbol_dialect_type),
QUERY_RS_RATING_RI_PANEL,
)
.await
}
}
#[cfg(test)]
mod tests {
use crate::test_support::mock_test;
#[tokio::test]
async fn rs_rating_ri_panel_parses_response() {
let (_server, client, mock) = mock_test("RSRatingRIPanel").await;
let resp = client
.rs_rating_ri_panel(&["AAPL"], None)
.await
.expect("rs_rating_ri_panel should succeed");
assert_eq!(resp.market_data.len(), 1);
let item = &resp.market_data[0];
assert_eq!(item.id.as_deref(), Some("AAPL"));
let origin = item.origin_request.as_ref().expect("origin_request");
assert_eq!(origin.from_dialect.as_deref(), Some("CHARTING"));
assert_eq!(origin.symbol.as_deref(), Some("AAPL"));
let ratings = item.ratings.as_ref().expect("ratings");
assert_eq!(ratings.rs_rating.len(), 2);
assert_eq!(ratings.rs_rating[0].letter_value.as_deref(), Some("A"));
assert_eq!(ratings.rs_rating[0].period.as_deref(), Some("DAILY"));
assert_eq!(
ratings.rs_rating[0].period_offset.as_deref(),
Some("CURRENT")
);
assert_eq!(ratings.rs_rating[0].value, Some(92));
assert_eq!(ratings.rs_rating[1].letter_value.as_deref(), Some("B"));
assert_eq!(
ratings.rs_rating[1].period_offset.as_deref(),
Some("P1W_AGO")
);
assert_eq!(ratings.rs_rating[1].value, Some(85));
let pricing = item
.pricing_statistics
.as_ref()
.expect("pricing_statistics");
let intraday = pricing
.intraday_statistics
.as_ref()
.expect("intraday_statistics");
assert_eq!(intraday.rs_line_new_high, Some(true));
mock.assert();
}
#[cfg(not(coverage))]
#[tokio::test]
#[ignore]
async fn integration_rs_rating_ri_panel() {
let client = crate::test_support::live_client().await;
let resp = client
.rs_rating_ri_panel(&["AAPL"], None)
.await
.expect("live rs_rating_ri_panel should succeed");
assert!(!resp.market_data.is_empty());
}
}