use std::collections::{BTreeMap, BTreeSet};
use brk_query::Vecs;
use brk_types::{Index, SeriesLeafWithSchema};
use super::{GenericSyntax, IndexSetPattern, PatternField, StructuralPattern, extract_inner_type};
use crate::{PatternBaseResult, analysis};
#[derive(Debug)]
pub struct ClientMetadata {
pub catalog: brk_types::TreeNode,
pub structural_patterns: Vec<StructuralPattern>,
pub index_set_patterns: Vec<IndexSetPattern>,
pattern_lookup: BTreeMap<Vec<PatternField>, String>,
concrete_to_type_param: BTreeMap<Vec<PatternField>, String>,
node_bases: BTreeMap<String, PatternBaseResult>,
}
impl ClientMetadata {
pub fn from_vecs(vecs: &Vecs) -> Self {
Self::from_catalog(vecs.catalog().clone())
}
pub fn from_catalog(catalog: brk_types::TreeNode) -> Self {
let (structural_patterns, concrete_to_pattern, concrete_to_type_param, node_bases) =
analysis::detect_structural_patterns(&catalog);
let index_set_patterns = analysis::detect_index_patterns(&catalog);
let mut pattern_lookup = concrete_to_pattern;
for p in &structural_patterns {
pattern_lookup.insert(p.fields.clone(), p.name.clone());
}
ClientMetadata {
catalog,
structural_patterns,
index_set_patterns,
pattern_lookup,
concrete_to_type_param,
node_bases,
}
}
pub fn find_index_set_pattern(&self, indexes: &BTreeSet<Index>) -> Option<&IndexSetPattern> {
self.index_set_patterns
.iter()
.find(|p| &p.indexes == indexes)
}
pub fn find_pattern(&self, name: &str) -> Option<&StructuralPattern> {
self.structural_patterns.iter().find(|p| p.name == name)
}
pub fn is_parameterizable(&self, name: &str) -> bool {
self.find_pattern(name).is_some_and(|p| {
p.is_parameterizable()
&& p.fields.iter().all(|f| {
!f.is_branch()
|| self.find_pattern(&f.rust_type).is_none()
|| self.is_parameterizable(&f.rust_type)
})
})
}
pub fn find_pattern_by_fields(&self, fields: &[PatternField]) -> Option<&StructuralPattern> {
self.pattern_lookup
.get(fields)
.and_then(|name| self.find_pattern(name))
}
pub fn get_type_param(&self, fields: &[PatternField]) -> Option<&String> {
self.concrete_to_type_param.get(fields)
}
pub fn pattern_lookup(&self) -> &BTreeMap<Vec<PatternField>, String> {
&self.pattern_lookup
}
pub fn get_node_base(&self, path: &str) -> Option<&PatternBaseResult> {
self.node_bases.get(path)
}
pub fn field_type_annotation(
&self,
field: &PatternField,
is_generic: bool,
generic_value_type: Option<&str>,
syntax: GenericSyntax,
) -> String {
if let Some(pattern) = self.find_pattern(&field.rust_type) {
if pattern.is_generic {
let type_param = field
.type_param
.as_deref()
.or(generic_value_type)
.unwrap_or(if is_generic { "T" } else { syntax.default_type });
return syntax.wrap(&field.rust_type, type_param);
}
return field.rust_type.clone();
}
if field.is_branch() {
return field.rust_type.clone();
}
let value_type = if is_generic && field.rust_type == "T" {
"T".to_string()
} else {
extract_inner_type(&field.rust_type)
};
if let Some(accessor) = self.find_index_set_pattern(&field.indexes) {
syntax.wrap(&accessor.name, &value_type)
} else {
syntax.wrap("SeriesNode", &value_type)
}
}
pub fn field_type_annotation_from_leaf(
&self,
leaf: &SeriesLeafWithSchema,
syntax: GenericSyntax,
) -> String {
let value_type = leaf.kind().to_string();
if let Some(accessor) = self.find_index_set_pattern(leaf.indexes()) {
syntax.wrap(&accessor.name, &value_type)
} else {
syntax.wrap("SeriesNode", &value_type)
}
}
}