use std::collections::HashMap;
use std::sync::Arc;
use crate::err::TemplateSubstitutionError;
use crate::tree::ast::clause::TemplatedTablePath;
use crate::tree::ast::dataset_identifier::DatasetIdentifier;
use crate::tree::ast::identifier::SimpleIdentifier;
use super::{
cartesian_template_values, materialize_templated_table_path, ordered_params_in_templated_path,
MAX_TABLE_PATH_EXPANSIONS,
};
pub fn expand_templated_table_path<F>(
path: &TemplatedTablePath,
lookup_domain: F,
) -> Result<Vec<DatasetIdentifier>, TemplateSubstitutionError>
where
F: Fn(&SimpleIdentifier) -> Result<Arc<[String]>, TemplateSubstitutionError>,
{
let param_order = ordered_params_in_templated_path(path)?;
let mut domain_lists: Vec<Arc<[String]>> = Vec::with_capacity(param_order.len());
for p in ¶m_order {
let domain = lookup_domain(p)?;
if domain.is_empty() {
return Err(TemplateSubstitutionError::EmptyIdentifierFragmentDomain(
p.to_string(),
));
}
domain_lists.push(domain);
}
let mut product: usize = 1;
for d in &domain_lists {
product = product.saturating_mul(d.len());
if product > MAX_TABLE_PATH_EXPANSIONS {
return Err(TemplateSubstitutionError::TooManyExpansions(
MAX_TABLE_PATH_EXPANSIONS,
));
}
}
let combos = cartesian_template_values(&domain_lists);
let mut out = Vec::with_capacity(combos.len());
for combo in combos {
let mut subst_map: HashMap<SimpleIdentifier, String> = HashMap::new();
for (p, v) in param_order.iter().zip(combo.iter()) {
subst_map.insert(p.clone(), v.clone());
}
out.push(materialize_templated_table_path(path, &subst_map)?);
}
Ok(out)
}