teamcraft/services/
stats.rs1use serde::Serialize;
4use sqlx::PgPool;
5
6use crate::{auth::Actor, error::AppResult, services::access};
7
8#[derive(Clone, Debug, Serialize, sqlx::FromRow)]
9pub struct Stats {
10 pub items: i64,
11 pub revisions_in_work: i64,
12 pub revisions_in_review: i64,
13 pub revisions_released: i64,
14 pub open_changes: i64,
15 pub files: i64,
16 pub stored_bytes: i64,
17}
18
19pub async fn load(pool: &PgPool, actor: &Actor) -> AppResult<Stats> {
21 let item = access::item_visible("i", 1);
22 let change = access::change_visible("c", 2, 1);
23 Ok(sqlx::query_as::<_, Stats>(&format!(
24 "WITH vr AS (SELECT r.id, r.state FROM revisions r JOIN items i ON i.id = r.item_id
25 WHERE {item}),
26 vf AS (SELECT f.sha256, f.size_bytes FROM files f JOIN vr ON vr.id = f.revision_id)
27 SELECT
28 (SELECT COUNT(*) FROM items i WHERE {item}) AS items,
29 (SELECT COUNT(*) FROM vr WHERE state = 'in_work') AS revisions_in_work,
30 (SELECT COUNT(*) FROM vr WHERE state = 'in_review') AS revisions_in_review,
31 (SELECT COUNT(*) FROM vr WHERE state = 'released') AS revisions_released,
32 (SELECT COUNT(*) FROM changes c
33 WHERE c.status IN ('draft', 'in_review', 'rejected') AND {change}) AS open_changes,
34 (SELECT COUNT(*) FROM vf) AS files,
35 -- byte-wise comparison: the hex digests sort several times
36 -- faster than with the database's linguistic collation
37 (SELECT COALESCE(SUM(size_bytes), 0)::bigint FROM
38 (SELECT DISTINCT sha256 COLLATE \"C\", size_bytes FROM vf) blobs) AS stored_bytes"
39 ))
40 .bind(&actor.hidden_projects)
41 .bind(actor.id)
42 .fetch_one(pool)
43 .await?)
44}