user_downloads/
user-downloads.rs

1//! $ cargo run --release --example user-downloads
2//!
3//! Computes time series of the fraction of crates.io downloads attributed to a
4//! single given user's crates.
5
6use chrono::Utc;
7use db_dump::Date;
8use std::collections::{BTreeMap as Map, BTreeSet as Set};
9
10const USER: &str = "dtolnay";
11
12#[derive(Default)]
13struct Downloads {
14    theirs: u64,
15    all: u64,
16}
17
18fn main() -> db_dump::Result<()> {
19    let mut user_id = None;
20    let mut crate_owners = Vec::new();
21    let mut versions = Vec::new();
22    let mut version_downloads = Vec::new();
23    db_dump::Loader::new()
24        .users(|row| {
25            if row.gh_login == USER {
26                user_id = Some(row.id);
27            }
28        })
29        .crate_owners(|row| crate_owners.push(row))
30        .versions(|row| versions.push(row))
31        .version_downloads(|row| version_downloads.push(row))
32        .load("./db-dump.tar.gz")?;
33
34    // User id of the crate author we care about.
35    let user_id = user_id.expect("no such user");
36
37    // Set of crate ids currently owned by that user.
38    let mut their_crates = Set::new();
39    for crate_owner in crate_owners {
40        if crate_owner.owner_id == user_id {
41            their_crates.insert(crate_owner.crate_id);
42        }
43    }
44
45    // Set of version ids of all of those crates.
46    let mut their_versions = Set::new();
47    for version in versions {
48        if their_crates.contains(&version.crate_id) {
49            their_versions.insert(version.id);
50        }
51    }
52
53    // Add up downloads across that user's crates, as well as total downloads of
54    // all crates.
55    let mut downloads = Map::<Date<Utc>, Downloads>::new();
56    for stat in version_downloads {
57        let entry = downloads.entry(stat.date).or_default();
58        entry.all += stat.downloads;
59        if their_versions.contains(&stat.version_id) {
60            entry.theirs += stat.downloads;
61        }
62    }
63
64    // Print user's downloads as a fraction of total crates.io downloads by day.
65    for (date, downloads) in downloads {
66        if downloads.theirs > 0 {
67            println!(
68                "{},{}",
69                date,
70                downloads.theirs as f64 / downloads.all as f64,
71            );
72        }
73    }
74
75    Ok(())
76}