From 9f48d7980b13b003fa5577d583627ea2b994ed82 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Wed, 10 Sep 2025 15:27:45 -0300 Subject: [PATCH] docs: document src/services/types.rs, src/modes/common.rs, and src/services/error.rs Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) --- PLAN.md | 6 ++-- src/modes/common.rs | 74 +++++++++++++++++++++++++++++++------------ src/services/error.rs | 22 +++++++++++++ src/services/types.rs | 21 +++++++++++- 4 files changed, 99 insertions(+), 24 deletions(-) diff --git a/PLAN.md b/PLAN.md index 2bffcba..643f085 100644 --- a/PLAN.md +++ b/PLAN.md @@ -233,16 +233,16 @@ Private helpers (e.g., internal `fn` without `pub`) are not flagged, as they don 40. **src/filter_parser.rs** (duplicate of filter_parser.rs) - Same issues as above. -41. **src/services/types.rs** +41. **src/services/types.rs** [DONE] - `ItemWithMeta` and `ItemWithContent` structs: Partial. - `meta_as_map()` method: No doc. -42. **src/modes/common.rs** +42. **src/modes/common.rs** [DONE] - `OutputFormat` enum: No doc. - `ColumnType` enum: Partial. - Functions (`get_meta_from_env`, `format_size`, etc.): Partial. -43. **src/services/error.rs** +43. **src/services/error.rs** [DONE] - `CoreError` enum: Partial variants. 44. **src/services/compression_service.rs** diff --git a/src/modes/common.rs b/src/modes/common.rs index 0fc868b..7cc9611 100644 --- a/src/modes/common.rs +++ b/src/modes/common.rs @@ -26,17 +26,25 @@ use std::io::IsTerminal; use std::str::FromStr; use strum::IntoEnumIterator; +#[derive(Debug, Clone, strum::EnumString, strum::Display, PartialEq)] +#[strum(ascii_case_insensitive)] /// Enum representing supported output formats for structured data. /// -/// Used to determine how to display lists, info, and status information. +/// Used to determine how to display lists, info, and status information in CLI modes. +/// Defaults to Table for human-readable output; JSON/YAML for machine parsing. /// /// # Variants /// /// * `Table` - Formatted table output (default). /// * `Json` - JSON structured output. /// * `Yaml` - YAML structured output. -#[derive(Debug, Clone, strum::EnumString, strum::Display, PartialEq)] -#[strum(ascii_case_insensitive)] +/// +/// # Examples +/// +/// ``` +/// use keep::modes::common::OutputFormat; +/// assert_eq!(OutputFormat::from_str("json").unwrap(), OutputFormat::Json); +/// ``` pub enum OutputFormat { Table, Json, @@ -46,16 +54,21 @@ pub enum OutputFormat { /// Extracts metadata from KEEP_META_* environment variables. /// /// Scans environment for variables prefixed with KEEP_META_ and extracts -/// key-value pairs for initial item metadata. +/// key-value pairs for initial item metadata. Ignores KEEP_META_PLUGINS. /// /// # Returns /// -/// `HashMap` - Metadata from environment variables. +/// `HashMap` - Metadata from environment variables, with keys in uppercase without prefix. +/// +/// # Errors +/// +/// None; silently ignores non-matching vars and PLUGINS. /// /// # Examples /// /// ``` /// # use std::env; +/// # use std::collections::HashMap; /// env::set_var("KEEP_META_COMMAND", "ls -la"); /// let meta = get_meta_from_env(); /// assert_eq!(meta.get("COMMAND"), Some(&"ls -la".to_string())); @@ -79,14 +92,16 @@ pub fn get_meta_from_env() -> HashMap { /// Formats a file size in bytes to human-readable or raw format. /// +/// Uses the humansize crate for human-readable output with decimal units (KB, MB, etc.). +/// /// # Arguments /// -/// * `size` - Size in bytes. -/// * `human_readable` - If true, use units like KB, MB; otherwise, raw bytes. +/// * `size` - Size in bytes as u64. +/// * `human_readable` - If true, use units like KB, MB; otherwise, raw bytes as string. /// /// # Returns /// -/// `String` - Formatted size string. +/// `String` - Formatted size string, e.g., "1.0K" or "1024". /// /// # Examples /// @@ -101,9 +116,11 @@ pub fn format_size(size: u64, human_readable: bool) -> String { } } +#[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString)] +#[strum(ascii_case_insensitive)] /// Enum representing column types for table display. /// -/// Defines standard and meta columns for list/info modes. +/// Defines standard and meta columns for list/info modes. Supports "meta:" for specific metadata columns. /// /// # Variants /// @@ -115,8 +132,14 @@ pub fn format_size(size: u64, human_readable: bool) -> String { /// * `FilePath` - File path column. /// * `Tags` - Tags column. /// * `Meta` - Metadata column (with sub-type via string parsing). -#[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString)] -#[strum(ascii_case_insensitive)] +/// +/// # Examples +/// +/// ``` +/// use keep::modes::common::ColumnType; +/// assert_eq!(ColumnType::from_str("id").unwrap(), ColumnType::Id); +/// assert_eq!(ColumnType::from_str("meta:hostname").unwrap(), ColumnType::Meta); +/// ``` pub enum ColumnType { Id, Time, @@ -131,18 +154,22 @@ pub enum ColumnType { impl ColumnType { /// Parses a string to a ColumnType, handling "meta:" pattern. /// + /// Supports direct enum variants or "meta:" for metadata columns. + /// /// # Arguments /// - /// * `s` - Input string to parse. + /// * `s` - Input string to parse, e.g., "size" or "meta:hostname". /// /// # Returns /// - /// * `anyhow::Result` - Parsed type or error. + /// * `Ok(ColumnType)` - Parsed type on success. + /// * `Err(anyhow::Error)` - If the string doesn't match any variant. /// /// # Examples /// /// ``` - /// let meta = ColumnType::from_str("meta:hostname")?; + /// use keep::modes::common::ColumnType; + /// let meta = ColumnType::from_str("meta:hostname").unwrap(); /// assert_eq!(meta, ColumnType::Meta); /// ``` pub fn from_str(s: &str) -> anyhow::Result { @@ -244,15 +271,22 @@ pub fn settings_compression_type(cmd: &mut Command, settings: &config::Settings) /// Parses output format from settings. /// -/// Defaults to `Table` if not specified or invalid. +/// Defaults to `Table` if not specified or invalid. Uses case-insensitive string parsing. /// /// # Arguments /// -/// * `settings` - Application settings. +/// * `settings` - Application settings with optional output_format field. /// /// # Returns /// -/// `OutputFormat` - Parsed or default format. +/// `OutputFormat` - Parsed enum variant or Table as default. +/// +/// # Examples +/// +/// ``` +/// let format = settings_output_format(&settings); +/// assert_eq!(format, OutputFormat::Json); // If settings.output_format = Some("json") +/// ``` pub fn settings_output_format(settings: &config::Settings) -> OutputFormat { settings.output_format .as_ref() @@ -262,15 +296,15 @@ pub fn settings_output_format(settings: &config::Settings) -> OutputFormat { /// Trims trailing whitespace from each line in a multi-line string. /// -/// Useful for cleaning up table output before printing. +/// Useful for cleaning up table output before printing. Preserves newlines but removes spaces/tabs at line ends. /// /// # Arguments /// -/// * `s` - Input string with potential trailing whitespace. +/// * `s` - Input string with potential trailing whitespace, e.g., "line1 \nline2 ". /// /// # Returns /// -/// `String` - Cleaned string with trimmed lines. +/// `String` - Cleaned string with trimmed lines, e.g., "line1\nline2". /// /// # Examples /// diff --git a/src/services/error.rs b/src/services/error.rs index 5d49c24..0d95e18 100644 --- a/src/services/error.rs +++ b/src/services/error.rs @@ -1,22 +1,44 @@ use thiserror::Error; /// Core error types used across services for consistent error handling. +/// +/// This enum centralizes errors from database, I/O, validation, and other operations. +/// It implements Error and Debug for propagation and logging. Use this for all service-level errors. +/// +/// # Variants +/// +/// * `Database(rusqlite::Error)` - Wraps SQLite errors from queries or transactions. +/// * `Io(std::io::Error)` - Wraps I/O errors from file operations or streams. +/// * `ItemNotFound(i64)` - Specific item not found by ID. +/// * `ItemNotFoundGeneric` - Generic item not found (no ID specified). +/// * `InvalidInput(String)` - User or config input validation failure with message. +/// * `Compression(String)` - Compression/decompression errors with details. +/// * `Other(anyhow::Error)` - Catch-all for other anyhow-wrapped errors. +/// * `Migration(rusqlite_migration::Error)` - Database migration failures. #[derive(Error, Debug)] pub enum CoreError { #[error("Database error: {0}")] + /// Database operation failed. Database(#[from] rusqlite::Error), #[error("I/O error: {0}")] + /// File or stream I/O operation failed. Io(#[from] std::io::Error), #[error("Item not found with id {0}")] + /// Item with the specified ID does not exist in the database. ItemNotFound(i64), #[error("Item not found")] + /// Item does not exist (no specific ID). ItemNotFoundGeneric, #[error("Invalid input: {0}")] + /// Input validation failed. InvalidInput(String), #[error("Compression error: {0}")] + /// Compression or decompression operation failed. Compression(String), #[error(transparent)] + /// Other unexpected error. Other(#[from] anyhow::Error), #[error("Migration error: {0}")] + /// Database schema migration failed. Migration(#[from] rusqlite_migration::Error), } diff --git a/src/services/types.rs b/src/services/types.rs index a53b4ec..0686fba 100644 --- a/src/services/types.rs +++ b/src/services/types.rs @@ -3,6 +3,10 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] +/// Structure representing an item with its associated tags and metadata. +/// +/// This is a composite type used for querying and displaying items with their relational data. +/// It combines the core Item with lists of Tags and Meta for complete item representation. pub struct ItemWithMeta { /// The core item data. pub item: Item, @@ -15,15 +19,30 @@ pub struct ItemWithMeta { impl ItemWithMeta { /// Converts metadata to a HashMap for easy lookup. /// + /// This method transforms the vec of Meta into a simple key-value map, + /// useful for quick access by metadata name. + /// /// # Returns /// - /// `HashMap` - Metadata as key-value pairs. + /// `HashMap` - Metadata as key-value pairs, where keys are names and values are strings. + /// + /// # Examples + /// + /// ``` + /// let item_with_meta = ItemWithMeta { /* ... */ }; + /// let meta_map = item_with_meta.meta_as_map(); + /// assert_eq!(meta_map.get("hostname"), Some(&"example.com".to_string())); + /// ``` pub fn meta_as_map(&self) -> HashMap { self.meta.iter().cloned().map(|m| (m.name, m.value)).collect() } } #[derive(Debug, Clone, Serialize, Deserialize)] +/// Structure representing an item with its content, tags, and metadata. +/// +/// This extends ItemWithMeta by including the actual content bytes, suitable for full item retrieval +/// including binary or text data. Note: For large content, consider streaming alternatives. pub struct ItemWithContent { /// Item with associated metadata and tags. pub item_with_meta: ItemWithMeta,