Skip to main content

boj_client/query/
metadata.rs

1use crate::error::BojError;
2
3use super::options::{CsvEncoding, Format, Language};
4use super::validation::validate_db;
5
6/// Query builder for the `getMetadata` endpoint.
7///
8/// Constraints enforced at build time:
9/// - `DB` must be non-empty ASCII and must not contain commas.
10///
11/// # Examples
12///
13/// ```
14/// use boj_client::query::{Format, Language, MetadataQuery};
15///
16/// let _query = MetadataQuery::new("ME")?
17///     .with_format(Format::Json)
18///     .with_lang(Language::En);
19/// # Ok::<(), boj_client::error::BojError>(())
20/// ```
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct MetadataQuery {
23    db: String,
24    format: Option<Format>,
25    lang: Option<Language>,
26}
27
28impl MetadataQuery {
29    /// Creates a `getMetadata` query.
30    ///
31    /// # Examples
32    ///
33    /// ```
34    /// use boj_client::query::MetadataQuery;
35    ///
36    /// let _query = MetadataQuery::new("ME")?;
37    /// # Ok::<(), boj_client::error::BojError>(())
38    /// ```
39    ///
40    /// # Errors
41    ///
42    /// Returns [`BojError`] if `db` violates API constraints.
43    pub fn new(db: impl Into<String>) -> Result<Self, BojError> {
44        let db = db.into();
45        validate_db(&db)?;
46
47        Ok(Self {
48            db: db.to_ascii_uppercase(),
49            format: None,
50            lang: None,
51        })
52    }
53
54    /// Sets the response format (`json` or `csv`).
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use boj_client::query::{Format, MetadataQuery};
60    ///
61    /// let _query = MetadataQuery::new("ME")?.with_format(Format::Csv);
62    /// # Ok::<(), boj_client::error::BojError>(())
63    /// ```
64    pub fn with_format(mut self, format: Format) -> Self {
65        self.format = Some(format);
66        self
67    }
68
69    /// Sets response language (`jp` or `en`).
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use boj_client::query::{Language, MetadataQuery};
75    ///
76    /// let _query = MetadataQuery::new("ME")?.with_lang(Language::Jp);
77    /// # Ok::<(), boj_client::error::BojError>(())
78    /// ```
79    pub fn with_lang(mut self, lang: Language) -> Self {
80        self.lang = Some(lang);
81        self
82    }
83
84    pub(crate) fn endpoint(&self) -> &'static str {
85        "/api/v1/getMetadata"
86    }
87
88    pub(crate) fn query_pairs(&self) -> Vec<(String, String)> {
89        let mut pairs = Vec::new();
90        if let Some(format) = self.format {
91            pairs.push(("format".to_string(), format.as_query_value().to_string()));
92        }
93        if let Some(lang) = self.lang {
94            pairs.push(("lang".to_string(), lang.as_query_value().to_string()));
95        }
96        pairs.push(("db".to_string(), self.db.clone()));
97        pairs
98    }
99
100    pub(crate) fn csv_encoding_hint(&self) -> CsvEncoding {
101        match self.lang.unwrap_or_default() {
102            Language::Jp => CsvEncoding::ShiftJis,
103            Language::En => CsvEncoding::Utf8,
104        }
105    }
106}