Skip to main content

obsidian_cli_inspector/db/
stats.rs

1use rusqlite::Connection;
2
3#[derive(Debug)]
4pub struct DatabaseStats {
5    pub note_count: usize,
6    pub link_count: usize,
7    pub tag_count: usize,
8    pub chunk_count: usize,
9    pub unresolved_links: usize,
10}
11
12pub fn get_stats(conn: &Connection) -> rusqlite::Result<DatabaseStats> {
13    let note_count: i32 = conn.query_row("SELECT COUNT(*) FROM notes", [], |row| row.get(0))?;
14
15    let link_count: i32 = conn.query_row("SELECT COUNT(*) FROM links", [], |row| row.get(0))?;
16
17    let tag_count: i32 =
18        conn.query_row("SELECT COUNT(DISTINCT tag) FROM tags", [], |row| row.get(0))?;
19
20    let chunk_count: i32 = conn.query_row("SELECT COUNT(*) FROM chunks", [], |row| row.get(0))?;
21
22    let unresolved_links: i32 = conn.query_row(
23        "SELECT COUNT(*) FROM links WHERE dst_note_id IS NULL",
24        [],
25        |row| row.get(0),
26    )?;
27
28    Ok(DatabaseStats {
29        note_count: note_count as usize,
30        link_count: link_count as usize,
31        tag_count: tag_count as usize,
32        chunk_count: chunk_count as usize,
33        unresolved_links: unresolved_links as usize,
34    })
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    fn create_test_db() -> Connection {
42        let conn = Connection::open_in_memory().unwrap();
43        conn.execute(
44            "CREATE TABLE notes (id INTEGER PRIMARY KEY, path TEXT, title TEXT, mtime INTEGER, hash TEXT, created_at TEXT, updated_at TEXT, frontmatter_json TEXT)",
45            [],
46        )
47        .unwrap();
48        conn.execute(
49            "CREATE TABLE links (id INTEGER PRIMARY KEY, src_note_id INTEGER, dst_note_id INTEGER, dst_text TEXT, kind TEXT, is_embed INTEGER, alias TEXT, heading_ref TEXT, block_ref TEXT)",
50            [],
51        )
52        .unwrap();
53        conn.execute(
54            "CREATE TABLE tags (id INTEGER PRIMARY KEY, note_id INTEGER, tag TEXT)",
55            [],
56        )
57        .unwrap();
58        conn.execute(
59            "CREATE TABLE chunks (id INTEGER PRIMARY KEY, note_id INTEGER, heading_path TEXT, text TEXT, byte_offset INTEGER, byte_length INTEGER)",
60            [],
61        )
62        .unwrap();
63        conn
64    }
65
66    #[test]
67    fn test_get_stats_empty_database() {
68        let conn = create_test_db();
69        let stats = get_stats(&conn).unwrap();
70        assert_eq!(stats.note_count, 0);
71        assert_eq!(stats.link_count, 0);
72        assert_eq!(stats.tag_count, 0);
73        assert_eq!(stats.chunk_count, 0);
74        assert_eq!(stats.unresolved_links, 0);
75    }
76
77    #[test]
78    fn test_database_stats_creation() {
79        let stats = DatabaseStats {
80            note_count: 10,
81            link_count: 20,
82            tag_count: 5,
83            chunk_count: 15,
84            unresolved_links: 2,
85        };
86        assert_eq!(stats.note_count, 10);
87        assert_eq!(stats.link_count, 20);
88    }
89}