diff --git a/src/db.rs b/src/db.rs index 6e5faa3..7ee1ffb 100644 --- a/src/db.rs +++ b/src/db.rs @@ -443,3 +443,66 @@ pub fn get_item_meta_value(conn: &Connection, item: &Item, name: String) -> Resu None => Ok(None), } } + +pub fn get_tags_for_items(conn: &Connection, item_ids: &[i64]) -> Result>> { + debug!("DB: Getting tags for items: {:?}", item_ids); + + if item_ids.is_empty() { + return Ok(std::collections::HashMap::new()); + } + + // Create placeholders for the IN clause + let placeholders: Vec = item_ids.iter().map(|_| "?".to_string()).collect(); + let placeholders_str = placeholders.join(","); + + let sql = format!("SELECT id, name FROM tags WHERE id IN ({}) ORDER BY id ASC, name ASC", placeholders_str); + + let mut statement = conn + .prepare_cached(&sql) + .context("Problem preparing SQL statement")?; + + let mut rows = statement.query(rusqlite::params_from_iter(item_ids))?; + + let mut tags_map: std::collections::HashMap> = std::collections::HashMap::new(); + + while let Some(row) = rows.next()? { + let id: i64 = row.get(0)?; + let name: String = row.get(1)?; + + tags_map.entry(id).or_insert_with(Vec::new).push(Tag { id, name }); + } + + Ok(tags_map) +} + +pub fn get_meta_for_items(conn: &Connection, item_ids: &[i64]) -> Result>> { + debug!("DB: Getting meta for items: {:?}", item_ids); + + if item_ids.is_empty() { + return Ok(std::collections::HashMap::new()); + } + + // Create placeholders for the IN clause + let placeholders: Vec = item_ids.iter().map(|_| "?".to_string()).collect(); + let placeholders_str = placeholders.join(","); + + let sql = format!("SELECT id, name, value FROM metas WHERE id IN ({}) ORDER BY id ASC, name ASC", placeholders_str); + + let mut statement = conn + .prepare_cached(&sql) + .context("Problem preparing SQL statement")?; + + let mut rows = statement.query(rusqlite::params_from_iter(item_ids))?; + + let mut meta_map: std::collections::HashMap> = std::collections::HashMap::new(); + + while let Some(row) = rows.next()? { + let id: i64 = row.get(0)?; + let name: String = row.get(1)?; + let value: String = row.get(2)?; + + meta_map.entry(id).or_insert_with(std::collections::HashMap::new).insert(name, value); + } + + Ok(meta_map) +} diff --git a/src/modes/list.rs b/src/modes/list.rs index d54b9f1..43e897f 100644 --- a/src/modes/list.rs +++ b/src/modes/list.rs @@ -38,30 +38,22 @@ pub fn mode_list( debug!("MAIN: Items: {:?}", items); + // Collect all item IDs for batch queries + let item_ids: Vec = items.iter().map(|item| item.id.unwrap()).collect(); + + // Fetch all tags for all items in a single query + let all_tags = crate::db::get_tags_for_items(conn, &item_ids)?; let mut tags_by_item: std::collections::HashMap> = std::collections::HashMap::new(); - let mut meta_by_item: std::collections::HashMap< - i64, - std::collections::HashMap, - > = std::collections::HashMap::new(); - - for item in items.iter() { - let item_id = item.id.unwrap(); - - let item_tags: Vec = crate::db::get_item_tags(conn, item)? - .into_iter() - .map(|x| x.name) - .collect(); - tags_by_item.insert(item_id, item_tags); - - let mut item_meta: std::collections::HashMap = - std::collections::HashMap::new(); - - for meta in crate::db::get_item_meta(conn, item)? { - item_meta.insert(meta.name.clone(), meta.value); - } - meta_by_item.insert(item_id, item_meta); + + // Convert Tag structs to just names + for (item_id, tags) in all_tags { + let tag_names: Vec = tags.into_iter().map(|tag| tag.name).collect(); + tags_by_item.insert(item_id, tag_names); } + + // Fetch all metadata for all items in a single query + let meta_by_item = crate::db::get_meta_for_items(conn, &item_ids)?; let mut table = Table::new(); table.set_format(*prettytable::format::consts::FORMAT_CLEAN);