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