redis_cloud/handlers/database.rs
1//! Database operations handler
2//!
3//! This module provides comprehensive database management capabilities for Redis Cloud,
4//! including CRUD operations, backups, imports, metrics, and scaling operations.
5//!
6//! # Examples
7//!
8//! ```rust,no_run
9//! use redis_cloud::{CloudClient, CloudDatabaseHandler};
10//! use serde_json::json;
11//!
12//! # #[tokio::main]
13//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
14//! let client = CloudClient::builder()
15//! .api_key("your-api-key")
16//! .api_secret("your-api-secret")
17//! .build()?;
18//!
19//! let db_handler = CloudDatabaseHandler::new(client);
20//!
21//! // Get database information
22//! let db_info = db_handler.get(123, 456).await?;
23//! println!("Database: {}", db_info.name);
24//!
25//! // Create database using raw client API
26//! let database_config = json!({
27//! "name": "my-redis-db",
28//! "memory_limit_in_gb": 2.5,
29//! "support_oss_cluster_api": false,
30//! "replication": true,
31//! "data_persistence": "aof-every-1-sec"
32//! });
33//! # Ok(())
34//! # }
35//! ```
36
37use crate::{
38 Result,
39 client::CloudClient,
40 models::{CloudDatabase, CreateDatabaseRequest, UpdateDatabaseRequest},
41};
42use serde_json::Value;
43
44/// Handler for Cloud database operations
45///
46/// Provides methods for managing Redis Cloud databases including creation, updates,
47/// backups, imports, metrics collection, and scaling operations.
48///
49/// All database operations require both a subscription ID and database ID, as databases
50/// are scoped within subscriptions in Redis Cloud.
51pub struct CloudDatabaseHandler {
52 client: CloudClient,
53}
54
55impl CloudDatabaseHandler {
56 /// Create a new database handler instance
57 ///
58 /// # Arguments
59 /// * `client` - The configured CloudClient instance
60 pub fn new(client: CloudClient) -> Self {
61 CloudDatabaseHandler { client }
62 }
63
64 /// Retrieve a specific database by ID
65 ///
66 /// Returns detailed information about a database including its configuration,
67 /// status, endpoints, and current metrics.
68 ///
69 /// # Arguments
70 /// * `subscription_id` - The ID of the subscription containing the database
71 /// * `database_id` - The unique database identifier
72 ///
73 /// # Examples
74 /// ```rust,no_run
75 /// # use redis_cloud::{CloudClient, CloudDatabaseHandler};
76 /// # #[tokio::main]
77 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
78 /// # let client = CloudClient::builder().api_key("key").api_secret("secret").build()?;
79 /// let db_handler = CloudDatabaseHandler::new(client);
80 /// let database = db_handler.get(123, 456).await?;
81 /// println!("Database name: {}", database.name);
82 /// println!("Memory limit: {} GB", database.memory_limit_in_gb);
83 /// # Ok(())
84 /// # }
85 /// ```
86 pub async fn get(&self, subscription_id: u32, database_id: u32) -> Result<CloudDatabase> {
87 self.client
88 .get(&format!(
89 "/subscriptions/{}/databases/{}",
90 subscription_id, database_id
91 ))
92 .await
93 }
94
95 /// Create a new database in a subscription
96 ///
97 /// Creates a new Redis database with the specified configuration. The database
98 /// will be deployed across the subscription's defined regions and cloud providers.
99 ///
100 /// # Arguments
101 /// * `subscription_id` - The ID of the subscription to create the database in
102 /// * `request` - Database configuration including name, memory, replication settings
103 ///
104 /// # Examples
105 /// ```rust,no_run
106 /// # use redis_cloud::{CloudClient, CloudDatabaseHandler};
107 /// # use serde_json::json;
108 /// # #[tokio::main]
109 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
110 /// # let client = CloudClient::builder().api_key("key").api_secret("secret").build()?;
111 /// let db_handler = CloudDatabaseHandler::new(client);
112 /// let config = json!({
113 /// "name": "production-cache",
114 /// "memory_limit_in_gb": 5.0,
115 /// "replication": true,
116 /// "data_persistence": "aof-every-1-sec",
117 /// "password": "secure-password"
118 /// });
119 /// // Note: create() takes a typed request struct, not JSON
120 /// // let result = db_handler.create(123, create_request).await?;
121 /// # Ok(())
122 /// # }
123 /// ```
124 pub async fn create(
125 &self,
126 subscription_id: u32,
127 request: CreateDatabaseRequest,
128 ) -> Result<Value> {
129 self.client
130 .post(
131 &format!("/subscriptions/{}/databases", subscription_id),
132 &request,
133 )
134 .await
135 }
136
137 /// Update an existing database configuration
138 ///
139 /// Modifies database settings such as memory limits, replication, persistence,
140 /// and other configuration options. Some changes may require a database restart.
141 ///
142 /// # Arguments
143 /// * `subscription_id` - The ID of the subscription containing the database
144 /// * `database_id` - The unique database identifier
145 /// * `request` - Updated configuration settings
146 ///
147 /// # Examples
148 /// ```rust,no_run
149 /// # use redis_cloud::{CloudClient, CloudDatabaseHandler};
150 /// # use serde_json::json;
151 /// # #[tokio::main]
152 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
153 /// # let client = CloudClient::builder().api_key("key").api_secret("secret").build()?;
154 /// let db_handler = CloudDatabaseHandler::new(client);
155 /// let updates = json!({
156 /// "memory_limit_in_gb": 10.0,
157 /// "replication": false
158 /// });
159 /// // Note: update() takes a typed request struct, not JSON
160 /// // let updated_db = db_handler.update(123, 456, update_request).await?;
161 /// # Ok(())
162 /// # }
163 /// ```
164 pub async fn update(
165 &self,
166 subscription_id: u32,
167 database_id: u32,
168 request: UpdateDatabaseRequest,
169 ) -> Result<CloudDatabase> {
170 self.client
171 .put(
172 &format!(
173 "/subscriptions/{}/databases/{}",
174 subscription_id, database_id
175 ),
176 &request,
177 )
178 .await
179 }
180
181 /// Delete a database permanently
182 ///
183 /// **Warning**: This operation is irreversible and will permanently delete
184 /// all data in the database. Consider creating a backup before deletion.
185 ///
186 /// # Arguments
187 /// * `subscription_id` - The ID of the subscription containing the database
188 /// * `database_id` - The unique database identifier
189 ///
190 /// # Examples
191 /// ```rust,no_run
192 /// # use redis_cloud::{CloudClient, CloudDatabaseHandler};
193 /// # #[tokio::main]
194 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
195 /// # let client = CloudClient::builder().api_key("key").api_secret("secret").build()?;
196 /// let db_handler = CloudDatabaseHandler::new(client);
197 /// let result = db_handler.delete(123, 456).await?;
198 /// println!("Database deleted successfully");
199 /// # Ok(())
200 /// # }
201 /// ```
202 pub async fn delete(&self, subscription_id: u32, database_id: u32) -> Result<Value> {
203 self.client
204 .delete(&format!(
205 "/subscriptions/{}/databases/{}",
206 subscription_id, database_id
207 ))
208 .await?;
209 Ok(serde_json::json!({"message": format!("Database {} deleted", database_id)}))
210 }
211
212 /// Resize database
213 pub async fn resize(
214 &self,
215 subscription_id: u32,
216 database_id: u32,
217 memory_limit_in_gb: f64,
218 ) -> Result<CloudDatabase> {
219 let request = UpdateDatabaseRequest {
220 memory_limit_in_gb: Some(memory_limit_in_gb),
221 name: None,
222 data_persistence: None,
223 replication: None,
224 data_eviction: None,
225 password: None,
226 };
227 self.update(subscription_id, database_id, request).await
228 }
229
230 /// List all databases across all subscriptions
231 pub async fn list_all(&self) -> Result<Vec<CloudDatabase>> {
232 let response: Value = self.client.get("/databases").await?;
233 if let Some(dbs) = response.get("databases") {
234 serde_json::from_value(dbs.clone()).map_err(Into::into)
235 } else {
236 Ok(vec![])
237 }
238 }
239
240 /// List databases for subscription as Value
241 pub async fn list(&self, subscription_id: u32) -> Result<Value> {
242 self.client
243 .get(&format!("/subscriptions/{}/databases", subscription_id))
244 .await
245 }
246
247 /// Get database as Value
248 pub async fn get_raw(&self, subscription_id: u32, database_id: u32) -> Result<Value> {
249 self.client
250 .get(&format!(
251 "/subscriptions/{}/databases/{}",
252 subscription_id, database_id
253 ))
254 .await
255 }
256
257 /// Create database with Value
258 pub async fn create_raw(&self, subscription_id: u32, request: Value) -> Result<Value> {
259 self.client
260 .post(
261 &format!("/subscriptions/{}/databases", subscription_id),
262 &request,
263 )
264 .await
265 }
266
267 /// Update database with Value
268 pub async fn update_raw(
269 &self,
270 subscription_id: u32,
271 database_id: u32,
272 request: Value,
273 ) -> Result<Value> {
274 self.client
275 .put(
276 &format!(
277 "/subscriptions/{}/databases/{}",
278 subscription_id, database_id
279 ),
280 &request,
281 )
282 .await
283 }
284
285 /// Backup database
286 pub async fn backup(&self, subscription_id: u32, database_id: u32) -> Result<Value> {
287 self.client
288 .post(
289 &format!(
290 "/subscriptions/{}/databases/{}/backup",
291 subscription_id, database_id
292 ),
293 &Value::Null,
294 )
295 .await
296 }
297
298 /// Import data
299 pub async fn import(
300 &self,
301 subscription_id: u32,
302 database_id: u32,
303 request: Value,
304 ) -> Result<Value> {
305 self.client
306 .post(
307 &format!(
308 "/subscriptions/{}/databases/{}/import",
309 subscription_id, database_id
310 ),
311 &request,
312 )
313 .await
314 }
315
316 /// Get metrics
317 pub async fn get_metrics(
318 &self,
319 subscription_id: u32,
320 database_id: u32,
321 metrics: &str,
322 period: &str,
323 ) -> Result<Value> {
324 self.client
325 .get(&format!(
326 "/subscriptions/{}/databases/{}/metrics?metrics={}&period={}",
327 subscription_id, database_id, metrics, period
328 ))
329 .await
330 }
331
332 /// Get database backup status
333 pub async fn backup_status(&self, subscription_id: u32, database_id: u32) -> Result<Value> {
334 self.client
335 .get(&format!(
336 "/subscriptions/{}/databases/{}/backup",
337 subscription_id, database_id
338 ))
339 .await
340 }
341}