// file: kb_lib/src/db/dtos/pair.rs //! Normalized pair DTO. /// Application-facing normalized pair DTO. #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct KbPairDto { /// Optional numeric primary key. pub id: std::option::Option, /// Related DEX id. pub dex_id: i64, /// Related pool id. pub pool_id: i64, /// Base token id. pub base_token_id: i64, /// Quote token id. pub quote_token_id: i64, /// Optional display symbol. pub symbol: std::option::Option, /// First seen timestamp. pub first_seen_at: chrono::DateTime, /// Update timestamp. pub updated_at: chrono::DateTime, } impl KbPairDto { /// Creates a new pair DTO. pub fn new( dex_id: i64, pool_id: i64, base_token_id: i64, quote_token_id: i64, symbol: std::option::Option, ) -> Self { let now = chrono::Utc::now(); Self { id: None, dex_id, pool_id, base_token_id, quote_token_id, symbol, first_seen_at: now, updated_at: now, } } } impl TryFrom for KbPairDto { type Error = crate::KbError; fn try_from(entity: crate::KbPairEntity) -> Result { let first_seen_at_result = chrono::DateTime::parse_from_rfc3339(&entity.first_seen_at); let first_seen_at = match first_seen_at_result { Ok(first_seen_at) => first_seen_at.with_timezone(&chrono::Utc), Err(error) => { return Err(crate::KbError::Db(format!( "cannot parse pair first_seen_at '{}': {}", entity.first_seen_at, error ))); } }; let updated_at_result = chrono::DateTime::parse_from_rfc3339(&entity.updated_at); let updated_at = match updated_at_result { Ok(updated_at) => updated_at.with_timezone(&chrono::Utc), Err(error) => { return Err(crate::KbError::Db(format!( "cannot parse pair updated_at '{}': {}", entity.updated_at, error ))); } }; Ok(Self { id: Some(entity.id), dex_id: entity.dex_id, pool_id: entity.pool_id, base_token_id: entity.base_token_id, quote_token_id: entity.quote_token_id, symbol: entity.symbol, first_seen_at, updated_at, }) } }