diff --git a/journal/src/journal.rs b/journal/src/journal.rs index 6dea1e1..f93575c 100644 --- a/journal/src/journal.rs +++ b/journal/src/journal.rs @@ -1,6 +1,5 @@ use crate::types::{ - AdministrationRoute, Consumer, CustomUnit, Ingestion, Session, Substance, SubstanceIngestion, - Unit, + CustomUnit, Ingestion, IngestionKind, Session, Substance, SubstanceIngestion, Sustenance, Unit, }; pub type JournalType = Box; @@ -9,19 +8,16 @@ pub trait Journal { fn get_custom_unit(&self, id: i32) -> Option; fn get_session(&self, id: i32) -> Option; fn get_session_ingestions(&self, id: i32) -> Option>; - fn get_session_substance_ingestions_by( - &self, - id: i32, - substance_filter: Option<&Vec>, - route_filter: Option<&Vec>, - consumer_filter: Option<&Vec>, - ) -> Option>; - fn get_substance(&self, name: &String) -> Option; - fn set_custom_unit(&mut self, unit_id: i32, unit: CustomUnit); - fn set_session(&mut self, session_id: i32, session: Session); + fn get_substance(&self, name: &str) -> Option; + fn get_sustenance(&self, sustenance_id: &str) -> Option; + fn get_sustenance_ingestions(&self, sustenance_id: &str) -> Option>; + + fn set_custom_unit(&mut self, unit: CustomUnit); + fn set_session(&mut self, session: Session); fn set_session_ingestions(&mut self, session_id: i32, ingestions: Vec); - fn set_substance(&mut self, name: &String, substance: Substance); + fn set_substance(&mut self, substance: Substance); + fn set_sustenance(&mut self, sustenance: Sustenance); fn first_session_by_title(&self, title: &str) -> Option; fn resolve_substance_unit(&self, ingestion: &SubstanceIngestion) -> Option; diff --git a/journal/src/journal/json_journal.rs b/journal/src/journal/json_journal.rs index 4da5a04..0479565 100644 --- a/journal/src/journal/json_journal.rs +++ b/journal/src/journal/json_journal.rs @@ -1,8 +1,7 @@ use std::{collections::HashMap, fs::File}; use crate::types::{ - AdministrationRoute, Consumer, CustomUnit, Ingestion, IngestionKind, Session, Substance, - SubstanceIngestion, Unit, + CustomUnit, Ingestion, IngestionKind, Session, Substance, SubstanceIngestion, Sustenance, Unit, }; use super::{Journal, JournalType}; @@ -10,6 +9,7 @@ use super::{Journal, JournalType}; #[derive(Debug, Default, Clone)] #[derive(serde::Serialize, serde::Deserialize)] pub struct JSONJournalData { + pub sustenances: HashMap, pub substances: HashMap, pub ingestions: HashMap>, pub sessions: HashMap, @@ -23,12 +23,12 @@ pub struct JSONJournal { } impl JSONJournal { - pub fn create(filename: &String) -> Result> { + pub fn create(filename: &str) -> Result> { let data: JSONJournalData = JSONJournalData::default(); let journal = JSONJournal { data, - filename: filename.clone(), + filename: filename.to_string(), }; journal.save()?; @@ -36,13 +36,15 @@ impl JSONJournal { Ok(Box::new(journal)) } - pub fn load(filename: &String) -> Result> { + pub fn load(filename: &str) -> Result> { let file = File::open(filename)?; let data: JSONJournalData = serde_json::from_reader(file)?; + //println!("{data:#?}"); + let journal = JSONJournal { data, - filename: filename.clone(), + filename: filename.to_string(), }; Ok(Box::new(journal)) @@ -69,52 +71,7 @@ impl Journal for JSONJournal { self.data.ingestions.get(&id).cloned() } - fn get_session_substance_ingestions_by( - &self, - id: i32, - substance_filter: Option<&Vec>, - route_filter: Option<&Vec>, - consumer_filter: Option<&Vec>, - ) -> Option> { - if let Some(ingestions) = self.get_session_ingestions(id) { - let ingestions = ingestions - .clone() - .into_iter() - .filter(|ingestion| { - if let Some(consumer_filter) = consumer_filter { - if !consumer_filter.contains(&ingestion.consumer) { - return false; - } - } - - let ingestion = match &ingestion.kind { - IngestionKind::Substance(ingestion) => ingestion, - _ => return false, - }; - - if let Some(substance_filter) = substance_filter { - if !substance_filter.contains(&ingestion.substance_name) { - return false; - } - } - - if let Some(route_filter) = route_filter { - if !route_filter.contains(&ingestion.roa) { - return false; - } - } - - true - }) - .collect::>(); - - Some(ingestions) - } else { - None - } - } - - fn get_substance(&self, name: &String) -> Option { + fn get_substance(&self, name: &str) -> Option { self.data.substances.get(name).cloned() } @@ -136,23 +93,63 @@ impl Journal for JSONJournal { .cloned() } - fn set_custom_unit(&mut self, unit_id: i32, unit: CustomUnit) { - self.data.custom_units.insert(unit_id, unit); + fn set_custom_unit(&mut self, unit: CustomUnit) { + self.data.custom_units.insert(unit.id, unit); } - fn set_session(&mut self, session_id: i32, session: Session) { - self.data.sessions.insert(session_id, session); + fn set_session(&mut self, session: Session) { + self.data.sessions.insert(session.id, session); } fn set_session_ingestions(&mut self, session_id: i32, ingestions: Vec) { self.data.ingestions.insert(session_id, ingestions); } - fn set_substance(&mut self, name: &String, substance: Substance) { - self.data.substances.insert(name.clone(), substance); + fn set_substance(&mut self, substance: Substance) { + self.data + .substances + .insert(substance.name.clone(), substance); } fn save(&self) -> Result<(), Box> { self.save() } + + fn get_sustenance(&self, sustenance_id: &str) -> Option { + self.data.sustenances.get(sustenance_id).cloned() + } + + fn set_sustenance(&mut self, sustenance: Sustenance) { + self.data + .sustenances + .insert(sustenance.id.clone(), sustenance); + } + + fn get_sustenance_ingestions(&self, sustenance_id: &str) -> Option> { + let sustenance = self.get_sustenance(sustenance_id).unwrap(); + + let mut ingestions: Vec = Vec::new(); + for include in sustenance.includes.into_iter() { + match include { + IngestionKind::Unknown => continue, + IngestionKind::Hydration { amount } => { + ingestions.push(IngestionKind::Hydration { amount }) + } + IngestionKind::Substance(substance_ingestion) => { + ingestions.push(IngestionKind::Substance(substance_ingestion)) + } + IngestionKind::Sustenance(sustenance_ingestion) => { + ingestions.push(IngestionKind::Sustenance(sustenance_ingestion.clone())); + + ingestions.append( + &mut self + .get_sustenance_ingestions(&sustenance_ingestion.sustenance_id) + .unwrap(), + ); + } + } + } + + Some(ingestions) + } } diff --git a/journal/src/types/ingestion.rs b/journal/src/types/ingestion.rs index ea8afff..ec5c71e 100644 --- a/journal/src/types/ingestion.rs +++ b/journal/src/types/ingestion.rs @@ -20,6 +20,9 @@ pub enum IngestionKind { Unknown, Substance(SubstanceIngestion), Sustenance(SustenanceIngestion), + Hydration { + amount: u64, + }, } #[derive(PartialEq, Default, Debug, Clone)] @@ -35,9 +38,8 @@ pub struct SubstanceIngestion { #[derive(PartialEq, Default, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize)] pub struct SustenanceIngestion { - pub sustenance_name: String, - pub sustenance_category: String, - pub amount: (u8, u8, u8), + pub sustenance_id: String, + pub amount: f64, } impl From for Ingestion { diff --git a/journal/src/types/mod.rs b/journal/src/types/mod.rs index 51a3ad5..a20a912 100644 --- a/journal/src/types/mod.rs +++ b/journal/src/types/mod.rs @@ -13,11 +13,17 @@ mod consumer; pub use consumer::Consumer; mod ingestion; -pub use ingestion::{Ingestion, IngestionKind, SubstanceIngestion}; +pub use ingestion::{Ingestion, IngestionKind, SubstanceIngestion, SustenanceIngestion}; mod substance; pub use substance::Substance; +mod nutrients; +pub use nutrients::Nutrients; + +mod sustenance; +pub use sustenance::Sustenance; + mod session; pub use session::Session; diff --git a/journal/src/types/nutrients.rs b/journal/src/types/nutrients.rs new file mode 100644 index 0000000..c6e9ef5 --- /dev/null +++ b/journal/src/types/nutrients.rs @@ -0,0 +1,5 @@ +#[derive(Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Nutrients { + pub kcal: u64, +} diff --git a/journal/src/types/sustenance.rs b/journal/src/types/sustenance.rs new file mode 100644 index 0000000..8dbcef4 --- /dev/null +++ b/journal/src/types/sustenance.rs @@ -0,0 +1,13 @@ +use super::{IngestionKind, Nutrients}; + +#[derive(Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Sustenance { + pub id: String, + pub name: String, + + pub unit: String, + pub nutrients: Option, + + pub includes: Vec, +} diff --git a/journal_cli/src/commands/journal/import_psychonaut.rs b/journal_cli/src/commands/journal/import_psychonaut.rs index c901330..44e8687 100644 --- a/journal_cli/src/commands/journal/import_psychonaut.rs +++ b/journal_cli/src/commands/journal/import_psychonaut.rs @@ -64,7 +64,7 @@ pub fn journal_import_psychonaut( let mut rng = rand::thread_rng(); for custom_unit in export_data.custom_units.into_iter() { - journal.set_custom_unit(custom_unit.id, CustomUnit::from(custom_unit)); + journal.set_custom_unit(CustomUnit::from(custom_unit)); } for custom_substance in export_data.custom_substances.into_iter() { @@ -79,14 +79,11 @@ pub fn journal_import_psychonaut( } None => { if args.infer_missing_substances { - journal.set_substance( - &custom_substance.name, - Substance { - name: custom_substance.name.clone(), - description: custom_substance.description.clone(), - unit: custom_substance.units, - }, - ); + journal.set_substance(Substance { + name: custom_substance.name.clone(), + description: custom_substance.description.clone(), + unit: custom_substance.units, + }); } } } @@ -114,14 +111,11 @@ pub fn journal_import_psychonaut( } } None => { - journal.set_substance( - substance_name, - Substance { - name: substance_name.clone(), - description: "".to_string(), - unit: ingestion_unit, - }, - ); + journal.set_substance(Substance { + name: substance_name.clone(), + description: "".to_string(), + unit: ingestion_unit, + }); } } } @@ -135,13 +129,10 @@ pub fn journal_import_psychonaut( let session_id = rng.gen::(); - journal.set_session( - session_id, - Session { - id: session_id, - ..Session::from(experience.clone()) - }, - ); + journal.set_session(Session { + id: session_id, + ..Session::from(experience.clone()) + }); let mut ingestions: Vec = Vec::new(); for ingestion in experience.ingestions.iter() { diff --git a/journal_cli/src/commands/print_session.rs b/journal_cli/src/commands/print_session.rs index 91ec204..1b18347 100644 --- a/journal_cli/src/commands/print_session.rs +++ b/journal_cli/src/commands/print_session.rs @@ -12,8 +12,6 @@ pub struct PrintSessionArgs { #[command(flatten)] pub journal_location: JournalLocation, - #[arg(long)] - pub substance_filter: Option>, #[arg(long, value_delimiter = ',')] pub consumer_filter: Option>, } @@ -46,15 +44,9 @@ pub fn print_session(args: &PrintSessionArgs) -> Result<(), Box Vec { + //println!("{ingestion:?}"); + + let mut ingestions: Vec = Vec::new(); + + match &ingestion { + IngestionKind::Substance(substance) => { + ingestions.push(IngestionKind::Substance(substance.clone())); + } + IngestionKind::Hydration { amount: _ } => { + ingestions.push(ingestion.clone()); + } + IngestionKind::Sustenance(sustenance) => { + let sustenance_ingestions = journal + .get_sustenance_ingestions(&sustenance.sustenance_id) + .unwrap(); + + for sustenance_ingestion in sustenance_ingestions.into_iter() { + match sustenance_ingestion { + IngestionKind::Substance(substance_ingestion) => { + ingestions.push(IngestionKind::Substance(SubstanceIngestion { + dose: Dose::new_precise(sustenance.amount) * substance_ingestion.dose, + ..substance_ingestion + })) + } + IngestionKind::Sustenance(sustenance_ingestion) => { + ingestions.push(IngestionKind::Sustenance(SustenanceIngestion { + amount: sustenance.amount * sustenance_ingestion.amount, + ..sustenance_ingestion + })) + } + IngestionKind::Hydration { amount } => { + ingestions.push(IngestionKind::Hydration { + amount: (sustenance.amount * amount as f64).round() as u64, + }) + } + _ => {} + } + } + } + _ => {} + }; + + //println!("{ingestions:#?}"); + ingestions +} + +pub fn print_ingestion(journal: &JournalType, ingestion: &Ingestion, kind: &IngestionKind) { + match kind { + IngestionKind::Unknown => {} + IngestionKind::Substance(substance_ingestion) => { + print_substance_ingestion(journal, ingestion, substance_ingestion); + } + IngestionKind::Sustenance(sustenance_ingestion) => { + print_sustenance_ingestion(journal, ingestion, sustenance_ingestion); + } + IngestionKind::Hydration { amount } => { + println!( + "Hydration|{} ml|{}|{}", + amount, + ingestion.consumer, + format_ingestion_time(ingestion) + ) + } + } +} + pub fn print_ingestion_log( journal: &JournalType, session: &Session, - substance_filter: Option<&Vec>, consumer_filter: Option<&Vec>, ) { for ingestion in journal - .get_session_substance_ingestions_by(session.id, substance_filter, None, consumer_filter) + .get_session_ingestions(session.id) .expect("could not find ingestions for session") .iter() { - let substance_ingestion = match &ingestion.kind { - IngestionKind::Substance(substance_ingestion) => substance_ingestion, - _ => continue, - }; + if let Some(consumer_filter) = consumer_filter { + if !consumer_filter.contains(&ingestion.consumer) { + continue; + } + } - let unit = journal.resolve_substance_unit(substance_ingestion).unwrap(); - // println!("{:#?} {:#?}", &ingestion, &custom_unit); + match &ingestion.kind { + IngestionKind::Sustenance(_) => { + print_ingestion(journal, ingestion, &ingestion.kind); - println!( - "{}|{}|{}|{}|{}", - substance_ingestion.substance_name, - format_dose(&substance_ingestion.dose, &unit), - format_substance_ingestion_roa(substance_ingestion, &unit), - ingestion.consumer, - format_ingestion_time(ingestion) - ) + for kind in resolve_ingestion(journal, &ingestion.kind) { + print!("- "); + print_ingestion(journal, ingestion, &kind) + } + } + _ => { + print_ingestion(journal, ingestion, &ingestion.kind); + } + } } }