use crate::prelude::*;
use beet_core::prelude::*;
use beet_router::prelude::*;
#[derive(Debug, Clone)]
pub struct RouteFileMethodTree {
pub name: PathPatternSegment,
pub funcs: Vec<Entity>,
pub children: Vec<RouteFileMethodTree>,
}
impl RouteFileMethodTree {
pub fn new(segment: impl Into<PathPatternSegment>) -> Self {
Self {
name: segment.into(),
funcs: Vec::new(),
children: Vec::new(),
}
}
#[allow(dead_code)]
pub fn into_path_tree(&self) -> Tree<String> {
let children = self
.children
.iter()
.map(|child| child.into_path_tree())
.collect::<Vec<_>>();
Tree {
value: self.name.to_string(),
children,
}
}
pub fn all_children_are_leaf_nodes(&self) -> bool {
self.children.iter().all(|child| child.children.is_empty())
}
pub fn flatten(self) -> Vec<Entity> {
let mut out = Vec::new();
out.extend(self.funcs.into_iter());
for child in self.children.into_iter() {
out.extend(child.flatten());
}
out
}
pub fn from_methods(funcs: Vec<(Entity, &RouteFileMethod)>) -> Self {
let mut this = RouteFileMethodTree::new("routes");
for func in funcs {
let mut current = &mut this;
for component in func.1.path.components() {
match component {
std::path::Component::Normal(os_str)
if let Some(str) = os_str.to_str() =>
{
current = VecExt::entry_or_insert_with(
&mut current.children,
|child| child.name.as_str() == str,
|| RouteFileMethodTree::new(str),
);
}
_ => {}
}
}
current.funcs.push(func.0);
}
this
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use beet_core::prelude::*;
fn world() -> World {
let mut world = World::new();
world.spawn_batch(vec![
RouteFileMethod::new("/", HttpMethod::Get),
RouteFileMethod::new("/bazz", HttpMethod::Get),
RouteFileMethod::new("/foo/bar", HttpMethod::Get),
RouteFileMethod::new("/foo/bazz", HttpMethod::Get),
RouteFileMethod::new("/foo/bazz/boo", HttpMethod::Get),
RouteFileMethod::new("/foo/bazz/boo", HttpMethod::Post),
]);
world
}
#[test]
fn correct_tree_structure() {
let mut world = world();
let methods = world
.query_once::<(Entity, &RouteFileMethod)>()
.iter()
.copied()
.collect();
RouteFileMethodTree::from_methods(methods)
.into_path_tree()
.to_string_indented()
.xpect_eq(
r#"routes
bazz
foo
bar
bazz
boo
"#,
);
}
}