sea_orm/database/
statement.rs

1use crate::DbBackend;
2use sea_query::{inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, SqliteQueryBuilder};
3pub use sea_query::{Value, Values};
4use std::fmt;
5
6/// Defines an SQL statement
7#[derive(Debug, Clone, PartialEq)]
8pub struct Statement {
9    /// The SQL query
10    pub sql: String,
11    /// The values for the SQL statement's parameters
12    pub values: Option<Values>,
13    /// The database backend this statement is constructed for.
14    /// The SQL dialect and values should be valid for the DbBackend.
15    pub db_backend: DbBackend,
16}
17
18/// Any type that can build a [Statement]
19pub trait StatementBuilder {
20    /// Method to call in order to build a [Statement]
21    fn build(&self, db_backend: &DbBackend) -> Statement;
22}
23
24impl Statement {
25    /// Create a [Statement] from a [crate::DatabaseBackend] and a raw SQL statement
26    pub fn from_string<T>(db_backend: DbBackend, stmt: T) -> Statement
27    where
28        T: Into<String>,
29    {
30        Statement {
31            sql: stmt.into(),
32            values: None,
33            db_backend,
34        }
35    }
36
37    /// Create a SQL statement from a [crate::DatabaseBackend], a
38    /// raw SQL statement and param values
39    pub fn from_sql_and_values<I, T>(db_backend: DbBackend, sql: T, values: I) -> Self
40    where
41        I: IntoIterator<Item = Value>,
42        T: Into<String>,
43    {
44        Self::from_string_values_tuple(db_backend, (sql, Values(values.into_iter().collect())))
45    }
46
47    pub(crate) fn from_string_values_tuple<T>(db_backend: DbBackend, stmt: (T, Values)) -> Statement
48    where
49        T: Into<String>,
50    {
51        Statement {
52            sql: stmt.0.into(),
53            values: Some(stmt.1),
54            db_backend,
55        }
56    }
57}
58
59impl fmt::Display for Statement {
60    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61        match &self.values {
62            Some(values) => {
63                let string = inject_parameters(
64                    &self.sql,
65                    values.0.clone(),
66                    self.db_backend.get_query_builder().as_ref(),
67                );
68                write!(f, "{}", &string)
69            }
70            None => {
71                write!(f, "{}", &self.sql)
72            }
73        }
74    }
75}
76
77macro_rules! build_any_stmt {
78    ($stmt: expr, $db_backend: expr) => {
79        match $db_backend {
80            DbBackend::MySql => $stmt.build(MysqlQueryBuilder),
81            DbBackend::Postgres => $stmt.build(PostgresQueryBuilder),
82            DbBackend::Sqlite => $stmt.build(SqliteQueryBuilder),
83        }
84    };
85}
86
87macro_rules! build_postgres_stmt {
88    ($stmt: expr, $db_backend: expr) => {
89        match $db_backend {
90            DbBackend::Postgres => $stmt.to_string(PostgresQueryBuilder),
91            DbBackend::MySql | DbBackend::Sqlite => unimplemented!(),
92        }
93    };
94}
95
96macro_rules! build_query_stmt {
97    ($stmt: ty) => {
98        impl StatementBuilder for $stmt {
99            fn build(&self, db_backend: &DbBackend) -> Statement {
100                let stmt = build_any_stmt!(self, db_backend);
101                Statement::from_string_values_tuple(*db_backend, stmt)
102            }
103        }
104    };
105}
106
107build_query_stmt!(sea_query::InsertStatement);
108build_query_stmt!(sea_query::SelectStatement);
109build_query_stmt!(sea_query::UpdateStatement);
110build_query_stmt!(sea_query::DeleteStatement);
111build_query_stmt!(sea_query::WithQuery);
112
113macro_rules! build_schema_stmt {
114    ($stmt: ty) => {
115        impl StatementBuilder for $stmt {
116            fn build(&self, db_backend: &DbBackend) -> Statement {
117                let stmt = build_any_stmt!(self, db_backend);
118                Statement::from_string(*db_backend, stmt)
119            }
120        }
121    };
122}
123
124build_schema_stmt!(sea_query::TableCreateStatement);
125build_schema_stmt!(sea_query::TableDropStatement);
126build_schema_stmt!(sea_query::TableAlterStatement);
127build_schema_stmt!(sea_query::TableRenameStatement);
128build_schema_stmt!(sea_query::TableTruncateStatement);
129build_schema_stmt!(sea_query::IndexCreateStatement);
130build_schema_stmt!(sea_query::IndexDropStatement);
131build_schema_stmt!(sea_query::ForeignKeyCreateStatement);
132build_schema_stmt!(sea_query::ForeignKeyDropStatement);
133
134macro_rules! build_type_stmt {
135    ($stmt: ty) => {
136        impl StatementBuilder for $stmt {
137            fn build(&self, db_backend: &DbBackend) -> Statement {
138                let stmt = build_postgres_stmt!(self, db_backend);
139                Statement::from_string(*db_backend, stmt)
140            }
141        }
142    };
143}
144
145build_type_stmt!(sea_query::extension::postgres::TypeAlterStatement);
146build_type_stmt!(sea_query::extension::postgres::TypeCreateStatement);
147build_type_stmt!(sea_query::extension::postgres::TypeDropStatement);