From 50b2b9567c267f564cb8af62a54a2137408935ab Mon Sep 17 00:00:00 2001 From: aecsocket <43144841+aecsocket@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:50:02 +0100 Subject: [PATCH] Fix token separators in game version search (#6435) * Fix token separators in game version search * fix --- apps/labrinth/AGENTS.md | 3 ++ .../src/search/backend/typesense/mod.rs | 33 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/apps/labrinth/AGENTS.md b/apps/labrinth/AGENTS.md index 65b5575c6..8cd2edd6c 100644 --- a/apps/labrinth/AGENTS.md +++ b/apps/labrinth/AGENTS.md @@ -26,3 +26,6 @@ - If some steps require you to create a project/mod or version for testing, ask the user to go into the web frontend and manually create a project/version - When using `sqlx::query` etc. always use the macro form like `sqlx::query!` or `sqlx::query_scalar!` - never the plain function form. Avoid using `query_as!`. - Do not run `cargo test`, even for a single specific test, unless explicitly prompted to by the user, since it takes a long time to run. +- You can force a search reindex by: + - Running `cd apps/labrinth && cargo run -p labrinth -- --run-background-task index-search` (prefer this if backend is running locally) + - Hitting the force reindex admin endpoint diff --git a/apps/labrinth/src/search/backend/typesense/mod.rs b/apps/labrinth/src/search/backend/typesense/mod.rs index 750458714..20122c7f9 100644 --- a/apps/labrinth/src/search/backend/typesense/mod.rs +++ b/apps/labrinth/src/search/backend/typesense/mod.rs @@ -359,6 +359,7 @@ pub struct TypesenseFieldSpec { pub facet: bool, pub sort: bool, pub optional: bool, + pub token_separators: Option<&'static [&'static str]>, } impl SearchField { @@ -370,6 +371,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::Name => TypesenseFieldSpec { path: "name", @@ -377,6 +379,7 @@ impl SearchField { facet: true, sort: false, optional: false, + token_separators: None, }, SearchField::Author => TypesenseFieldSpec { path: "author", @@ -384,6 +387,7 @@ impl SearchField { facet: true, sort: false, optional: false, + token_separators: None, }, SearchField::License => TypesenseFieldSpec { path: "license", @@ -391,6 +395,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::ProjectTypes => TypesenseFieldSpec { path: "project_types", @@ -398,6 +403,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::ProjectId => TypesenseFieldSpec { path: "project_id", @@ -405,6 +411,7 @@ impl SearchField { facet: true, sort: false, optional: false, + token_separators: None, }, SearchField::OpenSource => TypesenseFieldSpec { path: "open_source", @@ -412,6 +419,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::Environment => TypesenseFieldSpec { path: "environment", @@ -419,6 +427,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::GameVersions => TypesenseFieldSpec { path: "game_versions", @@ -426,6 +435,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: Some(&["-", "."]), }, SearchField::ClientSide => TypesenseFieldSpec { path: "client_side", @@ -433,6 +443,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::ServerSide => TypesenseFieldSpec { path: "server_side", @@ -440,6 +451,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::MinecraftServerRegion => TypesenseFieldSpec { path: "minecraft_server.region", @@ -447,6 +459,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::MinecraftServerLanguages => TypesenseFieldSpec { path: "minecraft_server.languages", @@ -454,6 +467,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::MinecraftJavaServerContentKind => TypesenseFieldSpec { path: "minecraft_java_server.content.kind", @@ -461,6 +475,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::MinecraftJavaServerContentSupportedGameVersions => { TypesenseFieldSpec { @@ -469,6 +484,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: Some(&["-", "."]), } } SearchField::MinecraftJavaServerPingData => TypesenseFieldSpec { @@ -477,6 +493,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::DependencyProjectIds => TypesenseFieldSpec { path: "dependency_project_ids", @@ -484,6 +501,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, SearchField::CompatibleDependencyProjectIds => TypesenseFieldSpec { path: "compatible_dependency_project_ids", @@ -491,6 +509,7 @@ impl SearchField { facet: true, sort: false, optional: true, + token_separators: None, }, } } @@ -515,6 +534,19 @@ static TYPESENSE_SEARCH_FIELDS: LazyLock> = LazyLock::new(|| { if spec.optional { obj.insert("optional".to_string(), Value::Bool(true)); } + if let Some(token_separators) = spec.token_separators { + obj.insert( + "token_separators".to_string(), + Value::Array( + token_separators + .iter() + .map(|separator| { + Value::String((*separator).to_string()) + }) + .collect(), + ), + ); + } Value::Object(obj) }) .collect() @@ -547,7 +579,6 @@ impl Typesense { json!({ "name": name, "enable_nested_fields": true, - "token_separators": ["-"], "fields": fields, "default_sorting_field": "log_downloads" })