//! //! 数据持久化客户端 //! //! 提供一个类型化的接口,用于与 `data-persistence-service` 进行通信。 //! use crate::error::Result; use common_contracts::{ config_models::DataSourcesConfig, dtos::{CompanyProfileDto, RealtimeQuoteDto, TimeSeriesFinancialBatchDto, TimeSeriesFinancialDto}, }; use tracing::info; #[derive(Clone)] pub struct PersistenceClient { client: reqwest::Client, base_url: String, } impl PersistenceClient { pub fn new(base_url: String) -> Self { Self { client: reqwest::Client::new(), base_url, } } pub async fn get_data_sources_config(&self) -> Result { let url = format!("{}/configs/data_sources", self.base_url); let config = self.client .get(&url) .send() .await? .error_for_status()? .json() .await?; Ok(config) } pub async fn upsert_company_profile(&self, profile: CompanyProfileDto) -> Result<()> { let url = format!("{}/companies", self.base_url); info!("Upserting company profile for {} to {}", profile.symbol, url); self.client .put(&url) .json(&profile) .send() .await? .error_for_status()?; Ok(()) } pub async fn upsert_realtime_quote(&self, quote: RealtimeQuoteDto) -> Result<()> { let url = format!("{}/market-data/quotes", self.base_url); info!("Upserting realtime quote for {} to {}", quote.symbol, url); self.client .post(&url) .json("e) .send() .await? .error_for_status()?; Ok(()) } pub async fn batch_insert_financials(&self, dtos: Vec) -> Result<()> { if dtos.is_empty() { return Ok(()); } let url = format!("{}/market-data/financials/batch", self.base_url); let symbol = dtos[0].symbol.clone(); info!("Batch inserting {} financial statements for {} to {}", dtos.len(), symbol, url); let batch = TimeSeriesFinancialBatchDto { records: dtos }; self.client .post(&url) .json(&batch) .send() .await? .error_for_status()?; Ok(()) } }