notionrs_schema/object/
comment.rs

1use serde::{Deserialize, Serialize};
2
3/// When creating a new comment, either the parent.page_id or discussion_id parameter must be provided — not both.
4#[derive(Debug, Deserialize, Serialize, Clone, notionrs_macro::Setter)]
5pub struct Comment {
6    /// Always `"comment"`,
7    #[serde(skip_serializing)]
8    pub object: String,
9
10    #[serde(skip_serializing)]
11    pub id: String,
12
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub parent: Option<crate::object::parent::Parent>,
15
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub discussion_id: Option<String>,
18
19    #[serde(skip_serializing)]
20    #[serde(with = "time::serde::rfc3339")]
21    pub created_time: time::OffsetDateTime,
22
23    #[serde(skip_serializing)]
24    #[serde(with = "time::serde::rfc3339")]
25    pub last_edited_time: time::OffsetDateTime,
26
27    #[serde(skip_serializing)]
28    pub created_by: Option<crate::object::user::User>,
29
30    pub rich_text: Vec<crate::object::rich_text::RichText>,
31}
32
33impl Default for Comment {
34    fn default() -> Self {
35        Comment {
36            object: "comment".to_string(),
37            id: String::new(),
38            parent: None,
39            discussion_id: None,
40            created_time: time::OffsetDateTime::now_utc(),
41            last_edited_time: time::OffsetDateTime::now_utc(),
42            created_by: None,
43            rich_text: vec![],
44        }
45    }
46}
47
48impl<T> From<T> for Comment
49where
50    T: AsRef<str>,
51{
52    fn from(value: T) -> Self {
53        Self {
54            rich_text: vec![crate::object::rich_text::RichText::from(value)],
55            ..Default::default()
56        }
57    }
58}
59
60impl std::fmt::Display for Comment {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(
63            f,
64            "{}",
65            self.rich_text
66                .iter()
67                .map(|s| s.to_string())
68                .collect::<String>()
69        )
70    }
71}
72
73#[cfg(test)]
74mod unit_tests {
75    use super::*;
76
77    #[test]
78    fn deserialize_url_property() {
79        let json_data = r#"
80        {
81            "object": "comment",
82            "id": "1e834608-d5c9-8021-894d-001df60d9340",
83            "parent": {
84                "type": "block_id",
85                "block_id": "1e334608-d5c9-80a4-a8a3-e524a536c43f"
86            },
87            "discussion_id": "1e834608-d5c9-80a2-ab7a-001c2c516cfd",
88            "created_time": "2025-05-03T11:45:00.000Z",
89            "last_edited_time": "2025-05-03T11:45:00.000Z",
90            "created_by": {
91                "object": "user",
92                "id": "79a215bc-a3f0-4977-bb62-1ef058f06556"
93            },
94            "rich_text": [
95                {
96                    "type": "text",
97                    "text": {
98                        "content": "Workers of the world, unite!",
99                        "link": null
100                    },
101                    "annotations": {
102                        "bold": false,
103                        "italic": false,
104                        "strikethrough": false,
105                        "underline": false,
106                        "code": false,
107                        "color": "default"
108                    },
109                    "plain_text": "Workers of the world, unite!",
110                    "href": null
111                }
112            ]
113        }
114        "#;
115
116        let comment = serde_json::from_str::<Comment>(json_data).unwrap();
117
118        assert_eq!(
119            comment.discussion_id,
120            Some("1e834608-d5c9-80a2-ab7a-001c2c516cfd".to_string())
121        );
122    }
123}