sea_orm/database/
statement.rs1use crate::DbBackend;
2#[cfg(feature = "rbac")]
3pub use sea_query::audit::{AuditTrait, Error as AuditError, QueryAccessAudit};
4use sea_query::{MysqlQueryBuilder, PostgresQueryBuilder, SqliteQueryBuilder, inject_parameters};
5pub use sea_query::{Value, Values};
6use std::fmt;
7
8#[derive(Debug, Clone, PartialEq)]
10pub struct Statement {
11 pub sql: String,
13 pub values: Option<Values>,
15 pub db_backend: DbBackend,
18}
19
20pub trait StatementBuilder: Sync {
22 fn build(&self, db_backend: &DbBackend) -> Statement;
24
25 #[cfg(feature = "rbac")]
26 fn audit(&self) -> Result<QueryAccessAudit, AuditError>;
28}
29
30impl Statement {
31 pub fn from_string<T>(db_backend: DbBackend, stmt: T) -> Statement
33 where
34 T: Into<String>,
35 {
36 Statement {
37 sql: stmt.into(),
38 values: None,
39 db_backend,
40 }
41 }
42
43 pub fn from_sql_and_values<I, T>(db_backend: DbBackend, sql: T, values: I) -> Self
46 where
47 I: IntoIterator<Item = Value>,
48 T: Into<String>,
49 {
50 Self::from_string_values_tuple(db_backend, (sql, Values(values.into_iter().collect())))
51 }
52
53 pub(crate) fn from_string_values_tuple<T>(db_backend: DbBackend, stmt: (T, Values)) -> Statement
54 where
55 T: Into<String>,
56 {
57 Statement {
58 sql: stmt.0.into(),
59 values: Some(stmt.1),
60 db_backend,
61 }
62 }
63}
64
65impl fmt::Display for Statement {
66 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67 match &self.values {
68 Some(values) => {
69 let string = inject_parameters(
70 &self.sql,
71 values.0.clone(),
72 self.db_backend.get_query_builder().as_ref(),
73 );
74 write!(f, "{}", &string)
75 }
76 None => {
77 write!(f, "{}", &self.sql)
78 }
79 }
80 }
81}
82
83macro_rules! build_any_stmt {
84 ($stmt: expr, $db_backend: expr) => {
85 match $db_backend {
86 DbBackend::MySql => $stmt.build(MysqlQueryBuilder),
87 DbBackend::Postgres => $stmt.build(PostgresQueryBuilder),
88 DbBackend::Sqlite => $stmt.build(SqliteQueryBuilder),
89 }
90 };
91}
92
93macro_rules! build_postgres_stmt {
94 ($stmt: expr, $db_backend: expr) => {
95 match $db_backend {
96 DbBackend::Postgres => $stmt.to_string(PostgresQueryBuilder),
97 DbBackend::MySql | DbBackend::Sqlite => unimplemented!(),
98 }
99 };
100}
101
102macro_rules! build_query_stmt {
103 ($stmt: ty) => {
104 impl StatementBuilder for $stmt {
105 fn build(&self, db_backend: &DbBackend) -> Statement {
106 let stmt = build_any_stmt!(self, db_backend);
107 Statement::from_string_values_tuple(*db_backend, stmt)
108 }
109
110 #[cfg(feature = "rbac")]
111 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
112 AuditTrait::audit(self)
113 }
114 }
115 };
116}
117
118build_query_stmt!(sea_query::InsertStatement);
119build_query_stmt!(sea_query::SelectStatement);
120build_query_stmt!(sea_query::UpdateStatement);
121build_query_stmt!(sea_query::DeleteStatement);
122build_query_stmt!(sea_query::WithQuery);
123
124macro_rules! build_schema_stmt {
125 ($stmt: ty) => {
126 impl StatementBuilder for $stmt {
127 fn build(&self, db_backend: &DbBackend) -> Statement {
128 let stmt = build_any_stmt!(self, db_backend);
129 Statement::from_string(*db_backend, stmt)
130 }
131
132 #[cfg(feature = "rbac")]
133 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
134 todo!("Audit not supported for {} yet", stringify!($stmt))
135 }
136 }
137 };
138}
139
140build_schema_stmt!(sea_query::TableCreateStatement);
141build_schema_stmt!(sea_query::TableDropStatement);
142build_schema_stmt!(sea_query::TableAlterStatement);
143build_schema_stmt!(sea_query::TableRenameStatement);
144build_schema_stmt!(sea_query::TableTruncateStatement);
145build_schema_stmt!(sea_query::IndexCreateStatement);
146build_schema_stmt!(sea_query::IndexDropStatement);
147build_schema_stmt!(sea_query::ForeignKeyCreateStatement);
148build_schema_stmt!(sea_query::ForeignKeyDropStatement);
149
150macro_rules! build_type_stmt {
151 ($stmt: ty) => {
152 impl StatementBuilder for $stmt {
153 fn build(&self, db_backend: &DbBackend) -> Statement {
154 let stmt = build_postgres_stmt!(self, db_backend);
155 Statement::from_string(*db_backend, stmt)
156 }
157
158 #[cfg(feature = "rbac")]
159 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
160 todo!("Audit not supported for {} yet", stringify!($stmt))
161 }
162 }
163 };
164}
165
166build_type_stmt!(sea_query::extension::postgres::TypeAlterStatement);
167build_type_stmt!(sea_query::extension::postgres::TypeCreateStatement);
168build_type_stmt!(sea_query::extension::postgres::TypeDropStatement);