reinhardt_query/query/materialized_view/
create_materialized_view.rs1use crate::{
9 backend::QueryBuilder,
10 query::SelectStatement,
11 types::{IntoIden, MaterializedViewDef},
12};
13
14use crate::query::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
15
16#[derive(Debug, Clone)]
37pub struct CreateMaterializedViewStatement {
38 pub(crate) def: MaterializedViewDef,
39 pub(crate) select: Option<SelectStatement>,
40}
41
42impl CreateMaterializedViewStatement {
43 pub fn new() -> Self {
45 Self {
46 def: MaterializedViewDef::new(""),
47 select: None,
48 }
49 }
50
51 pub fn take(&mut self) -> Self {
53 Self {
54 def: self.def.clone(),
55 select: self.select.take(),
56 }
57 }
58
59 pub fn name<N>(&mut self, name: N) -> &mut Self
70 where
71 N: IntoIden,
72 {
73 self.def.name = name.into_iden();
74 self
75 }
76
77 pub fn as_select(&mut self, select: SelectStatement) -> &mut Self {
93 self.select = Some(select);
94 self
95 }
96
97 pub fn if_not_exists(&mut self) -> &mut Self {
109 self.def.if_not_exists = true;
110 self
111 }
112
113 pub fn columns<I, C>(&mut self, cols: I) -> &mut Self
125 where
126 I: IntoIterator<Item = C>,
127 C: IntoIden,
128 {
129 for col in cols {
130 self.def.columns.push(col.into_iden());
131 }
132 self
133 }
134
135 pub fn tablespace<T>(&mut self, tablespace: T) -> &mut Self
147 where
148 T: IntoIden,
149 {
150 self.def.tablespace = Some(tablespace.into_iden());
151 self
152 }
153
154 pub fn with_data(&mut self, with_data: bool) -> &mut Self {
172 self.def.with_data = Some(with_data);
173 self
174 }
175}
176
177impl Default for CreateMaterializedViewStatement {
178 fn default() -> Self {
179 Self::new()
180 }
181}
182
183impl QueryStatementBuilder for CreateMaterializedViewStatement {
184 fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, crate::value::Values) {
185 use std::any::Any;
187 if let Some(builder) =
188 (query_builder as &dyn Any).downcast_ref::<crate::backend::PostgresQueryBuilder>()
189 {
190 return builder.build_create_materialized_view(self);
191 }
192 if let Some(builder) =
193 (query_builder as &dyn Any).downcast_ref::<crate::backend::CockroachDBQueryBuilder>()
194 {
195 return builder.build_create_materialized_view(self);
196 }
197 if let Some(_builder) =
198 (query_builder as &dyn Any).downcast_ref::<crate::backend::MySqlQueryBuilder>()
199 {
200 panic!(
201 "MySQL does not support materialized views. Use regular tables with triggers or scheduled queries instead."
202 );
203 }
204 if let Some(_builder) =
205 (query_builder as &dyn Any).downcast_ref::<crate::backend::SqliteQueryBuilder>()
206 {
207 panic!(
208 "SQLite does not support materialized views. Use regular tables with triggers or application-level caching instead."
209 );
210 }
211 panic!("Unsupported query builder type");
212 }
213}
214
215impl QueryStatementWriter for CreateMaterializedViewStatement {}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220 use rstest::*;
221
222 #[rstest]
223 fn test_create_materialized_view_basic() {
224 let mut stmt = CreateMaterializedViewStatement::new();
225 stmt.name("my_mv");
226 assert_eq!(stmt.def.name.to_string(), "my_mv");
227 assert!(!stmt.def.if_not_exists);
228 assert!(stmt.select.is_none());
229 }
230
231 #[rstest]
232 fn test_create_materialized_view_if_not_exists() {
233 let mut stmt = CreateMaterializedViewStatement::new();
234 stmt.name("my_mv").if_not_exists();
235 assert_eq!(stmt.def.name.to_string(), "my_mv");
236 assert!(stmt.def.if_not_exists);
237 }
238
239 #[rstest]
240 fn test_create_materialized_view_with_data() {
241 let mut stmt = CreateMaterializedViewStatement::new();
242 stmt.name("my_mv").with_data(true);
243 assert_eq!(stmt.def.with_data, Some(true));
244 }
245
246 #[rstest]
247 fn test_create_materialized_view_with_no_data() {
248 let mut stmt = CreateMaterializedViewStatement::new();
249 stmt.name("my_mv").with_data(false);
250 assert_eq!(stmt.def.with_data, Some(false));
251 }
252
253 #[rstest]
254 fn test_create_materialized_view_columns() {
255 let mut stmt = CreateMaterializedViewStatement::new();
256 stmt.name("my_mv").columns(["id", "name", "email"]);
257 assert_eq!(stmt.def.columns.len(), 3);
258 assert_eq!(stmt.def.columns[0].to_string(), "id");
259 assert_eq!(stmt.def.columns[1].to_string(), "name");
260 assert_eq!(stmt.def.columns[2].to_string(), "email");
261 }
262
263 #[rstest]
264 fn test_create_materialized_view_tablespace() {
265 let mut stmt = CreateMaterializedViewStatement::new();
266 stmt.name("my_mv").tablespace("pg_default");
267 assert_eq!(
268 stmt.def.tablespace.as_ref().unwrap().to_string(),
269 "pg_default"
270 );
271 }
272
273 #[rstest]
274 fn test_create_materialized_view_as_select() {
275 let mut stmt = CreateMaterializedViewStatement::new();
276 let select = SelectStatement::new();
277 stmt.name("my_mv").as_select(select);
278 assert!(stmt.select.is_some());
279 }
280
281 #[rstest]
282 fn test_create_materialized_view_all_options() {
283 let mut stmt = CreateMaterializedViewStatement::new();
284 let select = SelectStatement::new();
285 stmt.name("my_mv")
286 .if_not_exists()
287 .columns(["id", "name"])
288 .tablespace("pg_default")
289 .with_data(true)
290 .as_select(select);
291
292 assert_eq!(stmt.def.name.to_string(), "my_mv");
293 assert!(stmt.def.if_not_exists);
294 assert_eq!(stmt.def.columns.len(), 2);
295 assert_eq!(
296 stmt.def.tablespace.as_ref().unwrap().to_string(),
297 "pg_default"
298 );
299 assert_eq!(stmt.def.with_data, Some(true));
300 assert!(stmt.select.is_some());
301 }
302
303 #[rstest]
304 fn test_create_materialized_view_default() {
305 let stmt = CreateMaterializedViewStatement::default();
306 assert_eq!(stmt.def.name.to_string(), "");
307 assert!(!stmt.def.if_not_exists);
308 assert!(stmt.select.is_none());
309 }
310
311 #[rstest]
312 fn test_create_materialized_view_take() {
313 let mut stmt = CreateMaterializedViewStatement::new();
314 stmt.name("my_mv").if_not_exists();
315 let taken = stmt.take();
316 assert_eq!(taken.def.name.to_string(), "my_mv");
317 assert!(taken.def.if_not_exists);
318 }
319
320 #[rstest]
321 fn test_create_materialized_view_chaining() {
322 let mut stmt = CreateMaterializedViewStatement::new();
323 stmt.name("my_mv")
324 .if_not_exists()
325 .columns(["id"])
326 .with_data(true);
327 assert_eq!(stmt.def.name.to_string(), "my_mv");
328 assert!(stmt.def.if_not_exists);
329 assert_eq!(stmt.def.columns.len(), 1);
330 assert_eq!(stmt.def.with_data, Some(true));
331 }
332
333 #[rstest]
334 fn test_create_materialized_view_multiple_columns() {
335 let mut stmt = CreateMaterializedViewStatement::new();
336 stmt.name("my_mv").columns(["id", "name"]);
337 stmt.columns(["email"]);
338 assert_eq!(stmt.def.columns.len(), 3);
339 assert_eq!(stmt.def.columns[0].to_string(), "id");
340 assert_eq!(stmt.def.columns[1].to_string(), "name");
341 assert_eq!(stmt.def.columns[2].to_string(), "email");
342 }
343}