chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
A profile's badges count each repository's merge batches in one query
crates/knotless-serve/src/web/badges.rs+47−28
| @@ -75,11 +75,20 @@ fn badges(counts: [u64; 12]) -> Vec<BadgeView> { | ||
pub(super) fn badges_of(index: &Index, did: &str, home: Home) -> Vec<BadgeView> { | ||
let (shipped, stars, repos) = index.badge_counts(did).unwrap_or_default(); | ||
let mut c = Tally::default(); | ||
let mut batches = HashMap::new(); | ||
for pulls in index.pulls_by(did).unwrap_or_default() { | ||
let items = forge::assemble(&pulls.repo, &pulls.owner, &pulls.entries); | ||
let ejected = ejections(&pulls); | ||
// How many each batch landed, read once the first merged pull | ||
// names one: a query for each batch read the repository's records | ||
// as many times over. | ||
let mut batches = None; | ||
for item in items.iter().filter(|i| i.author == did) { | ||
c.authored(index, &pulls, item, &mut batches); | ||
let ejected = ejected | ||
.get(item.uri.as_str()) | ||
.map_or(&[][..], Vec::as_slice); | ||
c.authored(&pulls.owner, item, ejected, || { | ||
batches.get_or_insert_with(|| landed(index, &pulls)) | ||
}); | ||
} | ||
} | ||
let first = index.first_comments(did).unwrap_or_default(); | ||
| @@ -126,21 +135,21 @@ struct Tally { | ||
} | ||
| ||
impl Tally { | ||
/// Counts `item`, a pull the account opened on the repository of | ||
/// `pulls`: merged into another's repository; landed by the merge | ||
/// Counts `item`, a pull the account opened on the repository `owner` | ||
/// keeps: merged into another's repository; landed by the merge | ||
/// queue, never turned away, or in a batch of many; turned away for a | ||
/// conflict and landed after all; or found by halving a batch. | ||
/// `batches` keeps how many each batch landed, as they are counted. | ||
fn authored( | ||
/// `ejected` says why the runner turned it away each time, and | ||
/// `batches` how many pulls each batch of its repository landed. | ||
fn authored<'a>( | ||
&mut self, | ||
index: &Index, | ||
pulls: &Pulls, | ||
owner: &str, | ||
item: &Item, | ||
batches: &mut HashMap<String, usize>, | ||
ejected: &[&str], | ||
batches: impl FnOnce() -> &'a HashMap<String, usize>, | ||
) { | ||
let ejected = ejections(pulls, &item.uri); | ||
let merged = item.state == "merged"; | ||
self.upstream += (merged && pulls.owner != item.author) as u64; | ||
self.upstream += (merged && owner != item.author) as u64; | ||
let conflicted = ejected.iter().any(|r| r.contains(CONFLICTS)); | ||
self.peacemaker += (merged && conflicted) as u64; | ||
self.bisected += ejected.iter().any(|r| r.contains(HALVED)) as u64; | ||
| @@ -148,40 +157,50 @@ impl Tally { | ||
return; | ||
}; | ||
self.smooth += ejected.is_empty() as u64; | ||
let landed = *batches | ||
.entry(batch.clone()) | ||
.or_insert_with(|| landed(index, pulls, batch)); | ||
let landed = batches().get(batch).copied().unwrap_or_default(); | ||
self.company += (landed >= COMPANY) as u64; | ||
} | ||
} | ||
| ||
/// Why the runner of the repository of `pulls` turned the pull at `uri` | ||
/// away from its merge queue, each time it did. | ||
fn ejections<'a>(pulls: &'a Pulls, uri: &str) -> Vec<&'a str> { | ||
/// Why the runner of the repository of `pulls` turned each pull away from | ||
/// its merge queue, each time it did, by the pull's URI. | ||
fn ejections(pulls: &Pulls) -> HashMap<&str, Vec<&str>> { | ||
let mut ejected: HashMap<&str, Vec<&str>> = HashMap::new(); | ||
let queue = pulls | ||
.entries | ||
.iter() | ||
.filter(|e| e.uri.contains("/dev.knotless.queue/")); | ||
let ejected = queue.filter(|e| { | ||
e.value["subject"] == uri && e.value["state"] == EJECTED && pulls.repo.is_runner(&e.author) | ||
}); | ||
for e in queue { | ||
let turned = e.value["state"] == EJECTED && pulls.repo.is_runner(&e.author); | ||
if let Some(subject) = e.value["subject"].as_str().filter(|_| turned) { | ||
let reason = e.value["reason"].as_str().unwrap_or_default(); | ||
ejected.entry(subject).or_default().push(reason); | ||
} | ||
} | ||
ejected | ||
.map(|e| e.value["reason"].as_str().unwrap_or_default()) | ||
.collect() | ||
} | ||
| ||
/// How many pulls the merge queue landed in `batch` on the repository of | ||
/// `pulls`, as those who may merge said. | ||
fn landed(index: &Index, pulls: &Pulls, batch: &str) -> usize { | ||
let states = index.batch_states(&pulls.owner, &pulls.repo.key, batch); | ||
/// How many pulls the merge queue landed in each batch on the repository | ||
/// of `pulls`, as those who may merge said, by the batch's tip. | ||
fn landed(index: &Index, pulls: &Pulls) -> HashMap<String, usize> { | ||
let states = index.batch_states(&pulls.owner, &pulls.repo.key); | ||
let states = states.unwrap_or_default(); | ||
let merged = states.iter().filter(|e| { | ||
let at = e.uri.rsplit('/').next().unwrap_or_default(); | ||
let by = forge::allowed(&pulls.repo, &pulls.owner, "", &e.author, "merged", at); | ||
e.value["state"] == "merged" && by | ||
}); | ||
let pulls: HashSet<&str> = merged.filter_map(|e| e.value["subject"].as_str()).collect(); | ||
pulls.len() | ||
let mut batches: HashMap<&str, HashSet<&str>> = HashMap::new(); | ||
for e in merged { | ||
if let (Some(batch), Some(pull)) = (e.value["batch"].as_str(), e.value["subject"].as_str()) | ||
{ | ||
batches.entry(batch).or_default().insert(pull); | ||
} | ||
} | ||
let counted = batches | ||
.into_iter() | ||
.map(|(b, pulls)| (b.to_string(), pulls.len())); | ||
counted.collect() | ||
} | ||
| ||
/// Whether `did` first commented on `item`, at `first`, before it merged: | ||
crates/knotless-serve/src/index.rs+8−12
| @@ -1696,22 +1696,18 @@ impl Index { | ||
.collect()) | ||
} | ||
| ||
/// The `merged` states naming `batch` as the tip of the merge queue's | ||
/// batch they landed in, on the repository `owner` keeps at `key`. | ||
pub fn batch_states( | ||
&self, | ||
owner: &str, | ||
key: &str, | ||
batch: &str, | ||
) -> rusqlite::Result<Vec<Entry>> { | ||
/// The states naming a batch of the merge queue, by its tip, as the | ||
/// one they landed in, on the repository `owner` keeps at `key`. | ||
pub fn batch_states(&self, owner: &str, key: &str) -> rusqlite::Result<Vec<Entry>> { | ||
let db = self.readers.take(&self.db); | ||
let mut stmt = db.prepare_cached( | ||
"SELECT uri, author, value FROM forge | ||
WHERE json_extract(value, '$.batch') = ?3 | ||
AND repo_did = ?1 AND repo_key = ?2 | ||
AND instr(uri, '/dev.knotless.state/') AND uri NOT IN down", | ||
WHERE repo_did = ?1 AND repo_key = ?2 | ||
AND instr(uri, '/dev.knotless.state/') | ||
AND json_extract(value, '$.batch') IS NOT NULL | ||
AND uri NOT IN down", | ||
)?; | ||
stmt.query_map([owner, key, batch], entry)?.collect() | ||
stmt.query_map([owner, key], entry)?.collect() | ||
} | ||
| ||
/// What was last found of where `did`'s account lives, and when, in | ||