fix: add --meta filtering support to client/server list mode

Plumb metadata filter from client CLI through the HTTP API to the
server's data_service.list_items(). The server accepts a JSON-encoded
meta query parameter where null values mean 'key exists' and string
values mean 'exact match'.

Also fix LZ4 compression round-trip for client mode:
- Explicit flush FrameEncoder before drop to avoid sending only the
  frame header when compress=false
- Send _client_compression metadata so client knows actual compression
  on retrieval (server records compression=None when compress=false)
- Use FrameDecoder (frame format) instead of decompress_size_prepended
  (size-prepended format) to match server storage format
This commit is contained in:
2026-03-14 18:22:07 -03:00
parent f2d93a2812
commit 8acbd34150
7 changed files with 65 additions and 10 deletions

View File

@@ -23,14 +23,14 @@ pub fn mode(
ids[0]
} else if !tags.is_empty() {
// Find item by tags
let items = client.list_items(tags, "newest", 0, 1)?;
let items = client.list_items(tags, "newest", 0, 1, &std::collections::HashMap::new())?;
if items.is_empty() {
return Err(anyhow::anyhow!("No items found matching tags: {:?}", tags));
}
items[0].id
} else {
// Get latest item
let items = client.list_items(&[], "newest", 0, 1)?;
let items = client.list_items(&[], "newest", 0, 1, &std::collections::HashMap::new())?;
if items.is_empty() {
return Err(anyhow::anyhow!("No items found"));
}
@@ -60,8 +60,17 @@ pub fn mode(
}
}
// Decompress locally
let compression_type = CompressionType::from_str(&compression).unwrap_or(CompressionType::None);
// Decompress locally.
// Prefer _client_compression metadata (set by client save) over the server-reported
// compression header, because when compress=false the server stores compressed bytes
// but records compression=None.
let effective_compression = item_info
.metadata
.get("_client_compression")
.map(|s| s.as_str())
.unwrap_or(&compression);
let compression_type =
CompressionType::from_str(effective_compression).unwrap_or(CompressionType::None);
let decompressed = match compression_type {
CompressionType::GZip => {
@@ -71,8 +80,13 @@ pub fn mode(
decoder.read_to_end(&mut content)?;
content
}
CompressionType::LZ4 => lz4_flex::decompress_size_prepended(&raw_bytes)
.map_err(|e| anyhow::anyhow!("LZ4 decompression failed: {}", e))?,
CompressionType::LZ4 => {
use lz4_flex::frame::FrameDecoder;
let mut decoder = FrameDecoder::new(&raw_bytes[..]);
let mut content = Vec::new();
decoder.read_to_end(&mut content)?;
content
}
_ => raw_bytes,
};