Skip to main content

redis_cloud/fixed/
databases.rs

1//! Database management operations for Essentials (Fixed) subscriptions
2//!
3//! This module provides database management functionality for Redis Cloud Essentials
4//! (formerly Fixed) subscriptions, which offer a simplified, cost-effective option
5//! for smaller workloads with predictable capacity requirements.
6//!
7//! # Overview
8//!
9//! Essentials databases are pre-configured Redis instances with fixed memory allocations
10//! and simplified pricing. They're ideal for development, testing, and production
11//! workloads that don't require auto-scaling or advanced clustering features.
12//!
13//! # Key Features
14//!
15//! - **Fixed Capacity**: Pre-defined memory sizes from 250MB to 12GB
16//! - **Simple Pricing**: Predictable monthly costs
17//! - **Essential Features**: Replication, persistence, and backup support
18//! - **Module Support**: Limited module availability based on plan
19//! - **Quick Setup**: Simplified configuration for faster deployment
20//!
21//! # Differences from Pro Databases
22//!
23//! - Fixed memory allocations (no auto-scaling)
24//! - Limited to single-region deployments
25//! - Simplified module selection
26//! - No clustering support
27//! - Predictable pricing model
28//!
29//! # Example Usage
30//!
31//! ```no_run
32//! use redis_cloud::{CloudClient, FixedDatabaseHandler};
33//!
34//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
35//! let client = CloudClient::builder()
36//!     .api_key("your-api-key")
37//!     .api_secret("your-api-secret")
38//!     .build()?;
39//!
40//! let handler = FixedDatabaseHandler::new(client);
41//!
42//! // Example: List databases in a fixed subscription (ID 123)
43//! let databases = handler.list(123, None, None).await?;
44//! # Ok(())
45//! # }
46//! ```
47
48use crate::types::{Link, ProcessorResponse};
49use crate::{CloudClient, Result};
50use serde::{Deserialize, Serialize};
51use serde_json::Value;
52use std::collections::HashMap;
53
54// ============================================================================
55// Models
56// ============================================================================
57
58/// `RedisLabs` Account Subscription Databases information
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct AccountFixedSubscriptionDatabases {
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub account_id: Option<i32>,
64
65    /// HATEOAS links
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub links: Option<Vec<Link>>,
68}
69
70/// Database import request
71#[derive(Debug, Clone, Serialize, Deserialize)]
72#[serde(rename_all = "camelCase")]
73pub struct FixedDatabaseImportRequest {
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub subscription_id: Option<i32>,
76
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub database_id: Option<i32>,
79
80    /// Type of storage from which to import the database RDB file or Redis data.
81    pub source_type: String,
82
83    /// One or more paths to source data files or Redis databases, as appropriate to specified source type.
84    pub import_from_uri: Vec<String>,
85
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub command_type: Option<String>,
88}
89
90/// Database tag update request message
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct DatabaseTagUpdateRequest {
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub subscription_id: Option<i32>,
96
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub database_id: Option<i32>,
99
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub key: Option<String>,
102
103    /// Database tag value
104    pub value: String,
105
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub command_type: Option<String>,
108}
109
110/// `DynamicEndpoints`
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct DynamicEndpoints {
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub public: Option<String>,
115
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub private: Option<String>,
118}
119
120/// Database tag
121#[derive(Debug, Clone, Serialize, Deserialize)]
122#[serde(rename_all = "camelCase")]
123pub struct Tag {
124    /// Database tag key.
125    pub key: String,
126
127    /// Database tag value.
128    pub value: String,
129
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub command_type: Option<String>,
132}
133
134/// Database tags update request message
135#[derive(Debug, Clone, Serialize, Deserialize)]
136#[serde(rename_all = "camelCase")]
137pub struct DatabaseTagsUpdateRequest {
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub subscription_id: Option<i32>,
140
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub database_id: Option<i32>,
143
144    /// List of database tags.
145    pub tags: Vec<Tag>,
146
147    #[serde(skip_serializing_if = "Option::is_none")]
148    pub command_type: Option<String>,
149}
150
151/// Optional. This database will be a replica of the specified Redis databases, provided as a list of objects with endpoint and certificate details.
152#[derive(Debug, Clone, Serialize, Deserialize)]
153#[serde(rename_all = "camelCase")]
154pub struct DatabaseSyncSourceSpec {
155    /// 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>'.
156    pub endpoint: String,
157
158    /// 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.
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub encryption: Option<bool>,
161
162    /// 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.
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub server_cert: Option<String>,
165}
166
167/// 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'.
168#[derive(Debug, Clone, Serialize, Deserialize)]
169#[serde(rename_all = "camelCase")]
170pub struct DatabaseCertificateSpec {
171    /// Client certificate public key in PEM format, with new line characters replaced with '\n'.
172    pub public_certificate_pem_string: String,
173}
174
175/// Database tag
176#[derive(Debug, Clone, Serialize, Deserialize)]
177#[serde(rename_all = "camelCase")]
178pub struct CloudTag {
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub key: Option<String>,
181
182    #[serde(skip_serializing_if = "Option::is_none")]
183    pub value: Option<String>,
184
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub created_at: Option<String>,
187
188    #[serde(skip_serializing_if = "Option::is_none")]
189    pub updated_at: Option<String>,
190
191    /// HATEOAS links
192    #[serde(skip_serializing_if = "Option::is_none")]
193    pub links: Option<Vec<Link>>,
194}
195
196/// Database slowlog entry
197#[derive(Debug, Clone, Serialize, Deserialize)]
198#[serde(rename_all = "camelCase")]
199pub struct DatabaseSlowLogEntry {
200    #[serde(skip_serializing_if = "Option::is_none")]
201    pub id: Option<i32>,
202
203    #[serde(skip_serializing_if = "Option::is_none")]
204    pub start_time: Option<String>,
205
206    #[serde(skip_serializing_if = "Option::is_none")]
207    pub duration: Option<i32>,
208
209    #[serde(skip_serializing_if = "Option::is_none")]
210    pub arguments: Option<String>,
211}
212
213/// Database tag
214#[derive(Debug, Clone, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct DatabaseTagCreateRequest {
217    /// Database tag key.
218    pub key: String,
219
220    /// Database tag value.
221    pub value: String,
222
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub subscription_id: Option<i32>,
225
226    #[serde(skip_serializing_if = "Option::is_none")]
227    pub database_id: Option<i32>,
228
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub command_type: Option<String>,
231}
232
233/// Essentials database backup request message
234#[derive(Debug, Clone, Serialize, Deserialize)]
235#[serde(rename_all = "camelCase")]
236pub struct FixedDatabaseBackupRequest {
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub subscription_id: Option<i32>,
239
240    #[serde(skip_serializing_if = "Option::is_none")]
241    pub database_id: Option<i32>,
242
243    /// Optional. Manually backs up data to this location, instead of the set 'periodicBackupPath' location.
244    #[serde(skip_serializing_if = "Option::is_none")]
245    pub adhoc_backup_path: Option<String>,
246
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub command_type: Option<String>,
249}
250
251/// 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.
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct DatabaseModuleSpec {
254    /// Redis advanced capability name. Use GET /database-modules for a list of available capabilities.
255    pub name: String,
256
257    /// Optional. Redis advanced capability parameters. Use GET /database-modules to get the available capabilities and their parameters.
258    #[serde(skip_serializing_if = "Option::is_none")]
259    pub parameters: Option<HashMap<String, Value>>,
260}
261
262/// Optional. Changes Replica Of (also known as Active-Passive) configuration details.
263#[derive(Debug, Clone, Serialize, Deserialize)]
264#[serde(rename_all = "camelCase")]
265pub struct ReplicaOfSpec {
266    /// Description of the replica configuration
267    #[serde(skip_serializing_if = "Option::is_none")]
268    pub description: Option<String>,
269
270    /// Optional. This database will be a replica of the specified Redis databases, provided as a list of objects with endpoint and certificate details.
271    #[serde(default)]
272    pub sync_sources: Vec<DatabaseSyncSourceSpec>,
273}
274
275/// Database backup status and configuration
276#[derive(Debug, Clone, Serialize, Deserialize)]
277#[serde(rename_all = "camelCase")]
278pub struct DatabaseBackupStatus {
279    /// Whether backup is enabled
280    #[serde(skip_serializing_if = "Option::is_none")]
281    pub enabled: Option<bool>,
282
283    /// Current backup status
284    #[serde(skip_serializing_if = "Option::is_none")]
285    pub status: Option<String>,
286
287    /// Backup interval (e.g., "every-24-hours")
288    #[serde(skip_serializing_if = "Option::is_none")]
289    pub interval: Option<String>,
290
291    /// Backup destination path
292    #[serde(skip_serializing_if = "Option::is_none")]
293    pub destination: Option<String>,
294}
295
296/// Optional. Changes Redis database alert details.
297#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct DatabaseAlertSpec {
299    /// 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.
300    pub name: String,
301
302    /// 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.
303    pub value: i32,
304}
305
306/// Redis list of database tags
307#[derive(Debug, Clone, Serialize, Deserialize)]
308#[serde(rename_all = "camelCase")]
309pub struct CloudTags {
310    #[serde(skip_serializing_if = "Option::is_none")]
311    pub account_id: Option<i32>,
312
313    /// HATEOAS links
314    #[serde(skip_serializing_if = "Option::is_none")]
315    pub links: Option<Vec<Link>>,
316}
317
318/// `FixedDatabase`
319#[derive(Debug, Clone, Serialize, Deserialize)]
320#[serde(rename_all = "camelCase")]
321pub struct FixedDatabase {
322    #[serde(skip_serializing_if = "Option::is_none")]
323    pub database_id: Option<i32>,
324
325    #[serde(skip_serializing_if = "Option::is_none")]
326    pub name: Option<String>,
327
328    #[serde(skip_serializing_if = "Option::is_none")]
329    pub protocol: Option<String>,
330
331    #[serde(skip_serializing_if = "Option::is_none")]
332    pub provider: Option<String>,
333
334    #[serde(skip_serializing_if = "Option::is_none")]
335    pub region: Option<String>,
336
337    #[serde(skip_serializing_if = "Option::is_none")]
338    pub redis_version: Option<String>,
339
340    #[serde(skip_serializing_if = "Option::is_none")]
341    pub redis_version_compliance: Option<String>,
342
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub resp_version: Option<String>,
345
346    #[serde(skip_serializing_if = "Option::is_none")]
347    pub status: Option<String>,
348
349    #[serde(skip_serializing_if = "Option::is_none")]
350    pub plan_memory_limit: Option<f64>,
351
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub plan_dataset_size: Option<f64>,
354
355    #[serde(skip_serializing_if = "Option::is_none")]
356    pub memory_limit_measurement_unit: Option<String>,
357
358    #[serde(skip_serializing_if = "Option::is_none")]
359    pub memory_limit_in_gb: Option<f64>,
360
361    #[serde(skip_serializing_if = "Option::is_none")]
362    pub dataset_size_in_gb: Option<f64>,
363
364    #[serde(skip_serializing_if = "Option::is_none")]
365    pub memory_used_in_mb: Option<f64>,
366
367    #[serde(skip_serializing_if = "Option::is_none")]
368    pub network_monthly_usage_in_byte: Option<f64>,
369
370    #[serde(skip_serializing_if = "Option::is_none")]
371    pub memory_storage: Option<String>,
372
373    #[serde(skip_serializing_if = "Option::is_none")]
374    pub redis_flex: Option<bool>,
375
376    #[serde(skip_serializing_if = "Option::is_none")]
377    pub support_oss_cluster_api: Option<bool>,
378
379    #[serde(skip_serializing_if = "Option::is_none")]
380    pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
381
382    #[serde(skip_serializing_if = "Option::is_none")]
383    pub data_persistence: Option<String>,
384
385    #[serde(skip_serializing_if = "Option::is_none")]
386    pub replication: Option<bool>,
387
388    #[serde(skip_serializing_if = "Option::is_none")]
389    pub data_eviction_policy: Option<String>,
390
391    #[serde(skip_serializing_if = "Option::is_none")]
392    pub activated_on: Option<String>,
393
394    #[serde(skip_serializing_if = "Option::is_none")]
395    pub last_modified: Option<String>,
396
397    #[serde(skip_serializing_if = "Option::is_none")]
398    pub public_endpoint: Option<String>,
399
400    #[serde(skip_serializing_if = "Option::is_none")]
401    pub private_endpoint: Option<String>,
402
403    #[serde(skip_serializing_if = "Option::is_none")]
404    pub dynamic_endpoints: Option<DynamicEndpoints>,
405
406    /// Whether default Redis user is enabled
407    #[serde(skip_serializing_if = "Option::is_none")]
408    pub enable_default_user: Option<bool>,
409
410    /// Whether TLS is enabled for connections
411    #[serde(skip_serializing_if = "Option::is_none")]
412    pub enable_tls: Option<bool>,
413
414    /// Database password (masked in responses)
415    #[serde(skip_serializing_if = "Option::is_none")]
416    pub password: Option<String>,
417
418    /// List of source IP addresses or subnet masks allowed to connect
419    #[serde(skip_serializing_if = "Option::is_none")]
420    pub source_ips: Option<Vec<String>>,
421
422    /// Whether SSL client authentication is enabled
423    #[serde(skip_serializing_if = "Option::is_none")]
424    pub ssl_client_authentication: Option<bool>,
425
426    /// Whether TLS client authentication is enabled
427    #[serde(skip_serializing_if = "Option::is_none")]
428    pub tls_client_authentication: Option<bool>,
429
430    /// Replica of configuration
431    #[serde(skip_serializing_if = "Option::is_none")]
432    pub replica: Option<ReplicaOfSpec>,
433
434    /// Whether database clustering is enabled
435    #[serde(skip_serializing_if = "Option::is_none")]
436    pub clustering_enabled: Option<bool>,
437
438    /// Regex rules for custom hashing policy
439    #[serde(skip_serializing_if = "Option::is_none")]
440    pub regex_rules: Option<Vec<String>>,
441
442    /// Hashing policy for clustering
443    #[serde(skip_serializing_if = "Option::is_none")]
444    pub hashing_policy: Option<String>,
445
446    /// Redis modules/capabilities enabled on this database
447    #[serde(skip_serializing_if = "Option::is_none")]
448    pub modules: Option<Vec<DatabaseModuleSpec>>,
449
450    /// Database alert configurations
451    #[serde(skip_serializing_if = "Option::is_none")]
452    pub alerts: Option<Vec<DatabaseAlertSpec>>,
453
454    /// Backup configuration and status
455    #[serde(skip_serializing_if = "Option::is_none")]
456    pub backup: Option<DatabaseBackupStatus>,
457
458    /// HATEOAS links
459    #[serde(skip_serializing_if = "Option::is_none")]
460    pub links: Option<Vec<Link>>,
461}
462
463/// `DatabaseSlowLogEntries`
464#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct DatabaseSlowLogEntries {
466    #[serde(skip_serializing_if = "Option::is_none")]
467    pub entries: Option<Vec<DatabaseSlowLogEntry>>,
468
469    /// HATEOAS links
470    #[serde(skip_serializing_if = "Option::is_none")]
471    pub links: Option<Vec<Link>>,
472}
473
474/// `TaskStateUpdate`
475#[derive(Debug, Clone, Serialize, Deserialize)]
476#[serde(rename_all = "camelCase")]
477pub struct TaskStateUpdate {
478    #[serde(skip_serializing_if = "Option::is_none")]
479    pub task_id: Option<String>,
480
481    #[serde(skip_serializing_if = "Option::is_none")]
482    pub command_type: Option<String>,
483
484    #[serde(skip_serializing_if = "Option::is_none")]
485    pub status: Option<String>,
486
487    #[serde(skip_serializing_if = "Option::is_none")]
488    pub description: Option<String>,
489
490    #[serde(skip_serializing_if = "Option::is_none")]
491    pub timestamp: Option<String>,
492
493    #[serde(skip_serializing_if = "Option::is_none")]
494    pub response: Option<ProcessorResponse>,
495
496    /// HATEOAS links
497    #[serde(skip_serializing_if = "Option::is_none")]
498    pub links: Option<Vec<Link>>,
499}
500
501/// Essentials database definition
502#[derive(Debug, Clone, Serialize, Deserialize)]
503#[serde(rename_all = "camelCase")]
504pub struct FixedDatabaseCreateRequest {
505    #[serde(skip_serializing_if = "Option::is_none")]
506    pub subscription_id: Option<i32>,
507
508    /// 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.
509    pub name: String,
510
511    /// Optional. Database protocol. Use 'stack' to get all of Redis' advanced capabilities. Only use 'redis' for Pay-as-you-go or Redis Flex subscriptions. Default: 'stack' for most subscriptions, 'redis' for Redis Flex subscriptions.
512    #[serde(skip_serializing_if = "Option::is_none")]
513    pub protocol: Option<String>,
514
515    /// (Pay-as-you-go subscriptions only) Optional. Total memory in GB, including replication and other overhead. You cannot set both datasetSizeInGb and totalMemoryInGb.
516    #[serde(skip_serializing_if = "Option::is_none")]
517    pub memory_limit_in_gb: Option<f64>,
518
519    /// (Pay-as-you-go subscriptions only) 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.
520    #[serde(skip_serializing_if = "Option::is_none")]
521    pub dataset_size_in_gb: Option<f64>,
522
523    /// (Pay-as-you-go subscriptions only) Optional. Support Redis [OSS Cluster API](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#oss-cluster-api). Default: 'false'
524    #[serde(skip_serializing_if = "Option::is_none")]
525    pub support_oss_cluster_api: Option<bool>,
526
527    /// Optional. If specified, redisVersion defines the Redis database version. If omitted, the Redis version will be set to the default version.  (available in 'GET /fixed/redis-versions')
528    #[serde(skip_serializing_if = "Option::is_none")]
529    pub redis_version: Option<String>,
530
531    /// Optional. Redis Serialization Protocol version. Must be compatible with Redis version.
532    #[serde(skip_serializing_if = "Option::is_none")]
533    pub resp_version: Option<String>,
534
535    /// (Pay-as-you-go subscriptions only) 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'
536    #[serde(skip_serializing_if = "Option::is_none")]
537    pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
538
539    /// (Pay-as-you-go subscriptions only) Optional. Distributes database data to different cloud instances. Default: 'false'
540    #[serde(skip_serializing_if = "Option::is_none")]
541    pub enable_database_clustering: Option<bool>,
542
543    /// (Pay-as-you-go subscriptions only) Optional. Specifies the number of master shards.
544    #[serde(skip_serializing_if = "Option::is_none")]
545    pub number_of_shards: Option<i32>,
546
547    /// Optional. Type and rate of data persistence in persistent storage. Use GET /fixed/plans/{planId} to see if your plan supports data persistence.
548    #[serde(skip_serializing_if = "Option::is_none")]
549    pub data_persistence: Option<String>,
550
551    /// Optional. Data eviction policy.
552    #[serde(skip_serializing_if = "Option::is_none")]
553    pub data_eviction_policy: Option<String>,
554
555    /// Optional. Sets database replication. Use GET /fixed/plans/{planId} to see if your plan supports database replication.
556    #[serde(skip_serializing_if = "Option::is_none")]
557    pub replication: Option<bool>,
558
559    /// 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. Use GET /fixed/plans/{planId} to see if your plan supports database backups.
560    #[serde(skip_serializing_if = "Option::is_none")]
561    pub periodic_backup_path: Option<String>,
562
563    /// 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. Use GET /fixed/plans/{planId} to see how many CIDR allow rules your plan supports. Example: '['192.168.10.0/32', '192.168.12.0/24']'
564    #[serde(skip_serializing_if = "Option::is_none")]
565    pub source_ips: Option<Vec<String>>,
566
567    /// (Pay-as-you-go subscriptions only) Optional. Hashing policy Regex rules. Used only if 'enableDatabaseClustering' is set to 'true' and .
568    #[serde(skip_serializing_if = "Option::is_none")]
569    pub regex_rules: Option<Vec<String>>,
570
571    /// 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>'].
572    #[serde(skip_serializing_if = "Option::is_none")]
573    pub replica_of: Option<Vec<String>>,
574
575    #[serde(skip_serializing_if = "Option::is_none")]
576    pub replica: Option<ReplicaOfSpec>,
577
578    /// 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'
579    #[serde(skip_serializing_if = "Option::is_none")]
580    pub client_ssl_certificate: Option<String>,
581
582    /// Optional. A list of client TLS/SSL certificates. If specified, mTLS authentication will be required to authenticate user connections.
583    #[serde(skip_serializing_if = "Option::is_none")]
584    pub client_tls_certificates: Option<Vec<DatabaseCertificateSpec>>,
585
586    /// Optional. When 'true', requires TLS authentication for all connections - mTLS with valid clientTlsCertificates, regular TLS when clientTlsCertificates is not provided. Default: 'false'
587    #[serde(skip_serializing_if = "Option::is_none")]
588    pub enable_tls: Option<bool>,
589
590    /// Optional. Password to access the database. If not set, a random 32-character alphanumeric password will be automatically generated.
591    #[serde(skip_serializing_if = "Option::is_none")]
592    pub password: Option<String>,
593
594    /// Optional. Redis database alert details.
595    #[serde(skip_serializing_if = "Option::is_none")]
596    pub alerts: Option<Vec<DatabaseAlertSpec>>,
597
598    /// 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. Can only be set if 'protocol' is 'redis'.
599    #[serde(skip_serializing_if = "Option::is_none")]
600    pub modules: Option<Vec<DatabaseModuleSpec>>,
601
602    #[serde(skip_serializing_if = "Option::is_none")]
603    pub command_type: Option<String>,
604}
605
606/// Essentials database update request
607#[derive(Debug, Clone, Serialize, Deserialize)]
608#[serde(rename_all = "camelCase")]
609pub struct FixedDatabaseUpdateRequest {
610    #[serde(skip_serializing_if = "Option::is_none")]
611    pub subscription_id: Option<i32>,
612
613    #[serde(skip_serializing_if = "Option::is_none")]
614    pub database_id: Option<i32>,
615
616    /// Optional. Updated database name.
617    #[serde(skip_serializing_if = "Option::is_none")]
618    pub name: Option<String>,
619
620    /// (Pay-as-you-go subscriptions only) Optional. Total memory in GB, including replication and other overhead. You cannot set both datasetSizeInGb and totalMemoryInGb.
621    #[serde(skip_serializing_if = "Option::is_none")]
622    pub memory_limit_in_gb: Option<f64>,
623
624    /// (Pay-as-you-go subscriptions only) 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.
625    #[serde(skip_serializing_if = "Option::is_none")]
626    pub dataset_size_in_gb: Option<f64>,
627
628    /// (Pay-as-you-go subscriptions only) Optional. Support Redis [OSS Cluster API](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#oss-cluster-api).
629    #[serde(skip_serializing_if = "Option::is_none")]
630    pub support_oss_cluster_api: Option<bool>,
631
632    /// Optional. Redis Serialization Protocol version. Must be compatible with Redis version.
633    #[serde(skip_serializing_if = "Option::is_none")]
634    pub resp_version: Option<String>,
635
636    /// (Pay-as-you-go subscriptions only) 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'
637    #[serde(skip_serializing_if = "Option::is_none")]
638    pub use_external_endpoint_for_oss_cluster_api: Option<bool>,
639
640    /// (Pay-as-you-go subscriptions only) Optional. Distributes database data to different cloud instances.
641    #[serde(skip_serializing_if = "Option::is_none")]
642    pub enable_database_clustering: Option<bool>,
643
644    /// (Pay-as-you-go subscriptions only) Optional. Changes the number of master shards.
645    #[serde(skip_serializing_if = "Option::is_none")]
646    pub number_of_shards: Option<i32>,
647
648    /// Optional. Type and rate of data persistence in persistent storage. Use GET /fixed/plans/{planId} to see if your plan supports data persistence.
649    #[serde(skip_serializing_if = "Option::is_none")]
650    pub data_persistence: Option<String>,
651
652    /// Optional. Turns database replication on or off.
653    #[serde(skip_serializing_if = "Option::is_none")]
654    pub data_eviction_policy: Option<String>,
655
656    /// Optional. Sets database replication. Use GET /fixed/plans/{planId} to see if your plan supports database replication.
657    #[serde(skip_serializing_if = "Option::is_none")]
658    pub replication: Option<bool>,
659
660    /// 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. Use GET /fixed/plans/{planId} to see if your plan supports database backups. If set to an empty string, the backup path will be removed.
661    #[serde(skip_serializing_if = "Option::is_none")]
662    pub periodic_backup_path: Option<String>,
663
664    /// 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']'
665    #[serde(skip_serializing_if = "Option::is_none")]
666    pub source_ips: Option<Vec<String>>,
667
668    /// Optional. This database will be a replica of the specified Redis databases provided as one or more URI (sample format: 'redis://user:password@host:port)'. If the URI provided is Redis Cloud instance, only host and port should be provided (using the format: ['<redis://endpoint1:6379>', '<redis://endpoint2:6380>'] ).
669    #[serde(skip_serializing_if = "Option::is_none")]
670    pub replica_of: Option<Vec<String>>,
671
672    #[serde(skip_serializing_if = "Option::is_none")]
673    pub replica: Option<ReplicaOfSpec>,
674
675    /// (Pay-as-you-go subscriptions only) Optional. Hashing policy Regex rules. Used only if 'shardingType' is 'custom-regex-rules'.
676    #[serde(skip_serializing_if = "Option::is_none")]
677    pub regex_rules: Option<Vec<String>>,
678
679    /// 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'.
680    #[serde(skip_serializing_if = "Option::is_none")]
681    pub client_ssl_certificate: Option<String>,
682
683    /// 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'.
684    #[serde(skip_serializing_if = "Option::is_none")]
685    pub client_tls_certificates: Option<Vec<DatabaseCertificateSpec>>,
686
687    /// 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.
688    #[serde(skip_serializing_if = "Option::is_none")]
689    pub enable_tls: Option<bool>,
690
691    /// Optional. Changes the password used to access the database with the 'default' user.
692    #[serde(skip_serializing_if = "Option::is_none")]
693    pub password: Option<String>,
694
695    /// Optional. When 'true', allows connecting to the database with the 'default' user. When 'false', only defined access control users can connect to the database.
696    #[serde(skip_serializing_if = "Option::is_none")]
697    pub enable_default_user: Option<bool>,
698
699    /// Optional. Changes Redis database alert details.
700    #[serde(skip_serializing_if = "Option::is_none")]
701    pub alerts: Option<Vec<DatabaseAlertSpec>>,
702
703    #[serde(skip_serializing_if = "Option::is_none")]
704    pub command_type: Option<String>,
705}
706
707// ============================================================================
708// Handler
709// ============================================================================
710
711/// Handler for Essentials database operations
712///
713/// Manages fixed-capacity databases with simplified configuration
714/// and predictable pricing for Redis Cloud Essentials subscriptions.
715pub struct FixedDatabaseHandler {
716    client: CloudClient,
717}
718
719impl FixedDatabaseHandler {
720    /// Create a new handler
721    #[must_use]
722    pub fn new(client: CloudClient) -> Self {
723        Self { client }
724    }
725
726    /// Get all databases in an Essentials subscription
727    /// Gets a list of all databases in the specified Essentials subscription.
728    ///
729    /// GET /fixed/subscriptions/{subscriptionId}/databases
730    pub async fn list(
731        &self,
732        subscription_id: i32,
733        offset: Option<i32>,
734        limit: Option<i32>,
735    ) -> Result<AccountFixedSubscriptionDatabases> {
736        let mut query = Vec::new();
737        if let Some(v) = offset {
738            query.push(format!("offset={v}"));
739        }
740        if let Some(v) = limit {
741            query.push(format!("limit={v}"));
742        }
743        let query_string = if query.is_empty() {
744            String::new()
745        } else {
746            format!("?{}", query.join("&"))
747        };
748        self.client
749            .get(&format!(
750                "/fixed/subscriptions/{subscription_id}/databases{query_string}"
751            ))
752            .await
753    }
754
755    /// Create Essentials database
756    /// Creates a new database in the specified Essentials subscription.
757    ///
758    /// POST /fixed/subscriptions/{subscriptionId}/databases
759    pub async fn create(
760        &self,
761        subscription_id: i32,
762        request: &FixedDatabaseCreateRequest,
763    ) -> Result<TaskStateUpdate> {
764        self.client
765            .post(
766                &format!("/fixed/subscriptions/{subscription_id}/databases"),
767                request,
768            )
769            .await
770    }
771
772    /// Delete Essentials database
773    /// Deletes a database from an Essentials subscription.
774    ///
775    /// DELETE /fixed/subscriptions/{subscriptionId}/databases/{databaseId}
776    pub async fn delete_by_id(
777        &self,
778        subscription_id: i32,
779        database_id: i32,
780    ) -> Result<TaskStateUpdate> {
781        let response = self
782            .client
783            .delete_raw(&format!(
784                "/fixed/subscriptions/{subscription_id}/databases/{database_id}"
785            ))
786            .await?;
787        serde_json::from_value(response).map_err(Into::into)
788    }
789
790    /// Get a single Essentials database
791    /// Gets details and settings of a single database in an Essentials subscription.
792    ///
793    /// GET /fixed/subscriptions/{subscriptionId}/databases/{databaseId}
794    pub async fn get_by_id(&self, subscription_id: i32, database_id: i32) -> Result<FixedDatabase> {
795        self.client
796            .get(&format!(
797                "/fixed/subscriptions/{subscription_id}/databases/{database_id}"
798            ))
799            .await
800    }
801
802    /// Update Essentials database
803    /// Updates the specified Essentials database.
804    ///
805    /// PUT /fixed/subscriptions/{subscriptionId}/databases/{databaseId}
806    pub async fn update(
807        &self,
808        subscription_id: i32,
809        database_id: i32,
810        request: &FixedDatabaseUpdateRequest,
811    ) -> Result<TaskStateUpdate> {
812        self.client
813            .put(
814                &format!("/fixed/subscriptions/{subscription_id}/databases/{database_id}"),
815                request,
816            )
817            .await
818    }
819
820    /// Backup Essentials database status
821    /// Information on the latest database backup status identified by Essentials subscription Id and Essentials database Id
822    ///
823    /// GET /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/backup
824    pub async fn get_backup_status(
825        &self,
826        subscription_id: i32,
827        database_id: i32,
828    ) -> Result<TaskStateUpdate> {
829        self.client
830            .get(&format!(
831                "/fixed/subscriptions/{subscription_id}/databases/{database_id}/backup"
832            ))
833            .await
834    }
835
836    /// Back up Essentials database
837    /// Manually back up the specified Essentials database to a backup path. By default, backups will be stored in the 'periodicBackupPath' location for this database.
838    ///
839    /// POST /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/backup
840    pub async fn backup(
841        &self,
842        subscription_id: i32,
843        database_id: i32,
844        request: &FixedDatabaseBackupRequest,
845    ) -> Result<TaskStateUpdate> {
846        self.client
847            .post(
848                &format!("/fixed/subscriptions/{subscription_id}/databases/{database_id}/backup"),
849                request,
850            )
851            .await
852    }
853
854    /// Get Essentials database import status
855    /// Gets information on the latest import attempt for this Essentials database.
856    ///
857    /// GET /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/import
858    pub async fn get_import_status(
859        &self,
860        subscription_id: i32,
861        database_id: i32,
862    ) -> Result<TaskStateUpdate> {
863        self.client
864            .get(&format!(
865                "/fixed/subscriptions/{subscription_id}/databases/{database_id}/import"
866            ))
867            .await
868    }
869
870    /// Import data to an Essentials database
871    /// Imports data from an RDB file or from a different Redis database into this Essentials database. WARNING: Importing data into a database removes all existing data from the database.
872    ///
873    /// POST /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/import
874    pub async fn import(
875        &self,
876        subscription_id: i32,
877        database_id: i32,
878        request: &FixedDatabaseImportRequest,
879    ) -> Result<TaskStateUpdate> {
880        self.client
881            .post(
882                &format!("/fixed/subscriptions/{subscription_id}/databases/{database_id}/import"),
883                request,
884            )
885            .await
886    }
887
888    /// Get Essentials database slow-log by database id
889    /// Get slow-log for a specific database identified by Essentials subscription Id and database Id
890    ///
891    /// GET /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/slow-log
892    pub async fn get_slow_log(
893        &self,
894        subscription_id: i32,
895        database_id: i32,
896    ) -> Result<DatabaseSlowLogEntries> {
897        self.client
898            .get(&format!(
899                "/fixed/subscriptions/{subscription_id}/databases/{database_id}/slow-log"
900            ))
901            .await
902    }
903
904    /// Get database tags
905    /// Gets a list of all database tags.
906    ///
907    /// GET /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/tags
908    pub async fn get_tags(&self, subscription_id: i32, database_id: i32) -> Result<CloudTags> {
909        self.client
910            .get(&format!(
911                "/fixed/subscriptions/{subscription_id}/databases/{database_id}/tags"
912            ))
913            .await
914    }
915
916    /// Add a database tag
917    /// Adds a single database tag to a database.
918    ///
919    /// POST /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/tags
920    pub async fn create_tag(
921        &self,
922        subscription_id: i32,
923        database_id: i32,
924        request: &DatabaseTagCreateRequest,
925    ) -> Result<CloudTag> {
926        self.client
927            .post(
928                &format!("/fixed/subscriptions/{subscription_id}/databases/{database_id}/tags"),
929                request,
930            )
931            .await
932    }
933
934    /// Overwrite database tags
935    /// Overwrites all tags on the database.
936    ///
937    /// PUT /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/tags
938    pub async fn update_tags(
939        &self,
940        subscription_id: i32,
941        database_id: i32,
942        request: &DatabaseTagsUpdateRequest,
943    ) -> Result<CloudTags> {
944        self.client
945            .put(
946                &format!("/fixed/subscriptions/{subscription_id}/databases/{database_id}/tags"),
947                request,
948            )
949            .await
950    }
951
952    /// Delete database tag
953    /// Removes the specified tag from the database.
954    ///
955    /// DELETE /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/tags/{tagKey}
956    pub async fn delete_tag(
957        &self,
958        subscription_id: i32,
959        database_id: i32,
960        tag_key: String,
961    ) -> Result<HashMap<String, Value>> {
962        let response = self
963            .client
964            .delete_raw(&format!(
965                "/fixed/subscriptions/{subscription_id}/databases/{database_id}/tags/{tag_key}"
966            ))
967            .await?;
968        serde_json::from_value(response).map_err(Into::into)
969    }
970
971    /// Update database tag value
972    /// Updates the value of the specified database tag.
973    ///
974    /// PUT /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/tags/{tagKey}
975    pub async fn update_tag(
976        &self,
977        subscription_id: i32,
978        database_id: i32,
979        tag_key: String,
980        request: &DatabaseTagUpdateRequest,
981    ) -> Result<CloudTag> {
982        self.client
983            .put(
984                &format!(
985                    "/fixed/subscriptions/{subscription_id}/databases/{database_id}/tags/{tag_key}"
986                ),
987                request,
988            )
989            .await
990    }
991
992    // ========================================================================
993    // Additional endpoints
994    // ========================================================================
995
996    /// Get available target Redis versions for upgrade
997    /// Gets a list of Redis versions that the Essentials database can be upgraded to.
998    ///
999    /// GET /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/available-target-versions
1000    pub async fn get_available_target_versions(
1001        &self,
1002        subscription_id: i32,
1003        database_id: i32,
1004    ) -> Result<Value> {
1005        self.client
1006            .get_raw(&format!(
1007                "/fixed/subscriptions/{subscription_id}/databases/{database_id}/available-target-versions"
1008            ))
1009            .await
1010    }
1011
1012    /// Get Essentials database version upgrade status
1013    /// Gets information on the latest upgrade attempt for this Essentials database.
1014    ///
1015    /// GET /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/upgrade
1016    pub async fn get_upgrade_status(
1017        &self,
1018        subscription_id: i32,
1019        database_id: i32,
1020    ) -> Result<Value> {
1021        self.client
1022            .get_raw(&format!(
1023                "/fixed/subscriptions/{subscription_id}/databases/{database_id}/upgrade"
1024            ))
1025            .await
1026    }
1027
1028    /// Upgrade Essentials database Redis version
1029    /// Upgrades the specified Essentials database to a later Redis version.
1030    ///
1031    /// POST /fixed/subscriptions/{subscriptionId}/databases/{databaseId}/upgrade
1032    pub async fn upgrade_redis_version(
1033        &self,
1034        subscription_id: i32,
1035        database_id: i32,
1036        target_version: &str,
1037    ) -> Result<Value> {
1038        let request = serde_json::json!({
1039            "targetVersion": target_version
1040        });
1041        self.client
1042            .post_raw(
1043                &format!("/fixed/subscriptions/{subscription_id}/databases/{database_id}/upgrade"),
1044                request,
1045            )
1046            .await
1047    }
1048}