redis_enterprise/
bdb.rs

1//! Database (BDB) management for Redis Enterprise
2//!
3//! ## Overview
4//! - Create, list, update, and delete databases
5//! - Execute database actions (backup, restore, import, export)
6//! - Monitor database status and metrics
7//! - Configure database endpoints and sharding
8//!
9//! ## Examples
10//!
11//! ### Creating a Database
12//! ```no_run
13//! use redis_enterprise::{EnterpriseClient, BdbHandler as DatabaseHandler, CreateDatabaseRequest};
14//!
15//! # async fn example(client: EnterpriseClient) -> Result<(), Box<dyn std::error::Error>> {
16//! let handler = DatabaseHandler::new(client);
17//!
18//! // Simple cache database
19//! let cache_db = CreateDatabaseRequest::builder()
20//!     .name("my-cache")
21//!     .memory_size(1_073_741_824)  // 1GB
22//!     .eviction_policy("allkeys-lru")
23//!     .persistence("disabled")
24//!     .build();
25//!
26//! let db = handler.create(cache_db).await?;
27//! println!("Created database with ID: {}", db.uid);
28//! # Ok(())
29//! # }
30//! ```
31//!
32//! ### Database Actions
33//! ```no_run
34//! # use redis_enterprise::{EnterpriseClient, BdbHandler as DatabaseHandler};
35//! # async fn example(client: EnterpriseClient) -> Result<(), Box<dyn std::error::Error>> {
36//! let handler = DatabaseHandler::new(client);
37//! let db_id = 1;
38//!
39//! // Backup database
40//! let backup = handler.backup(db_id).await?;
41//! println!("Backup started: {:?}", backup.action_uid);
42//!
43//! // Export to remote location
44//! let export = handler.export(db_id, "ftp://backup.site/db.rdb").await?;
45//! println!("Export initiated: {:?}", export.action_uid);
46//!
47//! // Import from backup
48//! let import = handler.import(db_id, "ftp://backup.site/db.rdb", true).await?;
49//! println!("Import started: {:?}", import.action_uid);
50//! # Ok(())
51//! # }
52//! ```
53//!
54//! ### Monitoring Databases
55//! ```no_run
56//! # use redis_enterprise::{EnterpriseClient, BdbHandler as DatabaseHandler};
57//! # async fn example(client: EnterpriseClient) -> Result<(), Box<dyn std::error::Error>> {
58//! let handler = DatabaseHandler::new(client);
59//!
60//! // List all databases
61//! let databases = handler.list().await?;
62//! for db in databases {
63//!     println!("{}: {} MB used", db.name, db.memory_used.unwrap_or(0) / 1_048_576);
64//! }
65//!
66//! // Get database endpoints
67//! let endpoints = handler.endpoints(1).await?;
68//! for endpoint in endpoints {
69//!     println!("Endpoint: {:?}:{:?}", endpoint.dns_name, endpoint.port);
70//! }
71//! # Ok(())
72//! # }
73//! ```
74
75use crate::client::RestClient;
76use crate::error::Result;
77use serde::{Deserialize, Serialize};
78use serde_json::Value;
79use typed_builder::TypedBuilder;
80
81// Aliases for easier use
82pub type Database = DatabaseInfo;
83pub type BdbHandler = DatabaseHandler;
84
85/// Response from database action operations
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct DatabaseActionResponse {
88    /// The action UID for tracking async operations
89    pub action_uid: String,
90    /// Description of the action
91    pub description: Option<String>,
92    /// Additional fields from the response
93    #[serde(flatten)]
94    pub extra: Value,
95}
96
97/// Response from backup operation
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct BackupResponse {
100    /// The action UID for tracking the backup operation
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub action_uid: Option<String>,
103    /// Backup UID if available
104    pub backup_uid: Option<String>,
105    /// Additional fields from the response
106    #[serde(flatten)]
107    pub extra: Value,
108}
109
110/// Response from import operation
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct ImportResponse {
113    /// The action UID for tracking the import operation
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub action_uid: Option<String>,
116    /// Import status
117    pub status: Option<String>,
118    /// Additional fields from the response
119    #[serde(flatten)]
120    pub extra: Value,
121}
122
123/// Response from export operation
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct ExportResponse {
126    /// The action UID for tracking the export operation
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub action_uid: Option<String>,
129    /// Export status
130    pub status: Option<String>,
131    /// Additional fields from the response
132    #[serde(flatten)]
133    pub extra: Value,
134}
135
136/// Database information from the REST API - 100% field coverage (152/152 fields)
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct DatabaseInfo {
139    // Core database identification and status
140    pub uid: u32,
141    pub name: String,
142    pub port: Option<u16>,
143    pub status: Option<String>,
144    pub memory_size: Option<u64>,
145    pub memory_used: Option<u64>,
146
147    /// Database type (e.g., "redis", "memcached")
148    #[serde(rename = "type")]
149    pub type_: Option<String>,
150    pub version: Option<String>,
151
152    /// Account and action tracking
153    pub account_id: Option<u32>,
154    pub action_uid: Option<String>,
155
156    // Sharding and placement
157    pub shards_count: Option<u32>,
158    pub shard_list: Option<Vec<u32>>,
159    pub sharding: Option<bool>,
160    pub shards_placement: Option<String>,
161    pub replication: Option<bool>,
162
163    // Endpoints and networking
164    pub endpoints: Option<Vec<EndpointInfo>>,
165    pub endpoint: Option<String>,
166    pub endpoint_ip: Option<Vec<String>>,
167    pub endpoint_node: Option<u32>,
168    pub dns_address_master: Option<String>,
169
170    // Data persistence and backup
171    pub persistence: Option<String>,
172    pub data_persistence: Option<String>,
173    pub eviction_policy: Option<String>,
174
175    // Timestamps
176    pub created_time: Option<String>,
177    pub last_changed_time: Option<String>,
178    pub last_backup_time: Option<String>,
179    pub last_export_time: Option<String>,
180
181    // Security and authentication
182    pub mtls_allow_weak_hashing: Option<bool>,
183    pub mtls_allow_outdated_certs: Option<bool>,
184    pub authentication_redis_pass: Option<String>,
185    pub authentication_admin_pass: Option<String>,
186    pub authentication_sasl_pass: Option<String>,
187    pub authentication_sasl_uname: Option<String>,
188    pub authentication_ssl_client_certs: Option<Vec<Value>>,
189    pub authentication_ssl_crdt_certs: Option<Vec<Value>>,
190    pub authorized_subjects: Option<Vec<Value>>,
191    pub data_internode_encryption: Option<bool>,
192    pub ssl: Option<bool>,
193    pub tls_mode: Option<String>,
194    pub enforce_client_authentication: Option<String>,
195    pub default_user: Option<bool>,
196    /// ACL configuration
197    pub acl: Option<Value>,
198    /// Client certificate subject validation type
199    pub client_cert_subject_validation_type: Option<String>,
200    /// Compare key hslot
201    pub compare_key_hslot: Option<bool>,
202    /// DNS suffixes for endpoints
203    pub dns_suffixes: Option<Vec<String>>,
204    /// Group UID for the database
205    pub group_uid: Option<u32>,
206    /// Redis cluster mode enabled
207    pub redis_cluster_enabled: Option<bool>,
208
209    // CRDT/Active-Active fields
210    pub crdt: Option<bool>,
211    pub crdt_enabled: Option<bool>,
212    pub crdt_config_version: Option<u32>,
213    pub crdt_replica_id: Option<u32>,
214    pub crdt_ghost_replica_ids: Option<String>,
215    pub crdt_featureset_version: Option<u32>,
216    pub crdt_protocol_version: Option<u32>,
217    pub crdt_guid: Option<String>,
218    pub crdt_modules: Option<String>,
219    pub crdt_replicas: Option<String>,
220    pub crdt_sources: Option<Vec<Value>>,
221    pub crdt_sync: Option<String>,
222    pub crdt_sync_connection_alarm_timeout_seconds: Option<u32>,
223    pub crdt_sync_dist: Option<bool>,
224    pub crdt_syncer_auto_oom_unlatch: Option<bool>,
225    pub crdt_xadd_id_uniqueness_mode: Option<String>,
226    pub crdt_causal_consistency: Option<bool>,
227    pub crdt_repl_backlog_size: Option<String>,
228
229    // Replication settings
230    pub master_persistence: Option<String>,
231    pub slave_ha: Option<bool>,
232    pub slave_ha_priority: Option<u32>,
233    pub replica_read_only: Option<bool>,
234    pub replica_sources: Option<Vec<Value>>,
235    pub replica_sync: Option<String>,
236    pub replica_sync_connection_alarm_timeout_seconds: Option<u32>,
237    pub replica_sync_dist: Option<bool>,
238    pub repl_backlog_size: Option<String>,
239
240    // Connection and performance settings
241    pub max_connections: Option<u32>,
242    pub maxclients: Option<u32>,
243    pub conns: Option<u32>,
244    pub conns_type: Option<String>,
245    pub max_client_pipeline: Option<u32>,
246    pub max_pipelined: Option<u32>,
247
248    // AOF (Append Only File) settings
249    pub aof_policy: Option<String>,
250    pub max_aof_file_size: Option<String>,
251    pub max_aof_load_time: Option<u32>,
252
253    // Active defragmentation settings
254    pub activedefrag: Option<String>,
255    pub active_defrag_cycle_max: Option<u32>,
256    pub active_defrag_cycle_min: Option<u32>,
257    pub active_defrag_ignore_bytes: Option<String>,
258    pub active_defrag_max_scan_fields: Option<u32>,
259    pub active_defrag_threshold_lower: Option<u32>,
260    pub active_defrag_threshold_upper: Option<u32>,
261
262    // Backup settings
263    pub backup: Option<bool>,
264    pub backup_failure_reason: Option<String>,
265    pub backup_history: Option<u32>,
266    pub backup_interval: Option<u32>,
267    pub backup_interval_offset: Option<u32>,
268    pub backup_location: Option<Value>,
269    pub backup_progress: Option<f64>,
270    pub backup_status: Option<String>,
271
272    // Import/Export settings
273    pub dataset_import_sources: Option<Vec<Value>>,
274    pub import_failure_reason: Option<String>,
275    pub import_progress: Option<f64>,
276    pub import_status: Option<String>,
277    pub export_failure_reason: Option<String>,
278    pub export_progress: Option<f64>,
279    pub export_status: Option<String>,
280    pub skip_import_analyze: Option<bool>,
281
282    // Monitoring and metrics
283    pub metrics_export_all: Option<bool>,
284    pub generate_text_monitor: Option<bool>,
285    pub email_alerts: Option<bool>,
286
287    // Modules and features
288    pub module_list: Option<Vec<Value>>,
289    pub search: Option<bool>,
290    pub timeseries: Option<bool>,
291
292    // BigStore/Flash storage settings
293    pub bigstore: Option<bool>,
294    pub bigstore_ram_size: Option<u64>,
295    pub bigstore_max_ram_ratio: Option<u32>,
296    pub bigstore_ram_weights: Option<Vec<Value>>,
297    pub bigstore_version: Option<u32>,
298
299    // Network and proxy settings
300    pub proxy_policy: Option<String>,
301    pub oss_cluster: Option<bool>,
302    pub oss_cluster_api_preferred_endpoint_type: Option<String>,
303    pub oss_cluster_api_preferred_ip_type: Option<String>,
304    pub oss_sharding: Option<bool>,
305
306    // Redis-specific settings
307    pub redis_version: Option<String>,
308    pub resp3: Option<bool>,
309    pub disabled_commands: Option<String>,
310
311    // Clustering and sharding
312    pub hash_slots_policy: Option<String>,
313    pub shard_key_regex: Option<Vec<Value>>,
314    pub shard_block_crossslot_keys: Option<bool>,
315    pub shard_block_foreign_keys: Option<bool>,
316    pub implicit_shard_key: Option<bool>,
317
318    // Node placement and rack awareness
319    pub avoid_nodes: Option<Vec<String>>,
320    pub use_nodes: Option<Vec<String>>,
321    pub rack_aware: Option<bool>,
322
323    // Operational settings
324    pub auto_upgrade: Option<bool>,
325    pub internal: Option<bool>,
326    pub db_conns_auditing: Option<bool>,
327    pub flush_on_fullsync: Option<bool>,
328    pub use_selective_flush: Option<bool>,
329
330    // Sync and replication control
331    pub sync: Option<String>,
332    pub sync_sources: Option<Vec<Value>>,
333    pub sync_dedicated_threads: Option<bool>,
334    pub syncer_mode: Option<String>,
335    pub syncer_log_level: Option<String>,
336    pub support_syncer_reconf: Option<bool>,
337
338    // Gradual sync settings
339    pub gradual_src_mode: Option<String>,
340    pub gradual_src_max_sources: Option<u32>,
341    pub gradual_sync_mode: Option<String>,
342    pub gradual_sync_max_shards_per_source: Option<u32>,
343
344    // Slave and buffer settings
345    pub slave_buffer: Option<String>,
346
347    // Snapshot settings
348    pub snapshot_policy: Option<Vec<Value>>,
349
350    // Scheduling and recovery
351    pub sched_policy: Option<String>,
352    pub recovery_wait_time: Option<u32>,
353
354    // Performance and optimization
355    pub multi_commands_opt: Option<String>,
356    pub throughput_ingress: Option<f64>,
357    pub tracking_table_max_keys: Option<u32>,
358    pub wait_command: Option<bool>,
359
360    // Legacy and deprecated fields
361    pub background_op: Option<Vec<Value>>,
362
363    // Advanced configuration
364    pub mkms: Option<bool>,
365    pub roles_permissions: Option<Vec<Value>>,
366    pub tags: Option<Vec<String>>,
367    pub topology_epoch: Option<u32>,
368
369    /// Capture any additional fields not explicitly defined
370    #[serde(flatten)]
371    pub extra: Value,
372}
373
374/// Database endpoint information
375#[derive(Debug, Clone, Serialize, Deserialize)]
376pub struct EndpointInfo {
377    /// Unique identifier for the endpoint
378    pub uid: Option<String>,
379    /// List of IP addresses for the endpoint
380    pub addr: Option<Vec<String>>,
381    /// Port number for the endpoint
382    pub port: Option<u16>,
383    /// DNS name for the endpoint
384    pub dns_name: Option<String>,
385    /// Proxy policy for the endpoint
386    pub proxy_policy: Option<String>,
387    /// Address type (e.g., "internal", "external")
388    pub addr_type: Option<String>,
389    /// OSS cluster API preferred IP type
390    pub oss_cluster_api_preferred_ip_type: Option<String>,
391    /// List of proxy UIDs to exclude
392    pub exclude_proxies: Option<Vec<u32>>,
393    /// List of proxy UIDs to include
394    pub include_proxies: Option<Vec<u32>>,
395    /// Capture any additional fields
396    #[serde(flatten)]
397    pub extra: Value,
398}
399
400/// Module configuration for database creation
401#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
402pub struct ModuleConfig {
403    #[builder(setter(into))]
404    pub module_name: String,
405    #[serde(skip_serializing_if = "Option::is_none")]
406    #[builder(default, setter(into, strip_option))]
407    pub module_args: Option<String>,
408}
409
410/// Create database request
411///
412/// # Examples
413///
414/// ```rust,no_run
415/// use redis_enterprise::{CreateDatabaseRequest, ModuleConfig};
416///
417/// let request = CreateDatabaseRequest::builder()
418///     .name("my-database")
419///     .memory_size(1024 * 1024 * 1024) // 1GB
420///     .port(12000)
421///     .replication(true)
422///     .persistence("aof")
423///     .eviction_policy("volatile-lru")
424///     .shards_count(2)
425///     .authentication_redis_pass("secure-password")
426///     .build();
427/// ```
428#[derive(Debug, Serialize, Deserialize, TypedBuilder)]
429pub struct CreateDatabaseRequest {
430    #[builder(setter(into))]
431    pub name: String,
432    #[serde(skip_serializing_if = "Option::is_none")]
433    #[builder(default, setter(strip_option))]
434    pub memory_size: Option<u64>,
435    #[serde(skip_serializing_if = "Option::is_none")]
436    #[builder(default, setter(strip_option))]
437    pub port: Option<u16>,
438    #[serde(skip_serializing_if = "Option::is_none")]
439    #[builder(default, setter(strip_option))]
440    pub replication: Option<bool>,
441    #[serde(skip_serializing_if = "Option::is_none")]
442    #[builder(default, setter(into, strip_option))]
443    pub persistence: Option<String>,
444    #[serde(skip_serializing_if = "Option::is_none")]
445    #[builder(default, setter(into, strip_option))]
446    pub eviction_policy: Option<String>,
447    #[serde(skip_serializing_if = "Option::is_none")]
448    #[builder(default, setter(strip_option))]
449    pub sharding: Option<bool>,
450    #[serde(skip_serializing_if = "Option::is_none")]
451    #[builder(default, setter(strip_option))]
452    pub shards_count: Option<u32>,
453    #[serde(skip_serializing_if = "Option::is_none", alias = "shard_count")]
454    #[builder(default, setter(strip_option))]
455    pub shard_count: Option<u32>,
456    #[serde(skip_serializing_if = "Option::is_none")]
457    #[builder(default, setter(into, strip_option))]
458    pub proxy_policy: Option<String>,
459    #[serde(skip_serializing_if = "Option::is_none")]
460    #[builder(default, setter(strip_option))]
461    pub rack_aware: Option<bool>,
462    #[serde(skip_serializing_if = "Option::is_none")]
463    #[builder(default, setter(strip_option))]
464    pub module_list: Option<Vec<ModuleConfig>>,
465    #[serde(skip_serializing_if = "Option::is_none")]
466    #[builder(default, setter(strip_option))]
467    pub crdt: Option<bool>,
468    #[serde(skip_serializing_if = "Option::is_none")]
469    #[builder(default, setter(into, strip_option))]
470    pub authentication_redis_pass: Option<String>,
471}
472
473/// Database handler for executing database commands
474pub struct DatabaseHandler {
475    client: RestClient,
476}
477
478impl DatabaseHandler {
479    pub fn new(client: RestClient) -> Self {
480        DatabaseHandler { client }
481    }
482
483    /// List all databases (BDB.LIST)
484    pub async fn list(&self) -> Result<Vec<DatabaseInfo>> {
485        self.client.get("/v1/bdbs").await
486    }
487
488    /// Get specific database info (BDB.INFO)
489    pub async fn info(&self, uid: u32) -> Result<DatabaseInfo> {
490        self.client.get(&format!("/v1/bdbs/{}", uid)).await
491    }
492
493    /// Get specific database info (alias for info)
494    pub async fn get(&self, uid: u32) -> Result<DatabaseInfo> {
495        self.info(uid).await
496    }
497
498    /// Create a new database (BDB.CREATE)
499    pub async fn create(&self, request: CreateDatabaseRequest) -> Result<DatabaseInfo> {
500        self.client.post("/v1/bdbs", &request).await
501    }
502
503    /// Update database configuration (BDB.UPDATE)
504    pub async fn update(&self, uid: u32, updates: Value) -> Result<DatabaseInfo> {
505        self.client
506            .put(&format!("/v1/bdbs/{}", uid), &updates)
507            .await
508    }
509
510    /// Delete a database (BDB.DELETE)
511    pub async fn delete(&self, uid: u32) -> Result<()> {
512        self.client.delete(&format!("/v1/bdbs/{}", uid)).await
513    }
514
515    /// Get database stats (BDB.STATS)
516    pub async fn stats(&self, uid: u32) -> Result<Value> {
517        self.client.get(&format!("/v1/bdbs/{}/stats", uid)).await
518    }
519
520    /// Get database metrics (BDB.METRICS)
521    pub async fn metrics(&self, uid: u32) -> Result<Value> {
522        self.client.get(&format!("/v1/bdbs/{}/metrics", uid)).await
523    }
524
525    /// Start database (BDB.START)
526    pub async fn start(&self, uid: u32) -> Result<Value> {
527        self.client
528            .post(
529                &format!("/v1/bdbs/{}/actions/start", uid),
530                &serde_json::json!({}),
531            )
532            .await
533    }
534
535    /// Stop database (BDB.STOP)
536    pub async fn stop(&self, uid: u32) -> Result<Value> {
537        self.client
538            .post(
539                &format!("/v1/bdbs/{}/actions/stop", uid),
540                &serde_json::json!({}),
541            )
542            .await
543    }
544
545    /// Restart database (BDB.RESTART)
546    pub async fn restart(&self, uid: u32) -> Result<DatabaseActionResponse> {
547        self.client
548            .post(
549                &format!("/v1/bdbs/{}/actions/restart", uid),
550                &serde_json::json!({}),
551            )
552            .await
553    }
554
555    /// Export database (BDB.EXPORT)
556    pub async fn export(&self, uid: u32, export_location: &str) -> Result<ExportResponse> {
557        let body = serde_json::json!({
558            "export_location": export_location
559        });
560        self.client
561            .post(&format!("/v1/bdbs/{}/actions/export", uid), &body)
562            .await
563    }
564
565    /// Import database (BDB.IMPORT)
566    pub async fn import(
567        &self,
568        uid: u32,
569        import_location: &str,
570        flush: bool,
571    ) -> Result<ImportResponse> {
572        let body = serde_json::json!({
573            "import_location": import_location,
574            "flush": flush
575        });
576        self.client
577            .post(&format!("/v1/bdbs/{}/actions/import", uid), &body)
578            .await
579    }
580
581    /// Flush database (BDB.FLUSH)
582    pub async fn flush(&self, uid: u32) -> Result<DatabaseActionResponse> {
583        self.client
584            .post(
585                &format!("/v1/bdbs/{}/actions/flush", uid),
586                &serde_json::json!({}),
587            )
588            .await
589    }
590
591    /// Backup database (BDB.BACKUP)
592    pub async fn backup(&self, uid: u32) -> Result<BackupResponse> {
593        self.client
594            .post(
595                &format!("/v1/bdbs/{}/actions/backup", uid),
596                &serde_json::json!({}),
597            )
598            .await
599    }
600
601    /// Restore database from backup (BDB.RESTORE)
602    pub async fn restore(
603        &self,
604        uid: u32,
605        backup_uid: Option<&str>,
606    ) -> Result<DatabaseActionResponse> {
607        let body = if let Some(backup_id) = backup_uid {
608            serde_json::json!({ "backup_uid": backup_id })
609        } else {
610            serde_json::json!({})
611        };
612        self.client
613            .post(&format!("/v1/bdbs/{}/actions/restore", uid), &body)
614            .await
615    }
616
617    /// Get database shards (BDB.SHARDS)
618    pub async fn shards(&self, uid: u32) -> Result<Value> {
619        self.client.get(&format!("/v1/bdbs/{}/shards", uid)).await
620    }
621
622    /// Get database endpoints (BDB.ENDPOINTS)
623    pub async fn endpoints(&self, uid: u32) -> Result<Vec<EndpointInfo>> {
624        self.client
625            .get(&format!("/v1/bdbs/{}/endpoints", uid))
626            .await
627    }
628
629    /// Optimize shards placement (status) - GET
630    pub async fn optimize_shards_placement(&self, uid: u32) -> Result<Value> {
631        self.client
632            .get(&format!(
633                "/v1/bdbs/{}/actions/optimize_shards_placement",
634                uid
635            ))
636            .await
637    }
638
639    /// Recover database (status) - GET
640    pub async fn recover_status(&self, uid: u32) -> Result<Value> {
641        self.client
642            .get(&format!("/v1/bdbs/{}/actions/recover", uid))
643            .await
644    }
645
646    /// Recover database - POST
647    pub async fn recover(&self, uid: u32) -> Result<DatabaseActionResponse> {
648        self.client
649            .post(
650                &format!("/v1/bdbs/{}/actions/recover", uid),
651                &serde_json::json!({}),
652            )
653            .await
654    }
655
656    /// Resume traffic - POST
657    pub async fn resume_traffic(&self, uid: u32) -> Result<DatabaseActionResponse> {
658        self.client
659            .post(
660                &format!("/v1/bdbs/{}/actions/resume_traffic", uid),
661                &serde_json::json!({}),
662            )
663            .await
664    }
665
666    /// Stop traffic - POST
667    pub async fn stop_traffic(&self, uid: u32) -> Result<DatabaseActionResponse> {
668        self.client
669            .post(
670                &format!("/v1/bdbs/{}/actions/stop_traffic", uid),
671                &serde_json::json!({}),
672            )
673            .await
674    }
675
676    /// Rebalance database - PUT
677    pub async fn rebalance(&self, uid: u32) -> Result<DatabaseActionResponse> {
678        self.client
679            .put(
680                &format!("/v1/bdbs/{}/actions/rebalance", uid),
681                &serde_json::json!({}),
682            )
683            .await
684    }
685
686    /// Revamp database - PUT
687    pub async fn revamp(&self, uid: u32) -> Result<DatabaseActionResponse> {
688        self.client
689            .put(
690                &format!("/v1/bdbs/{}/actions/revamp", uid),
691                &serde_json::json!({}),
692            )
693            .await
694    }
695
696    /// Reset backup status - PUT
697    pub async fn backup_reset_status(&self, uid: u32) -> Result<Value> {
698        self.client
699            .put(
700                &format!("/v1/bdbs/{}/actions/backup_reset_status", uid),
701                &serde_json::json!({}),
702            )
703            .await
704    }
705
706    /// Reset export status - PUT
707    pub async fn export_reset_status(&self, uid: u32) -> Result<Value> {
708        self.client
709            .put(
710                &format!("/v1/bdbs/{}/actions/export_reset_status", uid),
711                &serde_json::json!({}),
712            )
713            .await
714    }
715
716    /// Reset import status - PUT
717    pub async fn import_reset_status(&self, uid: u32) -> Result<Value> {
718        self.client
719            .put(
720                &format!("/v1/bdbs/{}/actions/import_reset_status", uid),
721                &serde_json::json!({}),
722            )
723            .await
724    }
725
726    /// Peer stats for a database - GET
727    pub async fn peer_stats(&self, uid: u32) -> Result<Value> {
728        self.client
729            .get(&format!("/v1/bdbs/{}/peer_stats", uid))
730            .await
731    }
732
733    /// Peer stats for a specific peer - GET
734    pub async fn peer_stats_for(&self, uid: u32, peer_uid: u32) -> Result<Value> {
735        self.client
736            .get(&format!("/v1/bdbs/{}/peer_stats/{}", uid, peer_uid))
737            .await
738    }
739
740    /// Sync source stats for a database - GET
741    pub async fn sync_source_stats(&self, uid: u32) -> Result<Value> {
742        self.client
743            .get(&format!("/v1/bdbs/{}/sync_source_stats", uid))
744            .await
745    }
746
747    /// Sync source stats for a specific source - GET
748    pub async fn sync_source_stats_for(&self, uid: u32, src_uid: u32) -> Result<Value> {
749        self.client
750            .get(&format!("/v1/bdbs/{}/sync_source_stats/{}", uid, src_uid))
751            .await
752    }
753
754    /// Syncer state (all) - GET
755    pub async fn syncer_state(&self, uid: u32) -> Result<Value> {
756        self.client
757            .get(&format!("/v1/bdbs/{}/syncer_state", uid))
758            .await
759    }
760
761    /// Syncer state for CRDT - GET
762    pub async fn syncer_state_crdt(&self, uid: u32) -> Result<Value> {
763        self.client
764            .get(&format!("/v1/bdbs/{}/syncer_state/crdt", uid))
765            .await
766    }
767
768    /// Syncer state for replica - GET
769    pub async fn syncer_state_replica(&self, uid: u32) -> Result<Value> {
770        self.client
771            .get(&format!("/v1/bdbs/{}/syncer_state/replica", uid))
772            .await
773    }
774
775    /// Database passwords delete - DELETE
776    pub async fn passwords_delete(&self, uid: u32) -> Result<()> {
777        self.client
778            .delete(&format!("/v1/bdbs/{}/passwords", uid))
779            .await
780    }
781
782    /// List all database alerts - GET
783    pub async fn alerts_all(&self) -> Result<Value> {
784        self.client.get("/v1/bdbs/alerts").await
785    }
786
787    /// List alerts for a specific database - GET
788    pub async fn alerts_for(&self, uid: u32) -> Result<Value> {
789        self.client.get(&format!("/v1/bdbs/alerts/{}", uid)).await
790    }
791
792    /// Get a specific alert for a database - GET
793    pub async fn alert_detail(&self, uid: u32, alert: &str) -> Result<Value> {
794        self.client
795            .get(&format!("/v1/bdbs/alerts/{}/{}", uid, alert))
796            .await
797    }
798
799    /// CRDT source alerts - GET
800    pub async fn crdt_source_alerts_all(&self) -> Result<Value> {
801        self.client.get("/v1/bdbs/crdt_sources/alerts").await
802    }
803
804    /// CRDT source alerts for DB - GET
805    pub async fn crdt_source_alerts_for(&self, uid: u32) -> Result<Value> {
806        self.client
807            .get(&format!("/v1/bdbs/crdt_sources/alerts/{}", uid))
808            .await
809    }
810
811    /// CRDT source alerts for specific source - GET
812    pub async fn crdt_source_alerts_source(&self, uid: u32, source_id: u32) -> Result<Value> {
813        self.client
814            .get(&format!(
815                "/v1/bdbs/crdt_sources/alerts/{}/{}",
816                uid, source_id
817            ))
818            .await
819    }
820
821    /// CRDT source alert detail - GET
822    pub async fn crdt_source_alert_detail(
823        &self,
824        uid: u32,
825        source_id: u32,
826        alert: &str,
827    ) -> Result<Value> {
828        self.client
829            .get(&format!(
830                "/v1/bdbs/crdt_sources/alerts/{}/{}/{}",
831                uid, source_id, alert
832            ))
833            .await
834    }
835
836    /// Replica source alerts - GET
837    pub async fn replica_source_alerts_all(&self) -> Result<Value> {
838        self.client.get("/v1/bdbs/replica_sources/alerts").await
839    }
840
841    /// Replica source alerts for DB - GET
842    pub async fn replica_source_alerts_for(&self, uid: u32) -> Result<Value> {
843        self.client
844            .get(&format!("/v1/bdbs/replica_sources/alerts/{}", uid))
845            .await
846    }
847
848    /// Replica source alerts for specific source - GET
849    pub async fn replica_source_alerts_source(&self, uid: u32, source_id: u32) -> Result<Value> {
850        self.client
851            .get(&format!(
852                "/v1/bdbs/replica_sources/alerts/{}/{}",
853                uid, source_id
854            ))
855            .await
856    }
857
858    /// Replica source alert detail - GET
859    pub async fn replica_source_alert_detail(
860        &self,
861        uid: u32,
862        source_id: u32,
863        alert: &str,
864    ) -> Result<Value> {
865        self.client
866            .get(&format!(
867                "/v1/bdbs/replica_sources/alerts/{}/{}/{}",
868                uid, source_id, alert
869            ))
870            .await
871    }
872
873    /// Upgrade database with new module version (BDB.UPGRADE)
874    pub async fn upgrade(
875        &self,
876        uid: u32,
877        module_name: &str,
878        new_version: &str,
879    ) -> Result<DatabaseActionResponse> {
880        let body = serde_json::json!({
881            "module_name": module_name,
882            "new_version": new_version
883        });
884        self.client
885            .post(&format!("/v1/bdbs/{}/actions/upgrade", uid), &body)
886            .await
887    }
888
889    /// Reset database password (BDB.RESET_PASSWORD)
890    pub async fn reset_password(
891        &self,
892        uid: u32,
893        new_password: &str,
894    ) -> Result<DatabaseActionResponse> {
895        let body = serde_json::json!({
896            "authentication_redis_pass": new_password
897        });
898        self.client
899            .post(&format!("/v1/bdbs/{}/actions/reset_password", uid), &body)
900            .await
901    }
902
903    /// Check database availability
904    pub async fn availability(&self, uid: u32) -> Result<Value> {
905        self.client
906            .get(&format!("/v1/bdbs/{}/availability", uid))
907            .await
908    }
909
910    /// Check local database endpoint availability
911    pub async fn endpoint_availability(&self, uid: u32) -> Result<Value> {
912        self.client
913            .get(&format!("/v1/local/bdbs/{}/endpoint/availability", uid))
914            .await
915    }
916
917    /// Create database using v2 API (supports recovery plan)
918    pub async fn create_v2(&self, request: Value) -> Result<DatabaseInfo> {
919        self.client.post("/v2/bdbs", &request).await
920    }
921}