type CollectionGetterFn<S, C> = Box<dyn Fn(&S) -> &Vec<C>>;
type AttributeGetterFn<C, T> = Box<dyn Fn(&C) -> &T>;
pub struct AssociationCollection<S, C, T> {
collection_getter: CollectionGetterFn<S, C>,
attribute_getter: AttributeGetterFn<C, T>,
}
impl<S, C, T> AssociationCollection<S, C, T> {
pub fn new<F1, F2>(collection_getter: F1, attribute_getter: F2) -> Self
where
F1: Fn(&S) -> &Vec<C> + 'static,
F2: Fn(&C) -> &T + 'static,
{
Self {
collection_getter: Box::new(collection_getter),
attribute_getter: Box::new(attribute_getter),
}
}
pub fn get_all<'a>(&self, source: &'a S) -> Vec<&'a T>
where
C: 'a,
{
let collection = (self.collection_getter)(source);
collection
.iter()
.map(|item| (self.attribute_getter)(item))
.collect()
}
pub fn count(&self, source: &S) -> usize {
let collection = (self.collection_getter)(source);
collection.len()
}
pub fn is_empty(&self, source: &S) -> bool {
let collection = (self.collection_getter)(source);
collection.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(dead_code)]
#[derive(Clone)]
struct Order {
id: i64,
product_name: String,
}
#[allow(dead_code)]
#[derive(Clone)]
struct User {
id: i64,
orders: Vec<Order>,
}
#[test]
fn test_association_collection_basic() {
let user = User {
id: 1,
orders: vec![
Order {
id: 1,
product_name: "Book".to_string(),
},
Order {
id: 2,
product_name: "Pen".to_string(),
},
],
};
let proxy = AssociationCollection::new(|u: &User| &u.orders, |o: &Order| &o.product_name);
let products = proxy.get_all(&user);
assert_eq!(products.len(), 2);
assert_eq!(products[0], "Book");
assert_eq!(products[1], "Pen");
}
#[test]
fn test_association_collection_count() {
let user = User {
id: 1,
orders: vec![
Order {
id: 1,
product_name: "Item1".to_string(),
},
Order {
id: 2,
product_name: "Item2".to_string(),
},
],
};
let proxy = AssociationCollection::new(|u: &User| &u.orders, |o: &Order| &o.product_name);
assert_eq!(proxy.count(&user), 2);
assert!(!proxy.is_empty(&user));
}
#[test]
fn test_association_collection_empty() {
let user = User {
id: 1,
orders: vec![],
};
let proxy = AssociationCollection::new(|u: &User| &u.orders, |o: &Order| &o.product_name);
assert_eq!(proxy.count(&user), 0);
assert!(proxy.is_empty(&user));
}
}