use crate::content::node::NodeState;
use crate::content::property::PropertyValue;
use crate::index::{IndexResult, values_of};
pub const ENTRY_PROPERTY_NAME: &str = "entry";
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct UniqueEntry {
pub key: String,
pub paths: Vec<String>,
}
impl UniqueEntry {
#[must_use]
pub fn is_duplicate(&self) -> bool {
self.paths.len() > 1
}
}
pub struct UniqueIndex<'provider> {
entries_node: NodeState<'provider>,
}
impl<'provider> UniqueIndex<'provider> {
pub fn open(definition: &NodeState<'provider>, child_name: &str) -> IndexResult<Option<Self>> {
Ok(definition
.child_node(child_name)?
.map(|entries_node| Self { entries_node }))
}
pub fn entries(&self) -> IndexResult<Vec<UniqueEntry>> {
let mut entries = Vec::new();
for (key, key_node) in self.entries_node.child_node_entries()? {
let Some(property) = key_node.property(ENTRY_PROPERTY_NAME)? else {
continue;
};
entries.push(UniqueEntry {
key,
paths: values_of(&property)
.iter()
.filter_map(PropertyValue::as_text)
.collect(),
});
}
entries.sort();
Ok(entries)
}
pub fn paths_for_key(&self, key: &str) -> IndexResult<Vec<String>> {
let Some(key_node) = self.entries_node.child_node(key)? else {
return Ok(Vec::new());
};
let Some(property) = key_node.property(ENTRY_PROPERTY_NAME)? else {
return Ok(Vec::new());
};
Ok(values_of(&property)
.iter()
.filter_map(PropertyValue::as_text)
.collect())
}
pub fn approximate_counter_count(&self) -> IndexResult<usize> {
Ok(super::mirror::approximate_counters(&self.entries_node)?.len())
}
}