Skip to content

Commit

Permalink
feat(cli): Add display feature to CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
GeekMasher committed May 16, 2024
1 parent 66c3ae8 commit e67bac4
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 6 deletions.
17 changes: 16 additions & 1 deletion geekorm-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,20 @@ rust-version.workspace = true
authors.workspace = true

[dependencies]
anyhow = "1.0"
geekorm = { path = "../", version = "^0.3" }
# CLI
clap = { version = "4.0", features = ["derive", "env"] }
console = "0.15"
dialoguer = "0.11"
indicatif = "0.17"

anyhow = "1.0"
log = "0.4"
env_logger = "0.11"

serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
serde_json = "1"
glob = "0.3.1"
chrono = { version = "0.4.38", features = ["serde"] }

61 changes: 61 additions & 0 deletions geekorm-cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use clap::{Parser, Subcommand};
use console::style;
use geekorm::{GEEKORM_BANNER, GEEKORM_VERSION};
use std::path::PathBuf;

pub const AUTHOR: &str = env!("CARGO_PKG_AUTHORS");

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Arguments {
/// Enable Debugging
#[clap(long, env, default_value_t = false)]
pub debug: bool,

/// Disable Banner
#[clap(long, default_value_t = false)]
pub disable_banner: bool,

/// Configuration file path
#[clap(short, long, env, default_value = "./config.toml")]
pub config: PathBuf,

/// Working Directory
#[clap(short, long, env, default_value = "./")]
pub working_dir: PathBuf,

/// Subcommands
#[clap(subcommand)]
pub commands: Option<ArgumentCommands>,
}

#[derive(Subcommand, Debug)]
pub enum ArgumentCommands {
/// Read and display the database schema generated by GeekORM
Display,
}

pub fn init() -> Arguments {
let arguments = Arguments::parse();

let log_level = match &arguments.debug {
false => log::LevelFilter::Info,
true => log::LevelFilter::Debug,
};

env_logger::builder()
.parse_default_env()
.filter_level(log_level)
.init();

if !arguments.disable_banner {
println!(
"{} {} - v{}\n",
style(GEEKORM_BANNER).green(),
style(AUTHOR).red(),
style(GEEKORM_VERSION).blue()
);
}

arguments
}
24 changes: 19 additions & 5 deletions geekorm-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
use anyhow::Result;

mod cli;
mod utils;
mod workflows;

use crate::cli::*;
use crate::workflows::*;

fn main() -> Result<()> {
println!(
"{} - v{}\n",
geekorm::GEEKORM_BANNER,
geekorm::GEEKORM_VERSION
);
let arguments = init();

match arguments.commands {
Some(ArgumentCommands::Display) => display_database(&arguments)?,
None => {
println!("No subcommand selected...");
println!("Use --help for more information.\n");

println!("Thank you for trying out / using GeekORM!");
}
}

Ok(())
}
51 changes: 51 additions & 0 deletions geekorm-cli/src/utils/database.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#![allow(dead_code)]
use anyhow::Result;
use geekorm::Table;
use glob::glob;
use std::path::PathBuf;

use crate::Arguments;

/// This struct represents a database and is based on the `internal`
/// module of the `geekorm_derive` crate.
#[derive(Debug, Clone, serde::Deserialize)]
pub(crate) struct Database {
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub tables: Vec<Table>,
}

impl Database {
pub fn find_database(arguments: &Arguments) -> Result<Self> {
let target_path = "target/*/build/geekorm-derive-*/out/geekorm-*.json";

let path = arguments.working_dir.join(target_path);
let path_str = path.to_str().ok_or_else(|| {
anyhow::anyhow!(
"Failed to convert path to string: {:?}",
arguments.working_dir
)
})?;

// Find the latest database file based on the creation date
glob(path_str)?
.filter_map(|entry| entry.ok())
.fold(None, |acc, entry| {
let database = Self::load_database(entry).ok()?;
Some(acc.map_or(database.clone(), |ref acc: Database| {
if database.updated_at < acc.updated_at {
database
} else {
acc.clone()
}
}))
})
.ok_or_else(|| anyhow::anyhow!("Database not found"))
}

pub fn load_database(path: PathBuf) -> Result<Self> {
let database = std::fs::read_to_string(path)?;
let database: Database = serde_json::from_str(&database)?;
Ok(database)
}
}
1 change: 1 addition & 0 deletions geekorm-cli/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod database;
31 changes: 31 additions & 0 deletions geekorm-cli/src/workflows/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::utils::database::Database;
use anyhow::Result;
use console::style;
use log::debug;

pub(crate) fn display_database(arguments: &super::cli::Arguments) -> Result<()> {
println!("Displaying the database schema generated by GeekORM...\n");

let database = Database::find_database(arguments)?;
debug!("Database: {:#?}", database);

for table in database.tables {
println!(" Table({}) {{", style(table.name).green());

for column in table.columns {
if column.skip {
continue;
}

println!(
" Column({}, {})",
style(column.name).blue(),
style(column.column_type).yellow()
);
}

println!(" }}\n");
}

Ok(())
}

0 comments on commit e67bac4

Please sign in to comment.