kobo_db_tools/export/
bookmark.rs

1use super::{error::ExportError, Export};
2use crate::model::Bookmark;
3use chrono::{DateTime, Utc};
4use csv::Writer;
5use std::io::Write;
6use std::str::FromStr;
7use serde_json;
8
9impl Export for [Bookmark] {
10    fn to_csv(&self) -> Result<String, ExportError> {
11        let mut wtr = Writer::from_writer(vec![]);
12        for bookmark in self {
13            wtr.serialize(bookmark)?;
14        }
15        Ok(String::from_utf8(wtr.into_inner()?)?)
16    }
17
18    fn to_md(&self) -> Result<String, ExportError> {
19        let mut buffer = Vec::new();
20        for bookmark in self {
21            writeln!(buffer, "### {}", bookmark.book_title)?;
22            writeln!(buffer, "\n> {}", bookmark.content)?;
23            writeln!(
24                buffer,
25                "\n**Chapter Progress:** {:.2}%",
26                bookmark.chapter_progress * 100.0
27            )?;
28            let formatted_date = DateTime::<Utc>::from_str(&bookmark.create_date)
29                .map(|dt| dt.format("%Y-%m-%d %H:%M:%S UTC").to_string())
30                .unwrap_or_else(|_| bookmark.create_date.clone());
31            writeln!(buffer, "**Created:** {}", formatted_date)?;
32            writeln!(buffer, "\n---\n")?;
33        }
34        Ok(String::from_utf8(buffer)?)
35    }
36
37    fn to_json(&self) -> Result<String, ExportError> {
38        serde_json::to_string(self).map_err(ExportError::JsonToString)
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use crate::model::Bookmark;
46
47    #[test]
48    fn test_to_csv() {
49        let bookmarks = vec![
50            Bookmark {
51                content_id: "content1".to_string(),
52                content: "content text".to_string(),
53                book_id: "book1".to_string(),
54                book_title: "Book Title".to_string(),
55                color: 1,
56                chapter_progress: 0.5,
57                create_date: "2025-07-05T10:00:00Z".to_string(),
58                write_date: "2025-07-05T10:00:00Z".to_string(),
59            },
60        ];
61
62        let expected_csv = "content_id,content,book_id,book_title,color,chapter_progress,create_date,write_date\ncontent1,content text,book1,Book Title,1,0.5,2025-07-05T10:00:00Z,2025-07-05T10:00:00Z\n".to_string();
63        let result = bookmarks.to_csv().unwrap();
64        assert_eq!(result, expected_csv);
65    }
66
67    #[test]
68    fn test_to_json() {
69        let bookmarks = vec![
70            Bookmark {
71                content_id: "content1".to_string(),
72                content: "content text".to_string(),
73                book_id: "book1".to_string(),
74                book_title: "Book Title".to_string(),
75                color: 1,
76                chapter_progress: 0.5,
77                create_date: "2025-07-05T10:00:00Z".to_string(),
78                write_date: "2025-07-05T10:00:00Z".to_string(),
79            },
80        ];
81
82        let expected_json = serde_json::to_string(&bookmarks).unwrap();
83        let result = bookmarks.to_json().unwrap();
84        assert_eq!(result, expected_json);
85    }
86}