use sea_orm::Condition;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WhereNode {
And(Vec<WhereNode>),
Or(Vec<WhereNode>),
Not(Box<WhereNode>),
Leaf(WhereLeaf),
Empty,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WhereLeaf {
pub field: String,
pub lookup: String,
pub value: String,
}
impl WhereNode {
#[must_use]
pub fn and(nodes: Vec<WhereNode>) -> Self {
Self::And(nodes)
}
#[must_use]
pub fn or(nodes: Vec<WhereNode>) -> Self {
Self::Or(nodes)
}
#[must_use]
pub fn not(node: WhereNode) -> Self {
Self::Not(Box::new(node))
}
#[must_use]
pub fn leaf(
field: impl Into<String>,
lookup: impl Into<String>,
value: impl Into<String>,
) -> Self {
Self::Leaf(WhereLeaf {
field: field.into(),
lookup: lookup.into(),
value: value.into(),
})
}
#[must_use]
pub fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
#[must_use]
pub fn from_condition(_condition: Condition) -> Self {
Self::Empty
}
#[must_use]
pub fn leaf_count(&self) -> usize {
match self {
Self::And(nodes) | Self::Or(nodes) => nodes.iter().map(WhereNode::leaf_count).sum(),
Self::Not(node) => node.leaf_count(),
Self::Leaf(_) => 1,
Self::Empty => 0,
}
}
}
#[cfg(test)]
mod tests {
use sea_orm::Condition;
use super::{WhereLeaf, WhereNode};
#[test]
fn and_node_stores_children() {
let node = WhereNode::and(vec![WhereNode::leaf("name", "exact", "Ada")]);
match node {
WhereNode::And(nodes) => assert_eq!(nodes.len(), 1),
other => panic!("expected And node, got {other:?}"),
}
}
#[test]
fn or_node_stores_children() {
let node = WhereNode::or(vec![WhereNode::leaf("name", "exact", "Ada")]);
match node {
WhereNode::Or(nodes) => assert_eq!(nodes.len(), 1),
other => panic!("expected Or node, got {other:?}"),
}
}
#[test]
fn not_node_wraps_child() {
let node = WhereNode::not(WhereNode::leaf("name", "exact", "Ada"));
match node {
WhereNode::Not(child) => assert_eq!(child.leaf_count(), 1),
other => panic!("expected Not node, got {other:?}"),
}
}
#[test]
fn leaf_constructor_populates_leaf_fields() {
let node = WhereNode::leaf("name", "icontains", "Ada");
match node {
WhereNode::Leaf(leaf) => {
assert_eq!(leaf.field, "name");
assert_eq!(leaf.lookup, "icontains");
assert_eq!(leaf.value, "Ada");
}
other => panic!("expected Leaf node, got {other:?}"),
}
}
#[test]
fn empty_node_reports_empty() {
assert!(WhereNode::Empty.is_empty());
}
#[test]
fn non_empty_leaf_reports_not_empty() {
assert!(!WhereNode::leaf("id", "exact", "1").is_empty());
}
#[test]
fn from_condition_currently_returns_empty_placeholder() {
let node = WhereNode::from_condition(Condition::all());
assert!(node.is_empty());
assert_eq!(node.leaf_count(), 0);
}
#[test]
fn leaf_count_counts_nested_tree_leaves() {
let node = WhereNode::and(vec![
WhereNode::leaf("name", "exact", "Ada"),
WhereNode::or(vec![
WhereNode::leaf("age", "gte", "18"),
WhereNode::not(WhereNode::leaf("active", "exact", "false")),
]),
]);
assert_eq!(node.leaf_count(), 3);
}
#[test]
fn leaf_count_for_empty_node_is_zero() {
assert_eq!(WhereNode::Empty.leaf_count(), 0);
}
#[test]
fn where_leaf_stores_all_fields() {
let leaf = WhereLeaf {
field: "status".to_string(),
lookup: "exact".to_string(),
value: "published".to_string(),
};
assert_eq!(leaf.field, "status");
assert_eq!(leaf.lookup, "exact");
assert_eq!(leaf.value, "published");
}
}