diff --git a/crates/dbx-core/src/db/redis_driver.rs b/crates/dbx-core/src/db/redis_driver.rs index 1ef0e61ad3..28c02268b3 100644 --- a/crates/dbx-core/src/db/redis_driver.rs +++ b/crates/dbx-core/src/db/redis_driver.rs @@ -276,23 +276,25 @@ pub async fn scan_keys_page( .map_err(|e| e.to_string())?; let (next_cursor, keys) = parse_scan_keys(raw)?; + if keys.is_empty() { + return Ok(RedisScanResult { cursor: next_cursor, keys: Vec::new() }); + } - let mut result = Vec::new(); + let mut pipe = redis::pipe(); for key in &keys { - let key_type: String = - redis::cmd("TYPE").arg(key).query_async(con).await.unwrap_or_else(|_| "unknown".to_string()); - - let ttl: i64 = redis::cmd("TTL").arg(key).query_async(con).await.unwrap_or(-1); - - let (size, value_preview) = fetch_key_preview(con, key, &key_type).await; + pipe.cmd("TYPE").arg(key); + } + let key_types: Vec = pipe.query_async(con).await.unwrap_or_default(); + let mut result = Vec::with_capacity(keys.len()); + for (index, key) in keys.iter().enumerate() { result.push(RedisKeyInfo { key_display: redis_key_bytes_to_display(key), key_raw: redis_key_bytes_to_raw(key), - key_type, - ttl, - size, - value_preview, + key_type: key_types.get(index).cloned().unwrap_or_else(|| "unknown".to_string()), + ttl: -2, + size: 0, + value_preview: String::new(), }); } Ok(RedisScanResult { cursor: next_cursor, keys: result }) @@ -351,89 +353,6 @@ pub async fn get_value(con: &mut redis::aio::MultiplexedConnection, key: &[u8]) }) } -async fn fetch_key_preview(con: &mut redis::aio::MultiplexedConnection, key: &[u8], key_type: &str) -> (u64, String) { - match key_type { - "string" => { - let len: u64 = redis::cmd("STRLEN").arg(key).query_async(con).await.unwrap_or(0); - let v: Option = redis::cmd("GETRANGE").arg(key).arg(0).arg(199).query_async(con).await.ok(); - (len, v.unwrap_or_default()) - } - "list" => { - let len: u64 = redis::cmd("LLEN").arg(key).query_async(con).await.unwrap_or(0); - let items: Vec = - redis::cmd("LRANGE").arg(key).arg(0).arg(2).query_async(con).await.unwrap_or_default(); - let preview = format!("[{}]", items.join(", ")); - (len, preview) - } - "set" => { - let len: u64 = redis::cmd("SCARD").arg(key).query_async(con).await.unwrap_or(0); - let raw: RedisRawValue = redis::cmd("SSCAN") - .arg(key) - .arg(0) - .arg("COUNT") - .arg(3) - .query_async(con) - .await - .unwrap_or(RedisRawValue::Nil); - let members = parse_scan_members(raw).map(|(_, items)| items).unwrap_or_default(); - let parts: Vec = members.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).take(3).collect(); - let preview = format!("{{{}}}", parts.join(", ")); - (len, preview) - } - "hash" => { - let len: u64 = redis::cmd("HLEN").arg(key).query_async(con).await.unwrap_or(0); - let raw: RedisRawValue = redis::cmd("HSCAN") - .arg(key) - .arg(0) - .arg("COUNT") - .arg(3) - .query_async(con) - .await - .unwrap_or(RedisRawValue::Nil); - let pairs = parse_scan_pairs(raw, "hash").map(|(_, items)| items).unwrap_or_default(); - let parts: Vec = pairs - .iter() - .take(3) - .filter_map(|v| { - let f = v.get("field")?.as_str()?; - let val = v.get("value")?.as_str()?; - Some(format!("{f}:{val}")) - }) - .collect(); - let preview = format!("[{}]", parts.join(", ")); - (len, preview) - } - "zset" => { - let len: u64 = redis::cmd("ZCARD").arg(key).query_async(con).await.unwrap_or(0); - let raw: RedisRawValue = redis::cmd("ZSCAN") - .arg(key) - .arg(0) - .arg("COUNT") - .arg(3) - .query_async(con) - .await - .unwrap_or(RedisRawValue::Nil); - let pairs = parse_scan_pairs(raw, "zset").map(|(_, items)| items).unwrap_or_default(); - let parts: Vec = pairs - .iter() - .take(3) - .filter_map(|v| { - let m = v.get("member")?.as_str()?; - let s = v.get("score")?.as_str()?; - Some(format!("{m}:{s}")) - }) - .collect(); - let preview = format!("{{{}}}", parts.join(", ")); - (len, preview) - } - "stream" => { - let len: u64 = redis::cmd("XLEN").arg(key).query_async(con).await.unwrap_or(0); - (len, format!("{len} entries")) - } - _ => (0, String::new()), - } -} - async fn get_stream_entries( con: &mut redis::aio::MultiplexedConnection, key: &[u8], diff --git a/src/components/redis/RedisKeyBrowser.vue b/src/components/redis/RedisKeyBrowser.vue index 9d0d110274..323fe58e6f 100644 --- a/src/components/redis/RedisKeyBrowser.vue +++ b/src/components/redis/RedisKeyBrowser.vue @@ -304,7 +304,8 @@ function typeColor(type: string): string { } } -function formatSize(size: number, type: string): string { +function formatSize(size: number, type: string, valuePreview: string): string { + if (!valuePreview) return ""; if (type === "string") { if (size >= 1024) return `${(size / 1024).toFixed(1)} KB`; return `${size} B`; @@ -312,6 +313,11 @@ function formatSize(size: number, type: string): string { return String(size); } +function formatTtl(ttl: number): string { + if (ttl === -2) return ""; + return ttl === -1 ? "∞" : `${ttl}s`; +} + let searchTimer: ReturnType | null = null; function onSearchInput() { @@ -519,14 +525,14 @@ defineExpose({ focusSearch });
- +
- +