diff --git a/cli/src/main.rs b/cli/src/main.rs index 5d7be78..643e16a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,8 +1,6 @@ use std::{ - fs, io::{self, Write}, path::PathBuf, - str::FromStr, }; use clap::Parser; @@ -35,59 +33,20 @@ fn main() -> anyhow::Result<()> { fn handle_files(args: FilesArgs) -> Result<()> { let conn = try_database()?; - let mut sql = r#"SELECT path, group_concat(name) as tags FROM file_tag - JOIN file ON file.id = file_tag.file_id - JOIN tag ON tag.id = file_tag.tag_id"# - .to_string(); - - let mut show_tags = true; - - let mut paths: Vec = vec![]; - if args.all { - paths = fs::read_dir(".")? - .filter_map(|f| f.ok()) - .filter(|f| f.metadata().is_ok() && f.metadata().unwrap().is_file()) - .map(|f| f.path()) - .collect(); - } else if let Some(query) = args.query { - let path = PathBuf::from_str(&query).unwrap_or_default(); - match path.exists() { - true => { - sql.push_str(&format!(" WHERE path IN ('{}')", query)); - paths = vec![path]; - } - false => { - sql.push_str(&format!(" WHERE tag.name LIKE '%{}%'", query)); - show_tags = false; - } - }; - } - - let mut all_paths: Vec = paths - .iter_mut() - .map(|f| f.to_string_lossy().replace("./", "").to_string()) - .collect(); - - sql.push_str(" GROUP BY path"); - - let mut stmt = conn.prepare(&sql)?; - let tagged_files: Vec<(String, String)> = stmt - .query_map([], |row| Ok((row.get(0)?, row.get(1)?)))? - .flatten() - .collect(); + let mut files = taggo::list_files(&conn, args.all, args.query)?; let mut w = io::stdout(); - if !tagged_files.is_empty() { + if !files.files.is_empty() { if args.all { writeln!(&mut w, "{TERM_BOLD}Tagged Files: {TERM_RESET}")?; } - for (file, tags) in tagged_files { + for (file, tags) in files.files { // Remove already tagged files - if let Some(idx) = all_paths.iter().position(|v| *v == file) { - all_paths.swap_remove(idx); + if let Some(idx) = files.paths.iter().position(|v| *v == file) { + files.paths.swap_remove(idx); } - if show_tags { + if files.show_tags { writeln!(&mut w, "{}: {}", file, tags)?; } else { writeln!(&mut w, "{}", file)?; @@ -97,9 +56,9 @@ fn handle_files(args: FilesArgs) -> Result<()> { writeln!(&mut w, "No files registered!")?; } - if args.all && !all_paths.is_empty() { + if args.all && !files.paths.is_empty() { writeln!(&mut w, "\n{TERM_BOLD}Untagged Files: {TERM_RESET}")?; - for path in all_paths { + for path in files.paths { let path_str = path; writeln!(&mut w, "{}", path_str)?; } diff --git a/src/lib.rs b/src/lib.rs index 70bd57e..715276c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ +use std::fs; use std::io::Write; +use std::str::FromStr; use std::{io, path::PathBuf}; use anyhow::{Result, anyhow}; @@ -6,6 +8,12 @@ use rusqlite::{Connection, OpenFlags, params_from_iter, types::Value}; const DB_PATH: &str = ".tags"; +pub struct Files { + pub files: Vec<(String, String)>, + pub paths: Vec, + pub show_tags: bool, +} + pub fn init_db() -> anyhow::Result<()> { let conn = Connection::open(DB_PATH)?; @@ -250,3 +258,52 @@ pub fn untag_file(conn: &mut Connection, file: PathBuf, tags: Option Ok(()) } + +pub fn list_files(conn: &Connection, all_files: bool, query: Option) -> Result { + let mut sql = r#"SELECT path, group_concat(name) as tags FROM file_tag + JOIN file ON file.id = file_tag.file_id + JOIN tag ON tag.id = file_tag.tag_id"# + .to_string(); + + let mut show_tags = true; + + let mut paths: Vec = vec![]; + if all_files { + paths = fs::read_dir(".")? + .filter_map(|f| f.ok()) + .filter(|f| f.metadata().is_ok() && f.metadata().unwrap().is_file()) + .map(|f| f.path()) + .collect(); + } else if let Some(query) = query { + let path = PathBuf::from_str(&query).unwrap_or_default(); + match path.exists() { + true => { + sql.push_str(&format!(" WHERE path IN ('{}')", query)); + paths = vec![path]; + } + false => { + sql.push_str(&format!(" WHERE tag.name LIKE '%{}%'", query)); + show_tags = false; + } + }; + } + + let paths: Vec = paths + .iter_mut() + .map(|f| f.to_string_lossy().replace("./", "").to_string()) + .collect(); + + sql.push_str(" GROUP BY path"); + + let mut stmt = conn.prepare(&sql)?; + let files: Vec<(String, String)> = stmt + .query_map([], |row| Ok((row.get(0)?, row.get(1)?)))? + .flatten() + .collect(); + + Ok(Files { + files, + paths, + show_tags, + }) +}