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 {
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 = match self.db_backend {
70 DbBackend::MySql => inject_parameters(&self.sql, &values.0, &MysqlQueryBuilder),
71 DbBackend::Postgres => {
72 inject_parameters(&self.sql, &values.0, &PostgresQueryBuilder)
73 }
74 DbBackend::Sqlite => {
75 inject_parameters(&self.sql, &values.0, &SqliteQueryBuilder)
76 }
77 };
78 write!(f, "{}", &string)
79 }
80 None => {
81 write!(f, "{}", &self.sql)
82 }
83 }
84 }
85}
86
87macro_rules! build_any_stmt {
88 ($stmt: expr, $db_backend: expr) => {
89 match $db_backend {
90 DbBackend::MySql => $stmt.build(MysqlQueryBuilder),
91 DbBackend::Postgres => $stmt.build(PostgresQueryBuilder),
92 DbBackend::Sqlite => $stmt.build(SqliteQueryBuilder),
93 }
94 };
95}
96
97macro_rules! build_postgres_stmt {
98 ($stmt: expr, $db_backend: expr) => {
99 match $db_backend {
100 DbBackend::Postgres => $stmt.to_string(PostgresQueryBuilder),
101 DbBackend::MySql | DbBackend::Sqlite => unimplemented!(),
102 }
103 };
104}
105
106macro_rules! build_query_stmt {
107 ($stmt: ty) => {
108 impl StatementBuilder for $stmt {
109 fn build(&self, db_backend: &DbBackend) -> Statement {
110 let stmt = build_any_stmt!(self, db_backend);
111 Statement::from_string_values_tuple(*db_backend, stmt)
112 }
113
114 #[cfg(feature = "rbac")]
115 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
116 AuditTrait::audit(self)
117 }
118 }
119 };
120}
121
122build_query_stmt!(sea_query::InsertStatement);
123build_query_stmt!(sea_query::SelectStatement);
124build_query_stmt!(sea_query::UpdateStatement);
125build_query_stmt!(sea_query::DeleteStatement);
126build_query_stmt!(sea_query::WithQuery);
127
128macro_rules! build_schema_stmt {
129 ($stmt: ty) => {
130 impl StatementBuilder for $stmt {
131 fn build(&self, db_backend: &DbBackend) -> Statement {
132 let stmt = build_any_stmt!(self, db_backend);
133 Statement::from_string(*db_backend, stmt)
134 }
135
136 #[cfg(feature = "rbac")]
137 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
138 todo!("Audit not supported for {} yet", stringify!($stmt))
139 }
140 }
141 };
142}
143
144build_schema_stmt!(sea_query::TableCreateStatement);
145build_schema_stmt!(sea_query::TableDropStatement);
146build_schema_stmt!(sea_query::TableAlterStatement);
147build_schema_stmt!(sea_query::TableRenameStatement);
148build_schema_stmt!(sea_query::TableTruncateStatement);
149build_schema_stmt!(sea_query::IndexCreateStatement);
150build_schema_stmt!(sea_query::IndexDropStatement);
151build_schema_stmt!(sea_query::ForeignKeyCreateStatement);
152build_schema_stmt!(sea_query::ForeignKeyDropStatement);
153
154macro_rules! build_type_stmt {
155 ($stmt: ty) => {
156 impl StatementBuilder for $stmt {
157 fn build(&self, db_backend: &DbBackend) -> Statement {
158 let stmt = build_postgres_stmt!(self, db_backend);
159 Statement::from_string(*db_backend, stmt)
160 }
161
162 #[cfg(feature = "rbac")]
163 fn audit(&self) -> Result<QueryAccessAudit, AuditError> {
164 Err(AuditError::UnsupportedQuery)
165 }
166 }
167 };
168}
169
170build_type_stmt!(sea_query::extension::postgres::TypeAlterStatement);
171build_type_stmt!(sea_query::extension::postgres::TypeCreateStatement);
172build_type_stmt!(sea_query::extension::postgres::TypeDropStatement);