You've already forked AstralRinth
forked from didirus/AstralRinth
Search test + v3 (#731)
* search patch for accurate loader/gv filtering * backup * basic search test * finished test * incomplete commit; backing up * Working multipat reroute backup * working rough draft v3 * most tests passing * works * search v2 conversion * added some tags.rs v2 conversions * Worked through warnings, unwraps, prints * refactors * new search test * version files changes fixes * redesign to revs * removed old caches * removed games * fmt clippy * merge conflicts * fmt, prepare * moved v2 routes over to v3 * fixes; tests passing * project type changes * moved files over * fmt, clippy, prepare, etc * loaders to loader_fields, added tests * fmt, clippy, prepare * fixed sorting bug * reversed back- wrong order for consistency * fmt; clippy; prepare --------- Co-authored-by: Jai A <jaiagr+gpg@pm.me>
This commit is contained in:
208
src/database/models/legacy_loader_fields.rs
Normal file
208
src/database/models/legacy_loader_fields.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
// In V3, we switched to dynamic loader fields for a better support for more loaders, games, and potential metadata.
|
||||
// This file contains the legacy loader fields, which are still used by V2 projects.
|
||||
// They are still useful to have in several places where minecraft-java functionality is hardcoded- for example,
|
||||
// for fetching data from forge, maven, etc.
|
||||
// These fields only apply to minecraft-java, and are hardcoded to the minecraft-java game.
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::database::redis::RedisPool;
|
||||
|
||||
use super::{
|
||||
loader_fields::{LoaderFieldEnum, LoaderFieldEnumValue, VersionField, VersionFieldValue},
|
||||
DatabaseError, LoaderFieldEnumValueId,
|
||||
};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct MinecraftGameVersion {
|
||||
pub id: LoaderFieldEnumValueId,
|
||||
pub version: String,
|
||||
#[serde(rename = "type")]
|
||||
pub type_: String,
|
||||
pub created: DateTime<Utc>,
|
||||
pub major: bool,
|
||||
}
|
||||
|
||||
impl MinecraftGameVersion {
|
||||
// The name under which this legacy field is stored as a LoaderField
|
||||
pub const FIELD_NAME: &'static str = "game_versions";
|
||||
|
||||
pub fn builder() -> MinecraftGameVersionBuilder<'static> {
|
||||
MinecraftGameVersionBuilder::default()
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<MinecraftGameVersion>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let game_version_enum = LoaderFieldEnum::get(Self::FIELD_NAME, exec, redis)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
DatabaseError::SchemaError("Could not find game version enum.".to_string())
|
||||
})?;
|
||||
let game_version_enum_values =
|
||||
LoaderFieldEnumValue::list(game_version_enum.id, exec, redis).await?;
|
||||
Ok(game_version_enum_values
|
||||
.into_iter()
|
||||
.map(MinecraftGameVersion::from_enum_value)
|
||||
.collect())
|
||||
}
|
||||
|
||||
// TODO: remove this
|
||||
pub async fn list_transaction(
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<MinecraftGameVersion>, DatabaseError> {
|
||||
let game_version_enum = LoaderFieldEnum::get(Self::FIELD_NAME, &mut **transaction, redis)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
DatabaseError::SchemaError("Could not find game version enum.".to_string())
|
||||
})?;
|
||||
let game_version_enum_values =
|
||||
LoaderFieldEnumValue::list(game_version_enum.id, &mut **transaction, redis).await?;
|
||||
Ok(game_version_enum_values
|
||||
.into_iter()
|
||||
.map(MinecraftGameVersion::from_enum_value)
|
||||
.collect())
|
||||
}
|
||||
|
||||
// Tries to create a MinecraftGameVersion from a VersionField
|
||||
// Clones on success
|
||||
pub fn try_from_version_field(
|
||||
version_field: &VersionField,
|
||||
) -> Result<Vec<Self>, DatabaseError> {
|
||||
if version_field.field_name != Self::FIELD_NAME {
|
||||
return Err(DatabaseError::SchemaError(format!(
|
||||
"Field name {} is not {}",
|
||||
version_field.field_name,
|
||||
Self::FIELD_NAME
|
||||
)));
|
||||
}
|
||||
let game_versions = match version_field.clone() {
|
||||
VersionField {
|
||||
value: VersionFieldValue::ArrayEnum(_, values),
|
||||
..
|
||||
} => values.into_iter().map(Self::from_enum_value).collect(),
|
||||
VersionField {
|
||||
value: VersionFieldValue::Enum(_, value),
|
||||
..
|
||||
} => {
|
||||
vec![Self::from_enum_value(value)]
|
||||
}
|
||||
_ => {
|
||||
return Err(DatabaseError::SchemaError(format!(
|
||||
"Game version requires field value to be an enum: {:?}",
|
||||
version_field
|
||||
)));
|
||||
}
|
||||
};
|
||||
Ok(game_versions)
|
||||
}
|
||||
|
||||
pub fn from_enum_value(loader_field_enum_value: LoaderFieldEnumValue) -> MinecraftGameVersion {
|
||||
MinecraftGameVersion {
|
||||
id: loader_field_enum_value.id,
|
||||
version: loader_field_enum_value.value,
|
||||
created: loader_field_enum_value.created,
|
||||
type_: loader_field_enum_value
|
||||
.metadata
|
||||
.get("type")
|
||||
.and_then(|x| x.as_str())
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_default(),
|
||||
major: loader_field_enum_value
|
||||
.metadata
|
||||
.get("major")
|
||||
.and_then(|x| x.as_bool())
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MinecraftGameVersionBuilder<'a> {
|
||||
pub version: Option<&'a str>,
|
||||
pub version_type: Option<&'a str>,
|
||||
pub date: Option<&'a DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl<'a> MinecraftGameVersionBuilder<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
/// The game version. Spaces must be replaced with '_' for it to be valid
|
||||
pub fn version(
|
||||
self,
|
||||
version: &'a str,
|
||||
) -> Result<MinecraftGameVersionBuilder<'a>, DatabaseError> {
|
||||
Ok(Self {
|
||||
version: Some(version),
|
||||
..self
|
||||
})
|
||||
}
|
||||
|
||||
pub fn version_type(
|
||||
self,
|
||||
version_type: &'a str,
|
||||
) -> Result<MinecraftGameVersionBuilder<'a>, DatabaseError> {
|
||||
Ok(Self {
|
||||
version_type: Some(version_type),
|
||||
..self
|
||||
})
|
||||
}
|
||||
|
||||
pub fn created(self, created: &'a DateTime<Utc>) -> MinecraftGameVersionBuilder<'a> {
|
||||
Self {
|
||||
date: Some(created),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn insert<'b, E>(
|
||||
self,
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<LoaderFieldEnumValueId, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'b, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let game_versions_enum = LoaderFieldEnum::get("game_versions", exec, redis)
|
||||
.await?
|
||||
.ok_or(DatabaseError::SchemaError(
|
||||
"Missing loaders field: 'game_versions'".to_string(),
|
||||
))?;
|
||||
|
||||
// Get enum id for game versions
|
||||
let metadata = json!({
|
||||
"type": self.version_type,
|
||||
"major": false
|
||||
});
|
||||
|
||||
// This looks like a mess, but it *should* work
|
||||
// This allows game versions to be partially updated without
|
||||
// replacing the unspecified fields with defaults.
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
INSERT INTO loader_field_enum_values (enum_id, value, created, metadata)
|
||||
VALUES ($1, $2, COALESCE($3, timezone('utc', now())), $4)
|
||||
ON CONFLICT (enum_id, value) DO UPDATE
|
||||
SET metadata = COALESCE($4, loader_field_enum_values.metadata),
|
||||
created = COALESCE($3, loader_field_enum_values.created)
|
||||
RETURNING id
|
||||
",
|
||||
game_versions_enum.id.0,
|
||||
self.version,
|
||||
self.date.map(chrono::DateTime::naive_utc),
|
||||
metadata
|
||||
)
|
||||
.fetch_one(exec)
|
||||
.await?;
|
||||
|
||||
Ok(LoaderFieldEnumValueId(result.id))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user