mithril_common/entities/
file_uri.rsuse std::collections::{HashMap, HashSet};
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use crate::StdResult;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct FileUri(pub String);
impl From<FileUri> for String {
fn from(file_uri: FileUri) -> Self {
file_uri.0
}
}
pub type TemplateVariable = String;
pub type TemplateValue = String;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct TemplateUri(pub String);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub enum MultiFilesUri {
Template(TemplateUri),
}
impl MultiFilesUri {
pub fn extract_template_from_uris(
file_uris: Vec<String>,
extractor: impl Fn(&str) -> StdResult<Option<String>>,
) -> StdResult<Option<TemplateUri>> {
let mut templates = HashSet::new();
for file_uri in file_uris {
let template_uri = extractor(&file_uri)?;
template_uri.map(|template| templates.insert(template));
}
if templates.len() > 1 {
return Err(anyhow!("Multiple templates found in the file URIs"));
}
Ok(templates.into_iter().next().map(TemplateUri))
}
pub fn expand_to_file_uris(
&self,
variables: Vec<HashMap<TemplateVariable, TemplateValue>>,
) -> StdResult<Vec<FileUri>> {
match self {
MultiFilesUri::Template(template) => Ok(variables
.into_iter()
.map(|variable| {
let mut file_uri = template.0.clone();
for (key, value) in variable {
file_uri = file_uri.replace(&format!("{{{}}}", key), &value);
}
FileUri(file_uri)
})
.collect()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_template() {
let file_uris = vec![
"http://whatever/00001.tar.gz".to_string(),
"http://whatever/00002.tar.gz".to_string(),
];
fn extractor_returning_same_uri(_file_uri: &str) -> StdResult<Option<String>> {
Ok(Some(
"http://whatever/{immutable_file_number}.tar.gz".to_string(),
))
}
let template =
MultiFilesUri::extract_template_from_uris(file_uris, extractor_returning_same_uri)
.unwrap();
assert_eq!(
template,
Some(TemplateUri(
"http://whatever/{immutable_file_number}.tar.gz".to_string()
))
);
}
#[test]
fn returns_error_with_multiple_templates() {
let file_uris = vec![
"http://whatever/00001.tar.gz".to_string(),
"http://00002.tar.gz/whatever".to_string(),
];
fn extractor_returning_different_uri(file_uri: &str) -> StdResult<Option<String>> {
Ok(Some(file_uri.to_string()))
}
MultiFilesUri::extract_template_from_uris(file_uris, extractor_returning_different_uri)
.expect_err(
"Should return an error when multiple templates are found in the file URIs",
);
}
#[test]
fn expand_multi_file_template_to_multiple_file_uris() {
let template = MultiFilesUri::Template(TemplateUri(
"http://whatever/{var1}-{var2}.tar.gz".to_string(),
));
let variables = vec![
HashMap::from([
("var1".to_string(), "00001".to_string()),
("var2".to_string(), "abc".to_string()),
]),
HashMap::from([
("var1".to_string(), "00001".to_string()),
("var2".to_string(), "def".to_string()),
]),
HashMap::from([
("var1".to_string(), "00002".to_string()),
("var2".to_string(), "def".to_string()),
]),
];
let expanded_file_uris = template.expand_to_file_uris(variables).unwrap();
assert_eq!(
vec![
FileUri("http://whatever/00001-abc.tar.gz".to_string()),
FileUri("http://whatever/00001-def.tar.gz".to_string()),
FileUri("http://whatever/00002-def.tar.gz".to_string()),
],
expanded_file_uris,
);
}
}