1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
mod collection;
mod data;
pub(crate) mod raw;
mod text;
pub use data::BlockData;
use raw::{compress_properties, RawBlock, RawInput};
use serde_json::json;
use uuid::Uuid;
use {serde::Serialize, serde_json};
#[derive(Debug, Serialize, PartialEq, Clone)]
pub struct NotionBlock {
pub id: String,
pub data: BlockData,
pub title: Option<String>,
pub content: Vec<Uuid>,
}
impl<'de> serde::Deserialize<'de> for NotionBlock {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw_in: RawInput = RawInput::deserialize(deserializer)?;
let RawBlock {
id,
block_type,
properties,
content,
..
} = serde_json::from_value(raw_in.value)
.map_err(|why| serde::de::Error::custom(why.to_string()))?;
let compressed_props = compress_properties(properties.unwrap_or(json!({})))
.map_err(|why| serde::de::Error::custom(why.to_string()))?;
let inter = json!({
"type": block_type,
"properties": compressed_props,
});
let data: BlockData = serde_json::from_value(inter)
.map_err(|why| serde::de::Error::custom(why.to_string()))?;
let content = content
.unwrap_or(vec![])
.into_iter()
.map(|f| Uuid::parse_str(f.as_str()))
.filter_map(Result::ok)
.collect();
let title = compressed_props.get("title").map(|a| a.to_string());
let outblock = NotionBlock {
id,
data,
content,
title,
};
Ok(outblock)
}
}
#[test]
fn test_serde() {
let block = serde_json::json!({
"role": "editor",
"value": {
"id": "eb492325-3d15-4dd5-adf8-a80d773acb15",
"version": 59,
"type": "page",
"properties": { "title": [["KitchenSink Test"]] },
"content": [
"f1366603-f22f-40cf-bbe4-dd48dc9a023c",
"59ca4846-c2f5-4938-9c9f-6a85c175dec8",
"ab37cc91-5cee-473e-a559-73effa5e8b7b",
"63ebaf2b-de3b-415f-826c-0a842b3145f7",
"87ab67ca-8919-4086-98ba-35714248d088"
],
"permissions": [
{
"role": "editor",
"type": "user_permission",
"user_id": "e7ada895-daf9-4a77-84d3-7e136e3c2ea1"
}
],
"created_time": 159183,
"last_edited_time": 159184,
"parent_id": "9eb2b16c-8502-469d-a4f8-1c11e1d65051",
"parent_table": "space",
"alive": true,
"created_by_table": "notion_user",
"created_by_id": "e7ada895-daf9-4a77-84d3-7e136e3c2ea1",
"last_edited_by_table": "notion_user",
"last_edited_by_id": "e7ada895-daf9-4a77-84d3-7e136e3c2ea1",
"shard_id": 413777,
"space_id": "9eb2b16c-8502-469d-a4f8-1c11e1d65051"
}
});
let block: NotionBlock = serde_json::from_value(block).unwrap();
assert_eq!(block.id.as_str(), "eb492325-3d15-4dd5-adf8-a80d773acb15");
assert_eq!(block.data, BlockData::Page {});
assert_eq!(block.title.unwrap(), "KitchenSink Test".to_string());
assert_eq!(
block.content,
vec![
uuid::Uuid::parse_str("f1366603-f22f-40cf-bbe4-dd48dc9a023c").unwrap(),
uuid::Uuid::parse_str("59ca4846-c2f5-4938-9c9f-6a85c175dec8").unwrap(),
uuid::Uuid::parse_str("ab37cc91-5cee-473e-a559-73effa5e8b7b").unwrap(),
uuid::Uuid::parse_str("63ebaf2b-de3b-415f-826c-0a842b3145f7").unwrap(),
uuid::Uuid::parse_str("87ab67ca-8919-4086-98ba-35714248d088").unwrap()
]
)
}