aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjvech <jmvalenciae@unal.edu.co>2024-04-23 07:52:28 -0500
committerjvech <jmvalenciae@unal.edu.co>2024-04-23 07:52:28 -0500
commita5dfd2627853bd67e9d17ef870fc84be312b1397 (patch)
tree85e005be5e96916f2d45d85a703ff2717ed28c51 /src
add: first commit done
Diffstat (limited to 'src')
-rw-r--r--src/cli.rs81
-rw-r--r--src/database.rs68
-rw-r--r--src/main.rs48
3 files changed, 197 insertions, 0 deletions
diff --git a/src/cli.rs b/src/cli.rs
new file mode 100644
index 0000000..0bd0a78
--- /dev/null
+++ b/src/cli.rs
@@ -0,0 +1,81 @@
+use std::path::PathBuf;
+use clap::{Subcommand, Parser, ValueHint};
+use std::env;
+
+#[derive(Debug, Parser)]
+#[command(version, about, long_about = None)]
+pub struct Cli {
+ /// file path where data is stored [default:
+ /// $XDG_DATA_HOME/debt/debt.db
+ #[arg(short, long, env="DEBT_DB", value_hint = ValueHint::FilePath)]
+ pub database_path: Option<PathBuf>,
+
+ #[command(subcommand)]
+ pub action: Commands
+}
+
+#[derive(Debug, Subcommand)]
+pub enum Commands {
+ /// Initialize Database
+ Init,
+ /// Register a transaction
+ Register {
+ /// person to register the transaction
+ person: String,
+
+ /// amount of money
+ amount: i32,
+
+ /// additional notes
+ note: Option<String>,
+
+ /// Register the transaction as a payment
+ #[arg(short, long)]
+ payment: bool
+ },
+
+ View {
+ filter: Option<String>,
+ /// View register history
+ #[arg(short='H', long)]
+ history: bool,
+ /// Transaction accumulation by person
+ #[arg(short, long)]
+ total: bool
+ },
+
+ /// Add a new agent to lend or pay
+ Add {
+ name: String,
+ },
+}
+
+impl Cli {
+ pub fn new() -> Self {
+ let mut cli = Cli::parse();
+ load_datapath(&mut cli);
+ cli
+ }
+}
+
+fn load_datapath(cli: &mut Cli) {
+ let config_path = cli
+ .database_path
+ .clone()
+ .or_else(|| {
+ xdg::BaseDirectories::with_prefix("debt")
+ .ok()
+ .and_then(|x| {
+ x.find_data_file("cache.db")
+ })
+ }).or_else(|| {
+ if let Ok(home) = env::var("HOME") {
+ let fallback = PathBuf::from(&home).join(".debt.db");
+ if fallback.exists() {
+ return Some(fallback)
+ }
+ }
+ None
+ });
+ cli.database_path = config_path;
+}
diff --git a/src/database.rs b/src/database.rs
new file mode 100644
index 0000000..6a7bde0
--- /dev/null
+++ b/src/database.rs
@@ -0,0 +1,68 @@
+use rusqlite::Connection;
+use rusqlite::Result;
+use chrono::Utc;
+use std::path::PathBuf;
+
+pub struct Database {
+ date: i64,
+ person: String,
+ amount: i32,
+ note: Option<String>,
+}
+
+impl Database {
+ pub fn new(person: String, amount: i32, note: Option<String>, is_debt: bool) -> Database {
+ Database {
+ date: Utc::now().timestamp(),
+ amount: if !is_debt {amount} else {-amount},
+ person,
+ note,
+ }
+ }
+
+ pub fn add_register(&self, filepath: &PathBuf) -> Result<()> {
+ let conn = Connection::open(filepath)?;
+ conn.execute("PRAGMA foreign_key=1", ())?;
+ conn.execute("
+ INSERT INTO Registers (agent_id, register_date, amount, note)
+ VALUES (
+ (SELECT id FROM Agents WHERE name=?1),
+ ?2, ?3, ?4)",
+ (&self.person,
+ &self.date,
+ self.amount,
+ &self.note))?;
+ println!("Register added successfully");
+ Ok(())
+ }
+
+ pub fn add_agent(&self, filepath: &PathBuf) -> Result<()> {
+ let conn = Connection::open(filepath)?;
+ conn.execute("
+ INSERT INTO Agents (name)
+ VALUES (?1)", (&self.person,))?;
+ println!("agent '{}' successfully", &self.person);
+ Ok(())
+ }
+
+ pub fn init_database(filepath: &PathBuf) -> Result<()> {
+ let conn = Connection::open(filepath).expect("Database file creation Error");
+ conn.execute("
+ CREATE TABLE Agents (
+ id INTEGER PRIMARY KEY,
+ name TEXT NOT NULL UNIQUE)", ())
+ .expect("SQL initialization error");
+
+ conn.execute("
+ CREATE TABLE Registers (
+ id INTEGER PRIMARY KEY,
+ agent_id INTEGER,
+ register_date INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ note TEXT,
+ FOREIGN KEY(agent_id) REFERENCES Agents(id))", ())
+ .expect("SQL initialization error");
+ println!("'{}' database created", &filepath.display());
+ Ok(())
+ }
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..8ef62b3
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,48 @@
+use xdg;
+use rusqlite::Result;
+
+mod database;
+mod cli;
+
+use cli::{Cli, Commands};
+use crate::database::Database;
+
+fn main() -> Result<()> {
+ let cli = Cli::new();
+ match cli.action {
+ Commands::Init => {
+ if let Some(datapath) = cli.database_path {
+ Database::init_database(&datapath)?;
+ } else {
+ let datapath = xdg::BaseDirectories::with_prefix("debt")
+ .expect("xdg file setup failed")
+ .place_data_file("cache.db")
+ .expect("xdg directory creaton failed");
+ Database::init_database(&datapath)?;
+ }
+ },
+ Commands::Register {person, amount, note, payment} => {
+ let register = Database::new(person, amount, note, !payment);
+ if let Some(datapath) = cli.database_path {
+ register.add_register(&datapath)?;
+ } else {
+ panic!("database file not found");
+ }
+ },
+ Commands::View {history, filter, total} => {
+ println!("{}", filter.unwrap_or(String::from("None")));
+ println!("{}", history);
+ println!("{}", total);
+ },
+
+ Commands::Add {name} => {
+ let register = Database::new(name, 0, None, false);
+ if let Some(datapath) = cli.database_path {
+ register.add_agent(&datapath)?;
+ } else {
+ panic!("database file not found");
+ }
+ }
+ };
+ Ok(())
+}
Feel free to download, copy and edit any repo