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;

// todo!
// - enable custom equation support
// - enable collection support

// mod equation;

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()
        ]
    )
}