Skip to main content

edgebase_admin/
kv.rs

1//! KvClient — KV namespace access for server-side use.
2
3use std::collections::HashMap;
4use std::sync::Arc;
5
6use serde_json::Value;
7
8use crate::generated::admin_api_core::GeneratedAdminApi;
9use edgebase_core::error::Error;
10use edgebase_core::http_client::HttpClient;
11
12/// Client for a user-defined KV namespace.
13pub struct KvClient {
14    http: Arc<HttpClient>,
15    pub(crate) namespace: String,
16}
17
18impl KvClient {
19    pub(crate) fn new(http: Arc<HttpClient>, namespace: &str) -> Self {
20        Self {
21            http,
22            namespace: namespace.to_string(),
23        }
24    }
25
26    fn core(&self) -> GeneratedAdminApi<'_> {
27        GeneratedAdminApi::new(&self.http)
28    }
29
30    /// Get a value by key. Returns None if not found.
31    pub async fn get(&self, key: &str) -> Result<Option<String>, Error> {
32        let body = serde_json::json!({"action": "get", "key": key});
33        let res: serde_json::Value = self.core().kv_operation(&self.namespace, &body).await?;
34        Ok(res.get("value").and_then(|v: &serde_json::Value| v.as_str()).map(|s: &str| s.to_string()))
35    }
36
37    /// Set a key-value pair with optional TTL in seconds.
38    pub async fn set(&self, key: &str, value: &str, ttl: Option<u64>) -> Result<(), Error> {
39        let mut body = serde_json::json!({"action": "set", "key": key, "value": value});
40        if let Some(t) = ttl {
41            body["ttl"] = serde_json::json!(t);
42        }
43        self.core().kv_operation(&self.namespace, &body).await?;
44        Ok(())
45    }
46
47    /// Delete a key.
48    pub async fn delete(&self, key: &str) -> Result<(), Error> {
49        let body = serde_json::json!({"action": "delete", "key": key});
50        self.core().kv_operation(&self.namespace, &body).await?;
51        Ok(())
52    }
53
54    /// List keys with optional prefix, limit, and cursor.
55    pub async fn list(
56        &self,
57        prefix: Option<&str>,
58        limit: Option<u32>,
59        cursor: Option<&str>,
60    ) -> Result<HashMap<String, Value>, Error> {
61        let mut body = serde_json::json!({"action": "list"});
62        if let Some(p) = prefix { body["prefix"] = serde_json::json!(p); }
63        if let Some(l) = limit { body["limit"] = serde_json::json!(l); }
64        if let Some(c) = cursor { body["cursor"] = serde_json::json!(c); }
65        let res: serde_json::Value = self.core().kv_operation(&self.namespace, &body).await?;
66        if let Some(obj) = res.as_object() {
67            Ok(obj.iter().map(|(k, v): (&String, &serde_json::Value)| (k.clone(), v.clone())).collect())
68        } else {
69            Ok(HashMap::new())
70        }
71    }
72}