use crate::collection::Document;
use crate::common::{Value, TAG_MAP_METADATA};
use std::collections::HashSet;
pub trait Metadata {
fn get_info(&self) -> Document;
}
pub(crate) struct MapMeta {
pub(crate) map_names: HashSet<String>,
}
impl MapMeta {
pub fn new(metadata: &Document) -> Self {
let mut map_names = HashSet::new();
if let Ok(names) = metadata.get(TAG_MAP_METADATA) {
if let Some(names) = names.as_array() {
map_names.reserve(names.len());
for name in names {
if let Some(name_str) = name.as_string() {
map_names.insert(name_str.to_string());
} else {
log::warn!("Non-string value in map metadata, skipping: {:?}", name);
}
}
}
}
MapMeta { map_names }
}
}
impl Metadata for MapMeta {
fn get_info(&self) -> Document {
let mut doc = Document::new();
let mut names_vec = Vec::with_capacity(self.map_names.len());
for name in &self.map_names {
names_vec.push(Value::String(name.clone()));
}
let names = Value::Array(names_vec);
doc.put(TAG_MAP_METADATA, names).unwrap();
doc
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::collection::Document;
use crate::common::{Value, TAG_MAP_METADATA};
#[test]
fn test_map_meta_new_with_valid_metadata() {
let mut doc = Document::new();
let names = Value::Array(vec![
Value::String("map1".to_string()),
Value::String("map2".to_string()),
]);
doc.put(TAG_MAP_METADATA, names).unwrap();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.contains("map1"));
assert!(map_meta.map_names.contains("map2"));
}
#[test]
fn test_map_meta_new_with_empty_metadata() {
let doc = Document::new();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.is_empty());
}
#[test]
fn test_map_meta_new_with_invalid_metadata() {
let mut doc = Document::new();
let invalid_value = Value::String("invalid".to_string());
doc.put(TAG_MAP_METADATA, invalid_value).unwrap();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.is_empty());
}
#[test]
fn test_map_meta_get_info() {
let mut doc = Document::new();
let names = Value::Array(vec![
Value::String("map1".to_string()),
Value::String("map2".to_string()),
]);
doc.put(TAG_MAP_METADATA, names).unwrap();
let map_meta = MapMeta::new(&doc);
let info = map_meta.get_info();
let temp = info.get(TAG_MAP_METADATA).unwrap();
let retrieved_names = temp.as_array().unwrap();
assert_eq!(retrieved_names.len(), 2);
assert!(retrieved_names.contains(&Value::String("map1".to_string())));
assert!(retrieved_names.contains(&Value::String("map2".to_string())));
}
#[test]
fn test_map_meta_get_info_with_empty_map_names() {
let doc = Document::new();
let map_meta = MapMeta::new(&doc);
let info = map_meta.get_info();
let temp = info.get(TAG_MAP_METADATA).unwrap();
let retrieved_names = temp.as_array().unwrap();
assert!(retrieved_names.is_empty());
}
#[test]
fn test_map_meta_with_mixed_array_types() {
let mut doc = Document::new();
let mixed_array = Value::Array(vec![
Value::String("map1".to_string()),
Value::I32(42), Value::String("map2".to_string()),
Value::Null, ]);
doc.put(TAG_MAP_METADATA, mixed_array).unwrap();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.contains("map1"));
assert!(map_meta.map_names.contains("map2"));
assert_eq!(map_meta.map_names.len(), 2);
}
#[test]
fn test_map_meta_with_all_non_string_elements() {
let mut doc = Document::new();
let non_string_array = Value::Array(vec![
Value::I32(1),
Value::I32(2),
Value::Null,
]);
doc.put(TAG_MAP_METADATA, non_string_array).unwrap();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.is_empty());
}
#[test]
fn test_map_meta_with_single_non_string_element() {
let mut doc = Document::new();
let corrupted_array = Value::Array(vec![
Value::I32(999), ]);
doc.put(TAG_MAP_METADATA, corrupted_array).unwrap();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.is_empty());
}
#[test]
fn test_map_meta_preserves_valid_strings_with_corruption() {
let mut doc = Document::new();
let corrupted_array = Value::Array(vec![
Value::String("valid_map".to_string()),
Value::F64(3.14), Value::String("another_valid".to_string()),
Value::I32(100), ]);
doc.put(TAG_MAP_METADATA, corrupted_array).unwrap();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.contains("valid_map"));
assert!(map_meta.map_names.contains("another_valid"));
assert_eq!(map_meta.map_names.len(), 2);
}
#[test]
fn test_map_meta_reserve_efficiency() {
let mut doc = Document::new();
let names = Value::Array(vec![
Value::String("map1".to_string()),
Value::String("map2".to_string()),
Value::String("map3".to_string()),
Value::String("map4".to_string()),
Value::String("map5".to_string()),
]);
doc.put(TAG_MAP_METADATA, names).unwrap();
let map_meta = MapMeta::new(&doc);
assert_eq!(map_meta.map_names.len(), 5);
assert!(map_meta.map_names.capacity() >= 5);
}
#[test]
fn test_map_meta_get_info_pre_allocation() {
let mut doc = Document::new();
let names = Value::Array(vec![
Value::String("first".to_string()),
Value::String("second".to_string()),
Value::String("third".to_string()),
]);
doc.put(TAG_MAP_METADATA, names).unwrap();
let map_meta = MapMeta::new(&doc);
let info = map_meta.get_info();
let temp = info.get(TAG_MAP_METADATA).unwrap();
let retrieved_names = temp.as_array().unwrap();
assert_eq!(retrieved_names.len(), 3);
assert_eq!(retrieved_names.capacity(), 3);
}
#[test]
fn test_large_map_meta_efficiency() {
let mut doc = Document::new();
let mut names_vec = Vec::with_capacity(100);
for i in 0..100 {
names_vec.push(Value::String(format!("map_{}", i)));
}
let names = Value::Array(names_vec);
doc.put(TAG_MAP_METADATA, names).unwrap();
let map_meta = MapMeta::new(&doc);
assert_eq!(map_meta.map_names.len(), 100);
let info = map_meta.get_info();
let temp = info.get(TAG_MAP_METADATA).unwrap();
let retrieved = temp.as_array().unwrap();
assert_eq!(retrieved.len(), 100);
}
#[test]
fn test_map_meta_empty_array_efficiency() {
let mut doc = Document::new();
let empty_names = Value::Array(vec![]);
doc.put(TAG_MAP_METADATA, empty_names).unwrap();
let map_meta = MapMeta::new(&doc);
assert!(map_meta.map_names.is_empty());
let info = map_meta.get_info();
let temp = info.get(TAG_MAP_METADATA).unwrap();
let retrieved = temp.as_array().unwrap();
assert_eq!(retrieved.len(), 0);
assert_eq!(retrieved.capacity(), 0);
}
}