give proper types to metadata fields

This commit is contained in:
aecsocket
2026-08-04 17:20:20 +01:00
committed by Calum H.
parent a414ff0853
commit adb278b83b
7 changed files with 68 additions and 53 deletions
@@ -119,14 +119,13 @@ impl MinecraftGameVersion {
created: loader_field_enum_value.created, created: loader_field_enum_value.created,
type_: loader_field_enum_value type_: loader_field_enum_value
.metadata .metadata
.get("type") .as_ref()
.and_then(|x| x.as_str()) .map(|metadata| metadata.type_.clone())
.map(|x| x.to_string())
.unwrap_or_default(), .unwrap_or_default(),
major: loader_field_enum_value major: loader_field_enum_value
.metadata .metadata
.get("major") .as_ref()
.and_then(|x| x.as_bool()) .map(|metadata| metadata.major)
.unwrap_or_default(), .unwrap_or_default(),
} }
} }
@@ -87,6 +87,11 @@ impl Game {
} }
} }
#[derive(Clone, Serialize, Deserialize)]
pub struct LoaderMetadata {
pub platform: Option<bool>,
}
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct Loader { pub struct Loader {
pub id: LoaderId, pub id: LoaderId,
@@ -94,7 +99,7 @@ pub struct Loader {
pub icon: String, pub icon: String,
pub supported_project_types: Vec<String>, pub supported_project_types: Vec<String>,
pub supported_games: Vec<String>, // slugs pub supported_games: Vec<String>, // slugs
pub metadata: serde_json::Value, pub metadata: LoaderMetadata,
} }
impl Loader { impl Loader {
@@ -154,7 +159,8 @@ impl Loader {
let result = sqlx::query!( let result = sqlx::query!(
" "
SELECT l.id id, l.loader loader, l.icon icon, l.metadata metadata, SELECT l.id id, l.loader loader, l.icon icon,
(l.metadata->>'platform')::boolean AS platform,
ARRAY_AGG(DISTINCT pt.name) filter (where pt.name is not null) project_types, ARRAY_AGG(DISTINCT pt.name) filter (where pt.name is not null) project_types,
ARRAY_AGG(DISTINCT g.slug) filter (where g.slug is not null) games ARRAY_AGG(DISTINCT g.slug) filter (where g.slug is not null) games
FROM loaders l FROM loaders l
@@ -179,7 +185,9 @@ impl Loader {
supported_games: x supported_games: x
.games .games
.unwrap_or_default(), .unwrap_or_default(),
metadata: x.metadata metadata: LoaderMetadata {
platform: x.platform,
},
}) })
.try_collect::<Vec<_>>() .try_collect::<Vec<_>>()
.await?; .await?;
@@ -270,6 +278,13 @@ pub struct LoaderFieldEnum {
pub hidable: bool, pub hidable: bool,
} }
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct LoaderFieldEnumValueMetadata {
#[serde(rename = "type")]
pub type_: String,
pub major: bool,
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct LoaderFieldEnumValue { pub struct LoaderFieldEnumValue {
pub id: LoaderFieldEnumValueId, pub id: LoaderFieldEnumValueId,
@@ -278,7 +293,7 @@ pub struct LoaderFieldEnumValue {
pub ordering: Option<i32>, pub ordering: Option<i32>,
pub created: DateTime<Utc>, pub created: DateTime<Utc>,
#[serde(flatten)] #[serde(flatten)]
pub metadata: serde_json::Value, pub metadata: Option<LoaderFieldEnumValueMetadata>,
} }
impl std::hash::Hash for LoaderFieldEnumValue { impl std::hash::Hash for LoaderFieldEnumValue {
@@ -357,7 +372,7 @@ pub struct QueryLoaderFieldEnumValue {
pub value: String, pub value: String,
pub ordering: Option<i32>, pub ordering: Option<i32>,
pub created: DateTime<Utc>, pub created: DateTime<Utc>,
pub metadata: Option<serde_json::Value>, pub metadata: Option<LoaderFieldEnumValueMetadata>,
} }
impl LoaderField { impl LoaderField {
@@ -617,11 +632,13 @@ impl LoaderFieldEnumValue {
&loader_field_enum_ids.iter().map(|x| x.0).collect::<Vec<_>>(), &loader_field_enum_ids.iter().map(|x| x.0).collect::<Vec<_>>(),
|loader_field_enum_ids| async move { |loader_field_enum_ids| async move {
let values = sqlx::query!( let values = sqlx::query!(
" r#"
SELECT id, enum_id, value, ordering, metadata, created FROM loader_field_enum_values SELECT id, enum_id, value, ordering,
metadata AS "metadata?: sqlx::types::Json<LoaderFieldEnumValueMetadata>",
created FROM loader_field_enum_values
WHERE enum_id = ANY($1) WHERE enum_id = ANY($1)
ORDER BY enum_id, ordering, created DESC ORDER BY enum_id, ordering, created DESC
", "#,
&loader_field_enum_ids &loader_field_enum_ids
) )
.fetch(exec) .fetch(exec)
@@ -632,7 +649,7 @@ impl LoaderFieldEnumValue {
value: c.value, value: c.value,
ordering: c.ordering, ordering: c.ordering,
created: c.created, created: c.created,
metadata: c.metadata.unwrap_or_default(), metadata: c.metadata.map(|metadata| metadata.0),
}; };
acc.entry(c.enum_id) acc.entry(c.enum_id)
@@ -669,15 +686,15 @@ impl LoaderFieldEnumValue {
.await? .await?
.into_iter() .into_iter()
.filter(|x| { .filter(|x| {
let mut bool = true; filter.iter().all(|(key, value)| match key.as_str() {
for (key, value) in &filter { "type" => x.metadata.as_ref().is_some_and(|metadata| {
if let Some(metadata_value) = x.metadata.get(key) { value.as_str() == Some(metadata.type_.as_str())
bool &= metadata_value == value; }),
} else { "major" => x.metadata.as_ref().is_some_and(|metadata| {
bool = false; value.as_bool() == Some(metadata.major)
} }),
} _ => false,
bool })
}) })
.collect(); .collect();
@@ -1170,10 +1187,7 @@ impl VersionFieldValue {
value: lfev.value.clone(), value: lfev.value.clone(),
ordering: lfev.ordering, ordering: lfev.ordering,
created: lfev.created, created: lfev.created,
metadata: lfev metadata: lfev.metadata.clone(),
.metadata
.clone()
.unwrap_or_default(),
} }
}), }),
)) ))
@@ -1249,10 +1263,7 @@ impl VersionFieldValue {
value: lfev.value.clone(), value: lfev.value.clone(),
ordering: lfev.ordering, ordering: lfev.ordering,
created: lfev.created, created: lfev.created,
metadata: lfev metadata: lfev.metadata.clone(),
.metadata
.clone()
.unwrap_or_default(),
}) })
}) })
.collect::<Result<_, _>>()?, .collect::<Result<_, _>>()?,
@@ -1,6 +1,6 @@
use super::loader_fields::{ use super::loader_fields::{
QueryLoaderField, QueryLoaderFieldEnumValue, QueryVersionField, LoaderFieldEnumValueMetadata, QueryLoaderField, QueryLoaderFieldEnumValue,
VersionField, QueryVersionField, VersionField,
}; };
use super::{DBUser, ids::*}; use super::{DBUser, ids::*};
use crate::database::models::DatabaseError; use crate::database::models::DatabaseError;
@@ -657,12 +657,13 @@ impl DBProject {
.await?; .await?;
let loader_field_enum_values: Vec<QueryLoaderFieldEnumValue> = sqlx::query!( let loader_field_enum_values: Vec<QueryLoaderFieldEnumValue> = sqlx::query!(
" r#"
SELECT DISTINCT id, enum_id, value, ordering, created, metadata SELECT DISTINCT id, enum_id, value, ordering, created,
metadata AS "metadata?: sqlx::types::Json<LoaderFieldEnumValueMetadata>"
FROM loader_field_enum_values lfev FROM loader_field_enum_values lfev
WHERE id = ANY($1) WHERE id = ANY($1)
ORDER BY enum_id, ordering, created DESC ORDER BY enum_id, ordering, created DESC
", "#,
&loader_field_enum_value_ids &loader_field_enum_value_ids
.iter() .iter()
.map(|x| x.0) .map(|x| x.0)
@@ -675,7 +676,7 @@ impl DBProject {
value: m.value, value: m.value,
ordering: m.ordering, ordering: m.ordering,
created: m.created, created: m.created,
metadata: m.metadata, metadata: m.metadata.map(|metadata| metadata.0),
}) })
.try_collect() .try_collect()
.await?; .await?;
@@ -3,7 +3,8 @@ use super::ids::*;
use super::loader_fields::VersionField; use super::loader_fields::VersionField;
use crate::database::PgTransaction; use crate::database::PgTransaction;
use crate::database::models::loader_fields::{ use crate::database::models::loader_fields::{
QueryLoaderField, QueryLoaderFieldEnumValue, QueryVersionField, LoaderFieldEnumValueMetadata, QueryLoaderField, QueryLoaderFieldEnumValue,
QueryVersionField,
}; };
use crate::file_hosting::FileHost; use crate::file_hosting::FileHost;
use crate::models::exp; use crate::models::exp;
@@ -704,12 +705,13 @@ impl DBVersion {
.await?; .await?;
let loader_field_enum_values: Vec<QueryLoaderFieldEnumValue> = sqlx::query!( let loader_field_enum_values: Vec<QueryLoaderFieldEnumValue> = sqlx::query!(
" r#"
SELECT DISTINCT id, enum_id, value, ordering, created, metadata SELECT DISTINCT id, enum_id, value, ordering, created,
metadata AS "metadata?: sqlx::types::Json<LoaderFieldEnumValueMetadata>"
FROM loader_field_enum_values lfev FROM loader_field_enum_values lfev
WHERE id = ANY($1) WHERE id = ANY($1)
ORDER BY enum_id, ordering, created ASC ORDER BY enum_id, ordering, created ASC
", "#,
&loader_field_enum_value_ids &loader_field_enum_value_ids
.iter() .iter()
.map(|x| x.0) .map(|x| x.0)
@@ -722,7 +724,7 @@ impl DBVersion {
value: m.value, value: m.value,
ordering: m.ordering, ordering: m.ordering,
created: m.created, created: m.created,
metadata: m.metadata, metadata: m.metadata.map(|metadata| metadata.0),
}) })
.try_collect() .try_collect()
.await?; .await?;
+4 -4
View File
@@ -212,15 +212,15 @@ pub async fn game_version_list(
version: f.value, version: f.value,
version_type: f version_type: f
.metadata .metadata
.get("type") .as_ref()
.and_then(|m| m.as_str()) .map(|metadata| metadata.type_.as_str())
.unwrap_or_default() .unwrap_or_default()
.to_string(), .to_string(),
date: f.created, date: f.created,
major: f major: f
.metadata .metadata
.get("major") .as_ref()
.and_then(|m| m.as_bool()) .map(|metadata| metadata.major)
.unwrap_or_default(), .unwrap_or_default(),
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
+2 -1
View File
@@ -6,6 +6,7 @@ use crate::database::models::categories::{
}; };
use crate::database::models::loader_fields::{ use crate::database::models::loader_fields::{
Game, Loader, LoaderField, LoaderFieldEnumValue, LoaderFieldType, Game, Loader, LoaderField, LoaderFieldEnumValue, LoaderFieldType,
LoaderMetadata,
}; };
use actix_web::{HttpResponse, get, web}; use actix_web::{HttpResponse, get, web};
use xredis::RedisPool; use xredis::RedisPool;
@@ -103,7 +104,7 @@ pub struct LoaderData {
pub supported_project_types: Vec<String>, pub supported_project_types: Vec<String>,
pub supported_games: Vec<String>, pub supported_games: Vec<String>,
pub supported_fields: Vec<String>, // Available loader fields for this loader pub supported_fields: Vec<String>, // Available loader fields for this loader
pub metadata: Value, pub metadata: LoaderMetadata,
} }
#[utoipa::path(tag = "tags", responses((status = OK)))] #[utoipa::path(tag = "tags", responses((status = OK)))]
+7 -6
View File
@@ -11,8 +11,8 @@ use tracing::{info, warn};
use crate::database::PgPool; use crate::database::PgPool;
use crate::database::models::loader_fields::{ use crate::database::models::loader_fields::{
QueryLoaderField, QueryLoaderFieldEnumValue, QueryVersionField, LoaderFieldEnumValueMetadata, QueryLoaderField, QueryLoaderFieldEnumValue,
VersionField, QueryVersionField, VersionField,
}; };
use crate::database::models::{ use crate::database::models::{
DBOrganizationId, DBProjectId, DBUserId, DBVersionId, LoaderFieldEnumId, DBOrganizationId, DBProjectId, DBUserId, DBVersionId, LoaderFieldEnumId,
@@ -394,11 +394,12 @@ async fn build_search_documents(
let loader_field_enum_values: Vec<QueryLoaderFieldEnumValue> = let loader_field_enum_values: Vec<QueryLoaderFieldEnumValue> =
sqlx::query!( sqlx::query!(
" r#"
SELECT DISTINCT id, enum_id, value, ordering, created, metadata SELECT DISTINCT id, enum_id, value, ordering, created,
metadata AS "metadata?: sqlx::types::Json<LoaderFieldEnumValueMetadata>"
FROM loader_field_enum_values lfev FROM loader_field_enum_values lfev
ORDER BY enum_id, ordering, created DESC ORDER BY enum_id, ordering, created DESC
" "#
) )
.fetch(pool) .fetch(pool)
.map_ok(|m| QueryLoaderFieldEnumValue { .map_ok(|m| QueryLoaderFieldEnumValue {
@@ -407,7 +408,7 @@ async fn build_search_documents(
value: m.value, value: m.value,
ordering: m.ordering, ordering: m.ordering,
created: m.created, created: m.created,
metadata: m.metadata, metadata: m.metadata.map(|metadata| metadata.0),
}) })
.try_collect() .try_collect()
.await?; .await?;