use crate::error::Result;
use crate::models::discovery::reference::SymbolMatch;
use super::models::SearchCoinDTO;
fn to_symbol_match(dto: SearchCoinDTO) -> SymbolMatch {
SymbolMatch {
symbol: dto
.symbol
.map(|s| s.to_ascii_uppercase())
.unwrap_or_else(|| dto.id.clone()),
id: Some(dto.id),
name: Some(dto.name),
exchange: None,
asset_type: Some("Cryptocurrency".to_string()),
currency: None,
active: Some(true),
market_cap_rank: dto.market_cap_rank,
thumbnail: dto.thumb,
image: dto.large,
}
}
pub async fn fetch_symbol_search_response(query: &str, limit: u32) -> Result<Vec<SymbolMatch>> {
let resp = super::client()?.search(query).await?;
Ok(resp
.coins
.into_iter()
.take(limit as usize)
.map(to_symbol_match)
.collect())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn maps_a_search_hit_onto_the_neutral_model() {
let dto = SearchCoinDTO {
id: "bitcoin".to_string(),
name: "Bitcoin".to_string(),
symbol: Some("btc".to_string()),
market_cap_rank: Some(1),
thumb: Some("https://example.com/thumb.png".to_string()),
large: Some("https://example.com/large.png".to_string()),
};
let out = to_symbol_match(dto);
assert_eq!(out.symbol, "BTC");
assert_eq!(out.id.as_deref(), Some("bitcoin"));
assert_eq!(out.name.as_deref(), Some("Bitcoin"));
assert_eq!(out.asset_type.as_deref(), Some("Cryptocurrency"));
assert_eq!(out.exchange, None);
assert_eq!(out.active, Some(true));
assert_eq!(out.market_cap_rank, Some(1));
assert_eq!(
out.thumbnail.as_deref(),
Some("https://example.com/thumb.png")
);
assert_eq!(out.image.as_deref(), Some("https://example.com/large.png"));
}
#[test]
fn a_hit_without_a_ticker_falls_back_to_the_id() {
let dto = SearchCoinDTO {
id: "some-coin".to_string(),
name: "Some Coin".to_string(),
symbol: None,
market_cap_rank: None,
thumb: None,
large: None,
};
let out = to_symbol_match(dto);
assert_eq!(out.symbol, "some-coin");
assert_eq!(out.id.as_deref(), Some("some-coin"));
}
#[test]
fn search_response_parses_and_limit_truncates() {
let resp: super::super::models::SearchResponseDTO =
serde_json::from_value(serde_json::json!({
"coins": [
{ "id": "bitcoin", "name": "Bitcoin", "symbol": "btc", "market_cap_rank": 1 },
{ "id": "bitcoin-cash", "name": "Bitcoin Cash", "symbol": "bch", "market_cap_rank": 20 }
],
"exchanges": [],
"icos": [],
"categories": [],
"nfts": []
}))
.unwrap();
assert_eq!(resp.coins.len(), 2);
let matches: Vec<_> = resp
.coins
.into_iter()
.take(1)
.map(to_symbol_match)
.collect();
assert_eq!(matches.len(), 1);
assert_eq!(matches[0].symbol, "BTC");
assert_eq!(matches[0].id.as_deref(), Some("bitcoin"));
}
}