use std::collections::HashMap;
use std::fmt::Display;
use std::str::FromStr;
use strum_macros::EnumIter;
use crate::config::error::ConfigError::{NotFound, ParseBool, ParseInt};
use crate::config::Result;
use crate::config::{ConfigParser, HudiConfigValue};
#[derive(Clone, Debug, PartialEq, Eq, Hash, EnumIter)]
pub enum HudiReadConfig {
FileGroupStartTimestamp,
FileGroupEndTimestamp,
InputPartitions,
ListingParallelism,
UseReadOptimizedMode,
}
impl AsRef<str> for HudiReadConfig {
fn as_ref(&self) -> &str {
match self {
Self::FileGroupStartTimestamp => "hoodie.read.file_group.start_timestamp",
Self::FileGroupEndTimestamp => "hoodie.read.file_group.end_timestamp",
Self::InputPartitions => "hoodie.read.input.partitions",
Self::ListingParallelism => "hoodie.read.listing.parallelism",
Self::UseReadOptimizedMode => "hoodie.read.use.read_optimized.mode",
}
}
}
impl Display for HudiReadConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_ref())
}
}
impl ConfigParser for HudiReadConfig {
type Output = HudiConfigValue;
fn default_value(&self) -> Option<HudiConfigValue> {
match self {
HudiReadConfig::InputPartitions => Some(HudiConfigValue::UInteger(0usize)),
HudiReadConfig::ListingParallelism => Some(HudiConfigValue::UInteger(10usize)),
HudiReadConfig::UseReadOptimizedMode => Some(HudiConfigValue::Boolean(false)),
_ => None,
}
}
fn parse_value(&self, configs: &HashMap<String, String>) -> Result<Self::Output> {
let get_result = configs
.get(self.as_ref())
.map(|v| v.as_str())
.ok_or(NotFound(self.key()));
match self {
Self::FileGroupStartTimestamp => {
get_result.map(|v| HudiConfigValue::String(v.to_string()))
}
Self::FileGroupEndTimestamp => {
get_result.map(|v| HudiConfigValue::String(v.to_string()))
}
Self::InputPartitions => get_result
.and_then(|v| {
usize::from_str(v).map_err(|e| ParseInt(self.key(), v.to_string(), e))
})
.map(HudiConfigValue::UInteger),
Self::ListingParallelism => get_result
.and_then(|v| {
usize::from_str(v).map_err(|e| ParseInt(self.key(), v.to_string(), e))
})
.map(HudiConfigValue::UInteger),
Self::UseReadOptimizedMode => get_result
.and_then(|v| {
bool::from_str(v).map_err(|e| ParseBool(self.key(), v.to_string(), e))
})
.map(HudiConfigValue::Boolean),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::read::HudiReadConfig::{
InputPartitions, ListingParallelism, UseReadOptimizedMode,
};
#[test]
fn parse_valid_config_value() {
let options = HashMap::from([
(InputPartitions.as_ref().to_string(), "100".to_string()),
(ListingParallelism.as_ref().to_string(), "100".to_string()),
(
UseReadOptimizedMode.as_ref().to_string(),
"true".to_string(),
),
]);
assert_eq!(
InputPartitions.parse_value(&options).unwrap().to::<usize>(),
100
);
assert_eq!(
ListingParallelism
.parse_value(&options)
.unwrap()
.to::<usize>(),
100
);
assert!(UseReadOptimizedMode
.parse_value(&options)
.unwrap()
.to::<bool>());
}
#[test]
fn parse_invalid_config_value() {
let options = HashMap::from([
(InputPartitions.as_ref().to_string(), "foo".to_string()),
(ListingParallelism.as_ref().to_string(), "_100".to_string()),
(UseReadOptimizedMode.as_ref().to_string(), "1".to_string()),
]);
assert!(matches!(
InputPartitions.parse_value(&options).unwrap_err(),
ParseInt(_, _, _)
));
assert_eq!(
InputPartitions
.parse_value_or_default(&options)
.to::<usize>(),
0
);
assert!(matches!(
ListingParallelism.parse_value(&options).unwrap_err(),
ParseInt(_, _, _)
));
assert_eq!(
ListingParallelism
.parse_value_or_default(&options)
.to::<usize>(),
10
);
assert!(matches!(
UseReadOptimizedMode.parse_value(&options).unwrap_err(),
ParseBool(_, _, _)
));
assert!(!UseReadOptimizedMode
.parse_value_or_default(&options)
.to::<bool>())
}
}