use std::path::{Path, PathBuf};
use ahash::HashSet;
use anyhow::{Result, bail};
use dashmap::DashMap;
use crate::catalog;
use crate::err::Error;
use crate::expr::Filter;
use crate::iam::file::check_is_path_allowed;
use crate::idx::ft::analyzer::mapper::Mapper;
#[derive(Default)]
pub(crate) struct Mappers(DashMap<String, Mapper>);
impl Mappers {
pub(crate) async fn load(
&self,
az: &catalog::AnalyzerDefinition,
allow_list: &[PathBuf],
) -> Result<()> {
if let Some(filters) = &az.filters {
for f in filters {
if let Filter::Mapper(path) = f {
self.insert(path, allow_list).await?;
}
}
}
Ok(())
}
pub(crate) async fn check(
&self,
az: &catalog::AnalyzerDefinition,
allow_list: &[PathBuf],
) -> Result<()> {
if let Some(filters) = &az.filters {
for f in filters {
if let Filter::Mapper(path) = f
&& !self.0.contains_key(path)
{
self.insert(path, allow_list).await?;
}
}
}
Ok(())
}
async fn insert(&self, path: &str, allow_list: &[PathBuf]) -> Result<()> {
let p = Path::new(path);
check_is_path_allowed(p, allow_list)?;
if !p.exists() || !p.is_file() {
bail!(Error::Internal(format!("Invalid mapper path: {p:?}")));
}
let mapper = Mapper::new(p, allow_list).await?;
self.0.insert(path.to_string(), mapper);
Ok(())
}
pub(in crate::idx) fn get(&self, path: &str) -> Result<Mapper> {
match self.0.get(path) {
None => {
Err(anyhow::Error::new(Error::Internal(format!("Mapper not found for {path}"))))
}
Some(e) => Ok(e.value().clone()),
}
}
pub(crate) fn cleanup(&self, azs: &[catalog::AnalyzerDefinition]) {
let mut keys: HashSet<String> = self.0.iter().map(|e| e.key().clone()).collect();
for az in azs {
if let Some(filters) = &az.filters {
for f in filters {
if let Filter::Mapper(path) = f {
keys.remove(path);
}
}
}
}
for key in keys {
self.0.remove(&key);
}
}
}