diff --git a/src/db.rs b/src/db.rs index 7ec33f9..bcfcc0b 100644 --- a/src/db.rs +++ b/src/db.rs @@ -9,9 +9,46 @@ use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; -/// Database schema migrations for the Keep application - +/// Database module for the Keep application. +/// +/// This module provides SQLite database operations for storing and retrieving +/// items, tags, and metadata. It includes schema migrations, CRUD operations, +/// and query utilities for efficient data access. +/// +/// # Schema +/// +/// The database uses three main tables: +/// - `items`: Core item information (ID, timestamp, size, compression). +/// - `tags`: Item-tag associations (many-to-many). +/// - `metas`: Item-metadata associations (many-to-many). +/// +/// Foreign keys are enforced with cascading deletes. Indexes on tag and meta +/// names improve query performance. +/// +/// # Migrations +/// +/// Automatic schema migrations are applied on database open using +/// `rusqlite_migration`. The current schema includes: +/// - Items table with auto-increment ID. +/// - Tags and metas tables with composite primary keys. +/// - Indexes on tag and meta names. +/// +/// # Usage +/// +/// Open a connection: +/// ``` +/// let conn = db::open(PathBuf::from("keep.db"))?; +/// ``` +/// Insert an item: +/// ``` +/// let item = db::Item { id: None, ts: Utc::now(), size: None, compression: "lz4".to_string() }; +/// let id = db::insert_item(&conn, item)?; +/// ``` lazy_static! { + /// Database schema migrations for the Keep application. + /// + /// Defines the sequence of migrations to create and update the schema. + /// Applied automatically when opening a database connection. static ref MIGRATIONS: Migrations<'static> = Migrations::new(vec![ M::up( "CREATE TABLE items( @@ -40,48 +77,88 @@ lazy_static! { ]); } -/// Represents an item stored in the database +/// Represents an item stored in the database. +/// +/// Core structure for items containing basic properties. +/// +/// # Fields +/// +/// * `id` - Unique identifier, `None` for new items. +/// * `ts` - Creation timestamp in UTC. +/// * `size` - Content size in bytes, `None` if not set. +/// * `compression` - Compression algorithm used. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Item { - /// Unique identifier for the item, None for new items + /// Unique identifier for the item, None for new items. pub id: Option, - /// Timestamp when the item was created + /// Timestamp when the item was created. pub ts: DateTime, - /// Size of the item content in bytes, None if not set + /// Size of the item content in bytes, None if not set. pub size: Option, - /// Compression algorithm used for the item content + /// Compression algorithm used for the item content. pub compression: String, } -/// Represents a tag associated with an item +/// Represents a tag associated with an item. +/// +/// Defines the relationship between items and tags in a many-to-many structure. +/// +/// # Fields +/// +/// * `id` - Item ID this tag belongs to. +/// * `name` - Tag name (unique per item). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Tag { - /// ID of the item this tag belongs to + /// ID of the item this tag belongs to. pub id: i64, - /// Name of the tag + /// Name of the tag. pub name: String, } -/// Represents metadata associated with an item +/// Represents metadata associated with an item. +/// +/// Stores key-value metadata for items in a many-to-many relationship. +/// +/// # Fields +/// +/// * `id` - Item ID this metadata belongs to. +/// * `name` - Metadata field name (unique per item). +/// * `value` - Metadata field value. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Meta { - /// ID of the item this metadata belongs to + /// ID of the item this metadata belongs to. pub id: i64, - /// Name of the metadata field + /// Name of the metadata field. pub name: String, - /// Value of the metadata field + /// Value of the metadata field. pub value: String, } -/// Opens a database connection and ensures the schema is up to date +/// Opens a database connection and ensures the schema is up to date. +/// +/// Creates or opens the SQLite database file and applies any pending migrations. +/// Enables foreign keys and the array virtual table for advanced queries. /// /// # Arguments /// -/// * `path` - Path to the SQLite database file +/// * `path` - Path to the SQLite database file. /// /// # Returns /// -/// * `Result` - A SQLite connection on success, or an error if opening or migration fails +/// * `Result` - A SQLite connection on success, or an error if opening or migration fails. +/// +/// # Errors +/// +/// * Database file access issues. +/// * Migration failures. +/// * SQLite configuration errors. +/// +/// # Examples +/// +/// ``` +/// let db_path = PathBuf::from("keep.db"); +/// let conn = db::open(db_path)?; +/// ``` pub fn open(path: PathBuf) -> Result { debug!("DB: Opening file: {:?}", path); let mut conn = Connection::open_with_flags( @@ -102,16 +179,36 @@ pub fn open(path: PathBuf) -> Result { Ok(conn) } -/// Inserts a new item into the database +/// Inserts a new item into the database. +/// +/// Creates a new row in the `items` table and returns the generated ID. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item to insert +/// * `conn` - Database connection. +/// * `item` - Item to insert (ID will be set automatically). /// /// # Returns /// -/// * `Result` - The ID of the newly inserted item on success, or an error if insertion fails +/// * `Result` - The ID of the newly inserted item on success, or an error if insertion fails. +/// +/// # Errors +/// +/// * Database constraint violations. +/// * Connection issues. +/// +/// # Examples +/// +/// ``` +/// let item = Item { +/// id: None, +/// ts: Utc::now(), +/// size: None, +/// compression: "lz4".to_string(), +/// }; +/// let id = db::insert_item(&conn, item)?; +/// assert!(id > 0); +/// ``` pub fn insert_item(conn: &Connection, item: Item) -> Result { debug!("DB: Inserting item: {:?}", item); conn.execute( @@ -121,16 +218,30 @@ pub fn insert_item(conn: &Connection, item: Item) -> Result { Ok(conn.last_insert_rowid()) } -/// Creates a new item in the database with the current timestamp +/// Creates a new item in the database with the current timestamp. +/// +/// Convenience function to create and insert a new item with default values. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `compression_type` - Compression type to use for the item +/// * `conn` - Database connection. +/// * `compression_type` - Compression type to use for the item. /// /// # Returns /// -/// * `Result` - The created item with its ID set, or an error if creation fails +/// * `Result` - The created item with its ID set, or an error if creation fails. +/// +/// # Errors +/// +/// * Database insertion errors. +/// +/// # Examples +/// +/// ``` +/// let compression = CompressionType::LZ4; +/// let item = db::create_item(&conn, compression)?; +/// assert!(item.id.is_some()); +/// ``` pub fn create_item(conn: &Connection, compression_type: crate::compression_engine::CompressionType) -> Result { let item = Item { id: None, @@ -145,17 +256,30 @@ pub fn create_item(conn: &Connection, compression_type: crate::compression_engin }) } -/// Adds a tag to an item +/// Adds a tag to an item. +/// +/// Inserts a new tag association in the `tags` table. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item_id` - ID of the item to tag -/// * `tag_name` - Name of the tag to add +/// * `conn` - Database connection. +/// * `item_id` - ID of the item to tag. +/// * `tag_name` - Name of the tag to add. /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Duplicate tag constraint violation. +/// * Database errors. +/// +/// # Examples +/// +/// ``` +/// db::add_tag(&conn, 1, "important")?; +/// ``` pub fn add_tag(conn: &Connection, item_id: i64, tag_name: &str) -> Result<()> { let tag = Tag { id: item_id, @@ -164,18 +288,31 @@ pub fn add_tag(conn: &Connection, item_id: i64, tag_name: &str) -> Result<()> { insert_tag(conn, tag) } -/// Adds metadata to an item +/// Adds metadata to an item. +/// +/// Inserts a new metadata entry in the `metas` table. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item_id` - ID of the item -/// * `name` - Name of the metadata field -/// * `value` - Value of the metadata field +/// * `conn` - Database connection. +/// * `item_id` - ID of the item. +/// * `name` - Name of the metadata field. +/// * `value` - Value of the metadata field. /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Duplicate metadata constraint violation. +/// * Database errors. +/// +/// # Examples +/// +/// ``` +/// db::add_meta(&conn, 1, "mime_type", "text/plain")?; +/// ``` pub fn add_meta(conn: &Connection, item_id: i64, name: &str, value: &str) -> Result<()> { let meta = Meta { id: item_id, @@ -185,16 +322,30 @@ pub fn add_meta(conn: &Connection, item_id: i64, name: &str, value: &str) -> Res store_meta(conn, meta) } -/// Updates an existing item in the database +/// Updates an existing item in the database. +/// +/// Modifies size and compression fields for an existing item. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item with updated values +/// * `conn` - Database connection. +/// * `item` - Item with updated values (ID must be set). /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Item not found. +/// * Database errors. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), size: Some(1024), compression: "lz4".to_string(), ts: Utc::now() }; +/// db::update_item(&conn, item)?; +/// ``` pub fn update_item(conn: &Connection, item: Item) -> Result<()> { debug!("DB: Updating item: {:?}", item); conn.execute( @@ -208,32 +359,60 @@ pub fn update_item(conn: &Connection, item: Item) -> Result<()> { Ok(()) } -/// Deletes an item from the database +/// Deletes an item from the database. +/// +/// Removes the item and cascades to delete associated tags and metadata. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item to delete +/// * `conn` - Database connection. +/// * `item` - Item to delete (ID must be set). /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Item not found. +/// * Database errors. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), ..default_item() }; +/// db::delete_item(&conn, item)?; +/// ``` pub fn delete_item(conn: &Connection, item: Item) -> Result<()> { debug!("DB: Deleting item: {:?}", item); conn.execute("DELETE FROM items WHERE id=?1", params![item.id])?; Ok(()) } -/// Deletes a metadata entry from the database +/// Deletes a metadata entry from the database. +/// +/// Removes a specific metadata field for an item. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `meta` - Metadata entry to delete +/// * `conn` - Database connection. +/// * `meta` - Metadata entry to delete. /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Metadata not found. +/// * Database errors. +/// +/// # Examples +/// +/// ``` +/// let meta = Meta { id: 1, name: "temp".to_string(), value: "".to_string() }; +/// db::query_delete_meta(&conn, meta)?; +/// ``` pub fn query_delete_meta(conn: &Connection, meta: Meta) -> Result<()> { debug!("DB: Deleting meta: {:?}", meta); conn.execute( @@ -243,16 +422,30 @@ pub fn query_delete_meta(conn: &Connection, meta: Meta) -> Result<()> { Ok(()) } -/// Inserts or updates a metadata entry in the database +/// Inserts or updates a metadata entry in the database. +/// +/// Uses UPSERT to handle both insert and update cases. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `meta` - Metadata entry to upsert +/// * `conn` - Database connection. +/// * `meta` - Metadata entry to upsert. /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Database constraint violations. +/// * Connection issues. +/// +/// # Examples +/// +/// ``` +/// let meta = Meta { id: 1, name: "mime_type".to_string(), value: "text/plain".to_string() }; +/// db::query_upsert_meta(&conn, meta)?; +/// ``` pub fn query_upsert_meta(conn: &Connection, meta: Meta) -> Result<()> { debug!("DB: Inserting meta: {:?}", meta); conn.execute( @@ -263,16 +456,34 @@ pub fn query_upsert_meta(conn: &Connection, meta: Meta) -> Result<()> { Ok(()) } -/// Stores a metadata entry, deleting it if the value is empty +/// Stores a metadata entry, deleting it if the value is empty. +/// +/// Handles both insertion/update and deletion based on value presence. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `meta` - Metadata entry to store +/// * `conn` - Database connection. +/// * `meta` - Metadata entry to store (empty value triggers deletion). /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Database errors during insert/update/delete. +/// +/// # Examples +/// +/// ``` +/// // Insert new metadata +/// let meta = Meta { id: 1, name: "source".to_string(), value: "cli".to_string() }; +/// db::store_meta(&conn, meta)?; +/// +/// // Delete metadata with empty value +/// let meta = Meta { id: 1, name: "temp".to_string(), value: "".to_string() }; +/// db::store_meta(&conn, meta)?; +/// ``` pub fn store_meta(conn: &Connection, meta: Meta) -> Result<()> { if meta.value.is_empty() { query_delete_meta(conn, meta)?; @@ -282,16 +493,30 @@ pub fn store_meta(conn: &Connection, meta: Meta) -> Result<()> { Ok(()) } -/// Inserts a tag into the database +/// Inserts a tag into the database. +/// +/// Creates a new tag association (fails if duplicate). /// /// # Arguments /// -/// * `conn` - Database connection -/// * `tag` - Tag to insert +/// * `conn` - Database connection. +/// * `tag` - Tag to insert. /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Duplicate tag constraint violation. +/// * Database errors. +/// +/// # Examples +/// +/// ``` +/// let tag = Tag { id: 1, name: "work".to_string() }; +/// db::insert_tag(&conn, tag)?; +/// ``` pub fn insert_tag(conn: &Connection, tag: Tag) -> Result<()> { debug!("DB: Inserting tag: {:?}", tag); conn.execute( @@ -301,33 +526,61 @@ pub fn insert_tag(conn: &Connection, tag: Tag) -> Result<()> { Ok(()) } -/// Deletes all tags associated with an item +/// Deletes all tags associated with an item. +/// +/// Clears all tag associations for the specified item. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item whose tags should be deleted +/// * `conn` - Database connection. +/// * `item` - Item whose tags should be deleted (ID must be set). /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Database errors. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), .. }; +/// db::delete_item_tags(&conn, item)?; +/// ``` pub fn delete_item_tags(conn: &Connection, item: Item) -> Result<()> { debug!("DB: Deleting all item tags: {:?}", item); conn.execute("DELETE FROM tags WHERE id=?1", params![item.id])?; Ok(()) } -/// Sets the tags for an item, replacing any existing tags +/// Sets the tags for an item, replacing any existing tags. +/// +/// Deletes existing tags and inserts the new set. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item to set tags for -/// * `tags` - Vector of tag names to set +/// * `conn` - Database connection. +/// * `item` - Item to set tags for (ID must be set). +/// * `tags` - Vector of tag names to set. /// /// # Returns /// -/// * `Result<()>` - Success or error if the operation fails +/// * `Result<()>` - Success or error if the operation fails. +/// +/// # Errors +/// +/// * Database insertion errors. +/// * Item ID missing. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), .. }; +/// let tags = vec!["project_a".to_string(), "urgent".to_string()]; +/// db::set_item_tags(&conn, item, &tags)?; +/// ``` pub fn set_item_tags(conn: &Connection, item: Item, tags: &Vec) -> Result<()> { debug!("DB: Setting tags for item: {:?} ?{:?}", item, tags); delete_item_tags(conn, item.clone())?; @@ -345,15 +598,28 @@ pub fn set_item_tags(conn: &Connection, item: Item, tags: &Vec) -> Resul Ok(()) } -/// Queries all items from the database, ordered by ID +/// Queries all items from the database, ordered by ID. +/// +/// Retrieves all items in ascending ID order. /// /// # Arguments /// -/// * `conn` - Database connection +/// * `conn` - Database connection. /// /// # Returns /// -/// * `Result>` - All items in the database or an error +/// * `Result>` - All items in the database or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let all_items = db::query_all_items(&conn)?; +/// assert!(all_items.len() >= 0); +/// ``` pub fn query_all_items(conn: &Connection) -> Result> { debug!("DB: Querying all items"); let mut statement = conn @@ -375,16 +641,29 @@ pub fn query_all_items(conn: &Connection) -> Result> { Ok(items) } -/// Queries items that have all the specified tags +/// Queries items that have all the specified tags. +/// +/// Uses array-based subquery to find items matching all tags. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `tags` - Vector of tag names to match +/// * `conn` - Database connection. +/// * `tags` - Vector of tag names to match (all must match). /// /// # Returns /// -/// * `Result>` - Matching items or an error +/// * `Result>` - Matching items or an error. +/// +/// # Errors +/// +/// * Query preparation or execution errors. +/// +/// # Examples +/// +/// ``` +/// let tags = vec!["work".to_string(), "urgent".to_string()]; +/// let tagged_items = db::query_tagged_items(&conn, &tags)?; +/// ``` pub fn query_tagged_items<'a>(conn: &'a Connection, tags: &'a Vec) -> Result> { debug!("DB: Querying tagged items: {:?}", tags); let mut statement = conn @@ -427,31 +706,54 @@ pub fn query_tagged_items<'a>(conn: &'a Connection, tags: &'a Vec) -> Re Ok(items) } -/// Gets all items from the database +/// Gets all items from the database. +/// +/// Alias for `query_all_items` for consistency. /// /// # Arguments /// -/// * `conn` - Database connection +/// * `conn` - Database connection. /// /// # Returns /// -/// * `Result>` - All items or an error +/// * `Result>` - All items or an error. +/// +/// # Examples +/// +/// ``` +/// let items = db::get_items(&conn)?; +/// ``` pub fn get_items(conn: &Connection) -> Result> { debug!("DB: Getting all items"); query_all_items(conn) } -/// Gets items matching specified tags and metadata criteria +/// Gets items matching specified tags and metadata criteria. +/// +/// First filters by tags (if provided), then applies metadata matching. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `tags` - Vector of tag names to match -/// * `meta` - HashMap of metadata key-value pairs to match +/// * `conn` - Database connection. +/// * `tags` - Vector of tag names to match (all must match). +/// * `meta` - HashMap of metadata key-value pairs to match (exact match). /// /// # Returns /// -/// * `Result>` - Matching items or an error +/// * `Result>` - Matching items or an error. +/// +/// # Errors +/// +/// * Query errors. +/// * Metadata query failures. +/// +/// # Examples +/// +/// ``` +/// let tags = vec!["project".to_string()]; +/// let meta = HashMap::from([("status".to_string(), "active".to_string())]); +/// let matching = db::get_items_matching(&conn, &tags, &meta)?; +/// ``` pub fn get_items_matching( conn: &Connection, tags: &Vec, @@ -501,17 +803,30 @@ pub fn get_items_matching( } } -/// Gets a single item matching specified tags +/// Gets a single item matching specified tags. +/// +/// Returns the most recent item matching all tags (ignores metadata). /// /// # Arguments /// -/// * `conn` - Database connection -/// * `tags` - Vector of tag names to match -/// * `_meta` - Unused metadata parameter +/// * `conn` - Database connection. +/// * `tags` - Vector of tag names to match (all must match). +/// * `_meta` - Unused metadata parameter (for API consistency). /// /// # Returns /// -/// * `Result>` - The matching item or None if not found, or an error +/// * `Result>` - The matching item or None if not found, or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let tags = vec!["latest".to_string()]; +/// let item = db::get_item_matching(&conn, &tags, &HashMap::new())?; +/// ``` pub fn get_item_matching( conn: &Connection, tags: &Vec, @@ -556,16 +871,29 @@ pub fn get_item_matching( } } -/// Gets an item by its ID +/// Gets an item by its ID. +/// +/// Simple lookup by primary key. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item_id` - ID of the item to retrieve +/// * `conn` - Database connection. +/// * `item_id` - ID of the item to retrieve. /// /// # Returns /// -/// * `Result>` - The item if found, None if not found, or an error +/// * `Result>` - The item if found, None if not found, or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let item = db::get_item(&conn, 1)?; +/// assert!(item.is_some()); +/// ``` pub fn get_item(conn: &Connection, item_id: i64) -> Result> { debug!("DB: Getting item {:?}", item_id); let mut statement = conn @@ -590,15 +918,27 @@ pub fn get_item(conn: &Connection, item_id: i64) -> Result> { } } -/// Gets the most recently created item +/// Gets the most recently created item. +/// +/// Retrieves the item with the highest ID (most recent). /// /// # Arguments /// -/// * `conn` - Database connection +/// * `conn` - Database connection. /// /// # Returns /// -/// * `Result>` - The most recent item or None if no items exist, or an error +/// * `Result>` - The most recent item or None if no items exist, or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let latest = db::get_item_last(&conn)?; +/// ``` pub fn get_item_last(conn: &Connection) -> Result> { debug!("DB: Getting last item"); let mut statement = conn @@ -624,16 +964,29 @@ pub fn get_item_last(conn: &Connection) -> Result> { } } -/// Gets all tags for a specific item +/// Gets all tags for a specific item. +/// +/// Retrieves all tag associations ordered by name. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item to get tags for +/// * `conn` - Database connection. +/// * `item` - Item to get tags for (ID must be set). /// /// # Returns /// -/// * `Result>` - The item's tags or an error +/// * `Result>` - The item's tags or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), .. }; +/// let tags = db::get_item_tags(&conn, &item)?; +/// ``` pub fn get_item_tags(conn: &Connection, item: &Item) -> Result> { debug!("DB: Getting tags for item: {:?}", item); let mut statement = conn @@ -653,16 +1006,29 @@ pub fn get_item_tags(conn: &Connection, item: &Item) -> Result> { Ok(tags) } -/// Gets all metadata for a specific item +/// Gets all metadata for a specific item. +/// +/// Retrieves all metadata entries ordered by name. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item to get metadata for +/// * `conn` - Database connection. +/// * `item` - Item to get metadata for (ID must be set). /// /// # Returns /// -/// * `Result>` - The item's metadata or an error +/// * `Result>` - The item's metadata or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), .. }; +/// let meta = db::get_item_meta(&conn, &item)?; +/// ``` pub fn get_item_meta(conn: &Connection, item: &Item) -> Result> { debug!("DB: Getting item meta: {:?}", item); let mut statement = conn @@ -683,17 +1049,30 @@ pub fn get_item_meta(conn: &Connection, item: &Item) -> Result> { Ok(metas) } -/// Gets a specific metadata entry for an item by name +/// Gets a specific metadata entry for an item by name. +/// +/// Retrieves a single metadata field by name. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item to get metadata for -/// * `name` - Name of the metadata field +/// * `conn` - Database connection. +/// * `item` - Item to get metadata for (ID must be set). +/// * `name` - Name of the metadata field. /// /// # Returns /// -/// * `Result>` - The metadata entry if found, None if not found, or an error +/// * `Result>` - The metadata entry if found, None if not found, or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), .. }; +/// let meta = db::get_item_meta_name(&conn, &item, "mime_type".to_string())?; +/// ``` pub fn get_item_meta_name(conn: &Connection, item: &Item, name: String) -> Result> { debug!("DB: Getting item meta name: {:?} {:?}", item, name); let mut statement = conn @@ -711,17 +1090,30 @@ pub fn get_item_meta_name(conn: &Connection, item: &Item, name: String) -> Resul } } -/// Gets the value of a specific metadata field for an item +/// Gets the value of a specific metadata field for an item. +/// +/// Retrieves just the value string for a metadata field. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item` - Item to get metadata for -/// * `name` - Name of the metadata field +/// * `conn` - Database connection. +/// * `item` - Item to get metadata for (ID must be set). +/// * `name` - Name of the metadata field. /// /// # Returns /// -/// * `Result>` - The metadata value if found, None if not found, or an error +/// * `Result>` - The metadata value if found, None if not found, or an error. +/// +/// # Errors +/// +/// * Query execution errors. +/// +/// # Examples +/// +/// ``` +/// let item = Item { id: Some(1), .. }; +/// let value = db::get_item_meta_value(&conn, &item, "source".to_string())?; +/// ``` pub fn get_item_meta_value(conn: &Connection, item: &Item, name: String) -> Result> { debug!("DB: Getting item meta value: {:?} {:?}", item, name); let mut statement = conn @@ -735,16 +1127,29 @@ pub fn get_item_meta_value(conn: &Connection, item: &Item, name: String) -> Resu } } -/// Gets tags for multiple items in a single query +/// Gets tags for multiple items in a single query. +/// +/// Efficiently retrieves tags for a batch of items using IN clause. /// /// # Arguments /// -/// * `conn` - Database connection -/// * `item_ids` - Slice of item IDs to get tags for +/// * `conn` - Database connection. +/// * `item_ids` - Slice of item IDs to get tags for. /// /// # Returns /// -/// * `Result>>` - Mapping of item IDs to their tags, or an error +/// * `Result>>` - Mapping of item IDs to their tags, or an error. +/// +/// # Errors +/// +/// * Query preparation or execution errors. +/// +/// # Examples +/// +/// ``` +/// let ids = vec![1, 2, 3]; +/// let tags_map = db::get_tags_for_items(&conn, &ids)?; +/// ``` pub fn get_tags_for_items(conn: &Connection, item_ids: &[i64]) -> Result>> { debug!("DB: Getting tags for items: {:?}", item_ids); @@ -776,16 +1181,29 @@ pub fn get_tags_for_items(conn: &Connection, item_ids: &[i64]) -> Result>>` - Mapping of item IDs to their metadata, or an error +/// * `Result>>` - Mapping of item IDs to their metadata, or an error. +/// +/// # Errors +/// +/// * Query preparation or execution errors. +/// +/// # Examples +/// +/// ``` +/// let ids = vec![1, 2, 3]; +/// let meta_map = db::get_meta_for_items(&conn, &ids)?; +/// ``` pub fn get_meta_for_items(conn: &Connection, item_ids: &[i64]) -> Result>> { debug!("DB: Getting meta for items: {:?}", item_ids);