Skip to main content

08_composite/
08-composite.rs

1#[derive(Clone, Debug, elephantry::Composite)]
2pub struct Department {
3    department_id: i32,
4    name: String,
5    parent_id: Option<i32>,
6}
7
8mod employee {
9    #[derive(Debug, elephantry::Entity)]
10    #[elephantry(model = "Model", structure = "Structure", relation = "employee")]
11    pub struct Entity {
12        #[elephantry(pk)]
13        pub employee_id: i32,
14        pub first_name: String,
15        pub last_name: String,
16        pub birth_date: chrono::NaiveDate,
17        pub is_manager: bool,
18        pub day_salary: bigdecimal::BigDecimal,
19        #[elephantry(virtual)]
20        pub departments: Vec<super::Department>,
21    }
22
23    impl Model {
24        pub fn employee_with_department(&self, id: i32) -> elephantry::Result<Entity> {
25            use elephantry::{Model, Projectable};
26
27            let employee_projection = Self::create_projection()
28                .unset_field("department_id")
29                .add_field("departments", "array_agg(depts)")
30                .alias("e")
31                .to_string();
32
33            let employee = <Self as elephantry::Model>::Structure::relation();
34
35            let sql = format!(
36                r#"
37with recursive
38    depts (department_id, name, parent_id) as (
39        select d.department_id, d.name, d.parent_id from department d join {employee} e using(department_id) where e.employee_id = $1
40        union all
41        select d.department_id, d.name, d.parent_id from depts parent join department d on parent.parent_id = d.department_id
42    )
43select {employee_projection}
44    from {employee} e, depts
45    where e.employee_id = $1
46    group by e.employee_id
47"#
48            );
49
50            Ok(self.connection.query::<Entity>(&sql, &[&id])?.get(0))
51        }
52    }
53}
54
55fn main() -> elephantry::Result {
56    env_logger::init();
57
58    let database_url =
59        std::env::var("DATABASE_URL").unwrap_or_else(|_| "postgres://localhost".to_string());
60    let elephantry = elephantry::Pool::new(&database_url)?;
61    elephantry.execute(include_str!("structure.sql"))?;
62
63    let employee_with_department = elephantry
64        .model::<employee::Model>()
65        .employee_with_department(1)?;
66    dbg!(employee_with_department);
67
68    Ok(())
69}