feat(garage): enhance hit points structure with legacy field normalization and deserialization tests
This commit is contained in:
parent
9d5c217c26
commit
4bb4c8ff5e
@ -10,6 +10,9 @@ DEFINE FIELD IF NOT EXISTS classname ON garage_vehicle TYPE string;
|
|||||||
DEFINE FIELD IF NOT EXISTS fuel ON garage_vehicle TYPE number;
|
DEFINE FIELD IF NOT EXISTS fuel ON garage_vehicle TYPE number;
|
||||||
DEFINE FIELD IF NOT EXISTS damage ON garage_vehicle TYPE number;
|
DEFINE FIELD IF NOT EXISTS damage ON garage_vehicle TYPE number;
|
||||||
DEFINE FIELD IF NOT EXISTS hit_points ON garage_vehicle TYPE object;
|
DEFINE FIELD IF NOT EXISTS hit_points ON garage_vehicle TYPE object;
|
||||||
|
DEFINE FIELD IF NOT EXISTS hit_points.names ON garage_vehicle TYPE array<string>;
|
||||||
|
DEFINE FIELD IF NOT EXISTS hit_points.selections ON garage_vehicle TYPE array<string>;
|
||||||
|
DEFINE FIELD IF NOT EXISTS hit_points.values ON garage_vehicle TYPE array<number>;
|
||||||
DEFINE FIELD OVERWRITE updated_at ON garage_vehicle TYPE option<datetime>;
|
DEFINE FIELD OVERWRITE updated_at ON garage_vehicle TYPE option<datetime>;
|
||||||
DEFINE INDEX IF NOT EXISTS garage_vehicle_owner ON garage_vehicle COLUMNS uid;
|
DEFINE INDEX IF NOT EXISTS garage_vehicle_owner ON garage_vehicle COLUMNS uid;
|
||||||
DEFINE INDEX IF NOT EXISTS garage_vehicle_unique ON garage_vehicle COLUMNS uid, plate UNIQUE;
|
DEFINE INDEX IF NOT EXISTS garage_vehicle_unique ON garage_vehicle COLUMNS uid, plate UNIQUE;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use arma_rs::{FromArma, IntoArma};
|
use arma_rs::{FromArma, IntoArma};
|
||||||
use forge_shared::GarageValidationError;
|
use forge_shared::GarageValidationError;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -17,13 +17,23 @@ pub struct Vehicle {
|
|||||||
pub hit_points: HitPoints,
|
pub hit_points: HitPoints,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct HitPoints {
|
pub struct HitPoints {
|
||||||
pub names: Vec<String>,
|
pub names: Vec<String>,
|
||||||
pub selections: Vec<String>,
|
pub selections: Vec<String>,
|
||||||
pub values: Vec<f64>,
|
pub values: Vec<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct HitPointsWire {
|
||||||
|
#[serde(default)]
|
||||||
|
names: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
selections: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
values: Vec<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
impl HitPoints {
|
impl HitPoints {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -33,6 +43,22 @@ impl HitPoints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_legacy_fields(&mut self) {
|
||||||
|
if self.names.is_empty()
|
||||||
|
&& !self.selections.is_empty()
|
||||||
|
&& self.selections.len() == self.values.len()
|
||||||
|
{
|
||||||
|
self.names = self.selections.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.selections.is_empty()
|
||||||
|
&& !self.names.is_empty()
|
||||||
|
&& self.names.len() == self.values.len()
|
||||||
|
{
|
||||||
|
self.selections = self.names.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_json_str(json_str: &str) -> Result<Self, String> {
|
pub fn from_json_str(json_str: &str) -> Result<Self, String> {
|
||||||
let hit_points: HitPoints = serde_json::from_str(json_str)
|
let hit_points: HitPoints = serde_json::from_str(json_str)
|
||||||
.map_err(|e| format!("Failed to parse hit_points JSON: {}", e))?;
|
.map_err(|e| format!("Failed to parse hit_points JSON: {}", e))?;
|
||||||
@ -52,6 +78,22 @@ impl HitPoints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for HitPoints {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let wire = HitPointsWire::deserialize(deserializer)?;
|
||||||
|
let mut hit_points = Self {
|
||||||
|
names: wire.names,
|
||||||
|
selections: wire.selections,
|
||||||
|
values: wire.values,
|
||||||
|
};
|
||||||
|
hit_points.normalize_legacy_fields();
|
||||||
|
Ok(hit_points)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for HitPoints {
|
impl Default for HitPoints {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
@ -159,3 +201,38 @@ impl IntoArma for Vehicle {
|
|||||||
arma_rs::Value::String(json_str)
|
arma_rs::Value::String(json_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::HitPoints;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserializes_legacy_hit_points_missing_names() {
|
||||||
|
let hit_points =
|
||||||
|
HitPoints::from_json_str(r#"{"selections":["engine_hitpoint"],"values":[0.35]}"#)
|
||||||
|
.expect("legacy hit points should deserialize");
|
||||||
|
|
||||||
|
assert_eq!(hit_points.names, vec!["engine_hitpoint"]);
|
||||||
|
assert_eq!(hit_points.selections, vec!["engine_hitpoint"]);
|
||||||
|
assert_eq!(hit_points.values, vec![0.35]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserializes_empty_legacy_hit_points_object() {
|
||||||
|
let hit_points =
|
||||||
|
HitPoints::from_json_str(r#"{}"#).expect("empty legacy hit points should deserialize");
|
||||||
|
|
||||||
|
assert!(hit_points.names.is_empty());
|
||||||
|
assert!(hit_points.selections.is_empty());
|
||||||
|
assert!(hit_points.values.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_unbalanced_legacy_hit_points() {
|
||||||
|
let error =
|
||||||
|
HitPoints::from_json_str(r#"{"selections":["engine_hitpoint"],"values":[0.35,0.5]}"#)
|
||||||
|
.expect_err("unbalanced hit points should be rejected");
|
||||||
|
|
||||||
|
assert!(error.contains("Hitpoint array length mismatch"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user