#![doc = include_str!("../README.md")] #![doc = "\n## Example\n\n```rust"] #![doc = include_str!("../examples/main.rs")] #![doc = "```"] use std::collections::BTreeMap; use brk_computer::Computer; use brk_core::Result; use brk_indexer::Indexer; use brk_vec::AnyCollectableVec; use tabled::settings::Style; mod format; mod index; mod maybe_ids; mod output; mod pagination; mod params; mod table; mod vecs; pub use format::Format; pub use index::Index; pub use output::{Output, Value}; pub use pagination::{PaginatedIndexParam, PaginationParam}; pub use params::{IdParam, Params, ParamsOpt}; pub use table::Tabled; use vecs::Vecs; use crate::vecs::{IdToVec, IndexToVec}; pub struct Interface<'a> { vecs: Vecs<'a>, _indexer: &'a Indexer, _computer: &'a Computer, } impl<'a> Interface<'a> { pub fn build(indexer: &'a Indexer, computer: &'a Computer) -> Self { Self { vecs: Vecs::build(indexer, computer), _indexer: indexer, _computer: computer, } } pub fn search(&self, params: &Params) -> Vec<(String, &&dyn AnyCollectableVec)> { let tuples = params .ids .iter() .flat_map(|s| { s.to_lowercase() .replace("-", "_") .split_whitespace() .flat_map(|s| { s.split(',') .flat_map(|s| s.split('+').map(|s| s.to_string())) }) .collect::>() }) .map(|mut id| { let mut res = self.vecs.id_to_index_to_vec.get(id.as_str()); if res.is_none() { if let Ok(index) = Index::try_from(id.as_str()) { id = index.possible_values().last().unwrap().to_string(); res = self.vecs.id_to_index_to_vec.get(id.as_str()) } } (id, res) }) .filter(|(_, opt)| opt.is_some()) .map(|(id, vec)| (id, vec.unwrap())) .collect::>(); tuples .iter() .flat_map(|(str, i_to_v)| i_to_v.get(¶ms.index).map(|vec| (str.to_owned(), vec))) .collect::>() } pub fn format( &self, vecs: Vec<(String, &&dyn AnyCollectableVec)>, params: &ParamsOpt, ) -> color_eyre::Result { let from = params.from(); let to = params.to(); let format = params.format(); let mut values = vecs .iter() .map(|(_, vec)| -> Result> { vec.collect_range_serde_json(from, to) }) .collect::>>()?; if values.is_empty() { return Ok(Output::default(format)); } let ids_last_i = vecs.len() - 1; Ok(match format { Some(Format::CSV) | Some(Format::TSV) => { let delimiter = if format == Some(Format::CSV) { ',' } else { '\t' }; let mut text = vecs .iter() .map(|(id, _)| id.to_owned()) .collect::>() .join(&delimiter.to_string()); text.push('\n'); let values_len = values.first().unwrap().len(); (0..values_len).for_each(|i| { let mut line = "".to_string(); values.iter().enumerate().for_each(|(id_i, v)| { line += &v.get(i).unwrap().to_string(); if id_i == ids_last_i { line.push('\n'); } else { line.push(delimiter); } }); text += &line; }); if format == Some(Format::CSV) { Output::CSV(text) } else { Output::TSV(text) } } Some(Format::MD) => { let mut table = values.to_table(vecs.iter().map(|(s, _)| s.to_owned()).collect::>()); table.with(Style::markdown()); Output::MD(table.to_string()) } Some(Format::JSON) | None => { if values.len() == 1 { let mut values = values.pop().unwrap(); if values.len() == 1 { let value = values.pop().unwrap(); Output::Json(Value::Single(value)) } else { Output::Json(Value::List(values)) } } else { Output::Json(Value::Matrix(values)) } } }) } pub fn search_and_format(&self, params: Params) -> color_eyre::Result { self.format(self.search(¶ms), ¶ms.rest) } pub fn id_to_index_to_vec(&self) -> &BTreeMap<&str, IndexToVec<'_>> { &self.vecs.id_to_index_to_vec } pub fn index_to_id_to_vec(&self) -> &BTreeMap> { &self.vecs.index_to_id_to_vec } pub fn get_vecid_count(&self) -> usize { self.vecs.id_count } pub fn get_index_count(&self) -> usize { self.vecs.index_count } pub fn get_vec_count(&self) -> usize { self.vecs.vec_count } pub fn get_indexes(&self) -> &[&'static str] { &self.vecs.indexes } pub fn get_accepted_indexes(&self) -> &BTreeMap<&'static str, &'static [&'static str]> { &self.vecs.accepted_indexes } pub fn get_vecids(&self, pagination: PaginationParam) -> &[&str] { self.vecs.ids(pagination) } pub fn get_index_to_vecids(&self, paginated_index: PaginatedIndexParam) -> Vec<&str> { self.vecs.index_to_ids(paginated_index) } pub fn get_vecid_to_indexes(&self, id: String) -> Option<&Vec<&'static str>> { self.vecs.id_to_indexes(id) } }