Skip to main content

toolu_orm_query/select/relational/
postgres_sql.rs

1//! Postgres lateral join SQL generation for relational SELECT queries.
2
3use super::config::RelationalSelectBuilder;
4
5impl RelationalSelectBuilder {
6  /// Postgres: `LEFT JOIN LATERAL` + `json_agg` / `json_build_array`.
7  pub fn to_sql_postgres(&self) -> String {
8    let mut sql = String::new();
9    sql.push_str("SELECT ");
10    self.push_source_select(&mut sql);
11
12    for rel in &self.relations {
13      let alias = format!("{}_{}", self.source_table, rel.field_name);
14      sql.push_str(", \"");
15      sql.push_str(&alias);
16      sql.push_str("\".\"data\" AS \"");
17      sql.push_str(&rel.field_name);
18      sql.push('"');
19    }
20
21    sql.push_str(" FROM \"");
22    sql.push_str(&self.source_table);
23    sql.push('"');
24
25    for rel in &self.relations {
26      let alias = format!("{}_{}", self.source_table, rel.field_name);
27      let target_alias = format!("{}_sub", rel.field_name);
28      sql.push_str(" LEFT JOIN LATERAL (SELECT ");
29
30      if rel.is_many {
31        sql.push_str("coalesce(json_agg(json_build_array(");
32        Self::push_column_list(&mut sql, &target_alias, &rel.target_columns);
33        sql.push_str(")), '[]'::json) AS \"data\"");
34      } else {
35        sql.push_str("json_build_array(");
36        Self::push_column_list(&mut sql, &target_alias, &rel.target_columns);
37        sql.push_str(") AS \"data\"");
38      }
39
40      sql.push_str(" FROM \"");
41      sql.push_str(&rel.target_table);
42      sql.push_str("\" \"");
43      sql.push_str(&target_alias);
44      sql.push('"');
45      self.push_join_where(&mut sql, &target_alias, rel);
46
47      sql.push_str(") \"");
48      sql.push_str(&alias);
49      sql.push_str("\" ON true");
50    }
51
52    sql
53  }
54}