sea_query/extension/postgres/
extension.rs

1use crate::{QueryBuilder, QuotedBuilder, SqlWriter};
2
3/// Creates a new "CREATE or DROP EXTENSION" statement for PostgreSQL
4///
5/// # Exampl
6#[derive(Debug, Default, Clone, PartialEq, Eq)]
7pub struct Extension;
8
9impl Extension {
10    /// Creates a new [`ExtensionCreateStatement`]
11    pub fn create() -> ExtensionCreateStatement {
12        ExtensionCreateStatement::new()
13    }
14
15    /// Creates a new [`ExtensionDropStatement`]
16    pub fn drop() -> ExtensionDropStatement {
17        ExtensionDropStatement::new()
18    }
19}
20
21/// Creates a new "CREATE EXTENSION" statement for PostgreSQL
22///
23/// # Synopsis
24///
25/// ```ignore
26/// CREATE EXTENSION [ IF NOT EXISTS ] extension_name
27///     [ WITH ] [ SCHEMA schema_name ]
28///              [ VERSION version ]
29///              [ CASCADE ]
30/// ```
31///
32/// # Example
33///
34/// Creates the "ltree" extension if it doesn't exists.
35///
36/// ```
37/// use sea_query::{extension::postgres::Extension, *};
38///
39/// assert_eq!(
40///     Extension::create()
41///         .name("ltree")
42///         .schema("public")
43///         .version("v0.1.0")
44///         .cascade()
45///         .if_not_exists()
46///         .to_string(PostgresQueryBuilder),
47///     r#"CREATE EXTENSION IF NOT EXISTS ltree WITH SCHEMA public VERSION v0.1.0 CASCADE"#
48/// );
49/// ```
50///
51/// # References
52///
53/// [Refer to the PostgreSQL Documentation][1]
54///
55/// [1]: https://www.postgresql.org/docs/current/sql-createextension.html
56#[derive(Debug, Default, Clone, PartialEq, Eq)]
57pub struct ExtensionCreateStatement {
58    pub(crate) name: String,
59    pub(crate) schema: Option<String>,
60    pub(crate) version: Option<String>,
61
62    /// Conditional to execute query based on existance of the extension.
63    pub(crate) if_not_exists: bool,
64
65    /// Determines the presence of the `RESTRICT` statement
66    pub(crate) cascade: bool,
67}
68
69impl ExtensionCreateStatement {
70    pub fn new() -> Self {
71        Self::default()
72    }
73
74    /// Sets the name of the extension to be created.
75    pub fn name<T: Into<String>>(&mut self, name: T) -> &mut Self {
76        self.name = name.into();
77        self
78    }
79
80    /// Uses "WITH SCHEMA" on Create Extension Statement.
81    pub fn schema<T: Into<String>>(&mut self, schema: T) -> &mut Self {
82        self.schema = Some(schema.into());
83        self
84    }
85
86    /// Uses "VERSION" on Create Extension Statement.
87    pub fn version<T: Into<String>>(&mut self, version: T) -> &mut Self {
88        self.version = Some(version.into());
89        self
90    }
91
92    /// Uses "CASCADE" on Create Extension Statement.
93    pub fn cascade(&mut self) -> &mut Self {
94        self.cascade = true;
95        self
96    }
97
98    /// Uses "IF NOT EXISTS" on Create Extension Statement.
99    pub fn if_not_exists(&mut self) -> &mut Self {
100        self.if_not_exists = true;
101        self
102    }
103}
104
105/// Creates a new "DROP EXTENSION" statement for PostgreSQL
106///
107/// # Synopsis
108///
109/// ```ignore
110/// DROP EXTENSION [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]
111/// ```
112///
113/// # Example
114///
115/// Drops the "ltree" extension if it exists.
116///
117/// ```
118/// use sea_query::{extension::postgres::Extension, *};
119///
120/// assert_eq!(
121///     Extension::drop()
122///         .name("ltree")
123///         .cascade()
124///         .if_exists()
125///         .to_string(PostgresQueryBuilder),
126///     r#"DROP EXTENSION IF EXISTS ltree CASCADE"#
127/// );
128/// ```
129///
130/// # References
131///
132/// [Refer to the PostgreSQL Documentation][1]
133///
134/// [1]: https://www.postgresql.org/docs/current/sql-createextension.html
135#[derive(Debug, Default, Clone, PartialEq, Eq)]
136pub struct ExtensionDropStatement {
137    pub(crate) name: String,
138    pub(crate) schema: Option<String>,
139    pub(crate) version: Option<String>,
140
141    /// Conditional to execute query based on existance of the extension.
142    pub(crate) if_exists: bool,
143
144    /// Determines the presence of the `RESTRICT` statement.
145    pub(crate) restrict: bool,
146
147    /// Determines the presence of the `CASCADE` statement
148    pub(crate) cascade: bool,
149}
150
151impl ExtensionDropStatement {
152    pub fn new() -> Self {
153        Self::default()
154    }
155
156    /// Sets the name of the extension to be dropped.
157    pub fn name<T: Into<String>>(&mut self, name: T) -> &mut Self {
158        self.name = name.into();
159        self
160    }
161
162    /// Uses "IF EXISTS" on Drop Extension Statement.
163    pub fn if_exists(&mut self) -> &mut Self {
164        self.if_exists = true;
165        self
166    }
167
168    /// Uses "CASCADE" on Drop Extension Statement.
169    pub fn cascade(&mut self) -> &mut Self {
170        self.cascade = true;
171        self
172    }
173
174    /// Uses "RESTRICT" on Drop Extension Statement.
175    pub fn restrict(&mut self) -> &mut Self {
176        self.restrict = true;
177        self
178    }
179}
180
181pub trait ExtensionBuilder: QuotedBuilder {
182    /// Translate [`ExtensionCreateStatement`] into database specific SQL statement.
183    fn prepare_extension_create_statement(
184        &self,
185        create: &ExtensionCreateStatement,
186        sql: &mut dyn SqlWriter,
187    );
188
189    /// Translate [`ExtensionDropStatement`] into database specific SQL statement.
190    fn prepare_extension_drop_statement(
191        &self,
192        drop: &ExtensionDropStatement,
193        sql: &mut dyn SqlWriter,
194    );
195}
196
197macro_rules! impl_extension_statement_builder {
198    ( $struct_name: ident, $func_name: ident ) => {
199        impl $struct_name {
200            pub fn build_ref<T: ExtensionBuilder>(&self, extension_builder: &T) -> String {
201                let mut sql = String::with_capacity(256);
202                self.build_collect_ref(extension_builder, &mut sql)
203            }
204
205            pub fn build_collect<T: ExtensionBuilder>(
206                &self,
207                extension_builder: T,
208                sql: &mut dyn SqlWriter,
209            ) -> String {
210                self.build_collect_ref(&extension_builder, sql)
211            }
212
213            pub fn build_collect_ref<T: ExtensionBuilder>(
214                &self,
215                extension_builder: &T,
216                sql: &mut dyn SqlWriter,
217            ) -> String {
218                extension_builder.$func_name(self, sql);
219                sql.to_string()
220            }
221
222            /// Build corresponding SQL statement and return SQL string
223            pub fn to_string<T>(&self, extension_builder: T) -> String
224            where
225                T: ExtensionBuilder + QueryBuilder,
226            {
227                self.build_ref(&extension_builder)
228            }
229        }
230    };
231}
232
233impl_extension_statement_builder!(ExtensionCreateStatement, prepare_extension_create_statement);
234impl_extension_statement_builder!(ExtensionDropStatement, prepare_extension_drop_statement);
235
236#[cfg(test)]
237mod test {
238    use super::super::PgLTree;
239    use super::*;
240
241    #[test]
242    fn creates_a_stmt_for_create_extension() {
243        let create_extension_stmt = Extension::create()
244            .name(PgLTree)
245            .schema("public")
246            .version("v0.1.0")
247            .cascade()
248            .if_not_exists()
249            .to_owned();
250
251        assert_eq!(create_extension_stmt.name, "ltree");
252        assert_eq!(create_extension_stmt.schema, Some("public".to_string()));
253        assert_eq!(create_extension_stmt.version, Some("v0.1.0".to_string()));
254        assert!(create_extension_stmt.cascade);
255        assert!(create_extension_stmt.if_not_exists);
256    }
257
258    #[test]
259    fn creates_a_stmt_for_drop_extension() {
260        let drop_extension_stmt = Extension::drop()
261            .name(PgLTree)
262            .cascade()
263            .if_exists()
264            .restrict()
265            .to_owned();
266
267        assert_eq!(drop_extension_stmt.name, "ltree");
268        assert!(drop_extension_stmt.cascade);
269        assert!(drop_extension_stmt.if_exists);
270        assert!(drop_extension_stmt.restrict);
271    }
272}