Skip to main content

gbiz_info_api/
query.rs

1//! gBizINFO REST API (v2) のリクエストクエリ定義。
2
3use serde::Serialize;
4
5/// 法人検索(`GET /v2/hojin`)の検索条件。
6///
7/// フィールドを直接設定するか、チェーン可能なメソッドで組み立てる。
8///
9/// ```
10/// use gbiz_info_api::HojinSearchQuery;
11///
12/// let query = HojinSearchQuery::new()
13///     .name("トヨタ自動車")
14///     .prefecture("23")
15///     .limit(10);
16/// ```
17#[derive(Debug, Clone, Default, PartialEq, Serialize)]
18pub struct HojinSearchQuery {
19    /// 法人番号(完全一致)
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub corporate_number: Option<String>,
22    /// 法人名(部分一致)
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub name: Option<String>,
25    /// 法人活動情報の有無
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub exist_flg: Option<bool>,
28    /// 法人種別(`101` 国の機関、`201` 地方公共団体、`301` 株式会社、`302` 有限会社、
29    /// `303` 合名会社、`304` 合資会社、`305` 合同会社、`399` その他の設立登記法人、
30    /// `401` 外国会社等、`499` その他)
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub corporate_type: Option<String>,
33    /// 所在地(都道府県)。全国地方公共団体コードの先頭2桁
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub prefecture: Option<String>,
36    /// 所在地(市区町村)。全国地方公共団体コードの3-5桁目
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub city: Option<String>,
39    /// 資本金(以上)
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub capital_stock_from: Option<u64>,
42    /// 資本金(以下)
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub capital_stock_to: Option<u64>,
45    /// 従業員数(以上)
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub employee_number_from: Option<u64>,
48    /// 従業員数(以下)
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub employee_number_to: Option<u64>,
51    /// 創業年・設立年。複数の場合はカンマ区切り
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub founded_year: Option<String>,
54    /// 売上高(以上)
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub net_sales_summary_of_business_results_from: Option<u64>,
57    /// 売上高(以下)
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub net_sales_summary_of_business_results_to: Option<u64>,
60    /// 総資産額(以上)
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub total_assets_summary_of_business_results_from: Option<u64>,
63    /// 総資産額(以下)
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub total_assets_summary_of_business_results_to: Option<u64>,
66    /// 平均継続勤務年数(`A`: ~5年、`B`: 6年~10年、`C`: 11年~20年、`D`: 21年~)
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub average_continuous_service_years: Option<String>,
69    /// 従業員の平均年齢(`A`: ~30歳、`B`: 31歳~45歳、`C`: 46歳~60歳、`D`: 61歳~)
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub average_age: Option<String>,
72    /// 月平均所定外労働時間(`A`: 20時間未満、`B`: 40時間未満、`C`: 40時間以上)
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub month_average_predetermined_overtime_hours: Option<String>,
75    /// 労働者に占める女性労働者の割合(`A`: ~20%、`B`: 21%~40%、`C`: 41%~60%、`D`: 61%~)
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub female_workers_proportion: Option<String>,
78    /// 特許(商標)(部分一致)
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub patent: Option<String>,
81    /// 調達先(部分一致)
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub procurement: Option<String>,
84    /// 調達額(以上)
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub procurement_amount_from: Option<u64>,
87    /// 調達額(以下)
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub procurement_amount_to: Option<u64>,
90    /// 補助金名称(部分一致)
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub subsidy: Option<String>,
93    /// 補助金額(以上)
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub subsidy_amount_from: Option<u64>,
96    /// 補助金額(以下)
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub subsidy_amount_to: Option<u64>,
99    /// 届出・認定・表彰名(部分一致)
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub certification: Option<String>,
102    /// 担当府省の内部コード。複数の場合はカンマ区切り
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub ministry: Option<String>,
105    /// 出典元(`1` 調達、`2` 表彰、`3` 届出認定、`4` 補助金、`5` 特許、`6` 財務)。
106    /// 複数の場合はカンマ区切り
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub source: Option<String>,
109    /// 検索結果のページ番号(下限値1、上限値10)
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub page: Option<u32>,
112    /// 検索結果の1ページあたりの件数(下限値0、上限値5000)
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub limit: Option<u32>,
115    /// メタデータ取得フラグ
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub metadata_flg: Option<bool>,
118}
119
120impl HojinSearchQuery {
121    /// 空の検索条件を作成する。
122    pub fn new() -> Self {
123        Self::default()
124    }
125
126    /// 法人番号(完全一致)を設定する。
127    pub fn corporate_number(mut self, value: impl Into<String>) -> Self {
128        self.corporate_number = Some(value.into());
129        self
130    }
131
132    /// 法人名(部分一致)を設定する。
133    pub fn name(mut self, value: impl Into<String>) -> Self {
134        self.name = Some(value.into());
135        self
136    }
137
138    /// 法人活動情報の有無を設定する。
139    pub fn exist_flg(mut self, value: bool) -> Self {
140        self.exist_flg = Some(value);
141        self
142    }
143
144    /// 法人種別コードを設定する。
145    pub fn corporate_type(mut self, value: impl Into<String>) -> Self {
146        self.corporate_type = Some(value.into());
147        self
148    }
149
150    /// 所在地(都道府県コード)を設定する。
151    pub fn prefecture(mut self, value: impl Into<String>) -> Self {
152        self.prefecture = Some(value.into());
153        self
154    }
155
156    /// 所在地(市区町村コード)を設定する。
157    pub fn city(mut self, value: impl Into<String>) -> Self {
158        self.city = Some(value.into());
159        self
160    }
161
162    /// 資本金の範囲(以上・以下)を設定する。`None` は片側指定なし。
163    pub fn capital_stock(mut self, from: Option<u64>, to: Option<u64>) -> Self {
164        self.capital_stock_from = from;
165        self.capital_stock_to = to;
166        self
167    }
168
169    /// 従業員数の範囲(以上・以下)を設定する。`None` は片側指定なし。
170    pub fn employee_number(mut self, from: Option<u64>, to: Option<u64>) -> Self {
171        self.employee_number_from = from;
172        self.employee_number_to = to;
173        self
174    }
175
176    /// 創業年・設立年を設定する(複数はカンマ区切り)。
177    pub fn founded_year(mut self, value: impl Into<String>) -> Self {
178        self.founded_year = Some(value.into());
179        self
180    }
181
182    /// 売上高の範囲(以上・以下)を設定する。`None` は片側指定なし。
183    pub fn net_sales(mut self, from: Option<u64>, to: Option<u64>) -> Self {
184        self.net_sales_summary_of_business_results_from = from;
185        self.net_sales_summary_of_business_results_to = to;
186        self
187    }
188
189    /// 総資産額の範囲(以上・以下)を設定する。`None` は片側指定なし。
190    pub fn total_assets(mut self, from: Option<u64>, to: Option<u64>) -> Self {
191        self.total_assets_summary_of_business_results_from = from;
192        self.total_assets_summary_of_business_results_to = to;
193        self
194    }
195
196    /// 平均継続勤務年数の区分コード(`A`~`D`)を設定する。
197    pub fn average_continuous_service_years(mut self, value: impl Into<String>) -> Self {
198        self.average_continuous_service_years = Some(value.into());
199        self
200    }
201
202    /// 従業員の平均年齢の区分コード(`A`~`D`)を設定する。
203    pub fn average_age(mut self, value: impl Into<String>) -> Self {
204        self.average_age = Some(value.into());
205        self
206    }
207
208    /// 月平均所定外労働時間の区分コード(`A`~`C`)を設定する。
209    pub fn month_average_predetermined_overtime_hours(mut self, value: impl Into<String>) -> Self {
210        self.month_average_predetermined_overtime_hours = Some(value.into());
211        self
212    }
213
214    /// 労働者に占める女性労働者の割合の区分コード(`A`~`D`)を設定する。
215    pub fn female_workers_proportion(mut self, value: impl Into<String>) -> Self {
216        self.female_workers_proportion = Some(value.into());
217        self
218    }
219
220    /// 特許(商標)(部分一致)を設定する。
221    pub fn patent(mut self, value: impl Into<String>) -> Self {
222        self.patent = Some(value.into());
223        self
224    }
225
226    /// 調達先(部分一致)を設定する。
227    pub fn procurement(mut self, value: impl Into<String>) -> Self {
228        self.procurement = Some(value.into());
229        self
230    }
231
232    /// 調達額の範囲(以上・以下)を設定する。`None` は片側指定なし。
233    pub fn procurement_amount(mut self, from: Option<u64>, to: Option<u64>) -> Self {
234        self.procurement_amount_from = from;
235        self.procurement_amount_to = to;
236        self
237    }
238
239    /// 補助金名称(部分一致)を設定する。
240    pub fn subsidy(mut self, value: impl Into<String>) -> Self {
241        self.subsidy = Some(value.into());
242        self
243    }
244
245    /// 補助金額の範囲(以上・以下)を設定する。`None` は片側指定なし。
246    pub fn subsidy_amount(mut self, from: Option<u64>, to: Option<u64>) -> Self {
247        self.subsidy_amount_from = from;
248        self.subsidy_amount_to = to;
249        self
250    }
251
252    /// 届出・認定・表彰名(部分一致)を設定する。
253    pub fn certification(mut self, value: impl Into<String>) -> Self {
254        self.certification = Some(value.into());
255        self
256    }
257
258    /// 担当府省の内部コードを設定する(複数はカンマ区切り)。
259    pub fn ministry(mut self, value: impl Into<String>) -> Self {
260        self.ministry = Some(value.into());
261        self
262    }
263
264    /// 出典元コードを設定する(複数はカンマ区切り)。
265    pub fn source(mut self, value: impl Into<String>) -> Self {
266        self.source = Some(value.into());
267        self
268    }
269
270    /// 検索結果のページ番号(1~10)を設定する。
271    pub fn page(mut self, value: u32) -> Self {
272        self.page = Some(value);
273        self
274    }
275
276    /// 検索結果の1ページあたりの件数(0~5000)を設定する。
277    pub fn limit(mut self, value: u32) -> Self {
278        self.limit = Some(value);
279        self
280    }
281
282    /// メタデータ取得フラグを設定する。
283    pub fn metadata_flg(mut self, value: bool) -> Self {
284        self.metadata_flg = Some(value);
285        self
286    }
287}
288
289/// 更新情報取得(`GET /v2/hojin/updateInfo` 系)の検索条件。
290///
291/// 検索対象期間の開始日・終了日(`yyyyMMdd` 形式)は必須。
292///
293/// ```
294/// use gbiz_info_api::UpdateInfoQuery;
295///
296/// let query = UpdateInfoQuery::new("20260401", "20260430").page(2);
297/// ```
298#[derive(Debug, Clone, PartialEq, Serialize)]
299pub struct UpdateInfoQuery {
300    /// 検索対象期間の開始日(`yyyyMMdd` 形式)
301    pub from: String,
302    /// 検索対象期間の終了日(`yyyyMMdd` 形式)
303    pub to: String,
304    /// 検索結果のページ番号(下限値1)
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub page: Option<u32>,
307    /// メタデータ取得フラグ
308    #[serde(skip_serializing_if = "Option::is_none")]
309    pub metadata_flg: Option<bool>,
310}
311
312impl UpdateInfoQuery {
313    /// 検索対象期間(`yyyyMMdd` 形式)を指定して作成する。
314    pub fn new(from: impl Into<String>, to: impl Into<String>) -> Self {
315        Self {
316            from: from.into(),
317            to: to.into(),
318            page: None,
319            metadata_flg: None,
320        }
321    }
322
323    /// 検索結果のページ番号を設定する。
324    pub fn page(mut self, value: u32) -> Self {
325        self.page = Some(value);
326        self
327    }
328
329    /// メタデータ取得フラグを設定する。
330    pub fn metadata_flg(mut self, value: bool) -> Self {
331        self.metadata_flg = Some(value);
332        self
333    }
334}
335
336#[cfg(test)]
337mod tests {
338    use super::*;
339    use serde_json::{json, Value};
340
341    #[test]
342    fn search_query_skips_unset_fields() {
343        let query = HojinSearchQuery::new();
344        let value = serde_json::to_value(&query).unwrap();
345        assert_eq!(value, json!({}));
346    }
347
348    #[test]
349    fn search_query_serializes_set_fields() {
350        let query = HojinSearchQuery::new()
351            .name("トヨタ自動車")
352            .corporate_type("301")
353            .exist_flg(true)
354            .capital_stock(Some(1_000_000), None)
355            .page(1)
356            .limit(100)
357            .metadata_flg(false);
358        let value = serde_json::to_value(&query).unwrap();
359        assert_eq!(
360            value,
361            json!({
362                "name": "トヨタ自動車",
363                "corporate_type": "301",
364                "exist_flg": true,
365                "capital_stock_from": 1_000_000,
366                "page": 1,
367                "limit": 100,
368                "metadata_flg": false,
369            })
370        );
371    }
372
373    #[test]
374    fn search_query_all_fields_serialize() {
375        let query = HojinSearchQuery::new()
376            .corporate_number("1180301018771")
377            .name("n")
378            .exist_flg(true)
379            .corporate_type("301")
380            .prefecture("23")
381            .city("211")
382            .capital_stock(Some(1), Some(2))
383            .employee_number(Some(3), Some(4))
384            .founded_year("1937,1938")
385            .net_sales(Some(5), Some(6))
386            .total_assets(Some(7), Some(8))
387            .average_continuous_service_years("A")
388            .average_age("B")
389            .month_average_predetermined_overtime_hours("C")
390            .female_workers_proportion("D")
391            .patent("p")
392            .procurement("q")
393            .procurement_amount(Some(9), Some(10))
394            .subsidy("s")
395            .subsidy_amount(Some(11), Some(12))
396            .certification("c")
397            .ministry("100,200")
398            .source("1,6")
399            .page(2)
400            .limit(500)
401            .metadata_flg(true);
402        let value = serde_json::to_value(&query).unwrap();
403        let Value::Object(map) = value else {
404            panic!("object expected")
405        };
406        // 全32項目が設定されていること(未設定によるスキップがないこと)
407        assert_eq!(map.len(), 32);
408    }
409
410    #[test]
411    fn update_info_query_serializes() {
412        let query = UpdateInfoQuery::new("20260401", "20260430");
413        let value = serde_json::to_value(&query).unwrap();
414        assert_eq!(value, json!({"from": "20260401", "to": "20260430"}));
415
416        let query = UpdateInfoQuery::new("20260401", "20260430")
417            .page(2)
418            .metadata_flg(true);
419        let value = serde_json::to_value(&query).unwrap();
420        assert_eq!(
421            value,
422            json!({"from": "20260401", "to": "20260430", "page": 2, "metadata_flg": true})
423        );
424    }
425}