mirror of
https://github.com/xqtc161/meowlog.git
synced 2024-11-21 17:30:34 +01:00
this codebase redefines spaghetti holy fuck
This commit is contained in:
parent
8447e89f19
commit
ab8ac79434
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/target
|
||||
.idea
|
||||
|
|
35
Cargo.lock
generated
35
Cargo.lock
generated
|
@ -187,6 +187,15 @@ dependencies = [
|
|||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.5.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.18"
|
||||
|
@ -400,6 +409,12 @@ version = "1.70.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.70"
|
||||
|
@ -450,10 +465,12 @@ dependencies = [
|
|||
"bincode",
|
||||
"chrono",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"color-eyre",
|
||||
"inquire",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"toml",
|
||||
|
@ -588,6 +605,12 @@ version = "1.0.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
@ -614,6 +637,18 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
|
|
|
@ -11,7 +11,11 @@ color-eyre = "0.6.3"
|
|||
inquire = "0.7.5"
|
||||
lazy_static = "1.5.0"
|
||||
serde = { version = "1.0.210", features = ["derive"] }
|
||||
serde_json = "1.0.128"
|
||||
strum = { version = "0.26.3", features = ["derive"] }
|
||||
strum_macros = "0.26.4"
|
||||
toml = "0.8.19"
|
||||
uuid = { version = "1.10.0", features = ["serde", "v4"] }
|
||||
|
||||
[build-dependencies]
|
||||
clap_complete = "4.5.33"
|
||||
|
|
BIN
ingestions.bin
BIN
ingestions.bin
Binary file not shown.
|
@ -39,4 +39,5 @@ lazy_static! {
|
|||
format!("{}/substances.bin", LOCAL_PATH.to_string()).to_string();
|
||||
pub static ref INGESTIONS_FILE: String =
|
||||
format!("{}/ingestions.bin", LOCAL_PATH.to_string()).to_string();
|
||||
// pub static ref DRUGS: crate::drug_parser::Drugs = drug_parser::parse_drugs_json("drugs.json").unwrap();
|
||||
}
|
||||
|
|
|
@ -1,30 +1,41 @@
|
|||
use crate::ingestions_util::{
|
||||
ensure_ingestion_files, get_dose_unit, get_ingestion_confirmation, get_ingestion_method,
|
||||
get_substance, get_user_datetime,
|
||||
get_substance, get_user_date, get_user_time,
|
||||
};
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::{NaiveDate, NaiveTime, Utc};
|
||||
use inquire;
|
||||
use serde::{self, Deserialize, Serialize};
|
||||
use std::cmp::PartialEq;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Formatter;
|
||||
use std::process::exit;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::config::INGESTIONS_FILE;
|
||||
use crate::substances::Substance;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct Ingestion {
|
||||
pub substance: String,
|
||||
pub substance: Substance,
|
||||
pub dose: Dose,
|
||||
pub ingestion_method: IngestionMethod,
|
||||
pub time: NaiveDateTime,
|
||||
pub time: NaiveTime,
|
||||
pub date: NaiveDate,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
impl std::fmt::Display for Ingestion {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} {} {} {}{}", self.date, self.time.format("%H:%M"), self.substance.name, self.dose.value, self.dose.unit)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Dose {
|
||||
pub unit: String,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, strum::Display, strum::EnumIter)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, strum::Display, strum::EnumIter)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum DoseUnit {
|
||||
Ug,
|
||||
|
@ -33,7 +44,7 @@ pub enum DoseUnit {
|
|||
Ml,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, strum::Display, strum::EnumIter)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, strum::Display, strum::EnumIter, PartialEq)]
|
||||
pub enum IngestionMethod {
|
||||
Oral,
|
||||
Sublingual,
|
||||
|
@ -55,7 +66,9 @@ pub fn add_ingestion() {
|
|||
|
||||
let ingestion_method = get_ingestion_method();
|
||||
|
||||
let time: NaiveDateTime = get_user_datetime();
|
||||
let current_datetime = Utc::now().naive_utc();
|
||||
let date: NaiveDate = get_user_date(current_datetime);
|
||||
let time: NaiveTime = get_user_time(current_datetime);
|
||||
let dose_num: f64 = inquire::prompt_f64("Enter the amount consumed:").unwrap();
|
||||
let dose_unit: DoseUnit = get_dose_unit();
|
||||
|
||||
|
@ -68,6 +81,7 @@ pub fn add_ingestion() {
|
|||
substance,
|
||||
dose,
|
||||
ingestion_method,
|
||||
date,
|
||||
time,
|
||||
};
|
||||
|
||||
|
@ -83,11 +97,11 @@ pub fn add_ingestion() {
|
|||
|
||||
pub fn list_ingestions() -> Result<(), std::io::Error> {
|
||||
let ing_read = std::fs::read(INGESTIONS_FILE.to_string()).unwrap();
|
||||
let ing_dec: HashMap<Uuid, Ingestion> = bincode::deserialize(&ing_read).unwrap();
|
||||
for (id, ingestion) in ing_dec.clone().into_iter() {
|
||||
let ing_des: HashMap<Uuid, Ingestion> = bincode::deserialize(&ing_read).unwrap();
|
||||
for (id, ingestion) in ing_des.clone().into_iter() {
|
||||
println!(
|
||||
"Substance: {} ({})\nDose: {} {}\nTime: {}\nUUID: {:?}\n",
|
||||
ingestion.substance,
|
||||
ingestion.substance.name,
|
||||
ingestion.ingestion_method,
|
||||
ingestion.dose.value,
|
||||
ingestion.dose.unit,
|
||||
|
@ -99,6 +113,137 @@ pub fn list_ingestions() -> Result<(), std::io::Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn edit_ingestion() -> Result<(), std::io::Error> {
|
||||
let ing_des = ensure_ingestion_files();
|
||||
if ing_des.is_empty() {
|
||||
eprintln!("No ingestions to edit!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let mut ingest_sel_vec_id: Vec<Uuid> = Vec::new();
|
||||
let mut ingest_sel_vec_ing: Vec<Ingestion> = Vec::new();
|
||||
|
||||
|
||||
for ingestion in ing_des.clone().into_iter() {
|
||||
ingest_sel_vec_id.push(ingestion.0);
|
||||
ingest_sel_vec_ing.push(ingestion.1);
|
||||
}
|
||||
|
||||
let ingest_select = inquire::Select::new("Which ingestion do you want to edit?", ingest_sel_vec_ing).prompt().unwrap();
|
||||
let ing_id = ing_des.iter()
|
||||
.map(|(key, &ref val)| if val.substance.name == ingest_select.substance.name && val.substance.substance_class == ingest_select.substance.substance_class && val.date == ingest_select.date && val.time == ingest_select.time { key.clone() } else { unreachable!() }).collect::<Vec<Uuid>>();
|
||||
|
||||
let edit_select = inquire::MultiSelect::new("What do you want to edit?", vec!["Substance", "Dose", "Ingestion Method", "Time", "Date"]).prompt().unwrap();
|
||||
|
||||
for edit in edit_select {
|
||||
match edit {
|
||||
"Substance" => {
|
||||
let substance = get_substance();
|
||||
let ingestion = Ingestion {
|
||||
substance,
|
||||
dose: ingest_select.dose.clone(),
|
||||
ingestion_method: ingest_select.ingestion_method.clone(),
|
||||
time: ingest_select.time,
|
||||
date: ingest_select.date,
|
||||
};
|
||||
let confirm = get_ingestion_confirmation(ingestion.clone());
|
||||
if confirm {
|
||||
let mut ing_des = ensure_ingestion_files();
|
||||
ing_des.insert(ing_id[0], ingestion.clone());
|
||||
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
|
||||
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
|
||||
} else {
|
||||
edit_ingestion();
|
||||
}
|
||||
}
|
||||
"Dose" => {
|
||||
let dose_num: f64 = inquire::prompt_f64("Enter the amount consumed:").unwrap();
|
||||
let dose_unit: DoseUnit = get_dose_unit();
|
||||
let dose = Dose {
|
||||
unit: dose_unit.to_string(),
|
||||
value: dose_num,
|
||||
};
|
||||
let ingestion = Ingestion {
|
||||
substance: ingest_select.substance.clone(),
|
||||
dose,
|
||||
ingestion_method: ingest_select.ingestion_method.clone(),
|
||||
time: ingest_select.time,
|
||||
date: ingest_select.date,
|
||||
};
|
||||
let confirm = get_ingestion_confirmation(ingestion.clone());
|
||||
if confirm {
|
||||
let mut ing_des = ensure_ingestion_files();
|
||||
ing_des.insert(ing_id[0], ingestion.clone());
|
||||
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
|
||||
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
|
||||
} else {
|
||||
edit_ingestion();
|
||||
}
|
||||
}
|
||||
"Ingestion Method" => {
|
||||
let ingestion_method = get_ingestion_method();
|
||||
let ingestion = Ingestion {
|
||||
substance: ingest_select.substance.clone(),
|
||||
dose: ingest_select.dose.clone(),
|
||||
ingestion_method,
|
||||
time: ingest_select.time,
|
||||
date: ingest_select.date,
|
||||
};
|
||||
let confirm = get_ingestion_confirmation(ingestion.clone());
|
||||
if confirm {
|
||||
let mut ing_des = ensure_ingestion_files();
|
||||
ing_des.insert(ing_id[0], ingestion.clone());
|
||||
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
|
||||
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
|
||||
} else {
|
||||
edit_ingestion();
|
||||
}
|
||||
}
|
||||
"Time" => {
|
||||
let time: NaiveTime = get_user_time(Utc::now().naive_utc());
|
||||
let ingestion = Ingestion {
|
||||
substance: ingest_select.substance.clone(),
|
||||
dose: ingest_select.dose.clone(),
|
||||
ingestion_method: ingest_select.ingestion_method.clone(),
|
||||
time,
|
||||
date: ingest_select.date,
|
||||
};
|
||||
let confirm = get_ingestion_confirmation(ingestion.clone());
|
||||
if confirm {
|
||||
let mut ing_des = ensure_ingestion_files();
|
||||
ing_des.insert(ing_id[0], ingestion.clone());
|
||||
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
|
||||
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
|
||||
} else {
|
||||
edit_ingestion();
|
||||
}
|
||||
}
|
||||
"Date" => {
|
||||
let date: NaiveDate = get_user_date(Utc::now().naive_utc());
|
||||
let ingestion = Ingestion {
|
||||
substance: ingest_select.substance.clone(),
|
||||
dose: ingest_select.dose.clone(),
|
||||
ingestion_method: ingest_select.ingestion_method.clone(),
|
||||
time: ingest_select.time,
|
||||
date,
|
||||
};
|
||||
let confirm = get_ingestion_confirmation(ingestion.clone());
|
||||
if confirm {
|
||||
let mut ing_des = ensure_ingestion_files();
|
||||
ing_des.insert(ing_id[0], ingestion.clone());
|
||||
let ingestion_ser = bincode::serialize(&ing_des).unwrap();
|
||||
std::fs::write(INGESTIONS_FILE.to_string(), ingestion_ser).unwrap();
|
||||
} else {
|
||||
edit_ingestion();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_ingestions_file() -> Result<(), std::io::Error> {
|
||||
let hash: HashMap<Uuid, Ingestion> = HashMap::new();
|
||||
let hash_ser = bincode::serialize(&hash).unwrap();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::config::INGESTIONS_FILE;
|
||||
use crate::ingestions::{DoseUnit, Ingestion, IngestionMethod};
|
||||
use crate::substances::Substance;
|
||||
use crate::util::path_exists;
|
||||
use chrono::Utc;
|
||||
use chrono::NaiveDateTime;
|
||||
use inquire;
|
||||
use std::{collections::HashMap, process::exit};
|
||||
use strum::IntoEnumIterator;
|
||||
|
@ -10,8 +11,8 @@ use uuid::Uuid;
|
|||
pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
|
||||
let ingesstions_bytes_loaded_des: HashMap<Uuid, Ingestion>;
|
||||
if path_exists(INGESTIONS_FILE.to_string()) {
|
||||
let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).unwrap();
|
||||
ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).unwrap();
|
||||
let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).expect("Could not read ingestions file");
|
||||
ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).expect("Could not deserialize ingestions file. If you are tech-savvy try fixing it with a hex editor.");
|
||||
} else {
|
||||
std::fs::File::create(INGESTIONS_FILE.to_string()).unwrap();
|
||||
ingesstions_bytes_loaded_des = HashMap::new();
|
||||
|
@ -22,21 +23,39 @@ pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
|
|||
ingesstions_bytes_loaded_des
|
||||
}
|
||||
|
||||
pub fn get_user_datetime() -> chrono::NaiveDateTime {
|
||||
let current_time = Utc::now().naive_utc();
|
||||
let date_time: chrono::NaiveDateTime = inquire::CustomType::<chrono::NaiveDateTime>::new(
|
||||
"Enter the date and time (YYYY-MM-DD HH:MM):",
|
||||
pub fn get_user_date(current: NaiveDateTime) -> chrono::NaiveDate {
|
||||
let current_time = current.time();
|
||||
let current_date = current.date();
|
||||
let date: chrono::NaiveDate = inquire::CustomType::<chrono::NaiveDate>::new(
|
||||
"Enter the date (YYYY-MM-DD):",
|
||||
)
|
||||
.with_placeholder("YYYY-MM-DD HH:MM")
|
||||
.with_default(current_time)
|
||||
.with_placeholder("YYYY-MM-DD")
|
||||
.with_default(current_date)
|
||||
.with_parser(&|input| {
|
||||
chrono::NaiveDateTime::parse_from_str(input, "%Y-%m-%d %H:%M").map_err(|_| ())
|
||||
chrono::NaiveDate::parse_from_str(input, "%Y-%m-%d").map_err(|_| ())
|
||||
})
|
||||
.with_error_message("Please enter a valid date and time in the format YYYY-MM-DD HH:MM.")
|
||||
.with_help_message("Use the format YYYY-MM-DD HH:MM")
|
||||
.with_error_message("Please enter a valid date and time in the format YYYY-MM-DD")
|
||||
.with_help_message("Use the format YYYY-MM-DD")
|
||||
.prompt()
|
||||
.unwrap();
|
||||
date_time
|
||||
date
|
||||
}
|
||||
|
||||
pub fn get_user_time(current: NaiveDateTime) -> chrono::NaiveTime {
|
||||
let current_time = current.time();
|
||||
let time: chrono::NaiveTime = inquire::CustomType::<chrono::NaiveTime>::new(
|
||||
"Enter the time (HH:MM):",
|
||||
)
|
||||
.with_placeholder("HH:MM")
|
||||
.with_default(current_time)
|
||||
.with_parser(&|input| {
|
||||
chrono::NaiveTime::parse_from_str(input, "%H:%M").map_err(|_| ())
|
||||
})
|
||||
.with_error_message("Please enter a valid time in the format HH:MM.")
|
||||
.with_help_message("Use the format HH:MM")
|
||||
.prompt()
|
||||
.unwrap();
|
||||
time
|
||||
}
|
||||
|
||||
pub fn get_dose_unit() -> DoseUnit {
|
||||
|
@ -49,15 +68,30 @@ pub fn get_dose_unit() -> DoseUnit {
|
|||
dose_unit
|
||||
}
|
||||
|
||||
pub fn get_substance() -> String {
|
||||
pub fn get_substance() -> Substance {
|
||||
let substances = crate::substance_util::substances_to_vec();
|
||||
if substances.is_empty() {
|
||||
eprintln!("Add a substance before you log an ingestions");
|
||||
exit(1)
|
||||
}
|
||||
let substance = inquire::Select::new("What did yout ingest?", substances)
|
||||
let substance_select = inquire::Select::new("What did yout ingest?", substances)
|
||||
.prompt()
|
||||
.unwrap();
|
||||
|
||||
let substance_file: HashMap<Uuid, Substance> = crate::substance_util::ensure_substance_file();
|
||||
let substances: Vec<Substance> = substance_file
|
||||
.into_iter()
|
||||
.filter_map(|(_, s)| if s.name == substance_select { Some(s) } else { None })
|
||||
.collect();
|
||||
|
||||
if substances.len() != 1 {
|
||||
eprintln!("Substance not found or multiple substances with the same name.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let substance = substances.into_iter().next().unwrap();
|
||||
dbg!(&substance);
|
||||
|
||||
substance
|
||||
}
|
||||
|
||||
|
@ -74,7 +108,7 @@ pub fn get_ingestion_method() -> IngestionMethod {
|
|||
pub fn get_ingestion_confirmation(ingestion: Ingestion) -> bool {
|
||||
println!(
|
||||
"Substance: {} ({})\nDose: {}{}\nTime: {}\n",
|
||||
ingestion.substance,
|
||||
ingestion.substance.name,
|
||||
ingestion.ingestion_method,
|
||||
ingestion.dose.value,
|
||||
ingestion.dose.unit,
|
||||
|
|
|
@ -11,6 +11,8 @@ mod ingestions_util;
|
|||
mod substance_util;
|
||||
mod substances;
|
||||
|
||||
// mod drug_parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(propagate_version = true)]
|
||||
|
@ -53,7 +55,7 @@ fn main() {
|
|||
|
||||
match &cli.command {
|
||||
Some(Commands::AddIngestion) => ingestions::add_ingestion(),
|
||||
Some(Commands::EditIngestion) => {}
|
||||
Some(Commands::EditIngestion) => {ingestions::edit_ingestion().unwrap()}
|
||||
Some(Commands::ListIngestions) => ingestions::list_ingestions().unwrap(),
|
||||
Some(Commands::RemoveIngestion) => {}
|
||||
Some(Commands::AddSubstance) => substances::add_substance().unwrap(),
|
||||
|
|
|
@ -6,7 +6,7 @@ use uuid::Uuid;
|
|||
use crate::config::SUBSTANCES_FILE;
|
||||
use crate::substance_util::{ensure_substance_file, get_substance_class, substances_to_vec};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct Substance {
|
||||
pub name: String,
|
||||
pub substance_class: SubstanceClass,
|
||||
|
@ -25,6 +25,11 @@ pub enum SubstanceClass {
|
|||
Neurotransmitter,
|
||||
}
|
||||
|
||||
impl PartialEq for SubstanceClass {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::mem::discriminant(self) == std::mem::discriminant(other)
|
||||
}
|
||||
}
|
||||
pub fn add_substance() -> Result<(), std::io::Error> {
|
||||
let mut substances_bytes_loaded_des: HashMap<Uuid, Substance> = ensure_substance_file();
|
||||
let name = inquire::prompt_text("What is the substances name?").unwrap();
|
||||
|
|
BIN
substances.bin
BIN
substances.bin
Binary file not shown.
24921
substances.json
24921
substances.json
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue