diff --git a/apps/labrinth/.sqlx/query-dbdcaf9f2126e15892c28f782d4b5812d947582e3573da56e632f2b0b29fac7b.json b/apps/labrinth/.sqlx/query-7f483288e82d8c40adaed79463396e871f1a2303df9bdd4ab1b38171a8596065.json similarity index 53% rename from apps/labrinth/.sqlx/query-dbdcaf9f2126e15892c28f782d4b5812d947582e3573da56e632f2b0b29fac7b.json rename to apps/labrinth/.sqlx/query-7f483288e82d8c40adaed79463396e871f1a2303df9bdd4ab1b38171a8596065.json index eab35e7ca..6e2ad1f74 100644 --- a/apps/labrinth/.sqlx/query-dbdcaf9f2126e15892c28f782d4b5812d947582e3573da56e632f2b0b29fac7b.json +++ b/apps/labrinth/.sqlx/query-7f483288e82d8c40adaed79463396e871f1a2303df9bdd4ab1b38171a8596065.json @@ -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" } diff --git a/apps/labrinth/src/search/indexing/local_import.rs b/apps/labrinth/src/search/indexing/local_import.rs index 0afa79580..3aeb2ae49 100644 --- a/apps/labrinth/src/search/indexing/local_import.rs +++ b/apps/labrinth/src/search/indexing/local_import.rs @@ -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, project_types: Vec, version_fields: Vec, + date_published: DateTime, } async fn index_versions( pool: &PgPool, project_ids: Vec, ) -> Result>, IndexingError> { - let versions: HashMap> = sqlx::query!( - " - SELECT v.id, v.mod_id + let versions: HashMap)>> = + 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>, 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)>, + >, + 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::>(); let loaders_ptypes: DashMap = sqlx::query!( @@ -567,7 +576,7 @@ async fn index_versions( let mut res_versions: HashMap> = 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, }); } } diff --git a/apps/labrinth/src/search/indexing/mod.rs b/apps/labrinth/src/search/indexing/mod.rs index b334c9b0c..c68a820e7 100644 --- a/apps/labrinth/src/search/indexing/mod.rs +++ b/apps/labrinth/src/search/indexing/mod.rs @@ -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", ]; diff --git a/apps/labrinth/src/search/mod.rs b/apps/labrinth/src/search/mod.rs index 4763b3f91..d976f9a6f 100644 --- a/apps/labrinth/src/search/mod.rs +++ b/apps/labrinth/src/search/mod.rs @@ -209,6 +209,8 @@ pub struct UploadSearchProject { pub date_modified: DateTime, /// 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, @@ -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::()? .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?;