From 96ab120cd0446d8f6c9d288ea3b88d1480d5a271 Mon Sep 17 00:00:00 2001 From: Prospector <6166773+Prospector@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:30:42 -0700 Subject: [PATCH] feat: add all_project_types to search results (#6654) * feat: add all_project_types to search results * update docs --- apps/docs/public/openapi.yaml | 8 ++++++++ apps/labrinth/src/models/v2/search.rs | 2 ++ apps/labrinth/src/search/backend/typesense/mod.rs | 8 ++++++++ apps/labrinth/src/search/indexing.rs | 15 +++++++++++++++ apps/labrinth/src/search/mod.rs | 5 +++++ packages/api-client/src/modules/labrinth/types.ts | 2 ++ 6 files changed, 40 insertions(+) diff --git a/apps/docs/public/openapi.yaml b/apps/docs/public/openapi.yaml index b49357c030..110db62e58 100644 --- a/apps/docs/public/openapi.yaml +++ b/apps/docs/public/openapi.yaml @@ -692,6 +692,12 @@ components: type: string description: The ID of the project example: AABBCCDD + all_project_types: + type: array + items: + type: string + description: All project types across every version of the project, unlike `project_type` which only reflects a version-specific type + example: [mod, plugin, datapack] author: type: string description: The username of the project's author @@ -748,6 +754,7 @@ components: - client_side - server_side - project_id + - all_project_types - author - versions - follows @@ -1948,6 +1955,7 @@ paths: These are the most commonly used facet types: - `project_type` + - `all_project_types` (matches against every project type across all of the project's versions, not just the primary/version-specific type) - `categories` (loaders are lumped in with categories in search) - `versions` - `client_side` diff --git a/apps/labrinth/src/models/v2/search.rs b/apps/labrinth/src/models/v2/search.rs index c105fa3dc1..747ec5d6b4 100644 --- a/apps/labrinth/src/models/v2/search.rs +++ b/apps/labrinth/src/models/v2/search.rs @@ -15,6 +15,7 @@ pub struct LegacySearchResults { pub struct LegacyResultSearchProject { pub project_id: String, pub project_type: String, + pub all_project_types: Vec, pub slug: Option, pub author: String, #[serde(default)] @@ -136,6 +137,7 @@ impl LegacyResultSearchProject { Self { project_type, + all_project_types: result_search_project.all_project_types, client_side, server_side, versions, diff --git a/apps/labrinth/src/search/backend/typesense/mod.rs b/apps/labrinth/src/search/backend/typesense/mod.rs index 6bbb141bf7..89fd29ffd4 100644 --- a/apps/labrinth/src/search/backend/typesense/mod.rs +++ b/apps/labrinth/src/search/backend/typesense/mod.rs @@ -405,6 +405,14 @@ impl SearchField { optional: true, token_separators: &["-"], }, + SearchField::AllProjectTypes => TypesenseFieldSpec { + path: "all_project_types", + ty: "string[]", + facet: true, + sort: false, + optional: true, + token_separators: &["-"], + }, SearchField::ProjectId => TypesenseFieldSpec { path: "project_id", ty: "string", diff --git a/apps/labrinth/src/search/indexing.rs b/apps/labrinth/src/search/indexing.rs index 3c4c8a762f..50fc706206 100644 --- a/apps/labrinth/src/search/indexing.rs +++ b/apps/labrinth/src/search/indexing.rs @@ -495,6 +495,20 @@ async fn build_search_documents( .flat_map(|x| x.loaders.clone()) .collect::>(); + // all valid project types across every version of the project, so that + // filters can exclude projects that have *any* version of a given + // project type (unlike the version-specific `project_types` field). + let mut all_project_types = versions + .iter() + .flat_map(|x| x.project_types.clone()) + .collect::>(); + all_project_types.sort(); + all_project_types.dedup(); + exp::compat::correct_project_types( + &project.components, + &mut all_project_types, + ); + for version in versions { let version_fields = VersionField::from_query_json( version.version_fields, @@ -609,6 +623,7 @@ async fn build_search_documents( slug: project.slug.clone(), // TODO project_types, + all_project_types: all_project_types.clone(), gallery: gallery.clone(), featured_gallery: featured_gallery.clone(), open_source, diff --git a/apps/labrinth/src/search/mod.rs b/apps/labrinth/src/search/mod.rs index cfef656bc1..c206800e94 100644 --- a/apps/labrinth/src/search/mod.rs +++ b/apps/labrinth/src/search/mod.rs @@ -202,6 +202,7 @@ pub enum SearchField { Author, License, ProjectTypes, + AllProjectTypes, ProjectId, OpenSource, Environment, @@ -238,6 +239,7 @@ pub struct UploadSearchProject { pub project_id: String, // pub project_types: Vec, + pub all_project_types: Vec, pub slug: Option, pub author: String, pub author_id: String, @@ -307,6 +309,8 @@ pub struct ResultSearchProject { pub version_id: String, pub project_id: String, pub project_types: Vec, + #[serde(default)] + pub all_project_types: Vec, pub slug: Option, pub author: String, #[serde(default)] @@ -355,6 +359,7 @@ impl From for ResultSearchProject { version_id: source.version_id, project_id: source.project_id, project_types: source.project_types, + all_project_types: source.all_project_types, slug: source.slug, author: source.author, author_id: Some(source.author_id), diff --git a/packages/api-client/src/modules/labrinth/types.ts b/packages/api-client/src/modules/labrinth/types.ts index c7e8da75fb..770f17c1c2 100644 --- a/packages/api-client/src/modules/labrinth/types.ts +++ b/packages/api-client/src/modules/labrinth/types.ts @@ -1742,6 +1742,7 @@ export namespace Labrinth { export interface ResultSearchProject { project_id: string project_type: string + all_project_types: string[] slug: string | null author: string author_id: string | null @@ -1779,6 +1780,7 @@ export namespace Labrinth { version_id: string project_id: string project_types: string[] + all_project_types: string[] slug: string | null author: string author_id: string | null