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