notion_api_client/models/
mod.rs1pub mod block;
2pub mod error;
3pub mod paging;
4pub mod properties;
5pub mod search;
6#[cfg(test)]
7mod tests;
8pub mod text;
9pub mod users;
10
11use crate::models::properties::{PropertyConfiguration, PropertyValue};
12use crate::models::text::RichText;
13use crate::Error;
14use serde::{Deserialize, Serialize};
15use std::collections::HashMap;
16
17use crate::ids::{AsIdentifier, DatabaseId, PageId};
18use crate::models::block::{Block, CreateBlock};
19use crate::models::error::ErrorResponse;
20use crate::models::paging::PagingCursor;
21use crate::models::users::User;
22pub use chrono::{DateTime, Utc};
23pub use serde_json::value::Number;
24
25#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
26#[serde(rename_all = "snake_case")]
27enum ObjectType {
28 Database,
29 List,
30}
31
32#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
35pub struct Database {
36 pub id: DatabaseId,
38 pub created_time: DateTime<Utc>,
40 pub last_edited_time: DateTime<Utc>,
42 pub title: Vec<RichText>,
44 pub properties: HashMap<String, PropertyConfiguration>,
52}
53
54impl AsIdentifier<DatabaseId> for Database {
55 fn as_id(&self) -> &DatabaseId {
56 &self.id
57 }
58}
59
60impl Database {
61 pub fn title_plain_text(&self) -> String {
62 self.title
63 .iter()
64 .flat_map(|rich_text| rich_text.plain_text().chars())
65 .collect()
66 }
67}
68
69#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
71pub struct ListResponse<T> {
72 pub results: Vec<T>,
73 pub next_cursor: Option<PagingCursor>,
74 pub has_more: bool,
75}
76
77impl<T> ListResponse<T> {
78 pub fn results(&self) -> &[T] {
79 &self.results
80 }
81}
82
83impl ListResponse<Object> {
84 pub fn only_databases(self) -> ListResponse<Database> {
85 let databases = self
86 .results
87 .into_iter()
88 .filter_map(|object| match object {
89 Object::Database { database } => Some(database),
90 _ => None,
91 })
92 .collect();
93
94 ListResponse {
95 results: databases,
96 has_more: self.has_more,
97 next_cursor: self.next_cursor,
98 }
99 }
100
101 pub(crate) fn expect_databases(self) -> Result<ListResponse<Database>, crate::Error> {
102 let databases: Result<Vec<_>, _> = self
103 .results
104 .into_iter()
105 .map(|object| match object {
106 Object::Database { database } => Ok(database),
107 response => Err(Error::UnexpectedResponse { response }),
108 })
109 .collect();
110
111 Ok(ListResponse {
112 results: databases?,
113 has_more: self.has_more,
114 next_cursor: self.next_cursor,
115 })
116 }
117
118 pub(crate) fn expect_pages(self) -> Result<ListResponse<Page>, crate::Error> {
119 let items: Result<Vec<_>, _> = self
120 .results
121 .into_iter()
122 .map(|object| match object {
123 Object::Page { page } => Ok(page),
124 response => Err(Error::UnexpectedResponse { response }),
125 })
126 .collect();
127
128 Ok(ListResponse {
129 results: items?,
130 has_more: self.has_more,
131 next_cursor: self.next_cursor,
132 })
133 }
134
135 pub(crate) fn expect_blocks(self) -> Result<ListResponse<Block>, crate::Error> {
136 let items: Result<Vec<_>, _> = self
137 .results
138 .into_iter()
139 .map(|object| match object {
140 Object::Block { block } => Ok(block),
141 response => Err(Error::UnexpectedResponse { response }),
142 })
143 .collect();
144
145 Ok(ListResponse {
146 results: items?,
147 has_more: self.has_more,
148 next_cursor: self.next_cursor,
149 })
150 }
151}
152
153#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
154#[serde(tag = "type")]
155#[serde(rename_all = "snake_case")]
156pub enum Parent {
157 #[serde(rename = "database_id")]
158 Database {
159 database_id: DatabaseId,
160 },
161 #[serde(rename = "page_id")]
162 Page {
163 page_id: PageId,
164 },
165 Workspace,
166}
167
168#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
169pub struct Properties {
170 #[serde(flatten)]
171 pub properties: HashMap<String, PropertyValue>,
172}
173
174impl Properties {
175 pub fn title(&self) -> Option<String> {
176 self.properties.values().find_map(|p| match p {
177 PropertyValue::Title { title, .. } => {
178 Some(title.iter().map(|t| t.plain_text()).collect())
179 }
180 _ => None,
181 })
182 }
183}
184
185#[derive(Serialize, Debug, Eq, PartialEq)]
186pub struct PageCreateRequest {
187 pub parent: Parent,
188 pub properties: Properties,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub children: Option<Vec<CreateBlock>>,
191}
192
193#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
194pub struct Page {
195 pub id: PageId,
196 pub created_time: DateTime<Utc>,
198 pub last_edited_time: DateTime<Utc>,
200 pub archived: bool,
202 pub properties: Properties,
203 pub parent: Parent,
204}
205
206impl Page {
207 pub fn title(&self) -> Option<String> {
208 self.properties.title()
209 }
210}
211
212impl AsIdentifier<PageId> for Page {
213 fn as_id(&self) -> &PageId {
214 &self.id
215 }
216}
217
218#[derive(Eq, Serialize, Deserialize, Clone, Debug, PartialEq)]
219#[serde(tag = "object")]
220#[serde(rename_all = "snake_case")]
221pub enum Object {
222 Block {
223 #[serde(flatten)]
224 block: Block,
225 },
226 Database {
227 #[serde(flatten)]
228 database: Database,
229 },
230 Page {
231 #[serde(flatten)]
232 page: Page,
233 },
234 List {
235 #[serde(flatten)]
236 list: ListResponse<Object>,
237 },
238 User {
239 #[serde(flatten)]
240 user: User,
241 },
242 Error {
243 #[serde(flatten)]
244 error: ErrorResponse,
245 },
246}
247
248impl Object {
249 pub fn is_database(&self) -> bool {
250 matches!(self, Object::Database { .. })
251 }
252}