opendal_service_cloudflare_kv/
config.rs1use std::fmt::Debug;
19
20use opendal_core::raw::*;
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 opendal_core::Configurator for CloudflareKvConfig {
55 type Builder = CloudflareKvBuilder;
56
57 fn from_uri(uri: &opendal_core::OperatorUri) -> opendal_core::Result<Self> {
58 let account_id = uri.name().ok_or_else(|| {
59 opendal_core::Error::new(
60 opendal_core::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 opendal_core::Error::new(
68 opendal_core::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 opendal_core::Error::new(
77 opendal_core::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 && !rest.is_empty()
89 {
90 map.insert("root".to_string(), rest.to_string());
91 }
92
93 Self::from_iter(map)
94 }
95
96 fn into_builder(self) -> Self::Builder {
97 CloudflareKvBuilder { config: self }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use opendal_core::Configurator;
105 use opendal_core::OperatorUri;
106
107 #[test]
108 fn from_uri_extracts_ids_and_root() {
109 let uri = OperatorUri::new(
110 "cloudflare-kv://acc123/ns456/prefix/dir",
111 Vec::<(String, String)>::new(),
112 )
113 .unwrap();
114
115 let cfg = CloudflareKvConfig::from_uri(&uri).unwrap();
116 assert_eq!(cfg.account_id.as_deref(), Some("acc123"));
117 assert_eq!(cfg.namespace_id.as_deref(), Some("ns456"));
118 assert_eq!(cfg.root.as_deref(), Some("prefix/dir"));
119 }
120
121 #[test]
122 fn from_uri_requires_namespace() {
123 let uri =
124 OperatorUri::new("cloudflare-kv://acc123", Vec::<(String, String)>::new()).unwrap();
125
126 assert!(CloudflareKvConfig::from_uri(&uri).is_err());
127 }
128}