iceberg/io/storage/config/
mod.rs1mod azdls;
34mod gcs;
35mod hdfs_native;
36mod hf;
37mod oss;
38mod s3;
39
40use std::collections::HashMap;
41
42pub use azdls::*;
43pub use gcs::*;
44pub use hdfs_native::*;
45pub use hf::*;
46pub use oss::*;
47pub use s3::*;
48use serde::{Deserialize, Serialize};
49
50#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
56pub struct StorageConfig {
57 props: HashMap<String, String>,
59}
60
61impl StorageConfig {
62 pub fn new() -> Self {
64 Self {
65 props: HashMap::new(),
66 }
67 }
68
69 pub fn from_props(props: HashMap<String, String>) -> Self {
75 Self { props }
76 }
77
78 pub fn props(&self) -> &HashMap<String, String> {
80 &self.props
81 }
82
83 pub fn get(&self, key: &str) -> Option<&String> {
93 self.props.get(key)
94 }
95
96 pub fn with_prop(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
105 self.props.insert(key.into(), value.into());
106 self
107 }
108
109 pub fn with_props(
117 mut self,
118 props: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
119 ) -> Self {
120 self.props
121 .extend(props.into_iter().map(|(k, v)| (k.into(), v.into())));
122 self
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_storage_config_new() {
132 let config = StorageConfig::new();
133
134 assert!(config.props().is_empty());
135 }
136
137 #[test]
138 fn test_storage_config_from_props() {
139 let props = HashMap::from([
140 ("region".to_string(), "us-east-1".to_string()),
141 ("bucket".to_string(), "my-bucket".to_string()),
142 ]);
143 let config = StorageConfig::from_props(props.clone());
144
145 assert_eq!(config.props(), &props);
146 }
147
148 #[test]
149 fn test_storage_config_default() {
150 let config = StorageConfig::default();
151
152 assert!(config.props().is_empty());
153 }
154
155 #[test]
156 fn test_storage_config_get() {
157 let config = StorageConfig::new().with_prop("region", "us-east-1");
158
159 assert_eq!(config.get("region"), Some(&"us-east-1".to_string()));
160 assert_eq!(config.get("nonexistent"), None);
161 }
162
163 #[test]
164 fn test_storage_config_with_prop() {
165 let config = StorageConfig::new()
166 .with_prop("region", "us-east-1")
167 .with_prop("bucket", "my-bucket");
168
169 assert_eq!(config.get("region"), Some(&"us-east-1".to_string()));
170 assert_eq!(config.get("bucket"), Some(&"my-bucket".to_string()));
171 }
172
173 #[test]
174 fn test_storage_config_with_props() {
175 let additional_props = vec![("key1", "value1"), ("key2", "value2")];
176 let config = StorageConfig::new().with_props(additional_props);
177
178 assert_eq!(config.get("key1"), Some(&"value1".to_string()));
179 assert_eq!(config.get("key2"), Some(&"value2".to_string()));
180 }
181
182 #[test]
183 fn test_storage_config_clone() {
184 let config = StorageConfig::new().with_prop("region", "us-east-1");
185 let cloned = config.clone();
186
187 assert_eq!(config, cloned);
188 assert_eq!(cloned.get("region"), Some(&"us-east-1".to_string()));
189 }
190
191 #[test]
192 fn test_storage_config_serialization_roundtrip() {
193 let config = StorageConfig::new()
194 .with_prop("region", "us-east-1")
195 .with_prop("bucket", "my-bucket");
196
197 let serialized = serde_json::to_string(&config).unwrap();
198 let deserialized: StorageConfig = serde_json::from_str(&serialized).unwrap();
199
200 assert_eq!(config, deserialized);
201 }
202
203 #[test]
204 fn test_storage_config_clone_independence() {
205 let original = StorageConfig::new().with_prop("region", "us-east-1");
206 let mut cloned = original.clone();
207
208 cloned = cloned.with_prop("region", "eu-west-1");
210 cloned = cloned.with_prop("new_key", "new_value");
211
212 assert_eq!(original.get("region"), Some(&"us-east-1".to_string()));
214 assert_eq!(original.get("new_key"), None);
215
216 assert_eq!(cloned.get("region"), Some(&"eu-west-1".to_string()));
218 assert_eq!(cloned.get("new_key"), Some(&"new_value".to_string()));
219 }
220
221 #[test]
222 fn test_storage_config_from_props_empty() {
223 let config = StorageConfig::from_props(HashMap::new());
224
225 assert!(config.props().is_empty());
226 }
227
228 #[test]
229 fn test_storage_config_serialization_empty() {
230 let config = StorageConfig::new();
231
232 let serialized = serde_json::to_string(&config).unwrap();
233 let deserialized: StorageConfig = serde_json::from_str(&serialized).unwrap();
234
235 assert_eq!(config, deserialized);
236 assert!(deserialized.props().is_empty());
237 }
238}