diff --git a/core/Cargo.toml b/core/Cargo.toml index d14fc9bf..6141dd87 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -29,6 +29,7 @@ serde.workspace = true reqwest = { version = "0.12.5", default-features = false, features = ["json", "rustls-tls"] } js-sys = "0.3.67" thiserror = "1.0.63" +jisx0401 = "0.1.0-beta.2" [dev-dependencies] tokio.workspace = true diff --git a/core/src/domain/chimei_ruiju/entity.rs b/core/src/domain/chimei_ruiju/entity.rs index 1bc4e184..1d793d27 100644 --- a/core/src/domain/chimei_ruiju/entity.rs +++ b/core/src/domain/chimei_ruiju/entity.rs @@ -13,9 +13,9 @@ pub struct PrefectureMaster { #[derive(Deserialize, Debug)] pub struct CityMaster { /// 市区町村名 - name: String, + pub(crate) name: String, /// 町名リスト - towns: Vec, + pub(crate) towns: Vec, /// 緯度経度 coordinate: Coordinate, } @@ -23,7 +23,7 @@ pub struct CityMaster { #[derive(Deserialize, Debug)] pub struct TownMaster { /// 町名 - name: String, + pub(crate) name: String, /// 街区リスト blocks: Vec, /// 緯度経度 diff --git a/core/src/repository.rs b/core/src/repository.rs index bb3a487a..9df7829d 100644 --- a/core/src/repository.rs +++ b/core/src/repository.rs @@ -1 +1,2 @@ +pub mod chimei_ruiju; pub mod geolonia; diff --git a/core/src/repository/chimei_ruiju.rs b/core/src/repository/chimei_ruiju.rs new file mode 100644 index 00000000..5c4bae46 --- /dev/null +++ b/core/src/repository/chimei_ruiju.rs @@ -0,0 +1,3 @@ +pub mod city; +pub mod prefecture; +mod town; diff --git a/core/src/repository/chimei_ruiju/city.rs b/core/src/repository/chimei_ruiju/city.rs new file mode 100644 index 00000000..2d09d70a --- /dev/null +++ b/core/src/repository/chimei_ruiju/city.rs @@ -0,0 +1,138 @@ +use crate::domain::chimei_ruiju::entity::CityMaster; +use crate::domain::chimei_ruiju::error::ApiError; +use crate::service::chimei_ruiju::ChimeiRuijuApiService; +use jisx0401::Prefecture; + +pub struct CityMasterRepository { + api_service: ChimeiRuijuApiService, +} + +impl CityMasterRepository { + pub async fn get( + &self, + prefecture: &Prefecture, + city_name: &str, + ) -> Result { + let url = format!( + "https://{}.chimei-ruiju.org/{}/master.json", + prefecture.name_en(), + city_name + ); + self.api_service.get::(&url).await + } +} + +#[cfg(test)] +mod async_tests { + use crate::repository::chimei_ruiju::city::CityMasterRepository; + use crate::service::chimei_ruiju::ChimeiRuijuApiService; + use jisx0401::Prefecture; + + #[tokio::test] + async fn 神奈川県愛甲郡清川村() { + let repository = CityMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get(&Prefecture::KANAGAWA, "愛甲郡清川村").await; + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "愛甲郡清川村"); + assert_eq!(entity.towns, vec!["煤ヶ谷", "宮ヶ瀬"]); + } + + #[tokio::test] + async fn 京都府乙訓郡大山崎町() { + let repository = CityMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get(&Prefecture::KYOTO, "乙訓郡大山崎町").await; + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "乙訓郡大山崎町"); + assert_eq!(entity.towns, vec!["字円明寺", "字大山崎", "字下植野"]); + } +} + +#[cfg(feature = "blocking")] +impl CityMasterRepository { + pub fn get_blocking( + &self, + prefecture: &Prefecture, + city_name: &str, + ) -> Result { + let url = format!( + "https://{}.chimei-ruiju.org/{}/master.json", + prefecture.name_en(), + city_name + ); + self.api_service.get_blocking::(&url) + } +} + +#[cfg(all(test, feature = "blocking"))] +mod blocking_tests { + use crate::repository::chimei_ruiju::city::CityMasterRepository; + use crate::service::chimei_ruiju::ChimeiRuijuApiService; + use jisx0401::Prefecture; + + #[test] + fn 埼玉県比企郡嵐山町() { + let repository = CityMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get_blocking(&Prefecture::SAITAMA, "比企郡嵐山町"); + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "比企郡嵐山町"); + assert_eq!( + entity.towns, + vec![ + "むさし台一丁目", + "むさし台二丁目", + "むさし台三丁目", + "大字根岸", + "大字勝田", + "大字太郎丸", + "大字川島", + "花見台", + "大字遠山", + "大字大蔵", + "大字菅谷", + "大字千手堂", + "大字廣野", + "大字杉山", + "大字平澤", + "大字将軍澤", + "大字志賀", + "大字吉田", + "大字古里", + "大字越畑", + "大字鎌形" + ] + ); + } + + #[test] + fn 岐阜県不破郡関ケ原町() { + let repository = CityMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get_blocking(&Prefecture::GIFU, "不破郡関ケ原町"); + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "不破郡関ケ原町"); + assert_eq!( + entity.towns, + vec![ + "大字今須", + "大字大高", + "大字関ケ原", + "大字玉", + "大字藤下", + "大字野上", + "大字松尾", + "大字山中" + ] + ); + } +} diff --git a/core/src/repository/chimei_ruiju/prefecture.rs b/core/src/repository/chimei_ruiju/prefecture.rs new file mode 100644 index 00000000..702cb0d9 --- /dev/null +++ b/core/src/repository/chimei_ruiju/prefecture.rs @@ -0,0 +1,238 @@ +use crate::domain::chimei_ruiju::entity::PrefectureMaster; +use crate::domain::chimei_ruiju::error::ApiError; +use crate::service::chimei_ruiju::ChimeiRuijuApiService; +use jisx0401::Prefecture; + +pub struct PrefectureMasterRepository { + api_service: ChimeiRuijuApiService, +} + +impl PrefectureMasterRepository { + pub async fn get(&self, prefecture: &Prefecture) -> Result { + let url = format!( + "https://{}.chimei-ruiju.org/master.json", + prefecture.name_en() + ); + self.api_service.get::(&url).await + } +} + +#[cfg(test)] +mod async_tests { + use crate::repository::chimei_ruiju::prefecture::PrefectureMasterRepository; + use crate::service::chimei_ruiju::ChimeiRuijuApiService; + use jisx0401::Prefecture; + + #[tokio::test] + async fn 東京都() { + let repository = PrefectureMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get(&Prefecture::TOKYO).await; + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "東京都"); + assert_eq!( + entity.cities, + vec![ + "千代田区", + "中央区", + "港区", + "新宿区", + "文京区", + "台東区", + "墨田区", + "江東区", + "品川区", + "目黒区", + "大田区", + "世田谷区", + "渋谷区", + "中野区", + "杉並区", + "豊島区", + "北区", + "荒川区", + "板橋区", + "練馬区", + "足立区", + "葛飾区", + "江戸川区", + "八王子市", + "立川市", + "武蔵野市", + "三鷹市", + "青梅市", + "府中市", + "昭島市", + "調布市", + "町田市", + "小金井市", + "小平市", + "日野市", + "東村山市", + "国分寺市", + "国立市", + "福生市", + "狛江市", + "東大和市", + "清瀬市", + "東久留米市", + "武蔵村山市", + "多摩市", + "稲城市", + "羽村市", + "あきる野市", + "西東京市", + "西多摩郡瑞穂町", + "西多摩郡日の出町", + "西多摩郡檜原村", + "西多摩郡奥多摩町", + "大島町", + "利島村", + "新島村", + "神津島村", + "三宅村", + "御蔵島村", + "八丈町", + "青ヶ島村", + "小笠原村", + ] + ) + } + + #[tokio::test] + async fn 富山県() { + let repository = PrefectureMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get(&Prefecture::TOYAMA).await; + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "富山県"); + assert_eq!( + entity.cities, + vec![ + "富山市", + "高岡市", + "魚津市", + "氷見市", + "滑川市", + "黒部市", + "砺波市", + "小矢部市", + "南砺市", + "射水市", + "中新川郡舟橋村", + "中新川郡上市町", + "中新川郡立山町", + "下新川郡入善町", + "下新川郡朝日町", + ] + ); + } +} + +#[cfg(feature = "blocking")] +impl PrefectureMasterRepository { + pub fn get_blocking(&self, prefecture: Prefecture) -> Result { + let url = format!( + "https://{}.chimei-ruiju.org/master.json", + prefecture.name_en() + ); + self.api_service.get_blocking::(&url) + } +} + +#[cfg(all(test, feature = "blocking"))] +mod blocking_tests { + use crate::repository::chimei_ruiju::prefecture::PrefectureMasterRepository; + use crate::service::chimei_ruiju::ChimeiRuijuApiService; + use jisx0401::Prefecture; + + #[tokio::test] + async fn 高知県() { + let repository = PrefectureMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get(&Prefecture::KOCHI).await; + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "高知県"); + assert_eq!( + entity.cities, + vec![ + "高知市", + "室戸市", + "安芸市", + "南国市", + "土佐市", + "須崎市", + "宿毛市", + "土佐清水市", + "四万十市", + "香南市", + "香美市", + "安芸郡東洋町", + "安芸郡奈半利町", + "安芸郡田野町", + "安芸郡安田町", + "安芸郡北川村", + "安芸郡馬路村", + "安芸郡芸西村", + "長岡郡本山町", + "長岡郡大豊町", + "土佐郡土佐町", + "土佐郡大川村", + "吾川郡いの町", + "吾川郡仁淀川町", + "高岡郡中土佐町", + "高岡郡佐川町", + "高岡郡越知町", + "高岡郡檮原町", + "高岡郡日高村", + "高岡郡津野町", + "高岡郡四万十町", + "幡多郡大月町", + "幡多郡三原村", + "幡多郡黒潮町" + ] + ) + } + + #[tokio::test] + async fn 佐賀県() { + let repository = PrefectureMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get(&Prefecture::SAGA).await; + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "佐賀県"); + assert_eq!( + entity.cities, + vec![ + "佐賀市", + "唐津市", + "鳥栖市", + "多久市", + "伊万里市", + "武雄市", + "鹿島市", + "小城市", + "嬉野市", + "神埼市", + "神埼郡吉野ヶ里町", + "三養基郡基山町", + "三養基郡上峰町", + "三養基郡みやき町", + "東松浦郡玄海町", + "西松浦郡有田町", + "杵島郡大町町", + "杵島郡江北町", + "杵島郡白石町", + "藤津郡太良町" + ] + ); + } +} diff --git a/core/src/repository/chimei_ruiju/town.rs b/core/src/repository/chimei_ruiju/town.rs new file mode 100644 index 00000000..71b09122 --- /dev/null +++ b/core/src/repository/chimei_ruiju/town.rs @@ -0,0 +1,82 @@ +use crate::domain::chimei_ruiju::entity::TownMaster; +use crate::domain::chimei_ruiju::error::ApiError; +use crate::service::chimei_ruiju::ChimeiRuijuApiService; +use jisx0401::Prefecture; + +#[allow(dead_code)] +pub struct TownMasterRepository { + api_service: ChimeiRuijuApiService, +} + +impl TownMasterRepository { + pub async fn get( + &self, + prefecture: &Prefecture, + city_name: &str, + town_name: &str, + ) -> Result { + let url = format!( + "https://{}.chimei-ruiju.org/{}/{}/master.json", + prefecture.name_en(), + city_name, + town_name + ); + self.api_service.get::(&url).await + } +} + +#[cfg(test)] +mod async_tests { + use crate::repository::chimei_ruiju::town::TownMasterRepository; + use crate::service::chimei_ruiju::ChimeiRuijuApiService; + use jisx0401::Prefecture; + + #[tokio::test] + async fn 東京都千代田区千代田() { + let repository = TownMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository + .get(&Prefecture::TOKYO, "千代田区", "千代田") + .await; + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "千代田"); + } +} + +#[cfg(feature = "blocking")] +impl TownMasterRepository { + pub fn get_blocking( + &self, + prefecture: &Prefecture, + city_name: &str, + town_name: &str, + ) -> Result { + let url = format!( + "https://{}.chimei-ruiju.org/{}/{}/master.json", + prefecture.name_en(), + city_name, + town_name + ); + self.api_service.get_blocking::(&url) + } +} + +#[cfg(all(test, feature = "blocking"))] +mod blocking_tests { + use crate::repository::chimei_ruiju::town::TownMasterRepository; + use crate::service::chimei_ruiju::ChimeiRuijuApiService; + use jisx0401::Prefecture; + + #[test] + fn 京都府京都市伏見区魚屋町() { + let repository = TownMasterRepository { + api_service: ChimeiRuijuApiService {}, + }; + let result = repository.get_blocking(&Prefecture::KYOTO, "京都市伏見区", "魚屋町"); + assert!(result.is_ok()); + let entity = result.unwrap(); + assert_eq!(entity.name, "魚屋町"); + } +}