diff --git a/src/client.rs b/src/client.rs index 20896bd..44a1b4f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -253,6 +253,7 @@ impl KeepClient { pub fn list_items( &self, + ids: &[i64], tags: &[String], order: &str, start: u64, @@ -268,6 +269,15 @@ impl KeepClient { params.push(("order".to_string(), order.to_string())); params.push(("start".to_string(), start.to_string())); params.push(("count".to_string(), count.to_string())); + if !ids.is_empty() { + params.push(( + "ids".to_string(), + ids.iter() + .map(|i| i.to_string()) + .collect::>() + .join(","), + )); + } if !tags.is_empty() { params.push(("tags".to_string(), tags.join(","))); } diff --git a/src/main.rs b/src/main.rs index db5d2d5..af5fd60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,7 +81,7 @@ fn main() -> Result<(), Error> { let ids = &mut Vec::new(); let tags = &mut Vec::new(); - // For --info, --get, and --export modes, treat numeric strings as IDs + // For --info, --get, --export, and --list modes, treat numeric strings as IDs for v in args.ids_or_tags.iter() { debug!("MAIN: Parsed value: {v:?}"); match v.clone() { @@ -90,15 +90,15 @@ fn main() -> Result<(), Error> { ids.push(num) } NumberOrString::Str(str) => { - // For --info, --get, and --export, try to parse strings as numbers to treat them as IDs - if (args.mode.info || args.mode.get || args.mode.export) + // For --info, --get, --export, and --list, try to parse strings as numbers to treat them as IDs + if (args.mode.info || args.mode.get || args.mode.export || args.mode.list) && let Ok(num) = str.parse::() { debug!("MAIN: Adding parsed string to ids: {num}"); ids.push(num); continue; } - // If not a number, or not using --info/--get/--export, treat as tag + // If not a number, or not using --info/--get/--export/--list, treat as tag debug!("MAIN: Adding to tags: {str}"); tags.push(str) } @@ -256,7 +256,7 @@ fn main() -> Result<(), Error> { filter_chain, ), KeepModes::List => { - keep::modes::client::list::mode(&client, &mut cmd, &settings, tags) + keep::modes::client::list::mode(&client, &mut cmd, &settings, ids, tags) } KeepModes::Delete => { keep::modes::client::delete::mode(&client, &mut cmd, &settings, ids) diff --git a/src/modes/client/list.rs b/src/modes/client/list.rs index 7da113c..e9769f8 100644 --- a/src/modes/client/list.rs +++ b/src/modes/client/list.rs @@ -10,6 +10,7 @@ pub fn mode( client: &KeepClient, _cmd: &mut Command, settings: &crate::config::Settings, + ids: &[i64], tags: &[String], ) -> Result<(), anyhow::Error> { debug!("CLIENT_LIST: Listing items via remote server"); @@ -19,7 +20,7 @@ pub fn mode( .iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(); - let items = client.list_items(tags, "newest", 0, 100, &meta_filter)?; + let items = client.list_items(ids, tags, "newest", 0, 100, &meta_filter)?; if settings.ids_only { for item in &items { diff --git a/src/modes/common.rs b/src/modes/common.rs index 4bb2782..17e23e1 100644 --- a/src/modes/common.rs +++ b/src/modes/common.rs @@ -673,13 +673,13 @@ pub fn resolve_item_id( if !ids.is_empty() { Ok(ids[0]) } else if !tags.is_empty() { - let items = client.list_items(tags, "newest", 0, 1, &HashMap::new())?; + let items = client.list_items(&[], tags, "newest", 0, 1, &HashMap::new())?; if items.is_empty() { return Err(anyhow!("No items found matching tags: {:?}", tags)); } Ok(items[0].id) } else { - let items = client.list_items(&[], "newest", 0, 1, &HashMap::new())?; + let items = client.list_items(&[], &[], "newest", 0, 1, &HashMap::new())?; if items.is_empty() { return Err(anyhow!("No items found")); } @@ -696,13 +696,13 @@ pub fn resolve_item_ids( if !ids.is_empty() { Ok(ids.to_vec()) } else if !tags.is_empty() { - let items = client.list_items(tags, "newest", 0, 0, &HashMap::new())?; + let items = client.list_items(&[], tags, "newest", 0, 0, &HashMap::new())?; if items.is_empty() { return Err(anyhow!("No items found matching tags: {:?}", tags)); } Ok(items.into_iter().map(|i| i.id).collect()) } else { - let items = client.list_items(&[], "newest", 0, 1, &HashMap::new())?; + let items = client.list_items(&[], &[], "newest", 0, 1, &HashMap::new())?; if items.is_empty() { return Err(anyhow!("No items found")); } diff --git a/src/modes/list.rs b/src/modes/list.rs index 7dd2adf..c53b3a6 100644 --- a/src/modes/list.rs +++ b/src/modes/list.rs @@ -81,28 +81,20 @@ struct ListItem { /// /// * `Result<()>` - Success or error if listing fails. pub fn mode_list( - cmd: &mut clap::Command, + _cmd: &mut clap::Command, settings: &config::Settings, ids: &mut [i64], tags: &[String], conn: &mut rusqlite::Connection, data_path: std::path::PathBuf, ) -> Result<()> { - if !ids.is_empty() { - cmd.error( - clap::error::ErrorKind::InvalidValue, - "ID given, you can only supply tags when using --list", - ) - .exit(); - } - let item_service = ItemService::new(data_path.clone()); let meta_filter: std::collections::HashMap> = settings .meta .iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(); - let items_with_meta = item_service.list_items(conn, tags, &meta_filter)?; + let items_with_meta = item_service.get_items(conn, ids, tags, &meta_filter)?; if settings.ids_only { for item_with_meta in &items_with_meta { diff --git a/src/modes/server/api/item.rs b/src/modes/server/api/item.rs index e311439..f637d74 100644 --- a/src/modes/server/api/item.rs +++ b/src/modes/server/api/item.rs @@ -114,6 +114,17 @@ pub async fn handle_list_items( State(state): State, Query(params): Query, ) -> Result { + // Parse IDs from query parameter + let ids: Vec = params + .ids + .as_ref() + .map(|s| { + s.split(',') + .filter_map(|id| id.trim().parse::().ok()) + .collect() + }) + .unwrap_or_default(); + let tags: Vec = params .tags .as_ref() @@ -136,7 +147,7 @@ pub async fn handle_list_items( let mut items_with_meta = task::spawn_blocking(move || { let conn = db.blocking_lock(); let item_service = ItemService::new(data_dir); - item_service.list_items(&conn, &tags, &meta_filter) + item_service.get_items(&conn, &ids, &tags, &meta_filter) }) .await .map_err(|e| { diff --git a/src/modes/server/common.rs b/src/modes/server/common.rs index e43ea2f..d93ab8d 100644 --- a/src/modes/server/common.rs +++ b/src/modes/server/common.rs @@ -459,6 +459,10 @@ pub struct TagsQuery { /// ``` #[derive(Debug, Deserialize)] pub struct ListItemsQuery { + /// Optional comma-separated item IDs for filtering. + /// + /// String containing numeric IDs to filter the item list. + pub ids: Option, /// Optional comma-separated tags for filtering. /// /// String containing tags to filter the item list.