This commit is contained in:
chaos 2024-11-24 19:22:58 +00:00
parent 93105359f9
commit 956c3f6ad1
9 changed files with 235 additions and 125 deletions

View file

@ -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<dyn Journal>;
@ -9,19 +8,16 @@ pub trait Journal {
fn get_custom_unit(&self, id: i32) -> Option<CustomUnit>;
fn get_session(&self, id: i32) -> Option<Session>;
fn get_session_ingestions(&self, id: i32) -> Option<Vec<Ingestion>>;
fn get_session_substance_ingestions_by(
&self,
id: i32,
substance_filter: Option<&Vec<String>>,
route_filter: Option<&Vec<AdministrationRoute>>,
consumer_filter: Option<&Vec<Consumer>>,
) -> Option<Vec<Ingestion>>;
fn get_substance(&self, name: &String) -> Option<Substance>;
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<Substance>;
fn get_sustenance(&self, sustenance_id: &str) -> Option<Sustenance>;
fn get_sustenance_ingestions(&self, sustenance_id: &str) -> Option<Vec<IngestionKind>>;
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<Ingestion>);
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<Session>;
fn resolve_substance_unit(&self, ingestion: &SubstanceIngestion) -> Option<Unit>;

View file

@ -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<String, Sustenance>,
pub substances: HashMap<String, Substance>,
pub ingestions: HashMap<i32, Vec<Ingestion>>,
pub sessions: HashMap<i32, Session>,
@ -23,12 +23,12 @@ pub struct JSONJournal {
}
impl JSONJournal {
pub fn create(filename: &String) -> Result<JournalType, Box<dyn std::error::Error>> {
pub fn create(filename: &str) -> Result<JournalType, Box<dyn std::error::Error>> {
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<JournalType, Box<dyn std::error::Error>> {
pub fn load(filename: &str) -> Result<JournalType, Box<dyn std::error::Error>> {
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<String>>,
route_filter: Option<&Vec<AdministrationRoute>>,
consumer_filter: Option<&Vec<Consumer>>,
) -> Option<Vec<Ingestion>> {
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::<Vec<Ingestion>>();
Some(ingestions)
} else {
None
}
}
fn get_substance(&self, name: &String) -> Option<Substance> {
fn get_substance(&self, name: &str) -> Option<Substance> {
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<Ingestion>) {
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<dyn std::error::Error>> {
self.save()
}
fn get_sustenance(&self, sustenance_id: &str) -> Option<Sustenance> {
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<Vec<IngestionKind>> {
let sustenance = self.get_sustenance(sustenance_id).unwrap();
let mut ingestions: Vec<IngestionKind> = 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)
}
}

View file

@ -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<psychonaut_journal_types::Ingestion> for Ingestion {

View file

@ -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;

View file

@ -0,0 +1,5 @@
#[derive(Debug, Clone)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Nutrients {
pub kcal: u64,
}

View file

@ -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<Nutrients>,
pub includes: Vec<IngestionKind>,
}

View file

@ -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::<i32>();
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<Ingestion> = Vec::new();
for ingestion in experience.ingestions.iter() {

View file

@ -12,8 +12,6 @@ pub struct PrintSessionArgs {
#[command(flatten)]
pub journal_location: JournalLocation,
#[arg(long)]
pub substance_filter: Option<Vec<String>>,
#[arg(long, value_delimiter = ',')]
pub consumer_filter: Option<Vec<String>>,
}
@ -46,15 +44,9 @@ pub fn print_session(args: &PrintSessionArgs) -> Result<(), Box<dyn std::error::
println!("{}", format_session_title(&session));
let substance_filter = args.substance_filter.clone();
let consumer_filter = parse_consumer_filter(args.consumer_filter.clone());
print_ingestion_log(
&journal,
&session,
substance_filter.as_ref(),
consumer_filter.as_ref(),
);
print_ingestion_log(&journal, &session, consumer_filter.as_ref());
Ok(())
}

View file

@ -1,36 +1,144 @@
use journal::{
journal::JournalType,
types::{format_dose, Consumer, IngestionKind, Session},
types::{
format_dose, Consumer, Dose, Ingestion, IngestionKind, Session, SubstanceIngestion,
SustenanceIngestion,
},
};
use crate::formatting::{format_ingestion_time, format_substance_ingestion_roa};
fn print_substance_ingestion(
journal: &JournalType,
ingestion: &Ingestion,
substance_ingestion: &SubstanceIngestion,
) {
let unit = journal.resolve_substance_unit(substance_ingestion).unwrap();
println!(
"Substance|{}|{}|{}|{}|{}",
substance_ingestion.substance_name,
format_dose(&substance_ingestion.dose, &unit),
format_substance_ingestion_roa(substance_ingestion, &unit),
ingestion.consumer,
format_ingestion_time(ingestion)
)
}
fn print_sustenance_ingestion(
journal: &JournalType,
ingestion: &Ingestion,
sustenance_ingestion: &SustenanceIngestion,
) {
let sustenance = journal
.get_sustenance(&sustenance_ingestion.sustenance_id)
.unwrap();
println!(
"Sustenance|{}|{} {}|{}|{}",
sustenance.name,
sustenance_ingestion.amount,
sustenance.unit,
ingestion.consumer,
format_ingestion_time(ingestion)
)
}
pub fn resolve_ingestion(journal: &JournalType, ingestion: &IngestionKind) -> Vec<IngestionKind> {
//println!("{ingestion:?}");
let mut ingestions: Vec<IngestionKind> = 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<String>>,
consumer_filter: Option<&Vec<Consumer>>,
) {
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);
}
}
}
}