[CORE] More search fields for local search, tie breaking

This commit is contained in:
Ben C 2024-08-07 21:02:09 -04:00
parent 2f520ebb6b
commit 890890aa48
No known key found for this signature in database
4 changed files with 33 additions and 18 deletions

View File

@ -15,7 +15,7 @@ use crate::{
validate::{check_mod, ModValidationError},
};
use super::combined_search::LocalModWithRemoteName;
use super::combined_search::LocalModWithRemoteSearchData;
use super::{fix_version, RemoteDatabase};
/// Represents the local (on the local PC) database of mods.
@ -329,13 +329,11 @@ impl LocalDatabase {
remote_db: &RemoteDatabase,
) -> Vec<&UnsafeLocalMod> {
let mods: Vec<&UnsafeLocalMod> = self.all().collect();
let mods: Vec<LocalModWithRemoteName> = mods
let mods: Vec<LocalModWithRemoteSearchData> = mods
.into_iter()
.map(|m| {
let remote_name = remote_db
.get_mod(m.get_unique_name())
.map(|m| m.name.clone());
LocalModWithRemoteName::new(m, remote_name)
let remote = remote_db.get_mod(m.get_unique_name()).cloned();
LocalModWithRemoteSearchData::new(m, remote)
})
.collect();
let mods = mods.iter().collect();

View File

@ -13,34 +13,40 @@ fn fix_version(version: &str) -> &str {
mod combined_search {
use crate::mods::local::UnsafeLocalMod;
use crate::mods::remote::RemoteMod;
use crate::search::Searchable;
pub struct LocalModWithRemoteName<'a> {
pub struct LocalModWithRemoteSearchData<'a> {
pub local_mod: &'a UnsafeLocalMod,
remote_name: Option<String>,
remote: Option<RemoteMod>,
}
impl<'a> LocalModWithRemoteName<'a> {
pub fn new(local_mod: &'a UnsafeLocalMod, remote_name: Option<String>) -> Self {
Self {
local_mod,
remote_name,
}
impl<'a> LocalModWithRemoteSearchData<'a> {
pub fn new(local_mod: &'a UnsafeLocalMod, remote: Option<RemoteMod>) -> Self {
Self { local_mod, remote }
}
}
impl Searchable for LocalModWithRemoteName<'_> {
impl Searchable for LocalModWithRemoteSearchData<'_> {
fn get_values(&self) -> Vec<String> {
if let Some(name) = &self.remote_name {
if let Some(ref remote) = self.remote {
self.local_mod
.get_values()
.into_iter()
.chain(vec![name.clone()])
.chain(remote.get_values())
.collect()
} else {
self.local_mod.get_values()
}
}
fn break_tie(&self, other: &Self) -> std::cmp::Ordering {
if let (Some(self_remote), Some(other_remote)) = (&self.remote, &other.remote) {
self_remote.break_tie(other_remote)
} else {
self.remote.is_some().cmp(&other.remote.is_some()).reverse()
}
}
}
}

View File

@ -77,6 +77,10 @@ impl Searchable for RemoteMod {
self.description.clone(),
]
}
fn break_tie(&self, other: &Self) -> std::cmp::Ordering {
self.download_count.cmp(&other.download_count).reverse()
}
}
/// A prerelease for a mod

View File

@ -1,3 +1,5 @@
use std::cmp::Ordering;
use unicode_normalization::UnicodeNormalization;
/// Represents an object that can be searched
@ -6,6 +8,11 @@ pub trait Searchable {
/// Each value will be weighted based on its position in the list (first is most important)
/// Values are automatically normalized for optimal searching via [normalize_value] when using [search_list]
fn get_values(&self) -> Vec<String>;
/// In the event two items have the same score, this function will be called to break the tie
fn break_tie(&self, _other: &Self) -> Ordering {
Ordering::Equal
}
}
/// Normalizes a string for optimal searching
@ -88,7 +95,7 @@ where
}
})
.collect();
scores.sort_by(|(_, a), (_, b)| a.total_cmp(b).reverse());
scores.sort_by(|(s, a), (o, b)| a.total_cmp(b).reverse().then_with(|| s.break_tie(o)));
scores.iter().map(|(m, _)| *m).collect()
}
#[cfg(test)]