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}