use serde::{Deserialize, Serialize};
use super::{CollectionName, Extra, Meta, Timestamp, de, impl_document, time};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Food {
#[serde(flatten)]
pub meta: Meta,
#[serde(
rename = "type",
default,
skip_serializing_if = "Option::is_none",
with = "de::text"
)]
pub food_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::text")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::text")]
pub category: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::text")]
pub subcategory: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::num")]
pub portion: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::text")]
pub unit: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::num")]
pub carbs: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::num")]
pub fat: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::num")]
pub protein: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::num")]
pub energy: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::num")]
pub gi: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::flag")]
pub hidden: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::flag")]
pub hideafteruse: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "de::num")]
pub position: Option<f64>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "de::null_as_empty"
)]
pub foods: Vec<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "time::iso")]
pub created_at: Option<Timestamp>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "time::millis"
)]
pub date: Option<Timestamp>,
#[serde(flatten)]
pub extra: Extra,
}
impl Food {
#[must_use]
pub fn new(name: impl Into<String>, carbs: f64, portion: f64, unit: impl Into<String>) -> Self {
Self {
meta: Meta::default(),
food_type: Some("food".into()),
name: Some(name.into()),
category: None,
subcategory: None,
portion: Some(portion),
unit: Some(unit.into()),
carbs: Some(carbs),
fat: None,
protein: None,
energy: None,
gi: None,
hidden: None,
hideafteruse: None,
position: None,
foods: Vec::new(),
created_at: Some(Timestamp::now()),
date: None,
extra: Extra::new(),
}
}
fn fill_defaults(&mut self, _app: &str) {
let t = self.created_at.or(self.date).unwrap_or_else(Timestamp::now);
self.created_at.get_or_insert(t);
self.date.get_or_insert(t);
}
}
impl_document!(
Food,
CollectionName::Food,
timestamp = |s| s.created_at.or(s.date),
device = |_s| None
);