include compatible dependency projects field

This commit is contained in:
aecsocket
2026-06-11 20:33:17 +01:00
parent d2a66bb2b0
commit 7c9d6f29a2
5 changed files with 89 additions and 33 deletions
@@ -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,
},
}
}
}
+46 -29
View File
@@ -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,33 @@ 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: 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 +403,16 @@ 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.as_str(),
"required" | "optional"
)
})
.map(|dependency| dependency.project_id.clone())
.collect::<Vec<_>>();
if let Some(versions) = versions.remove(&project.id) {
// Aggregated project loader fields
@@ -539,6 +554,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(),
+8
View File
@@ -196,6 +196,7 @@ pub enum SearchField {
MinecraftJavaServerContentSupportedGameVersions,
MinecraftJavaServerPingData,
DependencyProjectIds,
CompatibleDependencyProjectIds,
}
#[derive(Debug, Error)]
@@ -252,6 +253,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 +270,7 @@ pub struct UploadSearchProject {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SearchProjectDependency {
pub project_id: String,
pub dependency_type: String,
pub name: String,
pub slug: Option<String>,
pub icon_url: Option<String>,
@@ -311,6 +315,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 +356,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,
+18
View File
@@ -95,6 +95,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 +157,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,
"required"
);
assert!(
projects.hits[0].dependencies[0]
.slug