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