drizzle_postgres/builder/
refresh.rs1use crate::values::PostgresValue;
21use drizzle_core::traits::{SQLTableInfo, SQLViewInfo};
22use drizzle_core::{SQL, ToSQL, Token};
23use std::marker::PhantomData;
24
25#[derive(Debug, Clone, Copy, Default)]
31pub struct RefreshInitial;
32
33#[derive(Debug, Clone, Copy, Default)]
35pub struct RefreshConcurrently;
36
37#[derive(Debug, Clone, Copy, Default)]
39pub struct RefreshWithNoData;
40
41#[derive(Debug, Clone)]
55pub struct RefreshMaterializedView<'a, State = RefreshInitial> {
56 sql: SQL<'a, PostgresValue<'a>>,
57 _state: PhantomData<State>,
58}
59
60impl<'a> RefreshMaterializedView<'a, RefreshInitial> {
61 #[must_use]
63 pub fn new<V: SQLViewInfo>(view: &'a V) -> Self {
64 let schema = SQLTableInfo::schema(view).unwrap_or("public");
65 let name = view.name();
66
67 let sql = SQL::from_iter([Token::REFRESH, Token::MATERIALIZED, Token::VIEW])
69 .append(SQL::ident(schema))
70 .push(Token::DOT)
71 .append(SQL::ident(name));
72
73 Self {
74 sql,
75 _state: PhantomData,
76 }
77 }
78
79 #[must_use]
86 pub fn concurrently(self) -> RefreshMaterializedView<'a, RefreshConcurrently> {
87 let chunks = self.sql.chunks;
93 let schema_name_start = 3; let mut new_sql = SQL::from_iter([
96 Token::REFRESH,
97 Token::MATERIALIZED,
98 Token::VIEW,
99 Token::CONCURRENTLY,
100 ]);
101
102 for chunk in chunks.into_iter().skip(schema_name_start) {
104 new_sql = new_sql.push(chunk);
105 }
106
107 RefreshMaterializedView {
108 sql: new_sql,
109 _state: PhantomData,
110 }
111 }
112
113 #[must_use]
120 pub fn with_no_data(self) -> RefreshMaterializedView<'a, RefreshWithNoData> {
121 RefreshMaterializedView {
122 sql: self.sql.push(Token::WITH).push(Token::NO).push(Token::DATA),
123 _state: PhantomData,
124 }
125 }
126
127 #[must_use]
129 pub fn with_data(self) -> Self {
130 Self {
131 sql: self.sql.push(Token::WITH).push(Token::DATA),
132 _state: PhantomData,
133 }
134 }
135}
136
137impl<'a, State> ToSQL<'a, PostgresValue<'a>> for RefreshMaterializedView<'a, State> {
142 fn to_sql(&self) -> SQL<'a, PostgresValue<'a>> {
143 self.sql.clone()
144 }
145}
146
147pub fn refresh_materialized_view<'a, V: SQLViewInfo>(
153 view: &'a V,
154) -> RefreshMaterializedView<'a, RefreshInitial> {
155 RefreshMaterializedView::new(view)
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 struct TestView;
164
165 impl drizzle_core::traits::SQLTableInfo for TestView {
166 fn name(&self) -> &str {
167 "user_stats"
168 }
169
170 fn columns(&self) -> &'static [&'static dyn drizzle_core::traits::SQLColumnInfo] {
171 &[]
172 }
173
174 fn dependencies(&self) -> &'static [&'static dyn drizzle_core::traits::SQLTableInfo] {
175 &[]
176 }
177 }
178
179 impl SQLViewInfo for TestView {
180 fn definition_sql(&self) -> std::borrow::Cow<'static, str> {
181 "SELECT * FROM users".into()
182 }
183
184 fn schema(&self) -> &'static str {
185 "public"
186 }
187
188 fn is_materialized(&self) -> bool {
189 true
190 }
191 }
192
193 #[test]
194 fn test_basic_refresh() {
195 let view = TestView;
196 let refresh = RefreshMaterializedView::new(&view);
197 let sql = refresh.to_sql();
198
199 assert_eq!(
200 sql.sql(),
201 r#"REFRESH MATERIALIZED VIEW "public"."user_stats""#
202 );
203 }
204
205 #[test]
206 fn test_concurrent_refresh() {
207 let view = TestView;
208 let refresh = RefreshMaterializedView::new(&view).concurrently();
209 let sql = refresh.to_sql();
210
211 assert_eq!(
212 sql.sql(),
213 r#"REFRESH MATERIALIZED VIEW CONCURRENTLY "public"."user_stats""#
214 );
215 }
216
217 #[test]
218 fn test_refresh_with_no_data() {
219 let view = TestView;
220 let refresh = RefreshMaterializedView::new(&view).with_no_data();
221 let sql = refresh.to_sql();
222
223 assert_eq!(
224 sql.sql(),
225 r#"REFRESH MATERIALIZED VIEW "public"."user_stats" WITH NO DATA"#
226 );
227 }
228
229 #[test]
230 fn test_refresh_with_data() {
231 let view = TestView;
232 let refresh = RefreshMaterializedView::new(&view).with_data();
233 let sql = refresh.to_sql();
234
235 assert_eq!(
236 sql.sql(),
237 r#"REFRESH MATERIALIZED VIEW "public"."user_stats" WITH DATA"#
238 );
239 }
240
241 #[test]
242 fn test_helper_function() {
243 let view = TestView;
244 let refresh = refresh_materialized_view(&view);
245 let sql = refresh.to_sql();
246
247 assert_eq!(
248 sql.sql(),
249 r#"REFRESH MATERIALIZED VIEW "public"."user_stats""#
250 );
251 }
252}