Skip to main content

quorum_core/db/queries/
stats.rs

1//! This file includse query functions for getting stats and information about the database
2//!
3//! This file includes functions to retrieve various statistics and information about the database,
4//! such as the number of records in specific tables, the size of the database, and other relevant metrics. These functions are useful for monitoring and analyzing the performance and usage of the database.
5
6use crate::db::DB;
7use std::error::Error;
8
9pub struct TableStat {
10    pub name: String,
11    pub count: usize,
12    pub size_bytes: usize,
13}
14
15pub struct DbStats {
16    pub tables: Vec<TableStat>,
17    pub total_size_bytes: usize,
18    pub total_rows: usize,
19}
20
21pub struct TableRecords {
22    pub records: Vec<serde_json::Value>,
23    pub total: usize,
24    pub page: usize,
25    pub total_pages: usize,
26    pub size_bytes: usize,
27}
28
29const PAGE_SIZE: usize = 20;
30
31/// Retrieves statistics about the database, including table names, record counts, and sizes.
32///
33/// # Arguments
34/// * `db` - A reference to the database connection.
35///
36/// # Returns
37/// * `Ok(DbStats)` - A struct containing statistics about the database if the query is successful.
38/// * `Err(Box<dyn Error + Send + Sync>)` - An error if the query fails.
39///
40/// # Examples
41/// ```rust
42/// let stats = get_stats(&db).await.unwrap();
43/// println!("Total tables: {}", stats.tables.len());
44/// for table in stats.tables {
45///     println!("Table: {}, Count: {}, Size: {} bytes", table.name, table.count, table.size_bytes);
46/// }
47/// ```
48pub async fn get_stats(db: &DB) -> Result<DbStats, Box<dyn Error + Send + Sync>> {
49    let mut info_response = db.query("INFO FOR DB").await?;
50    let info: Option<serde_json::Value> = info_response.take(0)?;
51
52    let table_names: Vec<String> = info
53        .as_ref()
54        .and_then(|v| v["tables"].as_object())
55        .map(|t| t.keys().cloned().collect())
56        .unwrap_or_default();
57
58    let mut tables = Vec::new();
59
60    for name in &table_names {
61        let mut records_response = db.query(format!("SELECT * FROM {}", name)).await?;
62
63        let records: Vec<serde_json::Value> = records_response.take(0)?;
64        let count = records.len();
65        let size_bytes = serde_json::to_string(&records)
66            .map(|s| s.len())
67            .unwrap_or(0);
68
69        tables.push(TableStat {
70            name: name.clone(),
71            count,
72            size_bytes,
73        });
74    }
75
76    tables.sort_by(|a, b| a.name.cmp(&b.name));
77
78    let total_size_bytes = tables.iter().map(|t| t.size_bytes).sum();
79    let total_rows = tables.iter().map(|t| t.count).sum();
80
81    Ok(DbStats {
82        tables,
83        total_size_bytes,
84        total_rows,
85    })
86}
87
88/// Retrieves records from a specific table in the database, with pagination support.
89///
90/// # Arguments
91/// * `db` - A reference to the database connection.
92/// * `table` - The name of the table to retrieve records from.
93/// * `page` - The page number to retrieve (1-based index).
94///
95/// # Returns
96/// * `Ok(TableRecords)` - A struct containing the records, total count, current page, total pages, and size in bytes if the query is successful.
97/// * `Err(Box<dyn Error + Send + Sync>)` - An error if the query fails or if the table does not exist.
98///
99/// # Examples
100/// ```rust
101/// let table_records = get_table(&db, "users", 1).await.unwrap();
102/// println!("Total records: {}", table_records.total);
103/// for record in table_records.records {
104///     println!("{:?}", record);
105/// }
106/// ```
107pub async fn get_table(
108    db: &DB,
109    table: &str,
110    page: usize,
111) -> Result<TableRecords, Box<dyn Error + Send + Sync>> {
112    let mut info_response = db.query("INFO FOR DB").await?;
113    let info: Option<serde_json::Value> = info_response.take(0)?;
114
115    let exists = info
116        .as_ref()
117        .and_then(|v| v["tables"].as_object())
118        .map(|t| t.contains_key(table))
119        .unwrap_or(false);
120
121    if !exists {
122        return Err(format!("Table '{}' does not exist.", table).into());
123    }
124
125    let mut all_response = db.query(format!("SELECT * FROM {}", table)).await?;
126
127    let all_records: Vec<serde_json::Value> = all_response.take(0)?;
128    let total = all_records.len();
129    let total_pages = (total + PAGE_SIZE - 1).max(1) / PAGE_SIZE;
130    let page = page.clamp(1, total_pages);
131
132    let start = (page - 1) * PAGE_SIZE;
133    let end = (start + PAGE_SIZE).min(total);
134    let records = all_records[start..end].to_vec();
135
136    let size_bytes = serde_json::to_string(&all_records)
137        .map(|s| s.len())
138        .unwrap_or(0);
139
140    Ok(TableRecords {
141        records,
142        total,
143        page,
144        total_pages,
145        size_bytes,
146    })
147}