mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 03:55:59 +00:00
* Add consume batching delay * maybe fix * max batch size * more logging * parallelize remove tasks * delete/upsert project/version messages * prepare * more logging * log number of docs * try more targeted, homogenous version change ops * ensure only necessary fields are serialized into typesense * disable index background task * wip: script changes * don't facet by project id * fix * fix clippy * batch by document and dedup loaders * fix test * wip: projects/versions collections * clean up SearchBackend interface * cleanup pass * cleanup pass 2 * standardise fn names * cleanup pass * fix compile * factor out filter rewriting * query perf * put categories into the project doc * wip: search filter AST * doc comment * more AST normalization * (temp) convert search request errors into internal errors * implement unary NOT * tombi fmt * fix tests * revert request error * try increase stack size
107 lines
3.0 KiB
Rust
107 lines
3.0 KiB
Rust
use crate::routes::ApiError;
|
|
use crate::search::SearchRequest;
|
|
use crate::util::error::Context;
|
|
use eyre::eyre;
|
|
use std::borrow::Cow;
|
|
|
|
pub struct ParsedSearchRequest<'a> {
|
|
pub offset: usize,
|
|
pub hits_per_page: usize,
|
|
pub page: usize,
|
|
pub index: &'a str,
|
|
pub query: &'a str,
|
|
}
|
|
|
|
pub fn parse_search_request(
|
|
info: &SearchRequest,
|
|
) -> Result<ParsedSearchRequest<'_>, ApiError> {
|
|
let offset = info
|
|
.offset
|
|
.as_deref()
|
|
.unwrap_or("0")
|
|
.parse::<usize>()
|
|
.wrap_request_err("invalid offset")?;
|
|
let limit = info
|
|
.limit
|
|
.as_deref()
|
|
.unwrap_or("10")
|
|
.parse::<usize>()
|
|
.wrap_request_err("invalid limit")?
|
|
.min(100);
|
|
let hits_per_page = if limit == 0 { 1 } else { limit };
|
|
|
|
Ok(ParsedSearchRequest {
|
|
offset,
|
|
hits_per_page,
|
|
page: offset / hits_per_page + 1,
|
|
index: info.index.as_deref().unwrap_or("relevance"),
|
|
query: info.query.as_deref().unwrap_or_default(),
|
|
})
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum SearchIndex {
|
|
Relevance,
|
|
Downloads,
|
|
Follows,
|
|
Updated,
|
|
Newest,
|
|
MinecraftJavaServerVerifiedPlays2w,
|
|
MinecraftJavaServerPlayersOnline,
|
|
}
|
|
|
|
pub struct SearchSort {
|
|
pub index: SearchIndex,
|
|
}
|
|
|
|
pub fn parse_search_index(
|
|
index: &str,
|
|
new_filters: Option<&str>,
|
|
) -> Result<SearchSort, ApiError> {
|
|
// TODO: this is a dumb hack, the frontend should pass the project type it's filtering directly
|
|
let is_server = new_filters
|
|
.is_some_and(|f| f.contains("project_types = minecraft_java_server"));
|
|
|
|
Ok(match index {
|
|
"relevance" => SearchSort {
|
|
index: if is_server {
|
|
SearchIndex::MinecraftJavaServerVerifiedPlays2w
|
|
} else {
|
|
SearchIndex::Relevance
|
|
},
|
|
},
|
|
"downloads" => SearchSort {
|
|
index: SearchIndex::Downloads,
|
|
},
|
|
"follows" => SearchSort {
|
|
index: SearchIndex::Follows,
|
|
},
|
|
"updated" | "date_modified" => SearchSort {
|
|
index: SearchIndex::Updated,
|
|
},
|
|
"newest" | "date_created" => SearchSort {
|
|
index: SearchIndex::Newest,
|
|
},
|
|
"minecraft_java_server.verified_plays_2w" => SearchSort {
|
|
index: SearchIndex::MinecraftJavaServerVerifiedPlays2w,
|
|
},
|
|
"minecraft_java_server.ping.data.players_online" => SearchSort {
|
|
index: SearchIndex::MinecraftJavaServerPlayersOnline,
|
|
},
|
|
i => return Err(ApiError::Request(eyre!("invalid index '{i}'"))),
|
|
})
|
|
}
|
|
|
|
pub fn combined_search_filters(info: &SearchRequest) -> Option<Cow<'_, str>> {
|
|
if let Some(filters) = info.new_filters.as_deref() {
|
|
return Some(filters.into());
|
|
}
|
|
|
|
match (info.filters.as_deref(), info.version.as_deref()) {
|
|
(Some(f), Some(v)) => Some(format!("({f}) AND ({v})").into()),
|
|
(Some(f), None) => Some(f.into()),
|
|
(None, Some(v)) => Some(v.into()),
|
|
(None, None) => None,
|
|
}
|
|
}
|