Fix search sorting (#5509)

* Ensure newest published versions get sorted at the top

* fix issue with querying

* sort by correct fields depending on server/not server project

* sqlx prepare
This commit is contained in:
aecsocket
2026-03-09 15:46:38 +00:00
committed by GitHub
parent 913dee9090
commit 4a0c610fc5
4 changed files with 80 additions and 32 deletions

View File

@@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "db_name": "PostgreSQL",
"query": "\n SELECT v.id, v.mod_id\n FROM versions v\n WHERE mod_id = ANY($1)\n ", "query": "\n SELECT v.id, v.mod_id, v.date_published\n FROM versions v\n WHERE mod_id = ANY($1)\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@@ -12,6 +12,11 @@
"ordinal": 1, "ordinal": 1,
"name": "mod_id", "name": "mod_id",
"type_info": "Int8" "type_info": "Int8"
},
{
"ordinal": 2,
"name": "date_published",
"type_info": "Timestamptz"
} }
], ],
"parameters": { "parameters": {
@@ -20,9 +25,10 @@
] ]
}, },
"nullable": [ "nullable": [
false,
false, false,
false false
] ]
}, },
"hash": "dbdcaf9f2126e15892c28f782d4b5812d947582e3573da56e632f2b0b29fac7b" "hash": "7f483288e82d8c40adaed79463396e871f1a2303df9bdd4ab1b38171a8596065"
} }

View File

@@ -436,6 +436,9 @@ pub async fn index_local(
created_timestamp: project.approved.timestamp(), created_timestamp: project.approved.timestamp(),
date_modified: project.updated, date_modified: project.updated,
modified_timestamp: project.updated.timestamp(), modified_timestamp: project.updated.timestamp(),
version_published_timestamp: version
.date_published
.timestamp(),
license: license.clone(), license: license.clone(),
slug: project.slug.clone(), slug: project.slug.clone(),
// TODO // TODO
@@ -464,31 +467,37 @@ struct PartialVersion {
loaders: Vec<String>, loaders: Vec<String>,
project_types: Vec<String>, project_types: Vec<String>,
version_fields: Vec<QueryVersionField>, version_fields: Vec<QueryVersionField>,
date_published: DateTime<Utc>,
} }
async fn index_versions( async fn index_versions(
pool: &PgPool, pool: &PgPool,
project_ids: Vec<i64>, project_ids: Vec<i64>,
) -> Result<HashMap<DBProjectId, Vec<PartialVersion>>, IndexingError> { ) -> Result<HashMap<DBProjectId, Vec<PartialVersion>>, IndexingError> {
let versions: HashMap<DBProjectId, Vec<DBVersionId>> = sqlx::query!( let versions: HashMap<DBProjectId, Vec<(DBVersionId, DateTime<Utc>)>> =
" sqlx::query!(
SELECT v.id, v.mod_id "
SELECT v.id, v.mod_id, v.date_published
FROM versions v FROM versions v
WHERE mod_id = ANY($1) WHERE mod_id = ANY($1)
", ",
&project_ids, &project_ids,
) )
.fetch(pool) .fetch(pool)
.try_fold( .try_fold(
HashMap::new(), HashMap::new(),
|mut acc: HashMap<DBProjectId, Vec<DBVersionId>>, m| { |mut acc: HashMap<
acc.entry(DBProjectId(m.mod_id)) DBProjectId,
.or_default() Vec<(DBVersionId, DateTime<Utc>)>,
.push(DBVersionId(m.id)); >,
async move { Ok(acc) } m| {
}, acc.entry(DBProjectId(m.mod_id))
) .or_default()
.await?; .push((DBVersionId(m.id), m.date_published));
async move { Ok(acc) }
},
)
.await?;
// Get project types, loaders // Get project types, loaders
#[derive(Default)] #[derive(Default)]
@@ -500,7 +509,7 @@ async fn index_versions(
let all_version_ids = versions let all_version_ids = versions
.iter() .iter()
.flat_map(|(_, version_ids)| version_ids.iter()) .flat_map(|(_, version_ids)| version_ids.iter())
.map(|x| x.0) .map(|(version_id, _)| version_id.0)
.collect::<Vec<i64>>(); .collect::<Vec<i64>>();
let loaders_ptypes: DashMap<DBVersionId, VersionLoaderData> = sqlx::query!( let loaders_ptypes: DashMap<DBVersionId, VersionLoaderData> = sqlx::query!(
@@ -567,7 +576,7 @@ async fn index_versions(
let mut res_versions: HashMap<DBProjectId, Vec<PartialVersion>> = let mut res_versions: HashMap<DBProjectId, Vec<PartialVersion>> =
HashMap::new(); HashMap::new();
for (project_id, version_ids) in &versions { for (project_id, version_ids) in &versions {
for version_id in version_ids { for (version_id, date_published) in version_ids {
// Extract version-specific data fetched // Extract version-specific data fetched
// We use 'remove' as every version is only in the map once // We use 'remove' as every version is only in the map once
let version_loader_data = loaders_ptypes let version_loader_data = loaders_ptypes
@@ -588,6 +597,7 @@ async fn index_versions(
loaders: version_loader_data.loaders, loaders: version_loader_data.loaders,
project_types: version_loader_data.project_types, project_types: version_loader_data.project_types,
version_fields, version_fields,
date_published: *date_published,
}); });
} }
} }

View File

@@ -629,6 +629,7 @@ const DEFAULT_ATTRIBUTES_FOR_FACETING: &[&str] = &[
"created_timestamp", "created_timestamp",
"date_modified", "date_modified",
"modified_timestamp", "modified_timestamp",
"version_published_timestamp",
"project_id", "project_id",
"open_source", "open_source",
"color", "color",
@@ -656,6 +657,7 @@ const DEFAULT_SORTABLE_ATTRIBUTES: &[&str] = &[
"follows", "follows",
"date_created", "date_created",
"date_modified", "date_modified",
"version_published_timestamp",
"minecraft_java_server.verified_plays_2w", "minecraft_java_server.verified_plays_2w",
"minecraft_java_server.ping.data.players_online", "minecraft_java_server.ping.data.players_online",
]; ];

View File

@@ -209,6 +209,8 @@ pub struct UploadSearchProject {
pub date_modified: DateTime<Utc>, pub date_modified: DateTime<Utc>,
/// Unix timestamp of the last major modification /// Unix timestamp of the last major modification
pub modified_timestamp: i64, pub modified_timestamp: i64,
/// Unix timestamp of the publication date of the version
pub version_published_timestamp: i64,
pub open_source: bool, pub open_source: bool,
pub color: Option<u32>, pub color: Option<u32>,
@@ -266,30 +268,58 @@ pub struct ResultSearchProject {
pub fn get_sort_index( pub fn get_sort_index(
config: &SearchConfig, config: &SearchConfig,
index: &str, index: &str,
new_filters: Option<&str>,
) -> Result<(String, &'static [&'static str]), SearchError> { ) -> Result<(String, &'static [&'static str]), SearchError> {
let projects_name = config.get_index_name("projects", false); let projects_name = config.get_index_name("projects", false);
let projects_filtered_name = let projects_filtered_name =
config.get_index_name("projects_filtered", false); config.get_index_name("projects_filtered", false);
// 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 { Ok(match index {
"relevance" => ( "relevance" => (
projects_name, projects_name,
&[ if is_server {
"minecraft_java_server.verified_plays_2w:desc", &[
"minecraft_java_server.ping.data.players_online:desc", "minecraft_java_server.verified_plays_2w:desc",
"downloads:desc", "minecraft_java_server.ping.data.players_online:desc",
], "version_published_timestamp:desc",
]
} else {
&["downloads:desc", "version_published_timestamp:desc"]
},
),
"downloads" => (
projects_filtered_name,
&["downloads:desc", "version_published_timestamp:desc"],
),
"follows" => (
projects_name,
&["follows:desc", "version_published_timestamp:desc"],
),
"updated" | "date_modified" => (
projects_name,
&["date_modified:desc", "version_published_timestamp:desc"],
),
"newest" | "date_created" => (
projects_name,
&["date_created:desc", "version_published_timestamp:desc"],
), ),
"downloads" => (projects_filtered_name, &["downloads:desc"]),
"follows" => (projects_name, &["follows:desc"]),
"updated" | "date_modified" => (projects_name, &["date_modified:desc"]),
"newest" | "date_created" => (projects_name, &["date_created:desc"]),
"minecraft_java_server.verified_plays_2w" => ( "minecraft_java_server.verified_plays_2w" => (
projects_name, projects_name,
&["minecraft_java_server.verified_plays_2w:desc"], &[
"minecraft_java_server.verified_plays_2w:desc",
"version_published_timestamp:desc",
],
), ),
"minecraft_java_server.ping.data.players_online" => ( "minecraft_java_server.ping.data.players_online" => (
projects_name, projects_name,
&["minecraft_java_server.ping.data.players_online:desc"], &[
"minecraft_java_server.ping.data.players_online:desc",
"version_published_timestamp:desc",
],
), ),
i => return Err(SearchError::InvalidIndex(i.to_string())), i => return Err(SearchError::InvalidIndex(i.to_string())),
}) })
@@ -334,7 +364,7 @@ pub async fn search_for_project(
.parse::<usize>()? .parse::<usize>()?
.min(100); .min(100);
let sort = get_sort_index(config, index)?; let sort = get_sort_index(config, index, info.new_filters.as_deref())?;
let client = config.make_loadbalanced_read_client()?; let client = config.make_loadbalanced_read_client()?;
let meilisearch_index = client.get_index(sort.0).await?; let meilisearch_index = client.get_index(sort.0).await?;