update
This commit is contained in:
parent
935672d716
commit
5e4a4cc54f
124
journal/src/calculate.rs
Normal file
124
journal/src/calculate.rs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
ops::{Add, Mul},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::types::{Dose, HydrationIngestion, IngestionKind, Nutrients, SubstanceIngestion};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq)]
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
|
||||||
|
pub struct CalculatedValues {
|
||||||
|
pub doses: HashMap<String, Dose>,
|
||||||
|
pub nutrients: Nutrients,
|
||||||
|
pub hydration: HydrationIngestion,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<CalculatedValues> for CalculatedValues {
|
||||||
|
type Output = CalculatedValues;
|
||||||
|
|
||||||
|
fn add(self, rhs: CalculatedValues) -> Self::Output {
|
||||||
|
let mut doses = self.doses.clone();
|
||||||
|
let mut nutrients = self.nutrients.clone();
|
||||||
|
let mut hydration = self.hydration.clone();
|
||||||
|
|
||||||
|
for (substance_id, substance_dose) in rhs.doses.iter() {
|
||||||
|
let dose = self
|
||||||
|
.doses
|
||||||
|
.get(substance_id)
|
||||||
|
.cloned()
|
||||||
|
.or(Some(Dose::new_precise(0.0)))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
doses.insert(substance_id.clone(), dose + substance_dose.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
nutrients.kcal += rhs.nutrients.kcal;
|
||||||
|
hydration.amount_ml += rhs.hydration.amount_ml;
|
||||||
|
|
||||||
|
CalculatedValues {
|
||||||
|
doses,
|
||||||
|
nutrients,
|
||||||
|
hydration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f64> for CalculatedValues {
|
||||||
|
type Output = CalculatedValues;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f64) -> Self::Output {
|
||||||
|
let mut doses = self.doses.clone();
|
||||||
|
let mut nutrients = self.nutrients.clone();
|
||||||
|
let mut hydration = self.hydration.clone();
|
||||||
|
|
||||||
|
for (_substance_id, substance_dose) in doses.iter_mut() {
|
||||||
|
*substance_dose = substance_dose.clone() * Dose::new_precise(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
nutrients.kcal = (rhs * nutrients.kcal as f64).round() as u64;
|
||||||
|
hydration.amount_ml *= rhs;
|
||||||
|
|
||||||
|
CalculatedValues {
|
||||||
|
doses,
|
||||||
|
nutrients,
|
||||||
|
hydration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalculatedValues {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate_ingestion_kind(kind: IngestionKind) -> CalculatedValues {
|
||||||
|
let mut values = CalculatedValues::new();
|
||||||
|
|
||||||
|
let mut ingestions: Vec<IngestionKind> = Vec::new();
|
||||||
|
ingestions.push(kind);
|
||||||
|
|
||||||
|
while !ingestions.is_empty() {
|
||||||
|
let current_ingestions = ingestions.clone();
|
||||||
|
for kind in current_ingestions {
|
||||||
|
match kind {
|
||||||
|
IngestionKind::Unknown => {}
|
||||||
|
IngestionKind::Substance(substance) => {
|
||||||
|
let dose = values
|
||||||
|
.doses
|
||||||
|
.get(&substance.id)
|
||||||
|
.cloned()
|
||||||
|
.or(Some(Dose::new_precise(0.0)))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
values
|
||||||
|
.doses
|
||||||
|
.insert(substance.id.clone(), dose + substance.dose.clone());
|
||||||
|
}
|
||||||
|
IngestionKind::Sustenance(sustenance) => {
|
||||||
|
let amount = sustenance.amount;
|
||||||
|
let mut sustenance = sustenance.sustenance.clone().unwrap();
|
||||||
|
|
||||||
|
for include in sustenance.includes.iter_mut() {
|
||||||
|
match include {
|
||||||
|
IngestionKind::Unknown => {}
|
||||||
|
IngestionKind::Substance(ingestion) => {
|
||||||
|
ingestion.dose = ingestion.dose.clone() * Dose::new_precise(amount)
|
||||||
|
}
|
||||||
|
IngestionKind::Sustenance(ingestion) => ingestion.amount *= amount,
|
||||||
|
IngestionKind::Hydration(ingestion) => ingestion.amount_ml *= amount,
|
||||||
|
}
|
||||||
|
ingestions.push(include.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IngestionKind::Hydration(hydration) => {
|
||||||
|
values.hydration.amount_ml += hydration.amount_ml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values
|
||||||
|
}
|
|
@ -4,11 +4,11 @@ use chrono::Utc;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
CustomUnit, Dose, Ingestion, IngestionKind, IngestionKinds, Session, Substance,
|
CustomUnit, Dose, Ingestion, IngestionKind, Session, Substance, SubstanceIngestion, Sustenance,
|
||||||
SubstanceIngestion, Sustenance, SustenanceIngestion, Unit,
|
SustenanceIngestion, Unit,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Journal, JournalType};
|
use super::{Journal, JournalIntegrityChecks, JournalTrait, JournalType};
|
||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
use data::JSONJournalData;
|
use data::JSONJournalData;
|
||||||
|
@ -67,7 +67,7 @@ impl JSONJournal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Journal for JSONJournal {
|
impl JournalTrait for JSONJournal {
|
||||||
fn save(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
fn save(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
self.save()
|
self.save()
|
||||||
}
|
}
|
||||||
|
@ -80,83 +80,40 @@ impl Journal for JSONJournal {
|
||||||
self.data.ingestions.get(&id).cloned()
|
self.data.ingestions.get(&id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_substance(&self, name: &str) -> Option<Substance> {
|
fn get_substance(&self, id: &str) -> Option<Substance> {
|
||||||
self.data.substances.get(name).cloned()
|
self.data.substances.get(id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sustenance(&self, sustenance_id: &str) -> Option<Sustenance> {
|
fn get_sustenance(&self, id: &str) -> Option<Sustenance> {
|
||||||
self.data.sustenances.get(sustenance_id).cloned()
|
self.data.sustenances.get(id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_custom_unit(&self, id: i32) -> Option<CustomUnit> {
|
fn get_custom_unit(&self, id: i32) -> Option<CustomUnit> {
|
||||||
self.data.custom_units.get(&id).cloned()
|
self.data.custom_units.get(&id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_ingestion_kind(
|
fn resolve_ingestion_kind(&self, kind: IngestionKind) -> Option<IngestionKind> {
|
||||||
&self,
|
let mut kind = kind;
|
||||||
kind: &IngestionKind,
|
|
||||||
calculate: bool,
|
|
||||||
) -> Option<IngestionKinds> {
|
|
||||||
println!("{kind:#?}");
|
|
||||||
let mut kinds: IngestionKinds = IngestionKinds::from(kind);
|
|
||||||
|
|
||||||
if let IngestionKind::Sustenance(sustenance) = kind {
|
if let IngestionKind::Sustenance(ingestion_type) = &mut kind {
|
||||||
let includes = self.get_sustenance(&sustenance.sustenance_id)?.includes;
|
if let Some(mut sustenance) = self.get_sustenance(&ingestion_type.id) {
|
||||||
|
sustenance.includes = sustenance
|
||||||
for include in includes.into_iter() {
|
|
||||||
if calculate {
|
|
||||||
match include {
|
|
||||||
IngestionKind::Sustenance(ingestion) => {
|
|
||||||
kinds.includes.push(IngestionKinds {
|
|
||||||
ingestion: IngestionKind::Sustenance(SustenanceIngestion {
|
|
||||||
amount: sustenance.amount * ingestion.amount,
|
|
||||||
..ingestion.clone()
|
|
||||||
}),
|
|
||||||
includes: self
|
|
||||||
.resolve_ingestion_kind(
|
|
||||||
&IngestionKind::Sustenance(ingestion),
|
|
||||||
calculate,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.includes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
IngestionKind::Unknown => {
|
|
||||||
kinds
|
|
||||||
.includes
|
.includes
|
||||||
.push(IngestionKinds::from(&IngestionKind::Unknown));
|
.into_iter()
|
||||||
}
|
.map(|include| self.resolve_ingestion_kind(include).unwrap())
|
||||||
IngestionKind::Substance(ingestion) => {
|
.collect();
|
||||||
kinds
|
ingestion_type.sustenance = Some(sustenance);
|
||||||
.includes
|
|
||||||
.push(IngestionKinds::from(&IngestionKind::Substance(
|
|
||||||
SubstanceIngestion {
|
|
||||||
dose: Dose::new_precise(sustenance.amount)
|
|
||||||
* ingestion.dose.clone(),
|
|
||||||
..ingestion
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
IngestionKind::Hydration { amount } => {
|
|
||||||
kinds
|
|
||||||
.includes
|
|
||||||
.push(IngestionKinds::from(&IngestionKind::Hydration {
|
|
||||||
amount: (sustenance.amount * amount as f64).round() as u64,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
kinds.includes.push(IngestionKinds::from(&include))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if let IngestionKind::Substance(ingestion_type) = &mut kind {
|
||||||
|
ingestion_type.substance = self.get_substance(&ingestion_type.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(kinds)
|
Some(kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_substance_unit(&self, ingestion: &SubstanceIngestion) -> Option<Unit> {
|
fn resolve_substance_unit(&self, ingestion: &SubstanceIngestion) -> Option<Unit> {
|
||||||
match ingestion.custom_unit_id {
|
match ingestion.custom_unit_id {
|
||||||
None => match self.get_substance(&ingestion.substance_name) {
|
None => match self.get_substance(&ingestion.id) {
|
||||||
Some(substance) => Some(Unit::Simple(substance.unit)),
|
Some(substance) => Some(Unit::Simple(substance.unit)),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
|
@ -180,14 +137,18 @@ impl Journal for JSONJournal {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_substance(&mut self, substance: Substance) -> Substance {
|
fn create_substance(&mut self, substance: Substance) -> Substance {
|
||||||
|
assert!(substance.id == substance.id.replace(" ", "_").to_ascii_uppercase());
|
||||||
|
|
||||||
self.data
|
self.data
|
||||||
.substances
|
.substances
|
||||||
.insert(substance.name.clone(), substance.clone());
|
.insert(substance.id.clone(), substance.clone());
|
||||||
|
|
||||||
substance
|
substance
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_sustenance(&mut self, sustenance: Sustenance) -> Sustenance {
|
fn create_sustenance(&mut self, sustenance: Sustenance) -> Sustenance {
|
||||||
|
assert!(sustenance.id == sustenance.id.replace(" ", "_").to_ascii_uppercase());
|
||||||
|
|
||||||
self.data
|
self.data
|
||||||
.sustenances
|
.sustenances
|
||||||
.insert(sustenance.id.clone(), sustenance.clone());
|
.insert(sustenance.id.clone(), sustenance.clone());
|
||||||
|
@ -211,13 +172,14 @@ impl Journal for JSONJournal {
|
||||||
self.data.sessions.insert(id, Session { id, ..session });
|
self.data.sessions.insert(id, Session { id, ..session });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_substance(&mut self, name: &str, substance: Substance, create: bool) {
|
fn update_substance(&mut self, id: &str, substance: Substance, create: bool) {
|
||||||
assert!(self.data.substances.contains_key(name) || create);
|
assert!(self.data.substances.contains_key(id) || create);
|
||||||
|
assert!(id == id.replace(" ", "_").to_ascii_uppercase());
|
||||||
|
|
||||||
self.data.substances.insert(
|
self.data.substances.insert(
|
||||||
name.to_string(),
|
id.to_string(),
|
||||||
Substance {
|
Substance {
|
||||||
name: name.to_string(),
|
id: id.to_string(),
|
||||||
..substance
|
..substance
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -225,6 +187,7 @@ impl Journal for JSONJournal {
|
||||||
|
|
||||||
fn update_sustenance(&mut self, id: &str, sustenance: Sustenance, create: bool) {
|
fn update_sustenance(&mut self, id: &str, sustenance: Sustenance, create: bool) {
|
||||||
assert!(self.data.sustenances.contains_key(id) || create);
|
assert!(self.data.sustenances.contains_key(id) || create);
|
||||||
|
assert!(id == id.replace(" ", "_").to_ascii_uppercase());
|
||||||
|
|
||||||
self.data.sustenances.insert(
|
self.data.sustenances.insert(
|
||||||
id.to_string(),
|
id.to_string(),
|
||||||
|
@ -253,3 +216,6 @@ impl Journal for JSONJournal {
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl JournalIntegrityChecks for JSONJournal {}
|
||||||
|
impl Journal for JSONJournal {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
CustomUnit, Ingestion, IngestionKind, IngestionKinds, Session, Substance, SubstanceIngestion,
|
CustomUnit, Ingestion, IngestionKind, Session, Substance, SubstanceIngestion, Sustenance, Unit,
|
||||||
Sustenance, Unit,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub trait Journal: JournalTrait + JournalIntegrityChecks {}
|
||||||
pub type JournalType = Box<dyn Journal>;
|
pub type JournalType = Box<dyn Journal>;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
@ -11,20 +11,16 @@ pub enum JournalError {
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Journal {
|
pub trait JournalTrait {
|
||||||
fn save(&mut self) -> Result<(), Box<dyn std::error::Error>>;
|
fn save(&mut self) -> Result<(), Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
fn get_session(&self, id: i32) -> Option<Session>;
|
fn get_session(&self, id: i32) -> Option<Session>;
|
||||||
fn get_session_ingestions(&self, id: i32) -> Option<Vec<Ingestion>>;
|
fn get_session_ingestions(&self, id: i32) -> Option<Vec<Ingestion>>;
|
||||||
fn get_substance(&self, name: &str) -> Option<Substance>;
|
fn get_substance(&self, id: &str) -> Option<Substance>;
|
||||||
fn get_sustenance(&self, id: &str) -> Option<Sustenance>;
|
fn get_sustenance(&self, id: &str) -> Option<Sustenance>;
|
||||||
fn get_custom_unit(&self, id: i32) -> Option<CustomUnit>;
|
fn get_custom_unit(&self, id: i32) -> Option<CustomUnit>;
|
||||||
|
|
||||||
fn resolve_ingestion_kind(
|
fn resolve_ingestion_kind(&self, ingestion: IngestionKind) -> Option<IngestionKind>;
|
||||||
&self,
|
|
||||||
ingestion: &IngestionKind,
|
|
||||||
calculate: bool,
|
|
||||||
) -> Option<IngestionKinds>;
|
|
||||||
fn resolve_substance_unit(&self, ingestion: &SubstanceIngestion) -> Option<Unit>;
|
fn resolve_substance_unit(&self, ingestion: &SubstanceIngestion) -> Option<Unit>;
|
||||||
|
|
||||||
fn create_session(&mut self, title: &str) -> Session;
|
fn create_session(&mut self, title: &str) -> Session;
|
||||||
|
@ -42,6 +38,12 @@ pub trait Journal {
|
||||||
fn first_session_by_title(&self, title: &str) -> Option<Session>;
|
fn first_session_by_title(&self, title: &str) -> Option<Session>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait JournalIntegrityChecks: JournalTrait {
|
||||||
|
fn check_sustenance_for_recursion(&self, _sustenance: Sustenance) -> Option<Vec<String>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "json_journal")]
|
#[cfg(feature = "json_journal")]
|
||||||
mod json_journal;
|
mod json_journal;
|
||||||
#[cfg(feature = "json_journal")]
|
#[cfg(feature = "json_journal")]
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
|
pub mod calculate;
|
||||||
pub mod journal;
|
pub mod journal;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
43
journal/src/types/administration_route.rs
Normal file
43
journal/src/types/administration_route.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
|
||||||
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
|
pub enum AdministrationRoute {
|
||||||
|
Oral,
|
||||||
|
Sublingual,
|
||||||
|
Buccal,
|
||||||
|
Insufflated,
|
||||||
|
Rectal,
|
||||||
|
Transdermal,
|
||||||
|
Subcutaneous,
|
||||||
|
Intramuscular,
|
||||||
|
Intravenous,
|
||||||
|
Smoked,
|
||||||
|
Inhaled,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AdministrationRoute {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Oral
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AdministrationRoute {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Self::Oral => f.write_str("Oral"),
|
||||||
|
Self::Sublingual => f.write_str("Sublingual"),
|
||||||
|
Self::Buccal => f.write_str("Buccal"),
|
||||||
|
Self::Insufflated => f.write_str("Insufflated"),
|
||||||
|
Self::Rectal => f.write_str("Rectal"),
|
||||||
|
Self::Transdermal => f.write_str("Transdermal"),
|
||||||
|
Self::Subcutaneous => f.write_str("Subcutaneous"),
|
||||||
|
Self::Intramuscular => f.write_str("Intramuscular"),
|
||||||
|
Self::Intravenous => f.write_str("Intravenous"),
|
||||||
|
Self::Smoked => f.write_str("Smoked"),
|
||||||
|
Self::Inhaled => f.write_str("Inhaled"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,73 +17,3 @@ pub struct CustomUnit {
|
||||||
pub creation_time: DateTime<Utc>,
|
pub creation_time: DateTime<Utc>,
|
||||||
pub is_archived: bool,
|
pub is_archived: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<psychonaut_journal_types::CustomUnit> for CustomUnit {
|
|
||||||
fn from(custom_unit: psychonaut_journal_types::CustomUnit) -> Self {
|
|
||||||
CustomUnit {
|
|
||||||
id: custom_unit.id,
|
|
||||||
name: custom_unit.name,
|
|
||||||
substance_name: custom_unit.substance_name,
|
|
||||||
unit: custom_unit.unit,
|
|
||||||
original_unit: custom_unit.original_unit,
|
|
||||||
|
|
||||||
dose: {
|
|
||||||
if custom_unit.estimate_standard_deviation.is_some() {
|
|
||||||
Dose::new_deviation(
|
|
||||||
custom_unit.dose.unwrap(),
|
|
||||||
custom_unit.estimate_standard_deviation.unwrap(),
|
|
||||||
)
|
|
||||||
} else if custom_unit.is_estimate && custom_unit.dose.is_some() {
|
|
||||||
Dose::new_estimate(custom_unit.dose.unwrap())
|
|
||||||
} else if custom_unit.dose.is_some() {
|
|
||||||
Dose::new_precise(custom_unit.dose.unwrap())
|
|
||||||
} else {
|
|
||||||
Dose::new_unknown()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
administration_route: custom_unit.administration_route,
|
|
||||||
|
|
||||||
creation_time: from_unix_millis(custom_unit.creation_time),
|
|
||||||
is_archived: custom_unit.is_archived,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::types::{from_unix_millis, AdministrationRoute, Dose};
|
|
||||||
|
|
||||||
use super::CustomUnit;
|
|
||||||
use psychonaut_journal_types::CustomUnit as PsychonautCustomUnit;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn psychonaut_journal_conversion() {
|
|
||||||
assert_eq!(
|
|
||||||
CustomUnit::from(PsychonautCustomUnit {
|
|
||||||
id: 0,
|
|
||||||
substance_name: "Caffeine".to_string(),
|
|
||||||
name: "Beverage".to_string(),
|
|
||||||
creation_time: 0,
|
|
||||||
administration_route: AdministrationRoute::Oral,
|
|
||||||
dose: Some(10.0),
|
|
||||||
unit: "sip".to_string(),
|
|
||||||
original_unit: "mg".to_string(),
|
|
||||||
is_estimate: true,
|
|
||||||
estimate_standard_deviation: Some(10.0),
|
|
||||||
is_archived: false
|
|
||||||
}),
|
|
||||||
CustomUnit {
|
|
||||||
id: 0,
|
|
||||||
name: "Beverage".to_string(),
|
|
||||||
substance_name: "Caffeine".to_string(),
|
|
||||||
unit: "sip".to_string(),
|
|
||||||
original_unit: "mg".to_string(),
|
|
||||||
dose: Dose::new_deviation(10.0, 10.0),
|
|
||||||
administration_route: AdministrationRoute::Oral,
|
|
||||||
creation_time: from_unix_millis(0),
|
|
||||||
is_archived: false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
use super::{dose::Dose, from_unix_millis, Consumer};
|
use super::Consumer;
|
||||||
|
|
||||||
mod kind;
|
mod kind;
|
||||||
pub use kind::{IngestionKind, IngestionKinds};
|
pub use kind::IngestionKind;
|
||||||
|
|
||||||
mod substance;
|
mod substance;
|
||||||
pub use substance::SubstanceIngestion;
|
pub use substance::SubstanceIngestion;
|
||||||
|
@ -11,6 +11,9 @@ pub use substance::SubstanceIngestion;
|
||||||
mod sustenance;
|
mod sustenance;
|
||||||
pub use sustenance::SustenanceIngestion;
|
pub use sustenance::SustenanceIngestion;
|
||||||
|
|
||||||
|
mod hydration;
|
||||||
|
pub use hydration::HydrationIngestion;
|
||||||
|
|
||||||
#[derive(PartialEq, Default, Debug, Clone)]
|
#[derive(PartialEq, Default, Debug, Clone)]
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Ingestion {
|
pub struct Ingestion {
|
||||||
|
@ -20,87 +23,3 @@ pub struct Ingestion {
|
||||||
pub notes: String,
|
pub notes: String,
|
||||||
pub kind: IngestionKind,
|
pub kind: IngestionKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<psychonaut_journal_types::Ingestion> for Ingestion {
|
|
||||||
fn from(ingestion: psychonaut_journal_types::Ingestion) -> Self {
|
|
||||||
Ingestion {
|
|
||||||
ingestion_time: from_unix_millis(ingestion.ingestion_time),
|
|
||||||
creation_time: from_unix_millis(ingestion.creation_time),
|
|
||||||
|
|
||||||
kind: IngestionKind::Substance(SubstanceIngestion {
|
|
||||||
substance_name: ingestion.substance_name,
|
|
||||||
dose: {
|
|
||||||
if ingestion.estimate_standard_deviation.is_some() {
|
|
||||||
Dose::new_deviation(
|
|
||||||
ingestion.dose.unwrap(),
|
|
||||||
ingestion.estimate_standard_deviation.unwrap(),
|
|
||||||
)
|
|
||||||
} else if ingestion.is_estimate && ingestion.dose.is_some() {
|
|
||||||
Dose::new_estimate(ingestion.dose.unwrap())
|
|
||||||
} else if ingestion.dose.is_some() {
|
|
||||||
Dose::new_precise(ingestion.dose.unwrap())
|
|
||||||
} else {
|
|
||||||
Dose::new_unknown()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
custom_unit_id: ingestion.custom_unit_id,
|
|
||||||
|
|
||||||
roa: ingestion.roa,
|
|
||||||
stomach_fullness: ingestion.stomach_fullness,
|
|
||||||
}),
|
|
||||||
|
|
||||||
consumer: match ingestion.consumer_name {
|
|
||||||
Some(name) => Consumer::Named(name),
|
|
||||||
None => Consumer::Default,
|
|
||||||
},
|
|
||||||
|
|
||||||
notes: ingestion.notes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::types::{
|
|
||||||
from_unix_millis,
|
|
||||||
ingestion::{IngestionKind, SubstanceIngestion},
|
|
||||||
AdministrationRoute, Consumer, Dose,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::Ingestion;
|
|
||||||
use psychonaut_journal_types::Ingestion as PsychonautIngestion;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn psychonaut_journal_conversion() {
|
|
||||||
assert_eq!(
|
|
||||||
Ingestion::from(PsychonautIngestion {
|
|
||||||
substance_name: "Caffeine".to_string(),
|
|
||||||
ingestion_time: 0,
|
|
||||||
creation_time: 0,
|
|
||||||
dose: Some(10.0),
|
|
||||||
unit: "mg".to_string(),
|
|
||||||
is_estimate: false,
|
|
||||||
estimate_standard_deviation: None,
|
|
||||||
custom_unit_id: None,
|
|
||||||
roa: AdministrationRoute::Oral,
|
|
||||||
consumer_name: None,
|
|
||||||
notes: "".to_string(),
|
|
||||||
stomach_fullness: None,
|
|
||||||
}),
|
|
||||||
Ingestion {
|
|
||||||
ingestion_time: from_unix_millis(0),
|
|
||||||
creation_time: from_unix_millis(0),
|
|
||||||
kind: IngestionKind::Substance(SubstanceIngestion {
|
|
||||||
substance_name: "Caffeine".to_string(),
|
|
||||||
dose: Dose::new_precise(10.0),
|
|
||||||
custom_unit_id: None,
|
|
||||||
roa: AdministrationRoute::Oral,
|
|
||||||
stomach_fullness: None
|
|
||||||
}),
|
|
||||||
consumer: Consumer::Default,
|
|
||||||
notes: "".to_string(),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
13
journal/src/types/ingestion/hydration.rs
Normal file
13
journal/src/types/ingestion/hydration.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Default, Debug, Clone)]
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct HydrationIngestion {
|
||||||
|
pub amount_ml: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for HydrationIngestion {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{} ml", self.amount_ml)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{SubstanceIngestion, SustenanceIngestion};
|
use super::{HydrationIngestion, SubstanceIngestion, SustenanceIngestion};
|
||||||
|
|
||||||
#[derive(PartialEq, Default, Debug, Clone)]
|
#[derive(PartialEq, Default, Debug, Clone)]
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
@ -8,23 +8,5 @@ pub enum IngestionKind {
|
||||||
Unknown,
|
Unknown,
|
||||||
Substance(SubstanceIngestion),
|
Substance(SubstanceIngestion),
|
||||||
Sustenance(SustenanceIngestion),
|
Sustenance(SustenanceIngestion),
|
||||||
Hydration {
|
Hydration(HydrationIngestion),
|
||||||
amount: u64,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Default, Debug, Clone)]
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
|
||||||
pub struct IngestionKinds {
|
|
||||||
pub ingestion: IngestionKind,
|
|
||||||
pub includes: Vec<IngestionKinds>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&IngestionKind> for IngestionKinds {
|
|
||||||
fn from(value: &IngestionKind) -> Self {
|
|
||||||
IngestionKinds {
|
|
||||||
ingestion: value.clone(),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use crate::types::{AdministrationRoute, Dose};
|
use crate::types::{AdministrationRoute, Dose, Substance};
|
||||||
|
|
||||||
#[derive(PartialEq, Default, Debug, Clone)]
|
#[derive(PartialEq, Default, Debug, Clone)]
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct SubstanceIngestion {
|
pub struct SubstanceIngestion {
|
||||||
pub substance_name: String,
|
pub id: String,
|
||||||
|
pub substance: Option<Substance>,
|
||||||
|
|
||||||
pub dose: Dose,
|
pub dose: Dose,
|
||||||
pub custom_unit_id: Option<i32>,
|
pub custom_unit_id: Option<i32>,
|
||||||
pub roa: AdministrationRoute,
|
pub roa: AdministrationRoute,
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
use crate::types::Sustenance;
|
||||||
|
|
||||||
#[derive(PartialEq, Default, Debug, Clone)]
|
#[derive(PartialEq, Default, Debug, Clone)]
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct SustenanceIngestion {
|
pub struct SustenanceIngestion {
|
||||||
pub sustenance_id: String,
|
pub id: String,
|
||||||
|
pub sustenance: Option<Sustenance>,
|
||||||
|
|
||||||
pub amount: f64,
|
pub amount: f64,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub use consumer::Consumer;
|
||||||
|
|
||||||
mod ingestion;
|
mod ingestion;
|
||||||
pub use ingestion::{
|
pub use ingestion::{
|
||||||
Ingestion, IngestionKind, IngestionKinds, SubstanceIngestion, SustenanceIngestion,
|
HydrationIngestion, Ingestion, IngestionKind, SubstanceIngestion, SustenanceIngestion,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod substance;
|
mod substance;
|
||||||
|
@ -32,7 +32,8 @@ pub use session::Session;
|
||||||
mod custom_unit;
|
mod custom_unit;
|
||||||
pub use custom_unit::CustomUnit;
|
pub use custom_unit::CustomUnit;
|
||||||
|
|
||||||
pub type AdministrationRoute = psychonaut_journal_types::AdministrationRoute;
|
pub mod administration_route;
|
||||||
|
pub use administration_route::AdministrationRoute;
|
||||||
|
|
||||||
pub(crate) fn from_unix_millis(time: u64) -> DateTime<Utc> {
|
pub(crate) fn from_unix_millis(time: u64) -> DateTime<Utc> {
|
||||||
Utc.timestamp_millis_opt(time as i64).unwrap()
|
Utc.timestamp_millis_opt(time as i64).unwrap()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#[derive(Debug, Clone)]
|
#[derive(PartialEq, Default, Debug, Clone)]
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Nutrients {
|
pub struct Nutrients {
|
||||||
pub kcal: u64,
|
pub kcal: u64,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Substance {
|
pub struct Substance {
|
||||||
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub unit: String,
|
pub unit: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{IngestionKind, Nutrients};
|
use super::{IngestionKind, Nutrients};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Sustenance {
|
pub struct Sustenance {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
|
@ -2,13 +2,19 @@ use std::{collections::HashMap, fs::File};
|
||||||
|
|
||||||
use journal::{
|
use journal::{
|
||||||
journal::JournalType,
|
journal::JournalType,
|
||||||
types::{CustomUnit, Ingestion, Session, Substance},
|
types::{
|
||||||
|
Consumer, CustomUnit, Dose, Ingestion, IngestionKind, Session, Substance,
|
||||||
|
SubstanceIngestion,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use psychonaut_journal_types::ExportData;
|
use psychonaut_journal_types::ExportData;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use types::{from_administration_route, from_unix_millis};
|
||||||
|
|
||||||
use crate::{args::JournalLocation, helpers::load_journal};
|
use crate::{args::JournalLocation, helpers::load_journal};
|
||||||
|
|
||||||
|
mod types;
|
||||||
|
|
||||||
mod custom_substance;
|
mod custom_substance;
|
||||||
mod custom_unit;
|
mod custom_unit;
|
||||||
|
|
||||||
|
@ -68,16 +74,14 @@ pub fn psychonaut_import(args: &PsychonautImportArgs) -> Result<(), Box<dyn std:
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
for custom_unit in export_data.custom_units.into_iter() {
|
for custom_unit in export_data.custom_units.into_iter() {
|
||||||
custom_unit::create_or_update_custom_unit(
|
custom_unit::create_or_update_custom_unit(&mut journal, custom_unit);
|
||||||
&mut journal,
|
|
||||||
CustomUnit::from(custom_unit),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for custom_substance in export_data.custom_substances.into_iter() {
|
for custom_substance in export_data.custom_substances.into_iter() {
|
||||||
custom_substance::create_or_check_custom_substance(
|
custom_substance::create_or_check_custom_substance(
|
||||||
&mut journal,
|
&mut journal,
|
||||||
Substance {
|
Substance {
|
||||||
|
id: custom_substance.name.replace(" ", "_").to_ascii_uppercase(),
|
||||||
name: custom_substance.name.clone(),
|
name: custom_substance.name.clone(),
|
||||||
description: custom_substance.description.clone(),
|
description: custom_substance.description.clone(),
|
||||||
unit: custom_substance.units,
|
unit: custom_substance.units,
|
||||||
|
@ -88,13 +92,14 @@ pub fn psychonaut_import(args: &PsychonautImportArgs) -> Result<(), Box<dyn std:
|
||||||
for experience in export_data.experiences.iter() {
|
for experience in export_data.experiences.iter() {
|
||||||
for ingestion in experience.ingestions.iter() {
|
for ingestion in experience.ingestions.iter() {
|
||||||
let substance_name = &ingestion.substance_name;
|
let substance_name = &ingestion.substance_name;
|
||||||
|
let substance_id = substance_name.replace(" ", "_").to_ascii_uppercase();
|
||||||
|
|
||||||
let ingestion_unit = match ingestion.custom_unit_id {
|
let ingestion_unit = match ingestion.custom_unit_id {
|
||||||
Some(id) => journal.get_custom_unit(id).unwrap().original_unit,
|
Some(id) => journal.get_custom_unit(id).unwrap().original_unit,
|
||||||
None => ingestion.unit.clone(),
|
None => ingestion.unit.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match journal.get_substance(substance_name) {
|
match journal.get_substance(&substance_id) {
|
||||||
Some(substance) => {
|
Some(substance) => {
|
||||||
if substance.unit != ingestion_unit {
|
if substance.unit != ingestion_unit {
|
||||||
panic!(
|
panic!(
|
||||||
|
@ -105,6 +110,7 @@ pub fn psychonaut_import(args: &PsychonautImportArgs) -> Result<(), Box<dyn std:
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
journal.create_substance(Substance {
|
journal.create_substance(Substance {
|
||||||
|
id: substance_id,
|
||||||
name: substance_name.clone(),
|
name: substance_name.clone(),
|
||||||
description: "".to_string(),
|
description: "".to_string(),
|
||||||
unit: ingestion_unit,
|
unit: ingestion_unit,
|
||||||
|
@ -134,8 +140,42 @@ pub fn psychonaut_import(args: &PsychonautImportArgs) -> Result<(), Box<dyn std:
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut ingestions: Vec<Ingestion> = Vec::new();
|
let mut ingestions: Vec<Ingestion> = Vec::new();
|
||||||
for ingestion in experience.ingestions.iter() {
|
for ingestion in experience.ingestions.into_iter() {
|
||||||
ingestions.push(Ingestion::from(ingestion.clone()))
|
ingestions.push(Ingestion {
|
||||||
|
ingestion_time: from_unix_millis(ingestion.ingestion_time),
|
||||||
|
creation_time: from_unix_millis(ingestion.creation_time),
|
||||||
|
|
||||||
|
kind: IngestionKind::Substance(SubstanceIngestion {
|
||||||
|
id: ingestion.substance_name.replace(" ", "_").to_uppercase(),
|
||||||
|
substance: None,
|
||||||
|
dose: {
|
||||||
|
if ingestion.estimate_standard_deviation.is_some() {
|
||||||
|
Dose::new_deviation(
|
||||||
|
ingestion.dose.unwrap(),
|
||||||
|
ingestion.estimate_standard_deviation.unwrap(),
|
||||||
|
)
|
||||||
|
} else if ingestion.is_estimate && ingestion.dose.is_some() {
|
||||||
|
Dose::new_estimate(ingestion.dose.unwrap())
|
||||||
|
} else if ingestion.dose.is_some() {
|
||||||
|
Dose::new_precise(ingestion.dose.unwrap())
|
||||||
|
} else {
|
||||||
|
Dose::new_unknown()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
custom_unit_id: ingestion.custom_unit_id,
|
||||||
|
|
||||||
|
roa: from_administration_route(ingestion.roa),
|
||||||
|
stomach_fullness: ingestion.stomach_fullness,
|
||||||
|
}),
|
||||||
|
|
||||||
|
consumer: match ingestion.consumer_name {
|
||||||
|
Some(name) => Consumer::Named(name),
|
||||||
|
None => Consumer::Default,
|
||||||
|
},
|
||||||
|
|
||||||
|
notes: ingestion.notes,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
journal.set_session_ingestions(session_id, ingestions);
|
journal.set_session_ingestions(session_id, ingestions);
|
||||||
|
|
|
@ -22,7 +22,6 @@ pub fn create_or_check_custom_substance(journal: &mut JournalType, custom_substa
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, clap::Args)]
|
#[derive(Debug, Clone, clap::Args)]
|
||||||
#[group(args = vec!["id", "name"], required = true, multiple = false)]
|
|
||||||
pub struct PsychonautImportCustomSubstanceArgs {
|
pub struct PsychonautImportCustomSubstanceArgs {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub import_global_args: PsychonautImportGlobalArgs,
|
pub import_global_args: PsychonautImportGlobalArgs,
|
||||||
|
@ -48,6 +47,7 @@ pub fn psychonaut_import_custom_substance(
|
||||||
create_or_check_custom_substance(
|
create_or_check_custom_substance(
|
||||||
&mut journal,
|
&mut journal,
|
||||||
Substance {
|
Substance {
|
||||||
|
id: custom_substance.name.replace(" ", "_").to_ascii_uppercase(),
|
||||||
name: custom_substance.name.clone(),
|
name: custom_substance.name.clone(),
|
||||||
description: custom_substance.description.clone(),
|
description: custom_substance.description.clone(),
|
||||||
unit: custom_substance.units,
|
unit: custom_substance.units,
|
||||||
|
|
|
@ -1,8 +1,46 @@
|
||||||
use journal::{journal::JournalType, types::CustomUnit};
|
use journal::{
|
||||||
|
journal::JournalType,
|
||||||
|
types::{CustomUnit, Dose},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{load_journal_and_export_data, PsychonautImportGlobalArgs};
|
use super::{
|
||||||
|
load_journal_and_export_data,
|
||||||
|
types::{from_administration_route, from_unix_millis},
|
||||||
|
PsychonautImportGlobalArgs,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn create_or_update_custom_unit(
|
||||||
|
journal: &mut JournalType,
|
||||||
|
custom_unit: psychonaut_journal_types::CustomUnit,
|
||||||
|
) {
|
||||||
|
let unit = CustomUnit {
|
||||||
|
id: custom_unit.id,
|
||||||
|
name: custom_unit.name,
|
||||||
|
substance_name: custom_unit.substance_name,
|
||||||
|
unit: custom_unit.unit,
|
||||||
|
original_unit: custom_unit.original_unit,
|
||||||
|
|
||||||
|
dose: {
|
||||||
|
if custom_unit.estimate_standard_deviation.is_some() {
|
||||||
|
Dose::new_deviation(
|
||||||
|
custom_unit.dose.unwrap(),
|
||||||
|
custom_unit.estimate_standard_deviation.unwrap(),
|
||||||
|
)
|
||||||
|
} else if custom_unit.is_estimate && custom_unit.dose.is_some() {
|
||||||
|
Dose::new_estimate(custom_unit.dose.unwrap())
|
||||||
|
} else if custom_unit.dose.is_some() {
|
||||||
|
Dose::new_precise(custom_unit.dose.unwrap())
|
||||||
|
} else {
|
||||||
|
Dose::new_unknown()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
administration_route: from_administration_route(custom_unit.administration_route),
|
||||||
|
|
||||||
|
creation_time: from_unix_millis(custom_unit.creation_time),
|
||||||
|
is_archived: custom_unit.is_archived,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn create_or_update_custom_unit(journal: &mut JournalType, unit: CustomUnit) {
|
|
||||||
match journal.get_custom_unit(unit.id) {
|
match journal.get_custom_unit(unit.id) {
|
||||||
Some(custom_unit) => {
|
Some(custom_unit) => {
|
||||||
println!(
|
println!(
|
||||||
|
@ -44,7 +82,7 @@ pub fn psychonaut_import_custom_unit(
|
||||||
|
|
||||||
match unit {
|
match unit {
|
||||||
Some(unit) => {
|
Some(unit) => {
|
||||||
create_or_update_custom_unit(&mut journal, CustomUnit::from(unit));
|
create_or_update_custom_unit(&mut journal, unit);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
panic!("Could not find custom unit with ID: {id}")
|
panic!("Could not find custom unit with ID: {id}")
|
||||||
|
@ -59,7 +97,7 @@ pub fn psychonaut_import_custom_unit(
|
||||||
|
|
||||||
match unit {
|
match unit {
|
||||||
Some(unit) => {
|
Some(unit) => {
|
||||||
create_or_update_custom_unit(&mut journal, CustomUnit::from(unit));
|
create_or_update_custom_unit(&mut journal, unit);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
panic!("Could not find custom unit with name: {name}")
|
panic!("Could not find custom unit with name: {name}")
|
||||||
|
|
36
journal_cli/src/commands/psychonaut/import/types.rs
Normal file
36
journal_cli/src/commands/psychonaut/import/types.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
|
use journal::types::AdministrationRoute;
|
||||||
|
|
||||||
|
pub fn from_unix_millis(time: u64) -> DateTime<Utc> {
|
||||||
|
Utc.timestamp_millis_opt(time as i64).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_administration_route(
|
||||||
|
roa: psychonaut_journal_types::AdministrationRoute,
|
||||||
|
) -> AdministrationRoute {
|
||||||
|
match roa {
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Oral => AdministrationRoute::Oral,
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Sublingual => {
|
||||||
|
AdministrationRoute::Sublingual
|
||||||
|
}
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Buccal => AdministrationRoute::Buccal,
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Insufflated => {
|
||||||
|
AdministrationRoute::Insufflated
|
||||||
|
}
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Rectal => AdministrationRoute::Rectal,
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Transdermal => {
|
||||||
|
AdministrationRoute::Transdermal
|
||||||
|
}
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Subcutaneous => {
|
||||||
|
AdministrationRoute::Subcutaneous
|
||||||
|
}
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Intramuscular => {
|
||||||
|
AdministrationRoute::Intramuscular
|
||||||
|
}
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Intravenous => {
|
||||||
|
AdministrationRoute::Intravenous
|
||||||
|
}
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Smoked => AdministrationRoute::Smoked,
|
||||||
|
psychonaut_journal_types::AdministrationRoute::Inhaled => AdministrationRoute::Inhaled,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
use journal::{
|
use journal::{
|
||||||
journal::JournalType,
|
journal::JournalType,
|
||||||
types::{
|
types::{
|
||||||
format_dose, Consumer, Dose, Ingestion, IngestionKind, IngestionKinds, Session,
|
format_dose, Consumer, Ingestion, IngestionKind, Session, SubstanceIngestion,
|
||||||
SubstanceIngestion, SustenanceIngestion,
|
SustenanceIngestion,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,7 +17,11 @@ fn print_substance_ingestion(
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Substance|{}|{}|{}|{}|{}",
|
"Substance|{}|{}|{}|{}|{}",
|
||||||
substance_ingestion.substance_name,
|
substance_ingestion
|
||||||
|
.substance
|
||||||
|
.as_ref()
|
||||||
|
.expect("substance_ingestion not provided with a substance")
|
||||||
|
.name,
|
||||||
format_dose(&substance_ingestion.dose, &unit),
|
format_dose(&substance_ingestion.dose, &unit),
|
||||||
format_substance_ingestion_roa(substance_ingestion, &unit),
|
format_substance_ingestion_roa(substance_ingestion, &unit),
|
||||||
ingestion.consumer,
|
ingestion.consumer,
|
||||||
|
@ -30,9 +34,7 @@ fn print_sustenance_ingestion(
|
||||||
ingestion: &Ingestion,
|
ingestion: &Ingestion,
|
||||||
sustenance_ingestion: &SustenanceIngestion,
|
sustenance_ingestion: &SustenanceIngestion,
|
||||||
) {
|
) {
|
||||||
let sustenance = journal
|
let sustenance = journal.get_sustenance(&sustenance_ingestion.id).unwrap();
|
||||||
.get_sustenance(&sustenance_ingestion.sustenance_id)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Sustenance|{}|{} {}|{}|{}",
|
"Sustenance|{}|{} {}|{}|{}",
|
||||||
|
@ -44,35 +46,7 @@ fn print_sustenance_ingestion(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_ingestion_kinds(kind: &mut IngestionKinds) {
|
pub fn print_ingestion(journal: &JournalType, ingestion: &Ingestion, depth: u64) {
|
||||||
//println!("{kind:#?}");
|
|
||||||
|
|
||||||
if let IngestionKind::Sustenance(sustenance) = &kind.ingestion {
|
|
||||||
for kinds in kind.includes.iter_mut() {
|
|
||||||
match &mut kinds.ingestion {
|
|
||||||
IngestionKind::Substance(ingestion) => {
|
|
||||||
ingestion.dose = Dose::new_precise(sustenance.amount) * ingestion.dose.clone();
|
|
||||||
}
|
|
||||||
IngestionKind::Sustenance(ingestion) => {
|
|
||||||
ingestion.amount *= sustenance.amount;
|
|
||||||
|
|
||||||
calculate_ingestion_kinds(kinds)
|
|
||||||
}
|
|
||||||
IngestionKind::Hydration { amount } => {
|
|
||||||
*amount = (sustenance.amount * *amount as f64).round() as u64
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_ingestion_kinds(
|
|
||||||
journal: &JournalType,
|
|
||||||
ingestion: &Ingestion,
|
|
||||||
kinds: &IngestionKinds,
|
|
||||||
depth: u64,
|
|
||||||
) {
|
|
||||||
for _ in 0..(depth) {
|
for _ in 0..(depth) {
|
||||||
print!(" ");
|
print!(" ");
|
||||||
}
|
}
|
||||||
|
@ -80,27 +54,35 @@ pub fn print_ingestion_kinds(
|
||||||
print!("- ");
|
print!("- ");
|
||||||
}
|
}
|
||||||
|
|
||||||
match &kinds.ingestion {
|
match &ingestion.kind {
|
||||||
IngestionKind::Unknown => {}
|
IngestionKind::Unknown => {}
|
||||||
IngestionKind::Substance(substance_ingestion) => {
|
IngestionKind::Substance(substance) => {
|
||||||
print_substance_ingestion(journal, ingestion, substance_ingestion);
|
print_substance_ingestion(journal, ingestion, &substance);
|
||||||
}
|
}
|
||||||
IngestionKind::Sustenance(sustenance_ingestion) => {
|
IngestionKind::Sustenance(sustenance) => {
|
||||||
print_sustenance_ingestion(journal, ingestion, sustenance_ingestion);
|
print_sustenance_ingestion(journal, ingestion, sustenance);
|
||||||
|
let sustenance = sustenance.sustenance.as_ref().unwrap();
|
||||||
|
|
||||||
|
for include in &sustenance.includes {
|
||||||
|
print_ingestion(
|
||||||
|
journal,
|
||||||
|
&Ingestion {
|
||||||
|
kind: include.clone(),
|
||||||
|
..ingestion.clone()
|
||||||
|
},
|
||||||
|
depth + 1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
IngestionKind::Hydration { amount } => {
|
}
|
||||||
|
IngestionKind::Hydration(hydration) => {
|
||||||
println!(
|
println!(
|
||||||
"Hydration|{} ml|{}|{}",
|
"Hydration|{}|{}|{}",
|
||||||
amount,
|
hydration,
|
||||||
ingestion.consumer,
|
ingestion.consumer,
|
||||||
format_ingestion_time(ingestion)
|
format_ingestion_time(ingestion)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for kinds in &kinds.includes {
|
|
||||||
print_ingestion_kinds(journal, ingestion, kinds, depth + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_ingestion_log(
|
pub fn print_ingestion_log(
|
||||||
|
@ -108,22 +90,23 @@ pub fn print_ingestion_log(
|
||||||
session: &Session,
|
session: &Session,
|
||||||
consumer_filter: Option<&Vec<Consumer>>,
|
consumer_filter: Option<&Vec<Consumer>>,
|
||||||
) {
|
) {
|
||||||
let ingestions = journal
|
let mut ingestions = journal
|
||||||
.get_session_ingestions(session.id)
|
.get_session_ingestions(session.id)
|
||||||
.expect("could not find ingestions for session");
|
.expect("could not find ingestions for session");
|
||||||
|
|
||||||
for ingestion in ingestions.iter() {
|
for ingestion in ingestions.iter_mut() {
|
||||||
if let Some(consumer_filter) = consumer_filter {
|
if let Some(consumer_filter) = consumer_filter {
|
||||||
if !consumer_filter.contains(&ingestion.consumer) {
|
if !consumer_filter.contains(&ingestion.consumer) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ingestion_kinds = journal
|
ingestion.kind = journal
|
||||||
.resolve_ingestion_kind(&ingestion.kind, true)
|
.resolve_ingestion_kind(ingestion.kind.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{ingestion_kinds:#?}");
|
|
||||||
|
|
||||||
print_ingestion_kinds(journal, ingestion, &ingestion_kinds, 0)
|
//let calculated_values = calculate_ingestion_kinds(ingestion_kinds);
|
||||||
|
|
||||||
|
print_ingestion(journal, ingestion, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue