monocle/server/handlers/
country.rs1use crate::lens::country::{CountryEntry, CountryLens, CountryLookupArgs};
6use crate::server::handler::{WsContext, WsError, WsMethod, WsRequest, WsResult};
7use crate::server::op_sink::WsOpSink;
8use async_trait::async_trait;
9use serde::{Deserialize, Serialize};
10use std::sync::Arc;
11
12#[derive(Debug, Clone, Default, Deserialize, Serialize)]
18pub struct CountryLookupParams {
19 #[serde(default)]
21 pub query: Option<String>,
22
23 #[serde(default)]
25 pub all: Option<bool>,
26}
27
28#[derive(Debug, Clone, Serialize)]
30pub struct CountryLookupResponse {
31 pub countries: Vec<CountryEntry>,
33}
34
35pub struct CountryLookupHandler;
37
38#[async_trait]
39impl WsMethod for CountryLookupHandler {
40 const METHOD: &'static str = "country.lookup";
41 const IS_STREAMING: bool = false;
42
43 type Params = CountryLookupParams;
44
45 fn validate(params: &Self::Params) -> WsResult<()> {
46 if params.query.is_none() && !params.all.unwrap_or(false) {
48 return Err(WsError::invalid_params(
49 "Either 'query' or 'all: true' is required",
50 ));
51 }
52 Ok(())
53 }
54
55 async fn handle(
56 _ctx: Arc<WsContext>,
57 _req: WsRequest,
58 params: Self::Params,
59 sink: WsOpSink,
60 ) -> WsResult<()> {
61 let lens = CountryLens::new();
63
64 let args = if params.all.unwrap_or(false) {
66 CountryLookupArgs::all_countries()
67 } else {
68 CountryLookupArgs::new(params.query.unwrap_or_default())
69 };
70
71 let countries = lens
73 .search(&args)
74 .map_err(|e| WsError::operation_failed(e.to_string()))?;
75
76 let response = CountryLookupResponse { countries };
78 sink.send_result(response)
79 .await
80 .map_err(|e| WsError::internal(e.to_string()))?;
81
82 Ok(())
83 }
84}
85
86#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_country_lookup_params_default() {
96 let params = CountryLookupParams::default();
97 assert!(params.query.is_none());
98 assert!(params.all.is_none());
99 }
100
101 #[test]
102 fn test_country_lookup_params_deserialization() {
103 let json = r#"{"query": "US"}"#;
104 let params: CountryLookupParams = serde_json::from_str(json).unwrap();
105 assert_eq!(params.query, Some("US".to_string()));
106 assert!(params.all.is_none());
107
108 let json = r#"{"all": true}"#;
109 let params: CountryLookupParams = serde_json::from_str(json).unwrap();
110 assert!(params.query.is_none());
111 assert_eq!(params.all, Some(true));
112 }
113
114 #[test]
115 fn test_country_lookup_params_validation() {
116 let params = CountryLookupParams::default();
118 assert!(CountryLookupHandler::validate(¶ms).is_err());
119
120 let params = CountryLookupParams {
122 query: Some("US".to_string()),
123 all: None,
124 };
125 assert!(CountryLookupHandler::validate(¶ms).is_ok());
126
127 let params = CountryLookupParams {
129 query: None,
130 all: Some(true),
131 };
132 assert!(CountryLookupHandler::validate(¶ms).is_ok());
133 }
134
135 #[test]
136 fn test_country_lookup_response_serialization() {
137 let response = CountryLookupResponse {
138 countries: vec![CountryEntry {
139 code: "US".to_string(),
140 name: "United States".to_string(),
141 }],
142 };
143 let json = serde_json::to_string(&response).unwrap();
144 assert!(json.contains("\"US\""));
145 assert!(json.contains("United States"));
146 }
147
148 #[test]
149 fn test_country_lens_lookup() {
150 let lens = CountryLens::new();
151 let results = lens.lookup("US");
152 assert_eq!(results.len(), 1);
153 assert_eq!(results[0].code, "US");
154 }
155}