Skip to main content

sqlink/postgres/
query_table.rs

1use crate::error::Error;
2use crate::postgres::query_field::{QueryWithParamsLoc};
3use crate::postgres::query_where::{QueryWheres, WhereOperator};
4use crate::postgres::static_constant::TABLE_ESCAPE;
5
6#[derive(Debug)]
7pub struct QueryTables(Vec<QueryTable>);
8
9impl Default for QueryTables {
10    fn default() -> Self {
11        QueryTables(Vec::new())
12    }
13}
14
15impl QueryTables {
16    pub fn len(&self) -> usize {
17        self.0.len()
18    }
19    pub fn build(&self, i: &mut i8) -> Result<QueryWithParamsLoc, Error> {
20        if self.0.len() != 1 {
21            return Err(Error::Syntax("Table can only select 1 time".into()));
22        }
23        let mut v: Vec<String> = Vec::new();
24        let mut q: Vec<usize> = Vec::new();
25        for join in &self.0 {
26            let built = join.build(i)?;
27            v.push(built.query);
28            q.extend(built.parameters_loc);
29        }
30        Ok(QueryWithParamsLoc {
31            query: v.join(","),
32            parameters_loc: q,
33        })
34    }
35    pub fn push(&mut self, field: QueryTable) {
36        self.0.push(field);
37    }
38    pub fn get_last_table(&mut self) -> &mut QueryTable {
39        let len = self.0.len();
40        if len == 0 {
41            panic!("cannot select without base table");
42        }
43        &mut self.0[len - 1]
44    }
45    pub fn inner_join(&mut self, query_table: QueryTable) -> &mut Self {
46        let table = self.get_last_table();
47        table.table_join.push(TableJoin::InnerJoin(query_table, QueryWheres::default()));
48        self
49    }
50    pub fn left_join(&mut self, query_table: QueryTable) -> &mut Self {
51        let table = self.get_last_table();
52        table.table_join.push(TableJoin::LeftJoin(query_table, QueryWheres::default()));
53        self
54    }
55    pub fn right_join(&mut self, query_table: QueryTable) -> &mut Self {
56        let table = self.get_last_table();
57        table.table_join.push(TableJoin::RightJoin(query_table, QueryWheres::default()));
58        self
59    }
60    pub fn full_join(&mut self, query_table: QueryTable) -> &mut Self {
61        let table = self.get_last_table();
62        table.table_join.push(TableJoin::FullJoin(query_table, QueryWheres::default()));
63        self
64    }
65    pub fn on(&mut self, query_where: QueryWheres) -> &mut Self {
66        let table = self.get_last_table();
67        let len = table.table_join.len();
68        if len == 0 {
69            panic!("cannot on without join table");
70        }
71        let w = match &mut table.table_join[len - 1] {
72            TableJoin::InnerJoin(_, w) => w,
73            TableJoin::LeftJoin(_, w) => w,
74            TableJoin::RightJoin(_, w) => w,
75            TableJoin::FullJoin(_, w) => w,
76        };
77        if w.len() != 0 {
78            w.push(WhereOperator::And);
79        }
80        w.extend(query_where);
81        self
82    }
83}
84
85#[derive(Debug)]
86pub enum TableJoin {
87    InnerJoin(QueryTable, QueryWheres),
88    LeftJoin(QueryTable, QueryWheres),
89    RightJoin(QueryTable, QueryWheres),
90    FullJoin(QueryTable, QueryWheres),
91}
92
93#[derive(Debug)]
94pub struct QueryTable {
95    alias: Option<String>,
96    name: String,
97    schema: Option<String>,
98    table_join: Vec<TableJoin>,
99}
100
101impl QueryTable {
102    fn get_table_name(&self) -> String {
103        let escaped_table_name = if let Some(schema) = &self.schema {
104            format!("{}{}{}.{}{}{}", TABLE_ESCAPE, schema, TABLE_ESCAPE, TABLE_ESCAPE, self.name, TABLE_ESCAPE)
105        } else {
106            format!("{}{}{}", TABLE_ESCAPE, self.name.clone(), TABLE_ESCAPE)
107        };
108        if let Some(alias) = &self.alias {
109            format!("{} AS {}", escaped_table_name, alias)
110        } else {
111            escaped_table_name
112        }
113    }
114    fn build(&self, i: &mut i8) -> Result<QueryWithParamsLoc, Error> {
115        let mut v: Vec<String> = Vec::new();
116        let mut p: Vec<usize> = Vec::new();
117        v.push(self.get_table_name());
118        for join in &self.table_join {
119            let (op, join_table, qw) = match join {
120                TableJoin::InnerJoin(join_table, qw) => {("INNER JOIN", join_table, qw)},
121                TableJoin::LeftJoin(join_table, qw) => {("LEFT JOIN", join_table, qw)},
122                TableJoin::RightJoin(join_table, qw) => {("RIGHT JOIN", join_table, qw)},
123                TableJoin::FullJoin(join_table, qw) => {("FULL JOIN", join_table, qw)},
124            };
125            v.push(op.to_owned());
126            v.push(join_table.get_table_name());
127            v.push("ON".to_owned());
128            let qwresult = qw.build(i)?;
129            v.push(qwresult.query);
130            p.extend(qwresult.parameters_loc);
131        }
132        Ok(QueryWithParamsLoc {
133            query: v.join(" "),
134            parameters_loc: p,
135        })
136    }
137}
138impl From<&str> for QueryTable {
139    fn from(table: &str) -> Self {
140        QueryTable {
141            alias: None,
142            name: table.to_owned(),
143            schema: None,
144            table_join: Vec::new(),
145        }
146    }
147}
148
149impl From<(&str, &str)> for QueryTable {
150    fn from(nameandalias: (&str, &str)) -> Self {
151        QueryTable {
152            alias: Some(nameandalias.1.to_owned()),
153            name: nameandalias.0.to_owned(),
154            schema: None,
155            table_join: Vec::new(),
156        }
157    }
158}
159
160impl From<(&str, &str, &str)> for QueryTable {
161    fn from(schemaxnamexalias: (&str, &str, &str)) -> Self {
162        QueryTable {
163            alias: Some(schemaxnamexalias.2.to_owned()),
164            name: schemaxnamexalias.1.to_owned(),
165            schema: Some(schemaxnamexalias.0.to_owned()),
166            table_join: Vec::new(),
167        }
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174    #[test]
175    fn test_table_1() {
176        let table: QueryTable = QueryTable {
177            alias: Some("u".to_owned()),
178            name: "user".to_owned(),
179            schema: Some("public".to_owned()),
180            table_join: Vec::new(),
181        };
182
183        assert_eq!(table.build(&mut 0).unwrap().query, "\"public\".\"user\" AS u");
184    }
185
186    #[test]
187    fn test_table_2() {
188        let table: QueryTable = "user".into();
189        assert_eq!(table.build(&mut 0).unwrap().query, "\"user\"");
190    }
191
192    #[test]
193    fn test_table_3() {
194        let table: QueryTable = ("user", "u").into();
195        assert_eq!(table.build(&mut 0).unwrap().query, "\"user\" AS u");
196    }
197}