177 lines
4.9 KiB
Rust
177 lines
4.9 KiB
Rust
cfg_if::cfg_if! {
|
|
if #[cfg(feature = "sql")] {
|
|
use mysql::prelude::*;
|
|
use mysql::*;
|
|
use mysql_common::frunk::{hlist_pat, HList};
|
|
use std::collections::HashMap;
|
|
use struct_field_names_as_array::FieldNamesAsArray;
|
|
} else {}
|
|
}
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[allow(non_snake_case)]
|
|
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(feature = "sql", derive(FieldNamesAsArray))]
|
|
pub struct Nutrition {
|
|
pub id: u32,
|
|
pub name: String,
|
|
pub manufacturer: String,
|
|
pub barcode: String,
|
|
pub amount: u32,
|
|
pub divisor: u32,
|
|
pub kJ: f32,
|
|
pub kcal: f32,
|
|
pub fat: f32,
|
|
pub saturated_fat: f32,
|
|
pub carbohydrate: f32,
|
|
pub sugar: f32,
|
|
pub fibres: f32,
|
|
pub protein: f32,
|
|
pub salt: f32,
|
|
pub vitamin_b2: f32,
|
|
pub vitamin_b12: f32,
|
|
pub calcium: f32,
|
|
pub phosphor: f32,
|
|
pub vitamin_d: f32,
|
|
}
|
|
|
|
#[cfg(feature = "sql")]
|
|
type RowType = HList!(
|
|
u32,
|
|
Option<String>,
|
|
Option<String>,
|
|
Option<String>,
|
|
Option<u32>,
|
|
Option<u32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
Option<f32>,
|
|
);
|
|
|
|
impl Nutrition {
|
|
#[cfg(feature = "sql")]
|
|
fn get_sql_fields() -> String {
|
|
Nutrition::FIELD_NAMES_AS_ARRAY
|
|
.iter()
|
|
.cloned()
|
|
.intersperse(", ")
|
|
.collect()
|
|
}
|
|
|
|
#[cfg(feature = "sql")]
|
|
fn query_map_helper() -> (String, impl Fn(RowType) -> Nutrition) {
|
|
let sql_query = format!("SELECT {} from nutrition", Self::get_sql_fields());
|
|
|
|
let construction_closure = |row: RowType| {
|
|
let hlist_pat![
|
|
id,
|
|
name,
|
|
manufacturer,
|
|
barcode,
|
|
amount,
|
|
divisor,
|
|
k_j,
|
|
kcal,
|
|
fat,
|
|
saturated_fat,
|
|
carbohydrate,
|
|
sugar,
|
|
fibres,
|
|
protein,
|
|
salt,
|
|
vitamin_b2,
|
|
vitamin_b12,
|
|
calcium,
|
|
phosphor,
|
|
vitamin_d,
|
|
] = row;
|
|
Nutrition {
|
|
id,
|
|
name: name.unwrap_or("".to_string()),
|
|
manufacturer: manufacturer.unwrap_or("".to_string()),
|
|
barcode: barcode.unwrap_or("".to_string()),
|
|
amount: amount.unwrap_or(0),
|
|
divisor: divisor.unwrap_or(0),
|
|
kJ: k_j.unwrap_or(0.),
|
|
kcal: kcal.unwrap_or(0.),
|
|
fat: fat.unwrap_or(0.),
|
|
saturated_fat: saturated_fat.unwrap_or(0.),
|
|
carbohydrate: carbohydrate.unwrap_or(0.),
|
|
sugar: sugar.unwrap_or(0.),
|
|
fibres: fibres.unwrap_or(0.),
|
|
protein: protein.unwrap_or(0.),
|
|
salt: salt.unwrap_or(0.),
|
|
vitamin_b2: vitamin_b2.unwrap_or(0.),
|
|
vitamin_b12: vitamin_b12.unwrap_or(0.),
|
|
calcium: calcium.unwrap_or(0.),
|
|
phosphor: phosphor.unwrap_or(0.),
|
|
vitamin_d: vitamin_d.unwrap_or(0.),
|
|
}
|
|
};
|
|
|
|
(sql_query, construction_closure)
|
|
}
|
|
|
|
#[cfg(feature = "sql")]
|
|
pub async fn get_nutrition_rows(sql_pool: Pool) -> Result<Vec<Nutrition>> {
|
|
let mut conn = sql_pool
|
|
.get_conn()
|
|
.expect("Cannot establish database connection");
|
|
|
|
let (nutrition_query, nutrition_closure) = Self::query_map_helper();
|
|
let nutrition_val: Vec<Nutrition> = conn
|
|
.query_map(nutrition_query, nutrition_closure)
|
|
.expect("Data in database doesn't match the Nutrition class");
|
|
|
|
Ok(nutrition_val)
|
|
}
|
|
|
|
#[cfg(feature = "sql")]
|
|
pub async fn get_nutrition_hashmap(sql_pool: Pool) -> Result<HashMap<u32, Nutrition>> {
|
|
let nutrition_vec = Self::get_nutrition_rows(sql_pool).await?;
|
|
let nutrition_hashmap: HashMap<u32, Nutrition> =
|
|
nutrition_vec.into_iter().map(|n| (n.id, n)).collect();
|
|
Ok(nutrition_hashmap)
|
|
}
|
|
|
|
pub fn total_kcal(&self) -> f32 {
|
|
match self.divisor {
|
|
0 => 0.,
|
|
_ => self.kcal * self.amount as f32 / self.divisor as f32,
|
|
}
|
|
}
|
|
|
|
pub fn is_valid(&self) -> bool {
|
|
// Comparing self.kcal with 0. should be okay, since it is initialized to 0. and if it is
|
|
// changed in any way, this function should return true
|
|
self.amount != 0 && self.divisor != 0 && self.kcal != 0.
|
|
}
|
|
|
|
pub fn id(&self) -> u32 {
|
|
self.id
|
|
}
|
|
|
|
pub fn name(&self) -> String {
|
|
self.name.clone()
|
|
}
|
|
|
|
pub fn manufacturer(&self) -> String {
|
|
self.manufacturer.clone()
|
|
}
|
|
|
|
pub fn barcode(&self) -> String {
|
|
self.barcode.clone()
|
|
}
|
|
}
|