opendal/services/cloudflare_kv/
config.rs1use std::fmt::Debug;
19use std::time::Duration;
20
21use serde::Deserialize;
22use serde::Serialize;
23
24use super::CLOUDFLARE_KV_SCHEME;
25use super::backend::CloudflareKvBuilder;
26
27#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
29pub struct CloudflareKvConfig {
30 pub api_token: Option<String>,
32 pub account_id: Option<String>,
34 pub namespace_id: Option<String>,
36 pub default_ttl: Option<Duration>,
38
39 pub root: Option<String>,
41}
42
43impl Debug for CloudflareKvConfig {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 f.debug_struct("CloudflareKvConfig")
46 .field("account_id", &self.account_id)
47 .field("namespace_id", &self.namespace_id)
48 .field("default_ttl", &self.default_ttl)
49 .field("root", &self.root)
50 .finish_non_exhaustive()
51 }
52}
53
54impl crate::Configurator for CloudflareKvConfig {
55 type Builder = CloudflareKvBuilder;
56
57 fn from_uri(uri: &crate::types::OperatorUri) -> crate::Result<Self> {
58 let account_id = uri.name().ok_or_else(|| {
59 crate::Error::new(
60 crate::ErrorKind::ConfigInvalid,
61 "uri host must contain account id",
62 )
63 .with_context("service", CLOUDFLARE_KV_SCHEME)
64 })?;
65
66 let raw_root = uri.root().ok_or_else(|| {
67 crate::Error::new(
68 crate::ErrorKind::ConfigInvalid,
69 "uri path must contain namespace id",
70 )
71 .with_context("service", CLOUDFLARE_KV_SCHEME)
72 })?;
73
74 let mut segments = raw_root.splitn(2, '/');
75 let namespace_id = segments.next().filter(|s| !s.is_empty()).ok_or_else(|| {
76 crate::Error::new(
77 crate::ErrorKind::ConfigInvalid,
78 "namespace id is required in uri path",
79 )
80 .with_context("service", CLOUDFLARE_KV_SCHEME)
81 })?;
82
83 let mut map = uri.options().clone();
84 map.insert("account_id".to_string(), account_id.to_string());
85 map.insert("namespace_id".to_string(), namespace_id.to_string());
86
87 if let Some(rest) = segments.next() {
88 if !rest.is_empty() {
89 map.insert("root".to_string(), rest.to_string());
90 }
91 }
92
93 Self::from_iter(map)
94 }
95
96 #[allow(deprecated)]
97 fn into_builder(self) -> Self::Builder {
98 CloudflareKvBuilder {
99 config: self,
100 http_client: None,
101 }
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::Configurator;
109 use crate::types::OperatorUri;
110
111 #[test]
112 fn from_uri_extracts_ids_and_root() {
113 let uri = OperatorUri::new(
114 "cloudflare-kv://acc123/ns456/prefix/dir",
115 Vec::<(String, String)>::new(),
116 )
117 .unwrap();
118
119 let cfg = CloudflareKvConfig::from_uri(&uri).unwrap();
120 assert_eq!(cfg.account_id.as_deref(), Some("acc123"));
121 assert_eq!(cfg.namespace_id.as_deref(), Some("ns456"));
122 assert_eq!(cfg.root.as_deref(), Some("prefix/dir"));
123 }
124
125 #[test]
126 fn from_uri_requires_namespace() {
127 let uri =
128 OperatorUri::new("cloudflare-kv://acc123", Vec::<(String, String)>::new()).unwrap();
129
130 assert!(CloudflareKvConfig::from_uri(&uri).is_err());
131 }
132}