nblm_core/models/
notebook.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use super::source::NotebookSource;
6
7#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8#[serde(rename_all = "camelCase")]
9pub struct Notebook {
10    pub name: Option<String>,
11    pub title: String,
12    #[serde(rename = "notebookId", skip_serializing_if = "Option::is_none")]
13    pub notebook_id: Option<String>,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub emoji: Option<String>,
16    #[serde(default, skip_serializing_if = "Vec::is_empty")]
17    pub sources: Vec<NotebookSource>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub metadata: Option<NotebookMetadata>,
20    #[serde(flatten)]
21    pub extra: HashMap<String, serde_json::Value>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct NotebookRef {
27    pub notebook_id: String,
28    pub name: String,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize, Default)]
32#[serde(rename_all = "camelCase")]
33pub struct NotebookMetadata {
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub create_time: Option<String>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub is_shareable: Option<bool>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub is_shared: Option<bool>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub last_viewed: Option<String>,
42    #[serde(flatten)]
43    pub extra: HashMap<String, serde_json::Value>,
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn notebook_skips_notebook_id_when_none() {
52        let notebook = Notebook {
53            name: Some("test".to_string()),
54            title: "Test Notebook".to_string(),
55            notebook_id: None,
56            emoji: None,
57            metadata: None,
58            sources: Vec::new(),
59            extra: Default::default(),
60        };
61        let json = serde_json::to_string(&notebook).unwrap();
62        assert!(!json.contains("notebookId"));
63    }
64
65    #[test]
66    fn notebook_includes_notebook_id_when_some() {
67        let notebook = Notebook {
68            name: Some("test".to_string()),
69            title: "Test Notebook".to_string(),
70            notebook_id: Some("nb123".to_string()),
71            emoji: None,
72            metadata: None,
73            sources: Vec::new(),
74            extra: Default::default(),
75        };
76        let json = serde_json::to_string(&notebook).unwrap();
77        assert!(json.contains("notebookId"));
78        assert!(json.contains("nb123"));
79    }
80}