redis_cloud/flexible/databases.rs
1//! Database management operations for Pro subscriptions
2//!
3//! This module provides comprehensive database management functionality for Redis Cloud
4//! Pro subscriptions, including creation, configuration, backup, import/export, and
5//! monitoring capabilities.
6//!
7//! # Overview
8//!
9//! Pro databases offer the full range of Redis Cloud features including high availability,
10//! auto-scaling, clustering, modules, and advanced data persistence options. They can be
11//! deployed across multiple cloud providers and regions.
12//!
13//! # Key Features
14//!
15//! - **Database Lifecycle**: Create, update, delete, and manage databases
16//! - **Backup & Restore**: Automated and on-demand backup operations
17//! - **Import/Export**: Import data from RDB files or other Redis instances
18//! - **Modules**: Support for `RedisJSON`, `RediSearch`, `RedisGraph`, `RedisTimeSeries`, `RedisBloom`
19//! - **High Availability**: Replication, auto-failover, and clustering support
20//! - **Monitoring**: Metrics, alerts, and performance insights
21//! - **Security**: TLS, password protection, and ACL support
22//!
23//! # Database Configuration Options
24//!
25//! - Memory limits from 250MB to 500GB+
26//! - Support for Redis OSS Cluster API
27//! - Data persistence: AOF, snapshot, or both
28//! - Data eviction policies
29//! - Replication and clustering
30//! - Custom Redis versions
31//!
32//! # Example Usage
33//!
34//! ```no_run
35//! use redis_cloud::{CloudClient, DatabaseHandler};
36//!
37//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
38//! let client = CloudClient::builder()
39//! .api_key("your-api-key")
40//! .api_secret("your-api-secret")
41//! .build()?;
42//!
43//! let handler = DatabaseHandler::new(client);
44//!
45//! // List all databases in a subscription (subscription ID 123)
46//! let databases = handler.get_subscription_databases(123, None, None).await?;
47//!
48//! // Get specific database details
49//! let database = handler.get_subscription_database_by_id(123, 456).await?;
50//! # Ok(())
51//! # }
52//! ```
53
54use crate::types::{Link, ProcessorResponse};
55use crate::{CloudClient, Result};
56use async_stream::try_stream;
57use futures_core::Stream;
58use serde::{Deserialize, Deserializer, Serialize};
59use serde_json::Value;
60use std::collections::HashMap;
61
62// ============================================================================
63// Models
64// ============================================================================
65
66/// `RedisLabs` Account Subscription Databases information
67///
68/// Response from GET /subscriptions/{subscriptionId}/databases
69#[derive(Debug, Clone, Serialize, Deserialize)]
70#[serde(rename_all = "camelCase")]
71pub struct AccountSubscriptionDatabases {
72 /// Account ID
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub account_id: Option<i32>,
75
76 /// Subscription information with nested databases array.
77 /// The API returns this as an array, each element containing subscriptionId, databases, and links.
78 #[serde(default, deserialize_with = "deserialize_subscription_info")]
79 pub subscription: Vec<SubscriptionDatabasesInfo>,
80
81 /// HATEOAS links for API navigation
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub links: Option<Vec<Link>>,
84}
85
86/// Subscription databases info returned within `AccountSubscriptionDatabases`
87#[derive(Debug, Clone, Serialize, Deserialize)]
88#[serde(rename_all = "camelCase")]
89pub struct SubscriptionDatabasesInfo {
90 /// Subscription ID
91 pub subscription_id: i32,
92
93 /// Number of databases (may not always be present)
94 #[serde(skip_serializing_if = "Option::is_none")]
95 pub number_of_databases: Option<i32>,
96
97 /// List of databases in this subscription
98 #[serde(default)]
99 pub databases: Vec<Database>,
100
101 /// HATEOAS links
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub links: Option<Vec<Link>>,
104}
105
106/// Custom deserializer that handles both object and array formats for subscription field.
107/// The API returns an array, but some test mocks use an object format.
108fn deserialize_subscription_info<'de, D>(
109 deserializer: D,
110) -> std::result::Result<Vec<SubscriptionDatabasesInfo>, D::Error>
111where
112 D: Deserializer<'de>,
113{
114 let value: Option<Value> = Option::deserialize(deserializer)?;
115
116 match value {
117 None => Ok(Vec::new()),
118 Some(Value::Array(arr)) => {
119 serde_json::from_value(Value::Array(arr)).map_err(serde::de::Error::custom)
120 }
121 Some(Value::Object(obj)) => {
122 // Single object - wrap in array
123 let item: SubscriptionDatabasesInfo =
124 serde_json::from_value(Value::Object(obj)).map_err(serde::de::Error::custom)?;
125 Ok(vec![item])
126 }
127 Some(other) => Err(serde::de::Error::custom(format!(
128 "expected array or object for subscription, got {other:?}"
129 ))),
130 }
131}
132
133/// Optional. Expected read and write throughput for this region.
134#[derive(Debug, Clone, Serialize, Deserialize)]
135#[serde(rename_all = "camelCase")]
136pub struct LocalThroughput {
137 /// Specify one of the selected cloud provider regions for the subscription.
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub region: Option<String>,
140
141 /// Write operations for this region per second. Default: 1000 ops/sec
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub write_operations_per_second: Option<i64>,
144
145 /// Read operations for this region per second. Default: 1000 ops/sec
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub read_operations_per_second: Option<i64>,
148}
149
150/// Database tag update request message
151#[derive(Debug, Clone, Serialize, Deserialize)]
152#[serde(rename_all = "camelCase")]
153pub struct DatabaseTagUpdateRequest {
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub subscription_id: Option<i32>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub database_id: Option<i32>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub key: Option<String>,
162
163 /// Database tag value
164 pub value: String,
165
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub command_type: Option<String>,
168}
169
170/// Database tag
171#[derive(Debug, Clone, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct Tag {
174 /// Database tag key.
175 pub key: String,
176
177 /// Database tag value.
178 pub value: String,
179
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub command_type: Option<String>,
182}
183
184/// Active-Active database flush request message
185#[derive(Debug, Clone, Serialize, Deserialize)]
186#[serde(rename_all = "camelCase")]
187pub struct CrdbFlushRequest {
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub subscription_id: Option<i32>,
190
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub database_id: Option<i32>,
193
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub command_type: Option<String>,
196}
197
198/// Database certificate
199#[derive(Debug, Clone, Serialize, Deserialize)]
200#[serde(rename_all = "camelCase")]
201pub struct DatabaseCertificate {
202 /// An X.509 PEM (base64) encoded server certificate with new line characters replaced by '\n'.
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub public_certificate_pem_string: Option<String>,
205}
206
207/// Database tags update request message
208#[derive(Debug, Clone, Serialize, Deserialize)]
209#[serde(rename_all = "camelCase")]
210pub struct DatabaseTagsUpdateRequest {
211 #[serde(skip_serializing_if = "Option::is_none")]
212 pub subscription_id: Option<i32>,
213
214 #[serde(skip_serializing_if = "Option::is_none")]
215 pub database_id: Option<i32>,
216
217 /// List of database tags.
218 pub tags: Vec<Tag>,
219
220 #[serde(skip_serializing_if = "Option::is_none")]
221 pub command_type: Option<String>,
222}
223
224/// Optional. This database will be a replica of the specified Redis databases, provided as a list of objects with endpoint and certificate details.
225#[derive(Debug, Clone, Serialize, Deserialize)]
226#[serde(rename_all = "camelCase")]
227pub struct DatabaseSyncSourceSpec {
228 /// Redis URI of a source database. Example format: 'redis://user:password@host:port'. If the URI provided is a Redis Cloud database, only host and port should be provided. Example: '<redis://endpoint1:6379>'.
229 pub endpoint: String,
230
231 /// Defines if encryption should be used to connect to the sync source. If not set the source is a Redis Cloud database, it will automatically detect if the source uses encryption.
232 #[serde(skip_serializing_if = "Option::is_none")]
233 pub encryption: Option<bool>,
234
235 /// TLS/SSL certificate chain of the sync source. If not set and the source is a Redis Cloud database, it will automatically detect the certificate to use.
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub server_cert: Option<String>,
238}
239
240/// Optional. A list of client TLS/SSL certificates. If specified, mTLS authentication will be required to authenticate user connections. If set to an empty list, TLS client certificates will be removed and mTLS will not be required. TLS connection may still apply, depending on the value of 'enableTls'.
241#[derive(Debug, Clone, Serialize, Deserialize)]
242#[serde(rename_all = "camelCase")]
243pub struct DatabaseCertificateSpec {
244 /// Client certificate public key in PEM format, with new line characters replaced with '\n'.
245 pub public_certificate_pem_string: String,
246}
247
248/// Database tag
249#[derive(Debug, Clone, Serialize, Deserialize)]
250#[serde(rename_all = "camelCase")]
251pub struct CloudTag {
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub key: Option<String>,
254
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub value: Option<String>,
257
258 #[serde(skip_serializing_if = "Option::is_none")]
259 pub created_at: Option<String>,
260
261 #[serde(skip_serializing_if = "Option::is_none")]
262 pub updated_at: Option<String>,
263
264 /// HATEOAS links
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub links: Option<Vec<Link>>,
267}
268
269/// `BdbVersionUpgradeStatus`
270#[derive(Debug, Clone, Serialize, Deserialize)]
271#[serde(rename_all = "camelCase")]
272pub struct BdbVersionUpgradeStatus {
273 #[serde(skip_serializing_if = "Option::is_none")]
274 pub database_id: Option<i32>,
275
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub target_redis_version: Option<String>,
278
279 #[serde(skip_serializing_if = "Option::is_none")]
280 pub progress: Option<f64>,
281
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub upgrade_status: Option<String>,
284}
285
286/// Active-Active database update local properties request message
287#[derive(Debug, Clone, Serialize, Deserialize)]
288#[serde(rename_all = "camelCase")]
289pub struct CrdbUpdatePropertiesRequest {
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub subscription_id: Option<i32>,
292
293 #[serde(skip_serializing_if = "Option::is_none")]
294 pub database_id: Option<i32>,
295
296 /// Optional. Updated database name. Database name is limited to 40 characters or less and must include only letters, digits, and hyphens ('-'). It must start with a letter and end with a letter or digit.
297 #[serde(skip_serializing_if = "Option::is_none")]
298 pub name: Option<String>,
299
300 /// Optional. When 'false': Creates a deployment plan and deploys it, updating any resources required by the plan. When 'true': creates a read-only deployment plan and does not update any resources. Default: 'false'
301 #[serde(skip_serializing_if = "Option::is_none")]
302 pub dry_run: Option<bool>,
303
304 /// Optional. Total memory in GB, including replication and other overhead. You cannot set both datasetSizeInGb and totalMemoryInGb.
305 #[serde(skip_serializing_if = "Option::is_none")]
306 pub memory_limit_in_gb: Option<f64>,
307
308 /// Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb.If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub dataset_size_in_gb: Option<f64>,
311
312 /// Optional. Support Redis [OSS Cluster API](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#oss-cluster-api). Default: 'false'
313 #[serde(skip_serializing_if = "Option::is_none")]
314 pub support_oss_cluster_api: Option<bool>,
315
316 /// Optional. If set to 'true', the database will use the external endpoint for OSS Cluster API. This setting blocks the database's private endpoint. Can only be set if 'supportOSSClusterAPI' is 'true'.
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
319
320 /// Optional. A public key client TLS/SSL certificate with new line characters replaced with '\n'. If specified, mTLS authentication will be required to authenticate user connections if it is not already required. If set to an empty string, TLS client certificates will be removed and mTLS will not be required. TLS connection may still apply, depending on the value of 'enableTls'.
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub client_ssl_certificate: Option<String>,
323
324 /// Optional. A list of client TLS/SSL certificates. If specified, mTLS authentication will be required to authenticate user connections. If set to an empty list, TLS client certificates will be removed and mTLS will not be required. TLS connection may still apply, depending on the value of 'enableTls'.
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub client_tls_certificates: Option<Vec<DatabaseCertificateSpec>>,
327
328 /// Optional. When 'true', requires TLS authentication for all connections - mTLS with valid clientTlsCertificates, regular TLS when clientTlsCertificates is not provided. If enableTls is set to 'false' while mTLS is required, it will remove the mTLS requirement and erase previously provided clientTlsCertificates.
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub enable_tls: Option<bool>,
331
332 /// Optional. Type and rate of data persistence in all regions that don't set local 'dataPersistence'.
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub global_data_persistence: Option<String>,
335
336 /// Optional. Changes the password used to access the database in all regions that don't set a local 'password'.
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub global_password: Option<String>,
339
340 /// Optional. List of source IP addresses or subnet masks to allow in all regions that don't set local 'sourceIp' settings. If set, Redis clients will be able to connect to this database only from within the specified source IP addresses ranges. Example: ['192.168.10.0/32', '192.168.12.0/24']
341 #[serde(skip_serializing_if = "Option::is_none")]
342 pub global_source_ip: Option<Vec<String>>,
343
344 /// Optional. Redis database alert settings in all regions that don't set local 'alerts'.
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub global_alerts: Option<Vec<DatabaseAlertSpec>>,
347
348 /// Optional. A list of regions and local settings to update.
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub regions: Option<Vec<LocalRegionProperties>>,
351
352 /// Optional. Data eviction policy.
353 #[serde(skip_serializing_if = "Option::is_none")]
354 pub data_eviction_policy: Option<String>,
355
356 #[serde(skip_serializing_if = "Option::is_none")]
357 pub command_type: Option<String>,
358}
359
360/// Database slowlog entry
361#[derive(Debug, Clone, Serialize, Deserialize)]
362#[serde(rename_all = "camelCase")]
363pub struct DatabaseSlowLogEntry {
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub id: Option<i32>,
366
367 #[serde(skip_serializing_if = "Option::is_none")]
368 pub start_time: Option<String>,
369
370 #[serde(skip_serializing_if = "Option::is_none")]
371 pub duration: Option<i32>,
372
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub arguments: Option<String>,
375}
376
377/// Database tag
378#[derive(Debug, Clone, Serialize, Deserialize)]
379#[serde(rename_all = "camelCase")]
380pub struct DatabaseTagCreateRequest {
381 /// Database tag key.
382 pub key: String,
383
384 /// Database tag value.
385 pub value: String,
386
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub subscription_id: Option<i32>,
389
390 #[serde(skip_serializing_if = "Option::is_none")]
391 pub database_id: Option<i32>,
392
393 #[serde(skip_serializing_if = "Option::is_none")]
394 pub command_type: Option<String>,
395}
396
397/// Optional. Throughput measurement method.
398#[derive(Debug, Clone, Serialize, Deserialize)]
399pub struct DatabaseThroughputSpec {
400 /// Throughput measurement method. Use 'operations-per-second' for all new databases.
401 pub by: String,
402
403 /// Throughput value in the selected measurement method.
404 pub value: i64,
405}
406
407/// Optional. Changes Remote backup configuration details.
408#[derive(Debug, Clone, Serialize, Deserialize)]
409#[serde(rename_all = "camelCase")]
410pub struct DatabaseBackupConfig {
411 /// Optional. Determine if backup should be active. Default: null
412 #[serde(skip_serializing_if = "Option::is_none")]
413 pub active: Option<bool>,
414
415 /// Required when active is 'true'. Defines the interval between backups. Format: 'every-x-hours', where x is one of 24, 12, 6, 4, 2, or 1. Example: "every-4-hours"
416 #[serde(skip_serializing_if = "Option::is_none")]
417 pub interval: Option<String>,
418
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub backup_interval: Option<String>,
421
422 /// Optional. Hour when the backup starts. Available only for "every-12-hours" and "every-24-hours" backup intervals. Specified as an hour in 24-hour UTC time. Example: "14:00" is 2 PM UTC.
423 #[serde(skip_serializing_if = "Option::is_none")]
424 pub time_utc: Option<String>,
425
426 #[serde(skip_serializing_if = "Option::is_none")]
427 pub database_backup_time_utc: Option<String>,
428
429 /// Required when active is 'true'. Type of storage to host backup files. Can be "aws-s3", "google-blob-storage", "azure-blob-storage", or "ftp". See [Set up backup storage locations](https://redis.io/docs/latest/operate/rc/databases/back-up-data/#set-up-backup-storage-locations) to learn how to set up backup storage locations.
430 #[serde(skip_serializing_if = "Option::is_none")]
431 pub storage_type: Option<String>,
432
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub backup_storage_type: Option<String>,
435
436 /// Required when active is 'true'. Path to the backup storage location.
437 #[serde(skip_serializing_if = "Option::is_none")]
438 pub storage_path: Option<String>,
439}
440
441/// Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities.
442#[derive(Debug, Clone, Serialize, Deserialize)]
443pub struct DatabaseModuleSpec {
444 /// Redis advanced capability name. Use GET /database-modules for a list of available capabilities.
445 pub name: String,
446
447 /// Optional. Redis advanced capability parameters. Use GET /database-modules to get the available capabilities and their parameters.
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub parameters: Option<HashMap<String, Value>>,
450}
451
452/// Optional. Changes Replica Of (also known as Active-Passive) configuration details.
453#[derive(Debug, Clone, Serialize, Deserialize)]
454#[serde(rename_all = "camelCase")]
455pub struct ReplicaOfSpec {
456 /// Optional. This database will be a replica of the specified Redis databases, provided as a list of objects with endpoint and certificate details.
457 pub sync_sources: Vec<DatabaseSyncSourceSpec>,
458}
459
460/// Regex rule for custom hashing policy
461#[derive(Debug, Clone, Serialize, Deserialize)]
462#[serde(rename_all = "camelCase")]
463pub struct RegexRule {
464 /// The ordinal/order of this rule
465 pub ordinal: i32,
466
467 /// The regex pattern for this rule
468 pub pattern: String,
469}
470
471/// Backup configuration status (response)
472#[derive(Debug, Clone, Serialize, Deserialize)]
473#[serde(rename_all = "camelCase")]
474pub struct Backup {
475 /// Whether remote backup is enabled
476 #[serde(skip_serializing_if = "Option::is_none")]
477 pub enable_remote_backup: Option<bool>,
478
479 /// Backup time in UTC
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub time_utc: Option<String>,
482
483 /// Backup interval (e.g., "every-24-hours", "every-12-hours")
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub interval: Option<String>,
486
487 /// Backup destination path
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub destination: Option<String>,
490}
491
492/// Security configuration (response)
493#[derive(Debug, Clone, Serialize, Deserialize)]
494#[serde(rename_all = "camelCase")]
495pub struct Security {
496 /// Whether default Redis user is enabled
497 #[serde(skip_serializing_if = "Option::is_none")]
498 pub enable_default_user: Option<bool>,
499
500 /// Whether SSL client authentication is enabled
501 #[serde(skip_serializing_if = "Option::is_none")]
502 pub ssl_client_authentication: Option<bool>,
503
504 /// Whether TLS client authentication is enabled
505 #[serde(skip_serializing_if = "Option::is_none")]
506 pub tls_client_authentication: Option<bool>,
507
508 /// List of source IP addresses allowed to connect
509 #[serde(skip_serializing_if = "Option::is_none")]
510 pub source_ips: Option<Vec<String>>,
511
512 /// Database password (masked in responses)
513 #[serde(skip_serializing_if = "Option::is_none")]
514 pub password: Option<String>,
515
516 /// Whether TLS is enabled
517 #[serde(skip_serializing_if = "Option::is_none")]
518 pub enable_tls: Option<bool>,
519}
520
521/// Clustering configuration (response)
522#[derive(Debug, Clone, Serialize, Deserialize)]
523#[serde(rename_all = "camelCase")]
524pub struct Clustering {
525 /// Number of shards
526 #[serde(skip_serializing_if = "Option::is_none")]
527 pub number_of_shards: Option<i32>,
528
529 /// Regex rules for custom hashing
530 #[serde(skip_serializing_if = "Option::is_none")]
531 pub regex_rules: Option<Vec<RegexRule>>,
532
533 /// Hashing policy
534 #[serde(skip_serializing_if = "Option::is_none")]
535 pub hashing_policy: Option<String>,
536}
537
538/// Active-Active (CRDB) database information
539///
540/// Represents an Active-Active database with global settings and per-region configurations.
541#[derive(Debug, Clone, Serialize, Deserialize)]
542#[serde(rename_all = "camelCase")]
543pub struct ActiveActiveDatabase {
544 /// Database ID
545 #[serde(skip_serializing_if = "Option::is_none")]
546 pub database_id: Option<i32>,
547
548 /// Database name
549 #[serde(skip_serializing_if = "Option::is_none")]
550 pub name: Option<String>,
551
552 /// Database protocol
553 #[serde(skip_serializing_if = "Option::is_none")]
554 pub protocol: Option<String>,
555
556 /// Database status
557 #[serde(skip_serializing_if = "Option::is_none")]
558 pub status: Option<String>,
559
560 /// Redis version
561 #[serde(skip_serializing_if = "Option::is_none")]
562 pub redis_version: Option<String>,
563
564 /// Memory storage type
565 #[serde(skip_serializing_if = "Option::is_none")]
566 pub memory_storage: Option<String>,
567
568 /// Whether this is an Active-Active database
569 #[serde(skip_serializing_if = "Option::is_none")]
570 pub active_active_redis: Option<bool>,
571
572 /// Timestamp when database was activated
573 #[serde(skip_serializing_if = "Option::is_none")]
574 pub activated_on: Option<String>,
575
576 /// Timestamp of last modification
577 #[serde(skip_serializing_if = "Option::is_none")]
578 pub last_modified: Option<String>,
579
580 /// Support for OSS Cluster API
581 #[serde(skip_serializing_if = "Option::is_none")]
582 pub support_oss_cluster_api: Option<bool>,
583
584 /// Use external endpoint for OSS Cluster API
585 #[serde(skip_serializing_if = "Option::is_none")]
586 pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
587
588 /// Whether replication is enabled
589 #[serde(skip_serializing_if = "Option::is_none")]
590 pub replication: Option<bool>,
591
592 /// Data eviction policy
593 #[serde(skip_serializing_if = "Option::is_none")]
594 pub data_eviction_policy: Option<String>,
595
596 /// Security configuration
597 #[serde(skip_serializing_if = "Option::is_none")]
598 pub security: Option<Security>,
599
600 /// Redis modules enabled
601 #[serde(skip_serializing_if = "Option::is_none")]
602 pub modules: Option<Vec<DatabaseModuleSpec>>,
603
604 /// Global data persistence setting
605 #[serde(skip_serializing_if = "Option::is_none")]
606 pub global_data_persistence: Option<String>,
607
608 /// Global source IP allowlist
609 #[serde(skip_serializing_if = "Option::is_none")]
610 pub global_source_ip: Option<Vec<String>>,
611
612 /// Global password
613 #[serde(skip_serializing_if = "Option::is_none")]
614 pub global_password: Option<String>,
615
616 /// Global alert configurations
617 #[serde(skip_serializing_if = "Option::is_none")]
618 pub global_alerts: Option<Vec<DatabaseAlertSpec>>,
619
620 /// Global enable default user setting
621 #[serde(skip_serializing_if = "Option::is_none")]
622 pub global_enable_default_user: Option<bool>,
623
624 /// Per-region CRDB database configurations
625 #[serde(skip_serializing_if = "Option::is_none")]
626 pub crdb_databases: Option<Vec<CrdbDatabase>>,
627
628 /// Whether automatic minor version upgrades are enabled
629 #[serde(skip_serializing_if = "Option::is_none")]
630 pub auto_minor_version_upgrade: Option<bool>,
631}
632
633/// Per-region configuration for an Active-Active (CRDB) database
634#[derive(Debug, Clone, Serialize, Deserialize)]
635#[serde(rename_all = "camelCase")]
636pub struct CrdbDatabase {
637 /// Cloud provider
638 #[serde(skip_serializing_if = "Option::is_none")]
639 pub provider: Option<String>,
640
641 /// Cloud region
642 #[serde(skip_serializing_if = "Option::is_none")]
643 pub region: Option<String>,
644
645 /// Redis version compliance
646 #[serde(skip_serializing_if = "Option::is_none")]
647 pub redis_version_compliance: Option<String>,
648
649 /// Public endpoint
650 #[serde(skip_serializing_if = "Option::is_none")]
651 pub public_endpoint: Option<String>,
652
653 /// Private endpoint
654 #[serde(skip_serializing_if = "Option::is_none")]
655 pub private_endpoint: Option<String>,
656
657 /// Memory limit in GB
658 #[serde(skip_serializing_if = "Option::is_none")]
659 pub memory_limit_in_gb: Option<f64>,
660
661 /// Dataset size in GB
662 #[serde(skip_serializing_if = "Option::is_none")]
663 pub dataset_size_in_gb: Option<f64>,
664
665 /// Memory used in MB
666 #[serde(skip_serializing_if = "Option::is_none")]
667 pub memory_used_in_mb: Option<f64>,
668
669 /// Read operations per second
670 #[serde(skip_serializing_if = "Option::is_none")]
671 pub read_operations_per_second: Option<i32>,
672
673 /// Write operations per second
674 #[serde(skip_serializing_if = "Option::is_none")]
675 pub write_operations_per_second: Option<i32>,
676
677 /// Data persistence setting for this region
678 #[serde(skip_serializing_if = "Option::is_none")]
679 pub data_persistence: Option<String>,
680
681 /// Alert configurations for this region
682 #[serde(skip_serializing_if = "Option::is_none")]
683 pub alerts: Option<Vec<DatabaseAlertSpec>>,
684
685 /// Security configuration for this region
686 #[serde(skip_serializing_if = "Option::is_none")]
687 pub security: Option<Security>,
688
689 /// Backup configuration for this region
690 #[serde(skip_serializing_if = "Option::is_none")]
691 pub backup: Option<Backup>,
692
693 /// Query performance factor
694 #[serde(skip_serializing_if = "Option::is_none")]
695 pub query_performance_factor: Option<String>,
696}
697
698/// Database backup request message
699#[derive(Debug, Clone, Serialize, Deserialize)]
700#[serde(rename_all = "camelCase")]
701pub struct DatabaseBackupRequest {
702 #[serde(skip_serializing_if = "Option::is_none")]
703 pub subscription_id: Option<i32>,
704
705 #[serde(skip_serializing_if = "Option::is_none")]
706 pub database_id: Option<i32>,
707
708 /// Required for Active-Active databases. Name of the cloud provider region to back up. When backing up an Active-Active database, you must back up each region separately.
709 #[serde(skip_serializing_if = "Option::is_none")]
710 pub region_name: Option<String>,
711
712 /// Optional. Manually backs up data to this location, instead of the set 'remoteBackup' location.
713 #[serde(skip_serializing_if = "Option::is_none")]
714 pub adhoc_backup_path: Option<String>,
715
716 #[serde(skip_serializing_if = "Option::is_none")]
717 pub command_type: Option<String>,
718}
719
720/// Database
721///
722/// Represents a Redis Cloud database with all known API fields as first-class struct members.
723/// The `extra` field is reserved only for truly unknown/future fields that may be added to the API.
724#[derive(Debug, Clone, Serialize, Deserialize)]
725#[serde(rename_all = "camelCase")]
726pub struct Database {
727 /// Database ID - always present in API responses
728 pub database_id: i32,
729
730 /// Database name
731 #[serde(skip_serializing_if = "Option::is_none")]
732 pub name: Option<String>,
733
734 /// Database status (e.g., "active", "pending", "error", "draft")
735 #[serde(skip_serializing_if = "Option::is_none")]
736 pub status: Option<String>,
737
738 /// Cloud provider (e.g., "AWS", "GCP", "Azure")
739 #[serde(skip_serializing_if = "Option::is_none")]
740 pub provider: Option<String>,
741
742 /// Cloud region (e.g., "us-east-1", "europe-west1")
743 #[serde(skip_serializing_if = "Option::is_none")]
744 pub region: Option<String>,
745
746 /// Redis version (e.g., "7.2", "7.0")
747 #[serde(skip_serializing_if = "Option::is_none")]
748 pub redis_version: Option<String>,
749
750 /// Redis Serialization Protocol version
751 #[serde(skip_serializing_if = "Option::is_none")]
752 pub resp_version: Option<String>,
753
754 /// Total memory limit in GB (including replication and overhead)
755 #[serde(skip_serializing_if = "Option::is_none")]
756 pub memory_limit_in_gb: Option<f64>,
757
758 /// Dataset size in GB (actual data size, excluding replication)
759 #[serde(skip_serializing_if = "Option::is_none")]
760 pub dataset_size_in_gb: Option<f64>,
761
762 /// Memory used in MB
763 #[serde(skip_serializing_if = "Option::is_none")]
764 pub memory_used_in_mb: Option<f64>,
765
766 /// Private endpoint for database connections
767 #[serde(skip_serializing_if = "Option::is_none")]
768 pub private_endpoint: Option<String>,
769
770 /// Public endpoint for database connections (if enabled)
771 #[serde(skip_serializing_if = "Option::is_none")]
772 pub public_endpoint: Option<String>,
773
774 /// TCP port on which the database is available
775 #[serde(skip_serializing_if = "Option::is_none")]
776 pub port: Option<i32>,
777
778 /// Data eviction policy (e.g., "volatile-lru", "allkeys-lru", "noeviction")
779 #[serde(skip_serializing_if = "Option::is_none")]
780 pub data_eviction_policy: Option<String>,
781
782 /// Data persistence setting (e.g., "aof-every-1-sec", "snapshot-every-1-hour", "none")
783 #[serde(skip_serializing_if = "Option::is_none")]
784 pub data_persistence: Option<String>,
785
786 /// Whether replication is enabled
787 #[serde(skip_serializing_if = "Option::is_none")]
788 pub replication: Option<bool>,
789
790 /// Protocol used (e.g., "redis", "memcached")
791 #[serde(skip_serializing_if = "Option::is_none")]
792 pub protocol: Option<String>,
793
794 /// Support for OSS Cluster API
795 #[serde(skip_serializing_if = "Option::is_none")]
796 pub support_oss_cluster_api: Option<bool>,
797
798 /// Use external endpoint for OSS Cluster API
799 #[serde(skip_serializing_if = "Option::is_none")]
800 pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
801
802 /// Whether TLS is enabled for connections
803 #[serde(skip_serializing_if = "Option::is_none")]
804 pub enable_tls: Option<bool>,
805
806 /// Throughput measurement configuration
807 #[serde(skip_serializing_if = "Option::is_none")]
808 pub throughput_measurement: Option<DatabaseThroughputSpec>,
809
810 /// Local throughput measurement for Active-Active databases
811 #[serde(skip_serializing_if = "Option::is_none")]
812 pub local_throughput_measurement: Option<Vec<LocalThroughput>>,
813
814 /// Average item size in bytes (for Auto Tiering)
815 #[serde(skip_serializing_if = "Option::is_none")]
816 pub average_item_size_in_bytes: Option<i64>,
817
818 /// Path to periodic backup storage location
819 #[serde(skip_serializing_if = "Option::is_none")]
820 pub periodic_backup_path: Option<String>,
821
822 /// Remote backup configuration
823 #[serde(skip_serializing_if = "Option::is_none")]
824 pub remote_backup: Option<DatabaseBackupConfig>,
825
826 /// List of source IP addresses or subnet masks allowed to connect
827 #[serde(skip_serializing_if = "Option::is_none")]
828 pub source_ip: Option<Vec<String>>,
829
830 /// Client TLS/SSL certificate (deprecated, use `client_tls_certificates`)
831 #[serde(skip_serializing_if = "Option::is_none")]
832 pub client_ssl_certificate: Option<String>,
833
834 /// List of client TLS/SSL certificates for mTLS authentication
835 #[serde(skip_serializing_if = "Option::is_none")]
836 pub client_tls_certificates: Option<Vec<DatabaseCertificateSpec>>,
837
838 /// Database password (masked in responses for security)
839 #[serde(skip_serializing_if = "Option::is_none")]
840 pub password: Option<String>,
841
842 /// Memcached SASL username
843 #[serde(skip_serializing_if = "Option::is_none")]
844 pub sasl_username: Option<String>,
845
846 /// Memcached SASL password (masked in responses)
847 #[serde(skip_serializing_if = "Option::is_none")]
848 pub sasl_password: Option<String>,
849
850 /// Database alert configurations
851 #[serde(skip_serializing_if = "Option::is_none")]
852 pub alerts: Option<Vec<DatabaseAlertSpec>>,
853
854 /// Redis modules/capabilities enabled on this database
855 #[serde(skip_serializing_if = "Option::is_none")]
856 pub modules: Option<Vec<DatabaseModuleSpec>>,
857
858 /// Database hashing policy for clustering
859 #[serde(skip_serializing_if = "Option::is_none")]
860 pub sharding_type: Option<String>,
861
862 /// Query performance factor (for search and query databases)
863 #[serde(skip_serializing_if = "Option::is_none")]
864 pub query_performance_factor: Option<String>,
865
866 /// List of databases this database is a replica of
867 #[serde(skip_serializing_if = "Option::is_none")]
868 pub replica_of: Option<Vec<String>>,
869
870 /// Replica configuration
871 #[serde(skip_serializing_if = "Option::is_none")]
872 pub replica: Option<ReplicaOfSpec>,
873
874 /// Whether default Redis user is enabled
875 #[serde(skip_serializing_if = "Option::is_none")]
876 pub enable_default_user: Option<bool>,
877
878 /// Whether this is an Active-Active (CRDB) database
879 #[serde(skip_serializing_if = "Option::is_none")]
880 pub active_active_redis: Option<bool>,
881
882 /// Memory storage type: "ram" or "ram-and-flash" (Auto Tiering)
883 #[serde(skip_serializing_if = "Option::is_none")]
884 pub memory_storage: Option<String>,
885
886 /// Redis version compliance status
887 #[serde(skip_serializing_if = "Option::is_none")]
888 pub redis_version_compliance: Option<String>,
889
890 /// Whether automatic minor version upgrades are enabled
891 #[serde(skip_serializing_if = "Option::is_none")]
892 pub auto_minor_version_upgrade: Option<bool>,
893
894 /// Number of shards in the database cluster
895 #[serde(skip_serializing_if = "Option::is_none")]
896 pub number_of_shards: Option<i32>,
897
898 /// Regex rules for custom hashing policy
899 #[serde(skip_serializing_if = "Option::is_none")]
900 pub regex_rules: Option<Vec<RegexRule>>,
901
902 /// Whether SSL client authentication is enabled
903 #[serde(skip_serializing_if = "Option::is_none")]
904 pub ssl_client_authentication: Option<bool>,
905
906 /// Whether TLS client authentication is enabled
907 #[serde(skip_serializing_if = "Option::is_none")]
908 pub tls_client_authentication: Option<bool>,
909
910 /// Timestamp when database was activated
911 #[serde(skip_serializing_if = "Option::is_none")]
912 pub activated: Option<String>,
913
914 /// Timestamp of last modification
915 #[serde(skip_serializing_if = "Option::is_none")]
916 pub last_modified: Option<String>,
917
918 /// HATEOAS links for API navigation
919 #[serde(skip_serializing_if = "Option::is_none")]
920 pub links: Option<Vec<Link>>,
921}
922
923/// Optional. Changes Redis database alert details.
924#[derive(Debug, Clone, Serialize, Deserialize)]
925pub struct DatabaseAlertSpec {
926 /// Alert type. Available options depend on Plan type. See [Configure alerts](https://redis.io/docs/latest/operate/rc/databases/monitor-performance/#configure-metric-alerts) for more information.
927 pub name: String,
928
929 /// Value over which an alert will be sent. Default values and range depend on the alert type. See [Configure alerts](https://redis.io/docs/latest/operate/rc/databases/monitor-performance/#configure-metric-alerts) for more information.
930 pub value: i32,
931}
932
933/// Request structure for creating a new Pro database
934///
935/// Contains all configuration options for creating a database in a Pro subscription,
936/// including memory settings, replication, persistence, modules, and networking.
937#[derive(Debug, Clone, Serialize, Deserialize)]
938#[serde(rename_all = "camelCase")]
939pub struct DatabaseCreateRequest {
940 #[serde(skip_serializing_if = "Option::is_none")]
941 pub subscription_id: Option<i32>,
942
943 /// Optional. When 'false': Creates a deployment plan and deploys it, creating any resources required by the plan. When 'true': creates a read-only deployment plan and does not create any resources. Default: 'false'
944 #[serde(skip_serializing_if = "Option::is_none")]
945 pub dry_run: Option<bool>,
946
947 /// Name of the database. Database name is limited to 40 characters or less and must include only letters, digits, and hyphens ('-'). It must start with a letter and end with a letter or digit.
948 pub name: String,
949
950 /// Optional. Database protocol. Only set to 'memcached' if you have a legacy application. Default: 'redis'
951 #[serde(skip_serializing_if = "Option::is_none")]
952 pub protocol: Option<String>,
953
954 /// Optional. TCP port on which the database is available (10000-19999). Generated automatically if not set.
955 #[serde(skip_serializing_if = "Option::is_none")]
956 pub port: Option<i32>,
957
958 /// Optional. Total memory in GB, including replication and other overhead. You cannot set both datasetSizeInGb and totalMemoryInGb.
959 #[serde(skip_serializing_if = "Option::is_none")]
960 pub memory_limit_in_gb: Option<f64>,
961
962 /// Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb. If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.
963 #[serde(skip_serializing_if = "Option::is_none")]
964 pub dataset_size_in_gb: Option<f64>,
965
966 /// Optional. If specified, redisVersion defines the Redis database version. If omitted, the Redis version will be set to the default version (available in 'GET /subscriptions/redis-versions')
967 #[serde(skip_serializing_if = "Option::is_none")]
968 pub redis_version: Option<String>,
969
970 /// Optional. Redis Serialization Protocol version. Must be compatible with Redis version.
971 #[serde(skip_serializing_if = "Option::is_none")]
972 pub resp_version: Option<String>,
973
974 /// Optional. Support [OSS Cluster API](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#oss-cluster-api). Default: 'false'
975 #[serde(skip_serializing_if = "Option::is_none")]
976 pub support_oss_cluster_api: Option<bool>,
977
978 /// Optional. If set to 'true', the database will use the external endpoint for OSS Cluster API. This setting blocks the database's private endpoint. Can only be set if 'supportOSSClusterAPI' is 'true'. Default: 'false'
979 #[serde(skip_serializing_if = "Option::is_none")]
980 pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
981
982 /// Optional. Type and rate of data persistence in persistent storage. Default: 'none'
983 #[serde(skip_serializing_if = "Option::is_none")]
984 pub data_persistence: Option<String>,
985
986 /// Optional. Data eviction policy. Default: 'volatile-lru'
987 #[serde(skip_serializing_if = "Option::is_none")]
988 pub data_eviction_policy: Option<String>,
989
990 /// Optional. Sets database replication. Default: 'true'
991 #[serde(skip_serializing_if = "Option::is_none")]
992 pub replication: Option<bool>,
993
994 /// Optional. This database will be a replica of the specified Redis databases provided as one or more URI(s). Example: 'redis://user:password@host:port'. If the URI provided is a Redis Cloud database, only host and port should be provided. Example: ['<redis://endpoint1:6379>', '<redis://endpoint2:6380>'].
995 #[serde(skip_serializing_if = "Option::is_none")]
996 pub replica_of: Option<Vec<String>>,
997
998 #[serde(skip_serializing_if = "Option::is_none")]
999 pub replica: Option<ReplicaOfSpec>,
1000
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 pub throughput_measurement: Option<DatabaseThroughputSpec>,
1003
1004 /// Optional. Expected throughput per region for an Active-Active database. Default: 1000 read and write ops/sec for each region
1005 #[serde(skip_serializing_if = "Option::is_none")]
1006 pub local_throughput_measurement: Option<Vec<LocalThroughput>>,
1007
1008 /// Optional. Relevant only to ram-and-flash (also known as Auto Tiering) subscriptions. Estimated average size in bytes of the items stored in the database. Default: 1000
1009 #[serde(skip_serializing_if = "Option::is_none")]
1010 pub average_item_size_in_bytes: Option<i64>,
1011
1012 /// Optional. The path to a backup storage location. If specified, the database will back up every 24 hours to this location, and you can manually back up the database to this location at any time.
1013 #[serde(skip_serializing_if = "Option::is_none")]
1014 pub periodic_backup_path: Option<String>,
1015
1016 #[serde(skip_serializing_if = "Option::is_none")]
1017 pub remote_backup: Option<DatabaseBackupConfig>,
1018
1019 /// Optional. List of source IP addresses or subnet masks to allow. If specified, Redis clients will be able to connect to this database only from within the specified source IP addresses ranges. Example: '['192.168.10.0/32', '192.168.12.0/24']'
1020 #[serde(skip_serializing_if = "Option::is_none")]
1021 pub source_ip: Option<Vec<String>>,
1022
1023 /// Optional. A public key client TLS/SSL certificate with new line characters replaced with '\n'. If specified, mTLS authentication will be required to authenticate user connections. Default: 'null'
1024 #[serde(skip_serializing_if = "Option::is_none")]
1025 pub client_ssl_certificate: Option<String>,
1026
1027 /// Optional. A list of client TLS/SSL certificates. If specified, mTLS authentication will be required to authenticate user connections.
1028 #[serde(skip_serializing_if = "Option::is_none")]
1029 pub client_tls_certificates: Option<Vec<DatabaseCertificateSpec>>,
1030
1031 /// Optional. When 'true', requires TLS authentication for all connections - mTLS with valid clientTlsCertificates, regular TLS when clientTlsCertificates is not provided. Default: 'false'
1032 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub enable_tls: Option<bool>,
1034
1035 /// Optional. Password to access the database. If not set, a random 32-character alphanumeric password will be automatically generated. Can only be set if 'protocol' is 'redis'.
1036 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub password: Option<String>,
1038
1039 /// Optional. Memcached (SASL) Username to access the database. If not set, the username will be set to a 'mc-' prefix followed by a random 5 character long alphanumeric. Can only be set if 'protocol' is 'memcached'.
1040 #[serde(skip_serializing_if = "Option::is_none")]
1041 pub sasl_username: Option<String>,
1042
1043 /// Optional. Memcached (SASL) Password to access the database. If not set, a random 32 character long alphanumeric password will be automatically generated. Can only be set if 'protocol' is 'memcached'.
1044 #[serde(skip_serializing_if = "Option::is_none")]
1045 pub sasl_password: Option<String>,
1046
1047 /// Optional. Redis database alert details.
1048 #[serde(skip_serializing_if = "Option::is_none")]
1049 pub alerts: Option<Vec<DatabaseAlertSpec>>,
1050
1051 /// Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities.
1052 #[serde(skip_serializing_if = "Option::is_none")]
1053 pub modules: Option<Vec<DatabaseModuleSpec>>,
1054
1055 /// Optional. Database [Hashing policy](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#manage-the-hashing-policy).
1056 #[serde(skip_serializing_if = "Option::is_none")]
1057 pub sharding_type: Option<String>,
1058
1059 #[serde(skip_serializing_if = "Option::is_none")]
1060 pub command_type: Option<String>,
1061
1062 /// Optional. The query performance factor adds extra compute power specifically for search and query databases. You can increase your queries per second by the selected factor.
1063 #[serde(skip_serializing_if = "Option::is_none")]
1064 pub query_performance_factor: Option<String>,
1065}
1066
1067/// Database import request
1068#[derive(Debug, Clone, Serialize, Deserialize)]
1069#[serde(rename_all = "camelCase")]
1070pub struct DatabaseImportRequest {
1071 #[serde(skip_serializing_if = "Option::is_none")]
1072 pub subscription_id: Option<i32>,
1073
1074 #[serde(skip_serializing_if = "Option::is_none")]
1075 pub database_id: Option<i32>,
1076
1077 /// Type of storage from which to import the database RDB file or Redis data.
1078 pub source_type: String,
1079
1080 /// One or more paths to source data files or Redis databases, as appropriate to specified source type.
1081 pub import_from_uri: Vec<String>,
1082
1083 #[serde(skip_serializing_if = "Option::is_none")]
1084 pub command_type: Option<String>,
1085}
1086
1087/// Redis list of database tags
1088#[derive(Debug, Clone, Serialize, Deserialize)]
1089#[serde(rename_all = "camelCase")]
1090pub struct CloudTags {
1091 #[serde(skip_serializing_if = "Option::is_none")]
1092 pub account_id: Option<i32>,
1093
1094 /// HATEOAS links
1095 #[serde(skip_serializing_if = "Option::is_none")]
1096 pub links: Option<Vec<Link>>,
1097}
1098
1099/// Upgrades the specified Pro database to a later Redis version.
1100#[derive(Debug, Clone, Serialize, Deserialize)]
1101#[serde(rename_all = "camelCase")]
1102pub struct DatabaseUpgradeRedisVersionRequest {
1103 #[serde(skip_serializing_if = "Option::is_none")]
1104 pub database_id: Option<i32>,
1105
1106 #[serde(skip_serializing_if = "Option::is_none")]
1107 pub subscription_id: Option<i32>,
1108
1109 /// The target Redis version the database will be upgraded to. Use GET /subscriptions/redis-versions to get a list of available Redis versions.
1110 pub target_redis_version: String,
1111
1112 #[serde(skip_serializing_if = "Option::is_none")]
1113 pub command_type: Option<String>,
1114}
1115
1116/// `DatabaseSlowLogEntries`
1117#[derive(Debug, Clone, Serialize, Deserialize)]
1118pub struct DatabaseSlowLogEntries {
1119 #[serde(skip_serializing_if = "Option::is_none")]
1120 pub entries: Option<Vec<DatabaseSlowLogEntry>>,
1121
1122 /// HATEOAS links
1123 #[serde(skip_serializing_if = "Option::is_none")]
1124 pub links: Option<Vec<Link>>,
1125}
1126
1127/// Optional. A list of regions and local settings to update.
1128#[derive(Debug, Clone, Serialize, Deserialize)]
1129#[serde(rename_all = "camelCase")]
1130pub struct LocalRegionProperties {
1131 /// Required. Name of the region to update.
1132 #[serde(skip_serializing_if = "Option::is_none")]
1133 pub region: Option<String>,
1134
1135 #[serde(skip_serializing_if = "Option::is_none")]
1136 pub remote_backup: Option<DatabaseBackupConfig>,
1137
1138 #[serde(skip_serializing_if = "Option::is_none")]
1139 pub local_throughput_measurement: Option<LocalThroughput>,
1140
1141 /// Optional. Type and rate of data persistence for this region. If set, 'globalDataPersistence' will not apply to this region.
1142 #[serde(skip_serializing_if = "Option::is_none")]
1143 pub data_persistence: Option<String>,
1144
1145 /// Optional. Changes the password used to access the database in this region. If set, 'globalPassword' will not apply to this region.
1146 #[serde(skip_serializing_if = "Option::is_none")]
1147 pub password: Option<String>,
1148
1149 /// Optional. List of source IP addresses or subnet masks to allow in this region. If set, Redis clients will be able to connect to the database in this region only from within the specified source IP addresses ranges, and 'globalSourceIp' will not apply to this region. Example: ['192.168.10.0/32', '192.168.12.0/24']
1150 #[serde(skip_serializing_if = "Option::is_none")]
1151 pub source_ip: Option<Vec<String>>,
1152
1153 /// Optional. Redis database alert settings for this region. If set, 'glboalAlerts' will not apply to this region.
1154 #[serde(skip_serializing_if = "Option::is_none")]
1155 pub alerts: Option<Vec<DatabaseAlertSpec>>,
1156
1157 /// Optional. Redis Serialization Protocol version for this region. Must be compatible with Redis version.
1158 #[serde(skip_serializing_if = "Option::is_none")]
1159 pub resp_version: Option<String>,
1160}
1161
1162/// `TaskStateUpdate`
1163#[derive(Debug, Clone, Serialize, Deserialize)]
1164#[serde(rename_all = "camelCase")]
1165pub struct TaskStateUpdate {
1166 #[serde(skip_serializing_if = "Option::is_none")]
1167 pub task_id: Option<String>,
1168
1169 #[serde(skip_serializing_if = "Option::is_none")]
1170 pub command_type: Option<String>,
1171
1172 #[serde(skip_serializing_if = "Option::is_none")]
1173 pub status: Option<String>,
1174
1175 #[serde(skip_serializing_if = "Option::is_none")]
1176 pub description: Option<String>,
1177
1178 #[serde(skip_serializing_if = "Option::is_none")]
1179 pub timestamp: Option<String>,
1180
1181 #[serde(skip_serializing_if = "Option::is_none")]
1182 pub response: Option<ProcessorResponse>,
1183
1184 /// HATEOAS links
1185 #[serde(skip_serializing_if = "Option::is_none")]
1186 pub links: Option<Vec<Link>>,
1187}
1188
1189/// Database update request
1190#[derive(Debug, Clone, Serialize, Deserialize)]
1191#[serde(rename_all = "camelCase")]
1192pub struct DatabaseUpdateRequest {
1193 #[serde(skip_serializing_if = "Option::is_none")]
1194 pub subscription_id: Option<i32>,
1195
1196 #[serde(skip_serializing_if = "Option::is_none")]
1197 pub database_id: Option<i32>,
1198
1199 /// Optional. When 'false': Creates a deployment plan and deploys it, updating any resources required by the plan. When 'true': creates a read-only deployment plan and does not update any resources. Default: 'false'
1200 #[serde(skip_serializing_if = "Option::is_none")]
1201 pub dry_run: Option<bool>,
1202
1203 /// Optional. Updated database name.
1204 #[serde(skip_serializing_if = "Option::is_none")]
1205 pub name: Option<String>,
1206
1207 /// Optional. Total memory in GB, including replication and other overhead. You cannot set both datasetSizeInGb and totalMemoryInGb.
1208 #[serde(skip_serializing_if = "Option::is_none")]
1209 pub memory_limit_in_gb: Option<f64>,
1210
1211 /// Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb.If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.
1212 #[serde(skip_serializing_if = "Option::is_none")]
1213 pub dataset_size_in_gb: Option<f64>,
1214
1215 /// Optional. Redis Serialization Protocol version. Must be compatible with Redis version.
1216 #[serde(skip_serializing_if = "Option::is_none")]
1217 pub resp_version: Option<String>,
1218
1219 #[serde(skip_serializing_if = "Option::is_none")]
1220 pub throughput_measurement: Option<DatabaseThroughputSpec>,
1221
1222 /// Optional. Type and rate of data persistence in persistent storage.
1223 #[serde(skip_serializing_if = "Option::is_none")]
1224 pub data_persistence: Option<String>,
1225
1226 /// Optional. Data eviction policy.
1227 #[serde(skip_serializing_if = "Option::is_none")]
1228 pub data_eviction_policy: Option<String>,
1229
1230 /// Optional. Turns database replication on or off.
1231 #[serde(skip_serializing_if = "Option::is_none")]
1232 pub replication: Option<bool>,
1233
1234 /// Optional. Hashing policy Regex rules. Used only if 'shardingType' is 'custom-regex-rules'.
1235 #[serde(skip_serializing_if = "Option::is_none")]
1236 pub regex_rules: Option<Vec<String>>,
1237
1238 /// Optional. This database will be a replica of the specified Redis databases provided as one or more URI(s). Example: 'redis://user:password@host:port'. If the URI provided is a Redis Cloud database, only host and port should be provided. Example: ['<redis://endpoint1:6379>', '<redis://endpoint2:6380>'].
1239 #[serde(skip_serializing_if = "Option::is_none")]
1240 pub replica_of: Option<Vec<String>>,
1241
1242 #[serde(skip_serializing_if = "Option::is_none")]
1243 pub replica: Option<ReplicaOfSpec>,
1244
1245 /// Optional. Support Redis [OSS Cluster API](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#oss-cluster-api).
1246 #[serde(skip_serializing_if = "Option::is_none")]
1247 pub support_oss_cluster_api: Option<bool>,
1248
1249 /// Optional. If set to 'true', the database will use the external endpoint for OSS Cluster API. This setting blocks the database's private endpoint. Can only be set if 'supportOSSClusterAPI' is 'true'.
1250 #[serde(skip_serializing_if = "Option::is_none")]
1251 pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
1252
1253 /// Optional. Changes the password used to access the database with the 'default' user. Can only be set if 'protocol' is 'redis'.
1254 #[serde(skip_serializing_if = "Option::is_none")]
1255 pub password: Option<String>,
1256
1257 /// Optional. Changes the Memcached (SASL) username to access the database. Can only be set if 'protocol' is 'memcached'.
1258 #[serde(skip_serializing_if = "Option::is_none")]
1259 pub sasl_username: Option<String>,
1260
1261 /// Optional. Changes the Memcached (SASL) password to access the database. Can only be set if 'protocol' is 'memcached'.
1262 #[serde(skip_serializing_if = "Option::is_none")]
1263 pub sasl_password: Option<String>,
1264
1265 /// Optional. List of source IP addresses or subnet masks to allow. If specified, Redis clients will be able to connect to this database only from within the specified source IP addresses ranges. Example: '['192.168.10.0/32', '192.168.12.0/24']'
1266 #[serde(skip_serializing_if = "Option::is_none")]
1267 pub source_ip: Option<Vec<String>>,
1268
1269 /// Optional. A public key client TLS/SSL certificate with new line characters replaced with '\n'. If specified, mTLS authentication will be required to authenticate user connections if it is not already required. If set to an empty string, TLS client certificates will be removed and mTLS will not be required. TLS connection may still apply, depending on the value of 'enableTls'.
1270 #[serde(skip_serializing_if = "Option::is_none")]
1271 pub client_ssl_certificate: Option<String>,
1272
1273 /// Optional. A list of client TLS/SSL certificates. If specified, mTLS authentication will be required to authenticate user connections. If set to an empty list, TLS client certificates will be removed and mTLS will not be required. TLS connection may still apply, depending on the value of 'enableTls'.
1274 #[serde(skip_serializing_if = "Option::is_none")]
1275 pub client_tls_certificates: Option<Vec<DatabaseCertificateSpec>>,
1276
1277 /// Optional. When 'true', requires TLS authentication for all connections - mTLS with valid clientTlsCertificates, regular TLS when clientTlsCertificates is not provided. If enableTls is set to 'false' while mTLS is required, it will remove the mTLS requirement and erase previously provided clientTlsCertificates.
1278 #[serde(skip_serializing_if = "Option::is_none")]
1279 pub enable_tls: Option<bool>,
1280
1281 /// Optional. When 'true', allows connecting to the database with the 'default' user. When 'false', only defined access control users can connect to the database. Can only be set if 'protocol' is 'redis'.
1282 #[serde(skip_serializing_if = "Option::is_none")]
1283 pub enable_default_user: Option<bool>,
1284
1285 /// Optional. Changes the backup location path. If specified, the database will back up every 24 hours to this location, and you can manually back up the database to this location at any time. If set to an empty string, the backup path will be removed.
1286 #[serde(skip_serializing_if = "Option::is_none")]
1287 pub periodic_backup_path: Option<String>,
1288
1289 #[serde(skip_serializing_if = "Option::is_none")]
1290 pub remote_backup: Option<DatabaseBackupConfig>,
1291
1292 /// Optional. Changes Redis database alert details.
1293 #[serde(skip_serializing_if = "Option::is_none")]
1294 pub alerts: Option<Vec<DatabaseAlertSpec>>,
1295
1296 #[serde(skip_serializing_if = "Option::is_none")]
1297 pub command_type: Option<String>,
1298
1299 /// Optional. Changes the query performance factor. The query performance factor adds extra compute power specifically for search and query databases. You can increase your queries per second by the selected factor.
1300 #[serde(skip_serializing_if = "Option::is_none")]
1301 pub query_performance_factor: Option<String>,
1302}
1303
1304// ============================================================================
1305// Handler
1306// ============================================================================
1307
1308/// Handler for Pro database operations
1309///
1310/// Manages database lifecycle, configuration, backup/restore, import/export,
1311/// and monitoring for Redis Cloud Pro subscriptions.
1312pub struct DatabaseHandler {
1313 client: CloudClient,
1314}
1315
1316impl DatabaseHandler {
1317 /// Create a new handler
1318 #[must_use]
1319 pub fn new(client: CloudClient) -> Self {
1320 Self { client }
1321 }
1322
1323 /// Get all databases in a Pro subscription
1324 ///
1325 /// Gets a list of all databases in the specified Pro subscription.
1326 ///
1327 /// GET /subscriptions/{subscriptionId}/databases
1328 ///
1329 /// # Arguments
1330 ///
1331 /// * `subscription_id` - The subscription ID
1332 /// * `offset` - Optional offset for pagination
1333 /// * `limit` - Optional limit for pagination
1334 ///
1335 /// # Example
1336 ///
1337 /// ```no_run
1338 /// use redis_cloud::CloudClient;
1339 ///
1340 /// # async fn example() -> redis_cloud::Result<()> {
1341 /// let client = CloudClient::builder()
1342 /// .api_key("your-api-key")
1343 /// .api_secret("your-api-secret")
1344 /// .build()?;
1345 ///
1346 /// // Get all databases in subscription 123
1347 /// let databases = client.databases().get_subscription_databases(123, None, None).await?;
1348 ///
1349 /// // With pagination
1350 /// let page = client.databases().get_subscription_databases(123, Some(0), Some(10)).await?;
1351 /// # Ok(())
1352 /// # }
1353 /// ```
1354 pub async fn get_subscription_databases(
1355 &self,
1356 subscription_id: i32,
1357 offset: Option<i32>,
1358 limit: Option<i32>,
1359 ) -> Result<AccountSubscriptionDatabases> {
1360 let mut query = Vec::new();
1361 if let Some(v) = offset {
1362 query.push(format!("offset={v}"));
1363 }
1364 if let Some(v) = limit {
1365 query.push(format!("limit={v}"));
1366 }
1367 let query_string = if query.is_empty() {
1368 String::new()
1369 } else {
1370 format!("?{}", query.join("&"))
1371 };
1372 self.client
1373 .get(&format!(
1374 "/subscriptions/{subscription_id}/databases{query_string}"
1375 ))
1376 .await
1377 }
1378
1379 /// Create Pro database in existing subscription
1380 /// Creates a new database in an existing Pro subscription.
1381 ///
1382 /// POST /subscriptions/{subscriptionId}/databases
1383 pub async fn create_database(
1384 &self,
1385 subscription_id: i32,
1386 request: &DatabaseCreateRequest,
1387 ) -> Result<TaskStateUpdate> {
1388 self.client
1389 .post(
1390 &format!("/subscriptions/{subscription_id}/databases"),
1391 request,
1392 )
1393 .await
1394 }
1395
1396 /// Delete Pro database
1397 /// Deletes a database from a Pro subscription.
1398 ///
1399 /// DELETE /subscriptions/{subscriptionId}/databases/{databaseId}
1400 pub async fn delete_database_by_id(
1401 &self,
1402 subscription_id: i32,
1403 database_id: i32,
1404 ) -> Result<TaskStateUpdate> {
1405 let response = self
1406 .client
1407 .delete_raw(&format!(
1408 "/subscriptions/{subscription_id}/databases/{database_id}"
1409 ))
1410 .await?;
1411 serde_json::from_value(response).map_err(Into::into)
1412 }
1413
1414 /// Get a single Pro database
1415 ///
1416 /// Gets details and settings of a single database in a Pro subscription.
1417 ///
1418 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}
1419 ///
1420 /// # Example
1421 ///
1422 /// ```no_run
1423 /// use redis_cloud::CloudClient;
1424 ///
1425 /// # async fn example() -> redis_cloud::Result<()> {
1426 /// let client = CloudClient::builder()
1427 /// .api_key("your-api-key")
1428 /// .api_secret("your-api-secret")
1429 /// .build()?;
1430 ///
1431 /// let database = client.databases().get_subscription_database_by_id(123, 456).await?;
1432 ///
1433 /// println!("Database: {} (status: {:?})",
1434 /// database.name.unwrap_or_default(),
1435 /// database.status);
1436 /// # Ok(())
1437 /// # }
1438 /// ```
1439 pub async fn get_subscription_database_by_id(
1440 &self,
1441 subscription_id: i32,
1442 database_id: i32,
1443 ) -> Result<Database> {
1444 self.client
1445 .get(&format!(
1446 "/subscriptions/{subscription_id}/databases/{database_id}"
1447 ))
1448 .await
1449 }
1450
1451 /// Update Pro database
1452 /// Updates an existing Pro database.
1453 ///
1454 /// PUT /subscriptions/{subscriptionId}/databases/{databaseId}
1455 pub async fn update_database(
1456 &self,
1457 subscription_id: i32,
1458 database_id: i32,
1459 request: &DatabaseUpdateRequest,
1460 ) -> Result<TaskStateUpdate> {
1461 self.client
1462 .put(
1463 &format!("/subscriptions/{subscription_id}/databases/{database_id}"),
1464 request,
1465 )
1466 .await
1467 }
1468
1469 /// Get Pro database backup status
1470 /// Gets information on the latest backup attempt for this Pro database.
1471 ///
1472 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}/backup
1473 pub async fn get_database_backup_status(
1474 &self,
1475 subscription_id: i32,
1476 database_id: i32,
1477 region_name: Option<String>,
1478 ) -> Result<TaskStateUpdate> {
1479 let mut query = Vec::new();
1480 if let Some(v) = region_name {
1481 query.push(format!("regionName={v}"));
1482 }
1483 let query_string = if query.is_empty() {
1484 String::new()
1485 } else {
1486 format!("?{}", query.join("&"))
1487 };
1488 self.client
1489 .get(&format!(
1490 "/subscriptions/{subscription_id}/databases/{database_id}/backup{query_string}"
1491 ))
1492 .await
1493 }
1494
1495 /// Back up Pro database
1496 /// Manually back up the specified Pro database to a backup path. By default, backups will be stored in the 'remoteBackup' location for this database.
1497 ///
1498 /// POST /subscriptions/{subscriptionId}/databases/{databaseId}/backup
1499 pub async fn backup_database(
1500 &self,
1501 subscription_id: i32,
1502 database_id: i32,
1503 request: &DatabaseBackupRequest,
1504 ) -> Result<TaskStateUpdate> {
1505 self.client
1506 .post(
1507 &format!("/subscriptions/{subscription_id}/databases/{database_id}/backup"),
1508 request,
1509 )
1510 .await
1511 }
1512
1513 /// Get Pro database TLS certificate
1514 /// Gets the X.509 PEM (base64) encoded server certificate for TLS connection to the database. Requires 'enableTLS' to be 'true' for the database.
1515 ///
1516 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}/certificate
1517 pub async fn get_subscription_database_certificate(
1518 &self,
1519 subscription_id: i32,
1520 database_id: i32,
1521 ) -> Result<DatabaseCertificate> {
1522 self.client
1523 .get(&format!(
1524 "/subscriptions/{subscription_id}/databases/{database_id}/certificate"
1525 ))
1526 .await
1527 }
1528
1529 /// Flush Pro database
1530 /// Deletes all data from the specified Pro database.
1531 ///
1532 /// PUT /subscriptions/{subscriptionId}/databases/{databaseId}/flush
1533 pub async fn flush_crdb(
1534 &self,
1535 subscription_id: i32,
1536 database_id: i32,
1537 request: &CrdbFlushRequest,
1538 ) -> Result<TaskStateUpdate> {
1539 self.client
1540 .put(
1541 &format!("/subscriptions/{subscription_id}/databases/{database_id}/flush"),
1542 request,
1543 )
1544 .await
1545 }
1546
1547 /// Get Pro database import status
1548 /// Gets information on the latest import attempt for this Pro database.
1549 ///
1550 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}/import
1551 pub async fn get_database_import_status(
1552 &self,
1553 subscription_id: i32,
1554 database_id: i32,
1555 ) -> Result<TaskStateUpdate> {
1556 self.client
1557 .get(&format!(
1558 "/subscriptions/{subscription_id}/databases/{database_id}/import"
1559 ))
1560 .await
1561 }
1562
1563 /// Import data to a Pro database
1564 /// Imports data from an RDB file or from a different Redis database into this Pro database. WARNING: Importing data into a database removes all existing data from the database.
1565 ///
1566 /// POST /subscriptions/{subscriptionId}/databases/{databaseId}/import
1567 pub async fn import_database(
1568 &self,
1569 subscription_id: i32,
1570 database_id: i32,
1571 request: &DatabaseImportRequest,
1572 ) -> Result<TaskStateUpdate> {
1573 self.client
1574 .post(
1575 &format!("/subscriptions/{subscription_id}/databases/{database_id}/import"),
1576 request,
1577 )
1578 .await
1579 }
1580
1581 /// Update Active-Active database
1582 /// (Active-Active databases only) Updates database properties for an Active-Active database.
1583 ///
1584 /// PUT /subscriptions/{subscriptionId}/databases/{databaseId}/regions
1585 pub async fn update_crdb_local_properties(
1586 &self,
1587 subscription_id: i32,
1588 database_id: i32,
1589 request: &CrdbUpdatePropertiesRequest,
1590 ) -> Result<TaskStateUpdate> {
1591 self.client
1592 .put(
1593 &format!("/subscriptions/{subscription_id}/databases/{database_id}/regions"),
1594 request,
1595 )
1596 .await
1597 }
1598
1599 /// Get database slowlog
1600 /// Gets the slowlog for a specific database.
1601 ///
1602 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}/slow-log
1603 pub async fn get_slow_log(
1604 &self,
1605 subscription_id: i32,
1606 database_id: i32,
1607 region_name: Option<String>,
1608 ) -> Result<DatabaseSlowLogEntries> {
1609 let mut query = Vec::new();
1610 if let Some(v) = region_name {
1611 query.push(format!("regionName={v}"));
1612 }
1613 let query_string = if query.is_empty() {
1614 String::new()
1615 } else {
1616 format!("?{}", query.join("&"))
1617 };
1618 self.client
1619 .get(&format!(
1620 "/subscriptions/{subscription_id}/databases/{database_id}/slow-log{query_string}"
1621 ))
1622 .await
1623 }
1624
1625 /// Get database tags
1626 /// Gets a list of all database tags.
1627 ///
1628 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}/tags
1629 pub async fn get_tags(&self, subscription_id: i32, database_id: i32) -> Result<CloudTags> {
1630 self.client
1631 .get(&format!(
1632 "/subscriptions/{subscription_id}/databases/{database_id}/tags"
1633 ))
1634 .await
1635 }
1636
1637 /// Add a database tag
1638 /// Adds a single database tag to a database.
1639 ///
1640 /// POST /subscriptions/{subscriptionId}/databases/{databaseId}/tags
1641 pub async fn create_tag(
1642 &self,
1643 subscription_id: i32,
1644 database_id: i32,
1645 request: &DatabaseTagCreateRequest,
1646 ) -> Result<CloudTag> {
1647 self.client
1648 .post(
1649 &format!("/subscriptions/{subscription_id}/databases/{database_id}/tags"),
1650 request,
1651 )
1652 .await
1653 }
1654
1655 /// Overwrite database tags
1656 /// Overwrites all tags on the database.
1657 ///
1658 /// PUT /subscriptions/{subscriptionId}/databases/{databaseId}/tags
1659 pub async fn update_tags(
1660 &self,
1661 subscription_id: i32,
1662 database_id: i32,
1663 request: &DatabaseTagsUpdateRequest,
1664 ) -> Result<CloudTags> {
1665 self.client
1666 .put(
1667 &format!("/subscriptions/{subscription_id}/databases/{database_id}/tags"),
1668 request,
1669 )
1670 .await
1671 }
1672
1673 /// Delete database tag
1674 /// Removes the specified tag from the database.
1675 ///
1676 /// DELETE /subscriptions/{subscriptionId}/databases/{databaseId}/tags/{tagKey}
1677 pub async fn delete_tag(
1678 &self,
1679 subscription_id: i32,
1680 database_id: i32,
1681 tag_key: String,
1682 ) -> Result<HashMap<String, Value>> {
1683 let response = self
1684 .client
1685 .delete_raw(&format!(
1686 "/subscriptions/{subscription_id}/databases/{database_id}/tags/{tag_key}"
1687 ))
1688 .await?;
1689 serde_json::from_value(response).map_err(Into::into)
1690 }
1691
1692 /// Update database tag value
1693 /// Updates the value of the specified database tag.
1694 ///
1695 /// PUT /subscriptions/{subscriptionId}/databases/{databaseId}/tags/{tagKey}
1696 pub async fn update_tag(
1697 &self,
1698 subscription_id: i32,
1699 database_id: i32,
1700 tag_key: String,
1701 request: &DatabaseTagUpdateRequest,
1702 ) -> Result<CloudTag> {
1703 self.client
1704 .put(
1705 &format!("/subscriptions/{subscription_id}/databases/{database_id}/tags/{tag_key}"),
1706 request,
1707 )
1708 .await
1709 }
1710
1711 /// Get Pro database version upgrade status
1712 /// Gets information on the latest upgrade attempt for this Pro database.
1713 ///
1714 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}/upgrade
1715 pub async fn get_database_redis_version_upgrade_status(
1716 &self,
1717 subscription_id: i32,
1718 database_id: i32,
1719 ) -> Result<BdbVersionUpgradeStatus> {
1720 self.client
1721 .get(&format!(
1722 "/subscriptions/{subscription_id}/databases/{database_id}/upgrade"
1723 ))
1724 .await
1725 }
1726
1727 /// Upgrade Pro database version
1728 ///
1729 /// POST /subscriptions/{subscriptionId}/databases/{databaseId}/upgrade
1730 pub async fn upgrade_database_redis_version(
1731 &self,
1732 subscription_id: i32,
1733 database_id: i32,
1734 request: &DatabaseUpgradeRedisVersionRequest,
1735 ) -> Result<TaskStateUpdate> {
1736 self.client
1737 .post(
1738 &format!("/subscriptions/{subscription_id}/databases/{database_id}/upgrade"),
1739 request,
1740 )
1741 .await
1742 }
1743
1744 /// Get available target Redis versions for upgrade
1745 /// Gets a list of Redis versions that the database can be upgraded to.
1746 ///
1747 /// GET /subscriptions/{subscriptionId}/databases/{databaseId}/available-target-versions
1748 pub async fn get_available_target_versions(
1749 &self,
1750 subscription_id: i32,
1751 database_id: i32,
1752 ) -> Result<Value> {
1753 self.client
1754 .get_raw(&format!(
1755 "/subscriptions/{subscription_id}/databases/{database_id}/available-target-versions"
1756 ))
1757 .await
1758 }
1759
1760 /// Flush Pro database (standard, non-Active-Active)
1761 /// Deletes all data from the specified Pro database.
1762 ///
1763 /// PUT /subscriptions/{subscriptionId}/databases/{databaseId}/flush
1764 pub async fn flush_database(
1765 &self,
1766 subscription_id: i32,
1767 database_id: i32,
1768 ) -> Result<TaskStateUpdate> {
1769 // Empty body for standard flush
1770 self.client
1771 .put_raw(
1772 &format!("/subscriptions/{subscription_id}/databases/{database_id}/flush"),
1773 serde_json::json!({}),
1774 )
1775 .await
1776 .and_then(|v| serde_json::from_value(v).map_err(Into::into))
1777 }
1778
1779 // ========================================================================
1780 // Pagination Helpers
1781 // ========================================================================
1782
1783 /// Stream all databases in a Pro subscription
1784 ///
1785 /// Returns an async stream that automatically handles pagination, yielding
1786 /// individual [`Database`] items. This is useful when you need to process
1787 /// a large number of databases without loading them all into memory at once.
1788 ///
1789 /// # Arguments
1790 ///
1791 /// * `subscription_id` - The subscription ID
1792 ///
1793 /// # Example
1794 ///
1795 /// ```no_run
1796 /// use redis_cloud::CloudClient;
1797 /// use futures::StreamExt;
1798 /// use std::pin::pin;
1799 ///
1800 /// # async fn example() -> redis_cloud::Result<()> {
1801 /// let client = CloudClient::builder()
1802 /// .api_key("your-api-key")
1803 /// .api_secret("your-api-secret")
1804 /// .build()?;
1805 ///
1806 /// let handler = client.databases();
1807 /// let mut stream = pin!(handler.stream_databases(123));
1808 /// while let Some(result) = stream.next().await {
1809 /// let database = result?;
1810 /// println!("Database: {} (ID: {})", database.name.unwrap_or_default(), database.database_id);
1811 /// }
1812 /// # Ok(())
1813 /// # }
1814 /// ```
1815 pub fn stream_databases(
1816 &self,
1817 subscription_id: i32,
1818 ) -> impl Stream<Item = Result<Database>> + '_ {
1819 self.stream_databases_with_page_size(subscription_id, 100)
1820 }
1821
1822 /// Stream all databases with custom page size
1823 ///
1824 /// Like [`stream_databases`](Self::stream_databases), but allows specifying
1825 /// the page size for API requests.
1826 ///
1827 /// # Arguments
1828 ///
1829 /// * `subscription_id` - The subscription ID
1830 /// * `page_size` - Number of databases to fetch per API request
1831 pub fn stream_databases_with_page_size(
1832 &self,
1833 subscription_id: i32,
1834 page_size: i32,
1835 ) -> impl Stream<Item = Result<Database>> + '_ {
1836 try_stream! {
1837 let mut offset = 0;
1838
1839 loop {
1840 let response = self
1841 .get_subscription_databases(subscription_id, Some(offset), Some(page_size))
1842 .await?;
1843
1844 // Extract databases from the response
1845 let databases = Self::extract_databases_from_response(&response);
1846
1847 if databases.is_empty() {
1848 break;
1849 }
1850
1851 let count = databases.len();
1852 for db in databases {
1853 yield db;
1854 }
1855
1856 // If we got fewer than page_size, we've reached the end
1857 #[allow(clippy::cast_sign_loss)]
1858 if count < page_size as usize {
1859 break;
1860 }
1861
1862 offset += page_size;
1863 }
1864 }
1865 }
1866
1867 /// Get all databases in a subscription (collected)
1868 ///
1869 /// Fetches all databases by automatically handling pagination and returns
1870 /// them as a single vector. Use [`stream_databases`](Self::stream_databases)
1871 /// if you prefer to process databases one at a time.
1872 ///
1873 /// # Arguments
1874 ///
1875 /// * `subscription_id` - The subscription ID
1876 ///
1877 /// # Example
1878 ///
1879 /// ```no_run
1880 /// use redis_cloud::CloudClient;
1881 ///
1882 /// # async fn example() -> redis_cloud::Result<()> {
1883 /// let client = CloudClient::builder()
1884 /// .api_key("your-api-key")
1885 /// .api_secret("your-api-secret")
1886 /// .build()?;
1887 ///
1888 /// let all_databases = client.databases().get_all_databases(123).await?;
1889 /// println!("Total databases: {}", all_databases.len());
1890 /// # Ok(())
1891 /// # }
1892 /// ```
1893 pub async fn get_all_databases(&self, subscription_id: i32) -> Result<Vec<Database>> {
1894 let mut databases = Vec::new();
1895 let mut offset = 0;
1896 let page_size = 100;
1897
1898 loop {
1899 let response = self
1900 .get_subscription_databases(subscription_id, Some(offset), Some(page_size))
1901 .await?;
1902
1903 let page = Self::extract_databases_from_response(&response);
1904 let count = page.len();
1905 databases.extend(page);
1906
1907 #[allow(clippy::cast_sign_loss)]
1908 if count < page_size as usize {
1909 break;
1910 }
1911 offset += page_size;
1912 }
1913
1914 Ok(databases)
1915 }
1916
1917 /// Extract databases from an `AccountSubscriptionDatabases` response
1918 fn extract_databases_from_response(response: &AccountSubscriptionDatabases) -> Vec<Database> {
1919 response
1920 .subscription
1921 .first()
1922 .map(|sub| sub.databases.clone())
1923 .unwrap_or_default()
1924 }
1925}