diff --git a/src/admin_meta.rs b/src/admin_meta.rs index 78ba22a..1112605 100644 --- a/src/admin_meta.rs +++ b/src/admin_meta.rs @@ -217,6 +217,32 @@ pub fn set_database_public( Ok(()) } +// Set database name +pub fn set_database_name( + base_dir: &str, + backend: options::BackendType, + admin_secret: &str, + id: u64, + name: &str, +) -> Result<(), DBError> { + let admin = open_admin_storage(base_dir, backend, admin_secret)?; + let mk = k_meta_db(id); + let _ = admin.hset(&mk, vec![("name".to_string(), name.to_string())])?; + Ok(()) +} + +// Get database name +pub fn get_database_name( + base_dir: &str, + backend: options::BackendType, + admin_secret: &str, + id: u64, +) -> Result, DBError> { + let admin = open_admin_storage(base_dir, backend, admin_secret)?; + let mk = k_meta_db(id); + admin.hget(&mk, "name") +} + // Internal: load public flag; default to true when meta missing fn load_public( admin: &Arc, diff --git a/src/rpc.rs b/src/rpc.rs index 49a69de..bf0eb2d 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -244,10 +244,15 @@ impl RpcServerImpl { let storage = server.current_storage().ok(); let encrypted = storage.as_ref().map(|s| s.is_encrypted()).unwrap_or(server.option.encrypt); - // Access key count via admin DB 0 - let key_count = admin_meta::list_access_keys(&self.base_dir, self.backend.clone(), &self.admin_secret, db_id) - .map(|v| v.len() as u64) - .ok(); + // Get actual key count from storage + let key_count = storage.as_ref() + .and_then(|s| s.dbsize().ok()) + .map(|count| count as u64); + + // Get database name from admin meta + let name = admin_meta::get_database_name(&self.base_dir, self.backend.clone(), &self.admin_secret, db_id) + .ok() + .flatten(); // Compute size on disk and timestamps from the DB file path let db_path = self.db_file_path(server, db_id); @@ -261,7 +266,7 @@ impl RpcServerImpl { DatabaseInfo { id: db_id, - name: None, + name, backend, encrypted, redis_version: Some("7.0".to_string()), @@ -279,7 +284,7 @@ impl RpcServer for RpcServerImpl { async fn create_database( &self, backend: BackendType, - _config: DatabaseConfig, + config: DatabaseConfig, encryption_key: Option, ) -> RpcResult { // Allocate new ID via admin DB 0 @@ -292,6 +297,12 @@ impl RpcServer for RpcServerImpl { .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned(-32000, e.0, None::<()>))?; } + // Persist database name if provided + if let Some(ref name) = config.name { + admin_meta::set_database_name(&self.base_dir, self.backend.clone(), &self.admin_secret, db_id, name) + .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned(-32000, e.0, None::<()>))?; + } + // Ensure base dir exists if let Err(e) = std::fs::create_dir_all(&self.base_dir) { return Err(jsonrpsee::types::ErrorObjectOwned::owned(-32000, format!("Failed to ensure base dir: {}", e), None::<()>)); diff --git a/tests/rpc_tests.rs b/tests/rpc_tests.rs index 741cf70..8f8e6ce 100644 --- a/tests/rpc_tests.rs +++ b/tests/rpc_tests.rs @@ -1,9 +1,6 @@ -use std::net::SocketAddr; -use jsonrpsee::http_client::HttpClientBuilder; -use jsonrpsee::core::client::ClientT; -use serde_json::json; - -use herodb::rpc::{RpcClient, BackendType, DatabaseConfig}; +use herodb::rpc::{BackendType, DatabaseConfig}; +use herodb::admin_meta; +use herodb::options::BackendType as OptionsBackendType; #[tokio::test] async fn test_rpc_server_basic() { @@ -59,4 +56,30 @@ async fn test_backend_type_serialization() { assert!(matches!(redb_deserialized, BackendType::Redb)); assert!(matches!(sled_deserialized, BackendType::Sled)); -} \ No newline at end of file +} + +#[tokio::test] +async fn test_database_name_persistence() { + let base_dir = "/tmp/test_db_name_persistence"; + let admin_secret = "test-admin-secret"; + let backend = OptionsBackendType::Redb; + let db_id = 1; + let test_name = "test-database-name"; + + // Clean up any existing test data + let _ = std::fs::remove_dir_all(base_dir); + + // Set the database name + admin_meta::set_database_name(base_dir, backend.clone(), admin_secret, db_id, test_name) + .expect("Failed to set database name"); + + // Retrieve the database name + let retrieved_name = admin_meta::get_database_name(base_dir, backend, admin_secret, db_id) + .expect("Failed to get database name"); + + // Verify the name matches + assert_eq!(retrieved_name, Some(test_name.to_string())); + + // Clean up + let _ = std::fs::remove_dir_all(base_dir); +}