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)]
14pub struct Statement {
15 pub sql: String,
17 pub values: Option<Values>,
20 pub db_backend: DbBackend,
23}
24
25pub trait StatementBuilder {
32 fn build(&self, db_backend: &DbBackend) -> Statement;
34
35 #[cfg(feature = "rbac")]
36 fn audit(&self) -> Result<QueryAccessAudit, AuditError>;
39}
40
41impl Statement {
42 pub fn from_string<T>(db_backend: DbBackend, stmt: T) -> Statement
44 where
45 T: Into<String>,
46 {
47 Statement {
48 sql: stmt.into(),
49 values: None,
50 db_backend,
51 }
52 }
53
54 pub fn from_sql_and_values<I, T>(db_backend: DbBackend, sql: T, values: I) -> Self
57 where
58 I: IntoIterator<Item = Value>,
59 T: Into<String>,
60 {
61 Self::from_string_values_tuple(db_backend, (sql, Values(values.into_iter().collect())))
62 }
63
64 pub(crate) fn from_string_values_tuple<T>(db_backend: DbBackend, stmt: (T, Values)) -> Statement
65 where
66 T: Into<String>,
67 {
68 Statement {
69 sql: stmt.0.into(),
70 values: Some(stmt.1),
71 db_backend,
72 }
73 }
74}
75
76impl fmt::Display for Statement {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 match &self.values {
79 Some(values) => {
80 let string = match self.db_backend {
81 DbBackend::MySql => inject_parameters(&self.sql, &values.0, &MysqlQueryBuilder),
82 DbBackend::Postgres => {
83 inject_parameters(&self.sql, &values.0, &PostgresQueryBuilder)
84 }
85 DbBackend::Sqlite => {
86 inject_parameters(&self.sql, &values.0, &SqliteQueryBuilder)
87 }
88 };
89 write!(f, "{}", &string)
90 }
91 None => {
92 write!(f, "{}", &self.sql)
93 }
94 }
95 }
96}
97
98macro_rules! build_any_stmt {
99 ($stmt: expr, $db_backend: expr) => {
100 match $db_backend {
101 DbBackend::MySql => $stmt.build(MysqlQueryBuilder),
102 DbBackend::Postgres => $stmt.build(PostgresQueryBuilder),
103 DbBackend::Sqlite => $stmt.build(SqliteQueryBuilder),
104 }
105 };
106}
107
108macro_rules! build_postgres_stmt {
109 ($stmt: expr, $db_backend: expr) => {
110 match $db_backend {
111 DbBackend::Postgres => $stmt.to_string(PostgresQueryBuilder),
112 DbBackend::MySql | DbBackend::Sqlite => unimplemented!(),
113 }
114 };
115}
116
117macro_rules! build_query_stmt {
118 ($stmt: ty) => {
119 impl StatementBuilder for $stmt {
120 fn build(&self, db_backend: &DbBackend) -> Statement {
121 let stmt = build_any_stmt!(self, db_backend);
122 Statement::from_string_values_tuple(*db_backend, stmt)
123 }
124
125 #[cfg(feature = "rbac")]
126 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
127 AuditTrait::audit(self)
128 }
129 }
130 };
131}
132
133build_query_stmt!(sea_query::InsertStatement);
134build_query_stmt!(sea_query::SelectStatement);
135build_query_stmt!(sea_query::UpdateStatement);
136build_query_stmt!(sea_query::DeleteStatement);
137build_query_stmt!(sea_query::WithQuery);
138
139macro_rules! build_schema_stmt {
140 ($stmt: ty) => {
141 impl StatementBuilder for $stmt {
142 fn build(&self, db_backend: &DbBackend) -> Statement {
143 let stmt = build_any_stmt!(self, db_backend);
144 Statement::from_string(*db_backend, stmt)
145 }
146
147 #[cfg(feature = "rbac")]
148 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
149 todo!("Audit not supported for {} yet", stringify!($stmt))
150 }
151 }
152 };
153}
154
155build_schema_stmt!(sea_query::TableCreateStatement);
156build_schema_stmt!(sea_query::TableDropStatement);
157build_schema_stmt!(sea_query::TableAlterStatement);
158build_schema_stmt!(sea_query::TableRenameStatement);
159build_schema_stmt!(sea_query::TableTruncateStatement);
160build_schema_stmt!(sea_query::IndexCreateStatement);
161build_schema_stmt!(sea_query::IndexDropStatement);
162build_schema_stmt!(sea_query::ForeignKeyCreateStatement);
163build_schema_stmt!(sea_query::ForeignKeyDropStatement);
164
165macro_rules! build_type_stmt {
166 ($stmt: ty) => {
167 impl StatementBuilder for $stmt {
168 fn build(&self, db_backend: &DbBackend) -> Statement {
169 let stmt = build_postgres_stmt!(self, db_backend);
170 Statement::from_string(*db_backend, stmt)
171 }
172
173 #[cfg(feature = "rbac")]
174 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
175 Err(AuditError::UnsupportedQuery)
176 }
177 }
178 };
179}
180
181build_type_stmt!(sea_query::extension::postgres::TypeAlterStatement);
182build_type_stmt!(sea_query::extension::postgres::TypeCreateStatement);
183build_type_stmt!(sea_query::extension::postgres::TypeDropStatement);