finance_query/models/search/
research.rs

1//! Research Report Model
2//!
3//! Represents research reports from search results
4
5use serde::{Deserialize, Serialize};
6use std::ops::Deref;
7
8/// A collection of research reports with DataFrame support.
9///
10/// This wrapper allows `search_results.research_reports.to_dataframe()` syntax while still
11/// acting like a `Vec<ResearchReport>` for iteration, indexing, etc.
12#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13#[serde(transparent)]
14pub struct ResearchReports(pub Vec<ResearchReport>);
15
16impl Deref for ResearchReports {
17    type Target = Vec<ResearchReport>;
18
19    fn deref(&self) -> &Self::Target {
20        &self.0
21    }
22}
23
24impl IntoIterator for ResearchReports {
25    type Item = ResearchReport;
26    type IntoIter = std::vec::IntoIter<ResearchReport>;
27
28    fn into_iter(self) -> Self::IntoIter {
29        self.0.into_iter()
30    }
31}
32
33impl<'a> IntoIterator for &'a ResearchReports {
34    type Item = &'a ResearchReport;
35    type IntoIter = std::slice::Iter<'a, ResearchReport>;
36
37    fn into_iter(self) -> Self::IntoIter {
38        self.0.iter()
39    }
40}
41
42#[cfg(feature = "dataframe")]
43impl ResearchReports {
44    /// Converts the research reports to a polars DataFrame.
45    pub fn to_dataframe(&self) -> ::polars::prelude::PolarsResult<::polars::prelude::DataFrame> {
46        ResearchReport::vec_to_dataframe(&self.0)
47    }
48}
49
50/// A research report result from search
51#[derive(Debug, Clone, Serialize, Deserialize)]
52#[cfg_attr(feature = "dataframe", derive(crate::ToDataFrame))]
53#[non_exhaustive]
54#[serde(rename_all = "camelCase")]
55pub struct ResearchReport {
56    /// Report headline/title
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub report_headline: Option<String>,
59    /// Report author
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub author: Option<String>,
62    /// Report publication date (Unix timestamp in milliseconds)
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub report_date: Option<i64>,
65    /// Report unique identifier
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub id: Option<String>,
68    /// Provider name (e.g., "Morningstar", "Argus")
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub provider: Option<String>,
71}