geekorm_core/builder/
joins.rs1use crate::{Table, ToSqlite};
2
3#[derive(Debug, Clone, Default)]
5pub struct TableJoins {
6 joins: Vec<TableJoin>,
7}
8
9impl Iterator for TableJoins {
10 type Item = TableJoin;
11
12 fn next(&mut self) -> Option<Self::Item> {
13 self.joins.pop()
14 }
15}
16
17impl TableJoins {
18 pub fn push(&mut self, join: TableJoin) {
20 self.joins.push(join);
21 }
22
23 pub fn get(&self, name: &str) -> Option<&TableJoin> {
25 self.joins.iter().find(|join| match join {
26 TableJoin::InnerJoin(opts) => opts.child.name == name,
27 })
28 }
29
30 pub fn is_empty(&self) -> bool {
32 self.joins.is_empty()
33 }
34}
35
36impl ToSqlite for TableJoins {
37 fn on_select(&self, query: &crate::QueryBuilder) -> Result<String, crate::Error> {
38 let mut full_query = String::new();
39 for join in self.joins.iter() {
40 let sql = join.on_select(query)?;
41 full_query.push_str(sql.as_str());
42 }
43 Ok(full_query)
44 }
45}
46
47#[derive(Debug, Clone)]
49pub enum TableJoin {
50 InnerJoin(TableJoinOptions),
52}
53
54impl TableJoin {
55 pub fn new(parent: Table, child: Table) -> Self {
57 TableJoin::InnerJoin(TableJoinOptions { parent, child })
58 }
59
60 pub fn is_valid_column(&self, column: &str) -> bool {
62 match self {
63 TableJoin::InnerJoin(opts) => opts.parent.is_valid_column(column),
64 }
65 }
66}
67
68impl ToSqlite for TableJoin {
69 fn on_select(&self, qb: &crate::QueryBuilder) -> Result<String, crate::Error> {
70 match self {
71 TableJoin::InnerJoin(opts) => Ok(format!(
72 "INNER JOIN {} ON {}",
73 opts.child.name,
74 opts.on_select(qb)?
75 )),
76 }
77 }
78}
79
80#[derive(Debug, Clone)]
84pub struct TableJoinOptions {
85 pub parent: Table,
87 pub child: Table,
89}
90
91impl TableJoinOptions {
92 pub fn is_valid_column(&self, column: &str) -> bool {
94 self.parent.is_valid_column(column) || self.child.is_valid_column(column)
95 }
96}
97
98impl ToSqlite for TableJoinOptions {
99 fn on_select(&self, _: &crate::QueryBuilder) -> Result<String, crate::Error> {
101 let pcolumn = self.parent.get_foreign_key(self.child.name.clone());
103 let pcolumn_name = if !pcolumn.alias.is_empty() {
105 pcolumn.alias.clone()
106 } else {
107 pcolumn.name.clone()
108 };
109 let ccolumn = self.child.get_primary_key();
112
113 Ok(format!(
114 "{ctable}.{ccolumn} = {ptable}.{pcolumn}",
115 ctable = self.child.name,
116 ccolumn = ccolumn,
117 ptable = self.parent.name,
118 pcolumn = pcolumn_name,
119 ))
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use crate::{Column, Columns};
126
127 use super::*;
128
129 fn table_parent(name: String) -> Table {
130 Table {
131 name,
132 database: None,
133 columns: Columns {
134 columns: vec![
135 Column {
136 name: String::from("id"),
137 column_type: crate::ColumnType::Identifier(
138 crate::ColumnTypeOptions::primary_key(),
139 ),
140 ..Default::default()
141 },
142 Column {
143 name: String::from("image_id"),
144 column_type: crate::ColumnType::ForeignKey(
145 crate::ColumnTypeOptions::foreign_key(String::from("Child.id")),
146 ),
147 ..Default::default()
148 },
149 ],
150 },
151 }
152 }
153
154 fn table_child(name: String) -> Table {
155 Table {
156 name,
157 database: None,
158 columns: Columns {
159 columns: vec![Column {
160 name: String::from("id"),
161 column_type: crate::ColumnType::Identifier(
162 crate::ColumnTypeOptions::primary_key(),
163 ),
164 ..Default::default()
165 }],
166 },
167 }
168 }
169
170 #[test]
171 fn test_table_join_on_select() {
172 let join = TableJoin::InnerJoin(TableJoinOptions {
173 parent: table_parent(String::from("Parent")),
174 child: table_child(String::from("Child")),
175 });
176
177 let select_query = join
178 .on_select(&crate::QueryBuilder::select())
179 .expect("Failed to generate select query");
180 assert_eq!(
181 select_query,
182 "INNER JOIN Child ON Child.id = Parent.image_id"
183 )
184 }
185
186 #[test]
187 fn test_join_options() {
188 let join = TableJoinOptions {
189 parent: table_parent(String::from("Parent")),
190 child: table_child(String::from("Child")),
191 };
192
193 let select_query = join.on_select(&crate::QueryBuilder::select()).unwrap();
194 assert_eq!(select_query, "Child.id = Parent.image_id");
195 }
196}