use std::{ collections::HashMap, fs::File, io::{BufReader, BufWriter}, path::PathBuf, }; use std::io::Write; use clap::{command, Parser}; pub use commands::Commands; use log::info; use schemars::schema_for; use crate::{ create_products::InputFile, graph::{Graph, RunnableGraph}, SourceType, }; mod commands; #[derive(Parser)] #[command(name = "coster-rs")] #[command(author = "Pivato M. ")] #[command(version = "0.0.1")] #[command(about = "Simple, fast, efficient costing tool", long_about = None)] pub struct Cli { #[clap(subcommand)] pub command: Commands, } impl Cli { pub fn run(self) -> anyhow::Result<()> { match self.command { Commands::MoveMoney { rules, lines, accounts, cost_centres, output, use_numeric_accounts, flush_pass, } => crate::move_money( &mut csv::Reader::from_path(rules)?, &mut csv::Reader::from_path(lines)?, &mut csv::Reader::from_path(accounts)?, &mut csv::Reader::from_path(cost_centres)?, &mut csv::Writer::from_path(output.unwrap_or(PathBuf::from("output.csv")))?, use_numeric_accounts, flush_pass, ), Commands::AllocateOverheads { lines, accounts, allocation_statistics, areas, cost_centres, use_numeric_accounts, account_type, exclude_negative_allocation_statistics, show_from, zero_threshold, output, msgpack_serialisation, } => { if msgpack_serialisation { let mut file = BufWriter::new(File::create(output)?); crate::reciprocal_allocation( &mut csv::Reader::from_path(lines)?, &mut csv::Reader::from_path(accounts)?, &mut csv::Reader::from_path(allocation_statistics)?, &mut csv::Reader::from_path(areas)?, &mut csv::Reader::from_path(cost_centres)?, &mut rmp_serde::Serializer::new(&mut file), use_numeric_accounts, exclude_negative_allocation_statistics, true, account_type, show_from, zero_threshold, ) } else { crate::reciprocal_allocation( &mut csv::Reader::from_path(lines)?, &mut csv::Reader::from_path(accounts)?, &mut csv::Reader::from_path(allocation_statistics)?, &mut csv::Reader::from_path(areas)?, &mut csv::Reader::from_path(cost_centres)?, &mut csv::Writer::from_path(output)?, use_numeric_accounts, exclude_negative_allocation_statistics, true, account_type, show_from, zero_threshold, ) } } Commands::CreateProducts { definitions, encounters, services, transfers, procedures, diagnoses, patients, revenues, output, } => { let mut inputs = HashMap::new(); inputs.insert( SourceType::Encounter, InputFile { file_path: encounters, joins: HashMap::new(), date_order_column: Some("StartDateTime".to_owned()), }, ); inputs.insert( SourceType::Service, InputFile { file_path: services, joins: HashMap::new(), date_order_column: Some("StartDateTime".to_owned()), }, ); inputs.insert( SourceType::Transfer, InputFile { file_path: transfers, joins: HashMap::new(), date_order_column: Some("StartDateTime".to_owned()), }, ); inputs.insert( SourceType::CodingProcedure, InputFile { file_path: procedures, joins: HashMap::new(), date_order_column: Some("ProcedureDateTime".to_owned()), }, ); inputs.insert( SourceType::CodingDiagnosis, InputFile { file_path: diagnoses, joins: HashMap::new(), date_order_column: None, }, ); inputs.insert( SourceType::Patient, InputFile { file_path: patients, joins: HashMap::new(), date_order_column: None, }, ); inputs.insert( SourceType::Revenue, InputFile { file_path: revenues, joins: HashMap::new(), date_order_column: None, }, ); crate::create_products::create_products_polars(definitions, vec![], output) } Commands::RunGraph { graph, threads } => { let file = File::open(graph)?; let reader = BufReader::new(file); let graph = serde_json::from_reader(reader)?; let graph = RunnableGraph::from_graph(graph); // TODO: Possible to await here? graph.run_default_tasks(threads, |id, status| { info!("Node with id {} finished with status {:?}", id, status) }); Ok(()) } Commands::GenerateSchema { output } => { let schema = schema_for!(Graph); let mut output = File::create(output).unwrap(); write!(output, "{}", serde_json::to_string_pretty(&schema).unwrap())?; Ok(()) } } } }