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",
"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": {
"columns": [
{
@@ -12,6 +12,11 @@
"ordinal": 1,
"name": "mod_id",
"type_info": "Int8"
},
{
"ordinal": 2,
"name": "date_published",
"type_info": "Timestamptz"
}
],
"parameters": {
@@ -20,9 +25,10 @@
]
},
"nullable": [
false,
false,
false
]
},
"hash": "dbdcaf9f2126e15892c28f782d4b5812d947582e3573da56e632f2b0b29fac7b"
"hash": "7f483288e82d8c40adaed79463396e871f1a2303df9bdd4ab1b38171a8596065"
}

View File

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

View File

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

View File

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