notionrs_schema/object/
select.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Eq)]
4pub struct Select {
5    #[serde(skip_serializing_if = "Option::is_none")]
6    pub id: Option<String>,
7
8    pub name: String,
9
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub color: Option<SelectColor>,
12}
13
14impl Select {
15    pub fn id<T>(mut self, id: T) -> Self
16    where
17        T: AsRef<str>,
18    {
19        self.id = Some(id.as_ref().to_string());
20        self
21    }
22
23    pub fn name<T>(mut self, name: T) -> Self
24    where
25        T: AsRef<str>,
26    {
27        self.name = name.as_ref().to_string();
28        self
29    }
30
31    pub fn color(mut self, color: SelectColor) -> Self {
32        self.color = Some(color);
33        self
34    }
35}
36
37impl<T> From<T> for Select
38where
39    T: AsRef<str>,
40{
41    fn from(value: T) -> Self {
42        Self::default().name(value)
43    }
44}
45
46impl std::fmt::Display for Select {
47    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
48        write!(f, "{}", self.name)
49    }
50}
51
52/// <https://developers.notion.com/reference/property-object#status>
53#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Eq)]
54pub struct SelectGroup {
55    pub id: String,
56    pub name: String,
57    pub color: SelectColor,
58    pub option_ids: Vec<String>,
59}
60
61impl std::fmt::Display for SelectGroup {
62    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63        write!(f, "{}", self.name)
64    }
65}
66
67/// Specifies the label colors. These colors can be used in the following property types.
68/// This color enumeration is different from the usual Color (which includes Background Color).
69///
70/// - [Status (docs)](https://developers.notion.com/reference/property-object#status)
71/// - [Select (docs)](https://developers.notion.com/reference/property-object#select)
72/// - [Multi-select (docs)](https://developers.notion.com/reference/property-object#multi-select)
73#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Default)]
74#[serde(rename_all = "snake_case")]
75pub enum SelectColor {
76    #[default]
77    Default,
78
79    Blue,
80    Brown,
81    Gray,
82    Green,
83    Orange,
84    Pink,
85    Purple,
86    Red,
87    Yellow,
88}
89
90impl std::str::FromStr for SelectColor {
91    type Err = serde_plain::Error;
92
93    fn from_str(s: &str) -> Result<Self, Self::Err> {
94        serde_plain::from_str(s)
95    }
96}
97
98impl std::fmt::Display for SelectColor {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        serde_plain::to_string(self)
101            .map_err(|_| std::fmt::Error)?
102            .fmt(f)
103    }
104}
105
106// # --------------------------------------------------------------------------------
107//
108// unit test
109//
110// # --------------------------------------------------------------------------------
111
112#[cfg(test)]
113mod tests {
114    use std::str::FromStr;
115
116    use super::*;
117
118    #[test]
119    fn deserialize_select() {
120        let json = r#"{
121            "id": "id",
122            "name": "name",
123            "color": "blue"
124        }"#;
125        let select: Select = serde_json::from_str(json).unwrap();
126        assert_eq!(select.id, Some("id".to_string()));
127        assert_eq!(select.name, "name");
128        assert_eq!(select.color, Some(SelectColor::Blue));
129    }
130
131    #[test]
132    fn serialize_select() {
133        let select = Select {
134            id: Some("id".to_string()),
135            name: "name".to_string(),
136            color: Some(SelectColor::Blue),
137        };
138
139        let json = serde_json::to_string(&select).expect("serialization failed");
140
141        let expected = r#"{"id":"id","name":"name","color":"blue"}"#;
142
143        assert_eq!(json, expected);
144    }
145
146    #[test]
147    fn deserialize_select_group() {
148        let json = r#"{
149            "id": "id",
150            "name": "name",
151            "color": "blue",
152            "option_ids": ["option_id"]
153        }"#;
154        let select_group: SelectGroup = serde_json::from_str(json).unwrap();
155        assert_eq!(select_group.id, "id");
156        assert_eq!(select_group.name, "name");
157        assert_eq!(select_group.color, SelectColor::Blue);
158        assert_eq!(select_group.option_ids, vec!["option_id"]);
159    }
160
161    #[test]
162    fn check_try_from_color() {
163        let cases = vec![
164            ("blue", Some(SelectColor::Blue)),
165            ("brown", Some(SelectColor::Brown)),
166            ("gray", Some(SelectColor::Gray)),
167            ("green", Some(SelectColor::Green)),
168            ("orange", Some(SelectColor::Orange)),
169            ("pink", Some(SelectColor::Pink)),
170            ("purple", Some(SelectColor::Purple)),
171            ("red", Some(SelectColor::Red)),
172            ("yellow", Some(SelectColor::Yellow)),
173            ("default", Some(SelectColor::Default)),
174            ("invalid_color", None),
175        ];
176
177        for (input, expected) in cases {
178            match SelectColor::from_str(input) {
179                Ok(color) => assert_eq!(Some(color), expected, "Input: {}", input),
180                Err(_) => assert!(expected.is_none(), "Expected None for input: {}", input),
181            }
182        }
183    }
184}