From 61d7dcb94ebeadf0ae5e71c989db55c543546757 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Tue, 2 Sep 2025 18:54:50 -0300 Subject: [PATCH] refactor: Consolidate item content filtering into a single filter string Co-authored-by: aider (openai/andrew/openrouter/deepseek/deepseek-chat-v3.1) --- src/modes/server/api/item.rs | 52 ++++++++++++++++++------------ src/services/async_item_service.rs | 32 +++--------------- src/services/item_service.rs | 12 ++----- 3 files changed, 38 insertions(+), 58 deletions(-) diff --git a/src/modes/server/api/item.rs b/src/modes/server/api/item.rs index f19ae24..16baa4d 100644 --- a/src/modes/server/api/item.rs +++ b/src/modes/server/api/item.rs @@ -392,6 +392,32 @@ pub async fn handle_get_item_content( debug!("ITEM_API: Getting content for item {} with stream={}, allow_binary={}, offset={}, length={}", item_id, params.stream, params.allow_binary, params.offset, params.length); + // Build filter string from query parameters + let mut filter_parts = Vec::new(); + if let Some(head_bytes) = params.head_bytes { + filter_parts.push(format!("head_bytes({})", head_bytes)); + } + if let Some(head_lines) = params.head_lines { + filter_parts.push(format!("head_lines({})", head_lines)); + } + if let Some(tail_bytes) = params.tail_bytes { + filter_parts.push(format!("tail_bytes({})", tail_bytes)); + } + if let Some(tail_lines) = params.tail_lines { + filter_parts.push(format!("tail_lines({})", tail_lines)); + } + if let Some(grep) = params.grep { + filter_parts.push(format!("grep({})", grep)); + } + // Note: head_words, tail_words, line_start, line_end are not implemented in the filter system yet + // You may need to add them to the filter syntax or handle them differently + + let filter = if filter_parts.is_empty() { + None + } else { + Some(filter_parts.join(" | ")) + }; + let item_service = AsyncItemService::new( state.data_dir.clone(), state.db.clone(), @@ -408,7 +434,7 @@ pub async fn handle_get_item_content( } result } else { - let result = stream_item_content_response(&item_service, item_id, params.allow_binary, params.offset, params.length, params.stream).await; + let result = stream_item_content_response(&item_service, item_id, params.allow_binary, params.offset, params.length, params.stream, filter).await; if let Ok(response) = &result { debug!("ITEM_API: Response content-length: {:?}", response.headers().get("content-length")); } @@ -423,6 +449,7 @@ async fn stream_item_content_response( offset: u64, length: u64, stream: bool, + filter: Option, ) -> Result { debug!("STREAM_ITEM_CONTENT_RESPONSE: stream={}", stream); // Get the item with metadata once @@ -432,7 +459,7 @@ async fn stream_item_content_response( })?; let metadata = item_with_meta.meta_as_map(); - stream_item_content_response_with_metadata(item_service, item_id, &metadata, allow_binary, offset, length, stream).await + stream_item_content_response_with_metadata(item_service, item_id, &metadata, allow_binary, offset, length, stream, filter).await } async fn stream_item_content_response_with_metadata( @@ -443,6 +470,7 @@ async fn stream_item_content_response_with_metadata( offset: u64, length: u64, stream: bool, + filter: Option, ) -> Result { debug!("STREAM_ITEM_CONTENT_RESPONSE_WITH_METADATA: stream={}", stream); let mime_type = metadata @@ -481,15 +509,7 @@ async fn stream_item_content_response_with_metadata( true, offset, length, - None, - None, - None, - None, - None, - None, - None, - None, - None + filter ).await { Ok((stream, _)) => { let body = axum::body::Body::from_stream(stream); @@ -508,15 +528,7 @@ async fn stream_item_content_response_with_metadata( debug!("NON-STREAMING: Building full response in memory"); match item_service.get_item_content_info( item_id, - None, - None, - None, - None, - None, - None, - None, - None, - None + filter ).await { Ok((content, _, _)) => { // Apply offset and length diff --git a/src/services/async_item_service.rs b/src/services/async_item_service.rs index cbd32c4..8b9fdde 100644 --- a/src/services/async_item_service.rs +++ b/src/services/async_item_service.rs @@ -68,15 +68,7 @@ impl AsyncItemService { pub async fn get_item_content_info( &self, id: i64, - head_bytes: Option, - head_words: Option, - head_lines: Option, - tail_bytes: Option, - tail_words: Option, - tail_lines: Option, - line_start: Option, - line_end: Option, - grep: Option, + filter: Option, ) -> Result<(Vec, String, bool), CoreError> { let db = self.db.clone(); let item_service = self.item_service.clone(); @@ -86,15 +78,7 @@ impl AsyncItemService { item_service.get_item_content_info( &conn, id, - head_bytes, - head_words, - head_lines, - tail_bytes, - tail_words, - tail_lines, - line_start, - line_end, - grep + filter ) }) .await @@ -182,15 +166,7 @@ impl AsyncItemService { allow_binary: bool, offset: u64, length: u64, - head_bytes: Option, - head_words: Option, - head_lines: Option, - tail_bytes: Option, - tail_words: Option, - tail_lines: Option, - line_start: Option, - line_end: Option, - grep: Option, + filter: Option, ) -> Result<(std::pin::Pin> + Send>>, String), CoreError> { // Use provided metadata to determine MIME type and binary status let mime_type = metadata @@ -225,7 +201,7 @@ impl AsyncItemService { item_service.get_item_content_info_streaming( &conn, item_id, - None + filter ).map(|(reader, _, _)| reader) }) .await diff --git a/src/services/item_service.rs b/src/services/item_service.rs index 63a6e0f..3a6539a 100644 --- a/src/services/item_service.rs +++ b/src/services/item_service.rs @@ -139,19 +139,11 @@ impl ItemService { &self, conn: &Connection, id: i64, - head_bytes: Option, - head_words: Option, - head_lines: Option, - tail_bytes: Option, - tail_words: Option, - tail_lines: Option, - line_start: Option, - line_end: Option, - grep: Option, + filter: Option, ) -> Result<(Vec, String, bool), CoreError> { // Use streaming approach to handle all filtering options consistently let (mut reader, mime_type, is_binary) = self.get_item_content_info_streaming( - conn, id, None + conn, id, filter )?; // Read all the filtered content into a buffer