1use std::sync::Arc;
2
3use crate::domain::common::token::Token;
4use crate::domain::geolonia::entity::Address;
5use crate::domain::geolonia::error::{Error, ParseErrorKind};
6use crate::http::reqwest_client::ReqwestApiClient;
7use crate::interactor::geolonia::{GeoloniaInteractor, GeoloniaInteractorImpl};
8use crate::tokenizer::{End, Tokenizer};
9use serde::Serialize;
10
11impl From<Tokenizer<End>> for Address {
12 fn from(value: Tokenizer<End>) -> Self {
13 let mut address = Address::new("", "", "", "");
14 for token in value.tokens {
15 match token {
16 Token::Prefecture(prefecture_name) => address.prefecture = prefecture_name,
17 Token::City(city_name) => address.city = city_name,
18 Token::Town(town_name) => address.town = town_name,
19 Token::Rest(rest) => address.rest = rest,
20 }
21 }
22 address
23 }
24}
25
26pub struct Parser {
39 interactor: Arc<GeoloniaInteractorImpl<ReqwestApiClient>>,
40}
41
42impl Default for Parser {
43 fn default() -> Self {
45 Self {
46 interactor: Arc::new(Default::default()),
47 }
48 }
49}
50
51impl Parser {
52 pub async fn parse(&self, address: &str) -> ParseResult {
54 let interactor = self.interactor.clone();
55 let tokenizer = Tokenizer::new(address);
56 let (prefecture, tokenizer) = match tokenizer.read_prefecture() {
58 Ok(found) => found,
59 Err(tokenizer) => {
60 return ParseResult {
61 address: Address::from(tokenizer),
62 error: Some(Error::new_parse_error(ParseErrorKind::Prefecture)),
63 }
64 }
65 };
66 let prefecture_master = match interactor.get_prefecture_master(prefecture.name_ja()).await {
68 Err(error) => {
69 return ParseResult {
70 address: Address::from(tokenizer.finish()),
71 error: Some(error),
72 };
73 }
74 Ok(result) => result,
75 };
76 let (city_name, tokenizer) = match tokenizer.read_city(&prefecture_master.cities) {
78 Ok(found) => found,
79 Err(not_found) => {
80 match not_found.read_city_with_county_name_completion(&prefecture_master.cities) {
82 Ok(found) if cfg!(feature = "city-name-correction") => found,
83 _ => {
84 return ParseResult {
86 address: Address::from(tokenizer.finish()),
87 error: Some(Error::new_parse_error(ParseErrorKind::City)),
88 };
89 }
90 }
91 }
92 };
93 let city = match interactor
95 .get_city_master(prefecture.name_ja(), &city_name)
96 .await
97 {
98 Err(error) => {
99 return ParseResult {
100 address: Address::from(tokenizer.finish()),
101 error: Some(error),
102 };
103 }
104 Ok(result) => result,
105 };
106 let Ok((_, tokenizer)) =
108 tokenizer.read_town(city.towns.iter().map(|x| x.name.clone()).collect())
109 else {
110 return ParseResult {
111 address: Address::from(tokenizer.finish()),
112 error: Some(Error::new_parse_error(ParseErrorKind::Town)),
113 };
114 };
115
116 ParseResult {
117 address: Address::from(tokenizer.finish()),
118 error: None,
119 }
120 }
121
122 #[cfg(feature = "blocking")]
124 pub fn parse_blocking(&self, address: &str) -> ParseResult {
125 let interactor = self.interactor.clone();
126 let tokenizer = Tokenizer::new(address);
127 let (prefecture, tokenizer) = match tokenizer.read_prefecture() {
128 Ok(found) => found,
129 Err(tokenizer) => {
130 return ParseResult {
131 address: Address::from(tokenizer),
132 error: Some(Error::new_parse_error(ParseErrorKind::Prefecture)),
133 }
134 }
135 };
136 let prefecture_master =
137 match interactor.get_blocking_prefecture_master(prefecture.name_ja()) {
138 Err(error) => {
139 return ParseResult {
140 address: Address::from(tokenizer.finish()),
141 error: Some(error),
142 };
143 }
144 Ok(result) => result,
145 };
146 let (city_name, tokenizer) = match tokenizer.read_city(&prefecture_master.cities) {
147 Ok(found) => found,
148 Err(not_found) => {
149 match not_found.read_city_with_county_name_completion(&prefecture_master.cities) {
150 Ok(found) if cfg!(feature = "city-name-correction") => found,
151 _ => {
152 return ParseResult {
153 address: Address::from(tokenizer.finish()),
154 error: Some(Error::new_parse_error(ParseErrorKind::City)),
155 };
156 }
157 }
158 }
159 };
160 let city = match interactor.get_blocking_city_master(prefecture.name_ja(), &city_name) {
161 Err(error) => {
162 return ParseResult {
163 address: Address::from(tokenizer.finish()),
164 error: Some(error),
165 };
166 }
167 Ok(result) => result,
168 };
169 let Ok((_, tokenizer)) =
170 tokenizer.read_town(city.towns.iter().map(|x| x.name.clone()).collect())
171 else {
172 return ParseResult {
173 address: Address::from(tokenizer.finish()),
174 error: Some(Error::new_parse_error(ParseErrorKind::Town)),
175 };
176 };
177
178 ParseResult {
179 address: Address::from(tokenizer.finish()),
180 error: None,
181 }
182 }
183}
184
185#[cfg(all(test, not(feature = "blocking")))]
186mod tests {
187 use crate::domain::geolonia::error::ParseErrorKind;
188 use crate::parser::Parser;
189 use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
190
191 #[tokio::test]
192 async fn 都道府県名が誤っている場合() {
193 let parser = Parser::default();
194 let result = parser.parse("青盛県青森市長島1丁目1−1").await;
195 assert_eq!(result.address.prefecture, "");
196 assert_eq!(result.address.city, "");
197 assert_eq!(result.address.town, "");
198 assert_eq!(result.address.rest, "青盛県青森市長島1丁目1−1");
199 assert_eq!(result.error.is_some(), true);
200 assert_eq!(
201 result.error.unwrap().error_message,
202 ParseErrorKind::Prefecture.to_string()
203 );
204 }
205
206 #[tokio::test]
207 async fn 市区町村名が誤っている場合() {
208 let parser = Parser::default();
209 let result = parser.parse("青森県青盛市長島1丁目1−1").await;
210 assert_eq!(result.address.prefecture, "青森県");
211 assert_eq!(result.address.city, "");
212 assert_eq!(result.address.town, "");
213 assert_eq!(result.address.rest, "青盛市長島1丁目1−1");
214 assert_eq!(result.error.is_some(), true);
215 assert_eq!(
216 result.error.unwrap().error_message,
217 ParseErrorKind::City.to_string()
218 );
219 }
220
221 #[tokio::test]
222 async fn 町名が誤っている場合() {
223 let parser = Parser::default();
224 let result = parser.parse("青森県青森市永嶋1丁目1−1").await;
225 assert_eq!(result.address.prefecture, "青森県");
226 assert_eq!(result.address.city, "青森市");
227 assert_eq!(result.address.town, "");
228 assert_eq!(result.address.rest, "永嶋1丁目1−1");
229 assert_eq!(result.error.is_some(), true);
230 assert_eq!(
231 result.error.unwrap().error_message,
232 ParseErrorKind::Town.to_string()
233 );
234 }
235
236 wasm_bindgen_test_configure!(run_in_browser);
237
238 #[wasm_bindgen_test]
239 async fn parse_wasm_success() {
240 let parser = Parser::default();
241 let result = parser.parse("兵庫県淡路市生穂新島8番地").await;
242 assert_eq!(result.address.prefecture, "兵庫県".to_string());
243 assert_eq!(result.address.city, "淡路市".to_string());
244 assert_eq!(result.address.town, "生穂".to_string());
245 assert_eq!(result.address.rest, "新島8番地".to_string());
246 assert_eq!(result.error, None);
247 }
248}
249
250#[cfg(all(test, feature = "blocking"))]
251mod blocking_tests {
252 use crate::domain::geolonia::error::ParseErrorKind;
253 use crate::parser::Parser;
254
255 #[test]
256 fn parse_blocking_success_埼玉県秩父市熊木町8番15号() {
257 let parser = Parser::default();
258 let result = parser.parse_blocking("埼玉県秩父市熊木町8番15号");
259 assert_eq!(result.address.prefecture, "埼玉県");
260 assert_eq!(result.address.city, "秩父市");
261 assert_eq!(result.address.town, "熊木町");
262 assert_eq!(result.address.rest, "8番15号");
263 assert_eq!(result.error, None);
264 }
265
266 #[test]
267 fn parse_blocking_fail_市町村名が間違っている場合() {
268 let parser = Parser::default();
269 let result = parser.parse_blocking("埼玉県秩父柿熊木町8番15号");
270 assert_eq!(result.address.prefecture, "埼玉県");
271 assert_eq!(result.address.city, "");
272 assert_eq!(result.address.town, "");
273 assert_eq!(result.address.rest, "秩父柿熊木町8番15号");
274 assert_eq!(
275 result.error.unwrap().error_message,
276 ParseErrorKind::City.to_string()
277 );
278 }
279}
280
281#[derive(Serialize, PartialEq, Debug)]
282pub struct ParseResult {
283 pub address: Address,
284 pub error: Option<Error>,
285}