pub struct GraphQuery<'g> {
graph: &'g crate::graph::hex_graph::HexGraph,
filters: Vec<QueryFilter>,
}
#[derive(Clone)]
pub enum QueryFilter {
Layer(crate::graph::layer::Layer),
Role(crate::graph::role::Role),
TypeNameContains(String),
ModulePathContains(String),
}
impl<'g> GraphQuery<'g> {
pub fn new(graph: &'g crate::graph::hex_graph::HexGraph) -> Self {
Self {
graph,
filters: Vec::new(),
}
}
pub fn layer(mut self, layer: crate::graph::layer::Layer) -> Self {
self.filters.push(QueryFilter::Layer(layer));
self
}
pub fn role(mut self, role: crate::graph::role::Role) -> Self {
self.filters.push(QueryFilter::Role(role));
self
}
pub fn type_name_contains(mut self, substring: impl Into<String>) -> Self {
self.filters.push(QueryFilter::TypeNameContains(substring.into()));
self
}
pub fn module_path_contains(mut self, substring: impl Into<String>) -> Self {
self.filters.push(QueryFilter::ModulePathContains(substring.into()));
self
}
pub fn execute(&self) -> Vec<&crate::graph::hex_node::HexNode> {
self.graph
.nodes()
.filter(|node| self.matches_all_filters(node))
.collect()
}
pub fn count(&self) -> usize {
self.graph
.nodes()
.filter(|node| self.matches_all_filters(node))
.count()
}
pub fn first(&self) -> Option<&crate::graph::hex_node::HexNode> {
self.graph
.nodes()
.find(|node| self.matches_all_filters(node))
}
fn matches_all_filters(&self, node: &crate::graph::hex_node::HexNode) -> bool {
self.filters.iter().all(|filter| self.matches_filter(node, filter))
}
fn matches_filter(&self, node: &crate::graph::hex_node::HexNode, filter: &QueryFilter) -> bool {
match filter {
QueryFilter::Layer(layer) => node.layer == *layer,
QueryFilter::Role(role) => node.role == *role,
QueryFilter::TypeNameContains(substring) => node.type_name.contains(substring),
QueryFilter::ModulePathContains(substring) => node.module_path.contains(substring),
}
}
}
impl crate::graph::hex_graph::HexGraph {
pub fn query(&self) -> GraphQuery {
GraphQuery::new(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_query_by_layer() {
let graph = crate::graph::builder::GraphBuilder::new()
.add_node(crate::graph::hex_node::HexNode::new(
crate::graph::node_id::NodeId::from_name("TestEntity"),
crate::graph::layer::Layer::Domain,
crate::graph::role::Role::Entity,
"TestEntity",
"test::domain",
))
.build();
let results = graph.query()
.layer(crate::graph::layer::Layer::Domain)
.execute();
assert_eq!(results.len(), 1);
}
#[test]
fn test_query_by_role() {
let graph = crate::graph::builder::GraphBuilder::new()
.add_node(crate::graph::hex_node::HexNode::new(
crate::graph::node_id::NodeId::from_name("TestRepo"),
crate::graph::layer::Layer::Port,
crate::graph::role::Role::Repository,
"TestRepo",
"test::ports",
))
.build();
let results = graph.query()
.role(crate::graph::role::Role::Repository)
.execute();
assert_eq!(results.len(), 1);
}
#[test]
fn test_query_count() {
let graph = crate::graph::builder::GraphBuilder::new()
.add_node(crate::graph::hex_node::HexNode::new(
crate::graph::node_id::NodeId::from_name("Test1"),
crate::graph::layer::Layer::Domain,
crate::graph::role::Role::Entity,
"Test1",
"test",
))
.add_node(crate::graph::hex_node::HexNode::new(
crate::graph::node_id::NodeId::from_name("Test2"),
crate::graph::layer::Layer::Domain,
crate::graph::role::Role::Entity,
"Test2",
"test",
))
.build();
let count = graph.query()
.layer(crate::graph::layer::Layer::Domain)
.count();
assert_eq!(count, 2);
}
}