Fundamental_Analysis/services/report-generator-service/src/persistence.rs
Lv, Qi 5327e76aaa chore: 提交本轮 Rust 架构迁移相关改动
- docker-compose: 下线 Python backend/config-service,切换至 config-service-rs
- archive: 归档 legacy Python 目录至 archive/python/*
- services: 新增/更新 common-contracts、api-gateway、各 provider、report-generator-service、config-service-rs
- data-persistence-service: API/system 模块与模型/DTO 调整
- frontend: 更新 useApi 与 API 路由
- docs: 更新路线图并勾选光荣退役
- cleanup: 移除 data-distance-service 占位测试
2025-11-16 20:55:46 +08:00

102 lines
2.9 KiB
Rust

//!
//! 数据持久化客户端
//!
//! 提供一个类型化的接口,用于与 `data-persistence-service` 进行通信。
//!
use crate::error::Result;
use common_contracts::{
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_company_profile(&self, symbol: &str) -> Result<CompanyProfileDto> {
let url = format!("{}/companies/{}", self.base_url, symbol);
info!("Fetching company profile for {} from {}", symbol, url);
let dto = self
.client
.get(&url)
.send()
.await?
.error_for_status()?
.json::<CompanyProfileDto>()
.await?;
Ok(dto)
}
pub async fn get_financial_statements(
&self,
symbol: &str,
) -> Result<Vec<TimeSeriesFinancialDto>> {
let url = format!("{}/market-data/financials/{}", self.base_url, symbol);
info!("Fetching financials for {} from {}", symbol, url);
let dtos = self
.client
.get(&url)
.send()
.await?
.error_for_status()?
.json::<Vec<TimeSeriesFinancialDto>>()
.await?;
Ok(dtos)
}
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(&quote)
.send()
.await?
.error_for_status()?;
Ok(())
}
pub async fn batch_insert_financials(&self, dtos: Vec<TimeSeriesFinancialDto>) -> 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(())
}
}