You've already forked AstralRinth
Include compatible dependencies field in project search (#6366)
* include compatible dependency projects field * fix
This commit is contained in:
+10
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT DISTINCT v.mod_id dependent_project_id, d.mod_dependency_id dependency_project_id,\n m.name dependency_name, m.slug dependency_slug, m.icon_url dependency_icon_url\n FROM versions v\n INNER JOIN dependencies d ON d.dependent_id = v.id\n INNER JOIN mods m ON m.id = d.mod_dependency_id\n WHERE v.mod_id = ANY($1)\n AND d.mod_dependency_id IS NOT NULL\n AND m.status = ANY($2)\n ",
|
||||
"query": "\n SELECT DISTINCT v.mod_id dependent_project_id,\n d.mod_dependency_id dependency_project_id,\n d.dependency_type dependency_type,\n m.name dependency_name,\n m.slug dependency_slug,\n m.icon_url dependency_icon_url\n FROM versions v\n INNER JOIN dependencies d ON d.dependent_id = v.id\n INNER JOIN mods m ON m.id = d.mod_dependency_id\n WHERE v.mod_id = ANY($1)\n AND d.mod_dependency_id IS NOT NULL\n AND m.status = ANY($2)\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -15,16 +15,21 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "dependency_name",
|
||||
"name": "dependency_type",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "dependency_slug",
|
||||
"name": "dependency_name",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "dependency_slug",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "dependency_icon_url",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
@@ -39,9 +44,10 @@
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "20cb8a3d45911a126aa17451b1e6e84e9238dee422cc2b400cea0048a71e4c27"
|
||||
"hash": "3afdd6b9070ea0951682facf207b9056ac842c402bd0941c45ebd1dc6d627d43"
|
||||
}
|
||||
@@ -485,6 +485,13 @@ impl SearchField {
|
||||
sort: false,
|
||||
optional: true,
|
||||
},
|
||||
SearchField::CompatibleDependencyProjectIds => TypesenseFieldSpec {
|
||||
path: "compatible_dependency_project_ids",
|
||||
ty: "string[]",
|
||||
facet: true,
|
||||
sort: false,
|
||||
optional: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::database::models::{
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::models::exp;
|
||||
use crate::models::ids::ProjectId;
|
||||
use crate::models::projects::from_duplicate_version_fields;
|
||||
use crate::models::projects::{DependencyType, from_duplicate_version_fields};
|
||||
use crate::models::v2::projects::LegacyProject;
|
||||
use crate::routes::v2_reroute;
|
||||
use crate::search::{SearchProjectDependency, UploadSearchProject};
|
||||
@@ -124,10 +124,14 @@ pub async fn index_local(
|
||||
info!("Indexing local dependencies!");
|
||||
|
||||
let dependencies: DashMap<DBProjectId, Vec<SearchProjectDependency>> =
|
||||
sqlx::query!(
|
||||
"
|
||||
SELECT DISTINCT v.mod_id dependent_project_id, d.mod_dependency_id dependency_project_id,
|
||||
m.name dependency_name, m.slug dependency_slug, m.icon_url dependency_icon_url
|
||||
sqlx::query!(
|
||||
"
|
||||
SELECT DISTINCT v.mod_id dependent_project_id,
|
||||
d.mod_dependency_id dependency_project_id,
|
||||
d.dependency_type dependency_type,
|
||||
m.name dependency_name,
|
||||
m.slug dependency_slug,
|
||||
m.icon_url dependency_icon_url
|
||||
FROM versions v
|
||||
INNER JOIN dependencies d ON d.dependent_id = v.id
|
||||
INNER JOIN mods m ON m.id = d.mod_dependency_id
|
||||
@@ -135,32 +139,35 @@ pub async fn index_local(
|
||||
AND d.mod_dependency_id IS NOT NULL
|
||||
AND m.status = ANY($2)
|
||||
",
|
||||
&project_ids,
|
||||
&searchable_statuses,
|
||||
)
|
||||
.fetch(pool)
|
||||
.try_fold(
|
||||
DashMap::new(),
|
||||
|acc: DashMap<DBProjectId, Vec<SearchProjectDependency>>, m| {
|
||||
if let Some(dependency_project_id) = m.dependency_project_id {
|
||||
acc.entry(DBProjectId(m.dependent_project_id))
|
||||
.or_default()
|
||||
.push(SearchProjectDependency {
|
||||
project_id: ProjectId::from(DBProjectId(
|
||||
dependency_project_id,
|
||||
))
|
||||
.to_string(),
|
||||
name: m.dependency_name,
|
||||
slug: m.dependency_slug,
|
||||
icon_url: m.dependency_icon_url,
|
||||
});
|
||||
}
|
||||
&project_ids,
|
||||
&searchable_statuses,
|
||||
)
|
||||
.fetch(pool)
|
||||
.try_fold(
|
||||
DashMap::new(),
|
||||
|acc: DashMap<DBProjectId, Vec<SearchProjectDependency>>, m| {
|
||||
if let Some(dependency_project_id) = m.dependency_project_id {
|
||||
acc.entry(DBProjectId(m.dependent_project_id))
|
||||
.or_default()
|
||||
.push(SearchProjectDependency {
|
||||
project_id: ProjectId::from(DBProjectId(
|
||||
dependency_project_id,
|
||||
))
|
||||
.to_string(),
|
||||
dependency_type: DependencyType::from_string(
|
||||
&m.dependency_type,
|
||||
),
|
||||
name: m.dependency_name,
|
||||
slug: m.dependency_slug,
|
||||
icon_url: m.dependency_icon_url,
|
||||
});
|
||||
}
|
||||
|
||||
async move { Ok(acc) }
|
||||
},
|
||||
)
|
||||
.await
|
||||
.wrap_err("failed to fetch project dependencies")?;
|
||||
async move { Ok(acc) }
|
||||
},
|
||||
)
|
||||
.await
|
||||
.wrap_err("failed to fetch project dependencies")?;
|
||||
|
||||
struct PartialGallery {
|
||||
url: String,
|
||||
@@ -398,6 +405,18 @@ pub async fn index_local(
|
||||
.iter()
|
||||
.map(|dependency| dependency.project_id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let compatible_dependency_project_ids = dependencies
|
||||
.iter()
|
||||
.filter(|dependency| {
|
||||
matches!(
|
||||
dependency.dependency_type,
|
||||
DependencyType::Required
|
||||
| DependencyType::Optional
|
||||
| DependencyType::Embedded
|
||||
)
|
||||
})
|
||||
.map(|dependency| dependency.project_id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(versions) = versions.remove(&project.id) {
|
||||
// Aggregated project loader fields
|
||||
@@ -539,6 +558,8 @@ pub async fn index_local(
|
||||
open_source,
|
||||
color: project.color.map(|x| x as u32),
|
||||
dependency_project_ids: dependency_project_ids.clone(),
|
||||
compatible_dependency_project_ids:
|
||||
compatible_dependency_project_ids.clone(),
|
||||
dependencies: dependencies.clone(),
|
||||
loader_fields,
|
||||
project_loader_fields: project_loader_fields.clone(),
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::database::redis::RedisPool;
|
||||
use crate::models::exp;
|
||||
use crate::models::exp::minecraft::JavaServerPing;
|
||||
use crate::models::ids::{ProjectId, VersionId};
|
||||
use crate::models::projects::DependencyType;
|
||||
use crate::queue::server_ping;
|
||||
use crate::routes::ApiError;
|
||||
use crate::{database::PgPool, env::ENV};
|
||||
@@ -196,6 +197,7 @@ pub enum SearchField {
|
||||
MinecraftJavaServerContentSupportedGameVersions,
|
||||
MinecraftJavaServerPingData,
|
||||
DependencyProjectIds,
|
||||
CompatibleDependencyProjectIds,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@@ -252,6 +254,8 @@ pub struct UploadSearchProject {
|
||||
#[serde(default)]
|
||||
pub dependency_project_ids: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub compatible_dependency_project_ids: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub dependencies: Vec<SearchProjectDependency>,
|
||||
|
||||
// Hidden fields to get the Project model out of the search results.
|
||||
@@ -267,6 +271,7 @@ pub struct UploadSearchProject {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct SearchProjectDependency {
|
||||
pub project_id: String,
|
||||
pub dependency_type: DependencyType,
|
||||
pub name: String,
|
||||
pub slug: Option<String>,
|
||||
pub icon_url: Option<String>,
|
||||
@@ -311,6 +316,8 @@ pub struct ResultSearchProject {
|
||||
#[serde(default)]
|
||||
pub dependency_project_ids: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub compatible_dependency_project_ids: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub dependencies: Vec<SearchProjectDependency>,
|
||||
|
||||
// Hidden fields to get the Project model out of the search results.
|
||||
@@ -350,6 +357,8 @@ impl From<UploadSearchProject> for ResultSearchProject {
|
||||
featured_gallery: source.featured_gallery,
|
||||
color: source.color,
|
||||
dependency_project_ids: source.dependency_project_ids,
|
||||
compatible_dependency_project_ids: source
|
||||
.compatible_dependency_project_ids,
|
||||
dependencies: source.dependencies,
|
||||
loaders: source.loaders,
|
||||
project_loader_fields: source.project_loader_fields,
|
||||
|
||||
@@ -9,6 +9,7 @@ use common::environment::TestEnvironment;
|
||||
use common::environment::with_test_environment;
|
||||
use common::search::setup_search_projects;
|
||||
use futures::stream::StreamExt;
|
||||
use labrinth::models::projects::DependencyType;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::api_common::Api;
|
||||
@@ -95,6 +96,12 @@ async fn search_projects() {
|
||||
)]]),
|
||||
vec![7],
|
||||
),
|
||||
(
|
||||
json!([[format!(
|
||||
"compatible_dependency_project_ids:{dependency_project_id}"
|
||||
)]]),
|
||||
vec![7],
|
||||
),
|
||||
];
|
||||
// TODO: versions, game versions
|
||||
// Untested:
|
||||
@@ -151,11 +158,23 @@ async fn search_projects() {
|
||||
projects.hits[0].dependency_project_ids[0],
|
||||
dependency_project_id
|
||||
);
|
||||
assert_eq!(
|
||||
projects.hits[0].compatible_dependency_project_ids.len(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
projects.hits[0].compatible_dependency_project_ids[0],
|
||||
dependency_project_id
|
||||
);
|
||||
assert_eq!(projects.hits[0].dependencies.len(), 1);
|
||||
assert_eq!(
|
||||
projects.hits[0].dependencies[0].project_id,
|
||||
dependency_project_id
|
||||
);
|
||||
assert_eq!(
|
||||
projects.hits[0].dependencies[0].dependency_type,
|
||||
DependencyType::Required
|
||||
);
|
||||
assert!(
|
||||
projects.hits[0].dependencies[0]
|
||||
.slug
|
||||
|
||||
Reference in New Issue
Block a user