deduplicate results keeping items with more metadata

This commit is contained in:
Tareq Imbasher 2025-03-31 01:57:11 +03:00
parent 78a0088e7f
commit c2c1b19b72
4 changed files with 125 additions and 16 deletions

13
Cargo.lock generated
View File

@ -517,6 +517,7 @@ dependencies = [
"enum-iterator",
"futures",
"human-panic",
"indexmap",
"json5",
"lazy_static",
"num-format",
@ -1526,6 +1527,12 @@ dependencies = [
"allocator-api2",
]
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
version = "0.5.0"
@ -1723,12 +1730,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "indexmap"
version = "2.5.0"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
dependencies = [
"equivalent",
"hashbrown 0.14.5",
"hashbrown 0.15.2",
]
[[package]]

View File

@ -60,6 +60,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] }
tui-input = "0.10.1"
strum_macros = "0.26.4"
async-trait = "0.1"
indexmap = "2.8.0"
[build-dependencies]
anyhow = "1.0.86"

View File

@ -75,7 +75,7 @@ impl App {
pub async fn run(&mut self) -> AppResult<()> {
let mut tui = Tui::new()?
// .mouse(true)
.paste(true)
// .paste(true)
.tick_rate(self.tick_rate)
.frame_rate(self.frame_rate);
tui.enter()?;

View File

@ -1,4 +1,5 @@
use crates_io_api::{AsyncClient, CratesQuery};
use indexmap::IndexMap;
use reqwest::{header, Client};
use std::sync::Arc;
use std::time::Duration;
@ -130,7 +131,6 @@ impl CrateSearchManager {
return;
}
// Back-fill is_local and is_installed for search results that don't have it
Self::update_results(&mut search_results, &cargo_env);
tx.send(Action::Search(SearchAction::Render(search_results)))
@ -138,16 +138,6 @@ impl CrateSearchManager {
})
}
pub fn update_results(search_results: &mut SearchResults, cargo_env: &CargoEnv) {
for cr in &mut search_results.crates {
if let Some(proj) = &cargo_env.project {
cr.project_version = proj.get_local_version(&cr.name);
}
cr.installed_version = cargo_env.get_installed_version(&cr.name);
}
}
fn search_binaries(term: &str, cargo_env: &CargoEnv) -> Vec<Crate> {
let mut results: Vec<Crate> = Vec::new();
@ -294,6 +284,32 @@ impl CrateSearchManager {
Ok(())
}
pub fn update_results(search_results: &mut SearchResults, cargo_env: &CargoEnv) {
Self::deduplicate(search_results);
// Calculate project_version and installed_version
for cr in &mut search_results.crates {
if let Some(proj) = &cargo_env.project {
cr.project_version = proj.get_local_version(&cr.name);
}
cr.installed_version = cargo_env.get_installed_version(&cr.name);
}
}
fn deduplicate(search_results: &mut SearchResults) {
let mut map = IndexMap::<String, Crate>::new();
for cr in search_results.crates.drain(0..) {
if map.get(&cr.id).is_some_and(|v| v.is_metadata_loaded()) {
continue;
}
map.insert(cr.id.clone(), cr);
}
search_results.crates = map.into_values().collect();
}
pub fn hydrate(data: Box<crates_io_api::Crate>, cr: &mut Crate) {
cr.name = data.name;
cr.description = data.description;
@ -310,6 +326,91 @@ impl CrateSearchManager {
cr.recent_downloads = data.recent_downloads;
cr.created_at = Some(data.created_at);
cr.updated_at = Some(data.updated_at);
cr.exact_match = data.exact_match.unwrap_or(false);
cr.exact_match = data.exact_match.unwrap_or_default();
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
struct Crate {
pub id: String,
pub is_initialized: bool,
}
fn deduplicate(crates: Vec<Crate>) -> Vec<Crate> {
let mut map = HashMap::<String, Crate>::new();
for cr in crates {
let existing = map.get(&cr.id);
if let Some(existing) = existing {
if existing.is_initialized {
continue;
}
}
map.insert(cr.id.clone(), cr);
}
map.into_values().collect()
}
#[test]
fn test_deduplicate() {
let crates = vec![
Crate {
id: "1".into(),
is_initialized: true,
},
Crate {
id: "2".into(),
is_initialized: true,
},
Crate {
id: "3".into(),
is_initialized: false,
},
Crate {
id: "3".into(),
is_initialized: false,
},
Crate {
id: "2".into(),
is_initialized: false,
},
Crate {
id: "2".into(),
is_initialized: false,
},
Crate {
id: "1".into(),
is_initialized: false,
},
Crate {
id: "2".into(),
is_initialized: false,
},
Crate {
id: "4".into(),
is_initialized: true,
},
Crate {
id: "4".into(),
is_initialized: true,
},
];
let mut crates = deduplicate(crates);
crates.sort_by(|a, b| a.id.cmp(&b.id));
assert_eq!(crates.len(), 4);
assert_eq!(crates[0].id, "1".to_string());
assert_eq!(crates[0].is_initialized, true);
assert_eq!(crates[1].id, "2".to_string());
assert_eq!(crates[1].is_initialized, true);
assert_eq!(crates[2].id, "3".to_string());
assert_eq!(crates[2].is_initialized, false);
assert_eq!(crates[3].id, "4".to_string());
assert_eq!(crates[3].is_initialized, true);
}
}