Execute unprepared statement (#1327)

This commit is contained in:
Billy Chan 2023-01-05 14:08:18 +08:00 committed by GitHub
parent d332afa99c
commit e927a0e5f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 148 additions and 1 deletions

View File

@ -15,6 +15,9 @@ pub trait ConnectionTrait: Sync {
/// Execute a [Statement]
async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr>;
/// Execute a unprepared [Statement]
async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr>;
/// Execute a [Statement] and return a query
async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr>;

View File

@ -122,6 +122,32 @@ impl ConnectionTrait for DatabaseConnection {
}
}
#[instrument(level = "trace")]
#[allow(unused_variables)]
async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
match self {
#[cfg(feature = "sqlx-mysql")]
DatabaseConnection::SqlxMySqlPoolConnection(conn) => conn.execute_unprepared(sql).await,
#[cfg(feature = "sqlx-postgres")]
DatabaseConnection::SqlxPostgresPoolConnection(conn) => {
conn.execute_unprepared(sql).await
}
#[cfg(feature = "sqlx-sqlite")]
DatabaseConnection::SqlxSqlitePoolConnection(conn) => {
conn.execute_unprepared(sql).await
}
#[cfg(feature = "mock")]
DatabaseConnection::MockDatabaseConnection(conn) => {
let db_backend = conn.get_database_backend();
let stmt = Statement::from_string(db_backend, sql.into());
conn.execute(stmt)
}
DatabaseConnection::Disconnected => {
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
}
}
}
#[instrument(level = "trace")]
#[allow(unused_variables)]
async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {

View File

@ -330,6 +330,38 @@ impl ConnectionTrait for DatabaseTransaction {
}
}
#[instrument(level = "trace")]
#[allow(unused_variables)]
async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
debug_print!("{}", sql);
match &mut *self.conn.lock().await {
#[cfg(feature = "sqlx-mysql")]
InnerConnection::MySql(conn) => sqlx::Executor::execute(conn, sql)
.await
.map(Into::into)
.map_err(sqlx_error_to_exec_err),
#[cfg(feature = "sqlx-postgres")]
InnerConnection::Postgres(conn) => sqlx::Executor::execute(conn, sql)
.await
.map(Into::into)
.map_err(sqlx_error_to_exec_err),
#[cfg(feature = "sqlx-sqlite")]
InnerConnection::Sqlite(conn) => sqlx::Executor::execute(conn, sql)
.await
.map(Into::into)
.map_err(sqlx_error_to_exec_err),
#[cfg(feature = "mock")]
InnerConnection::Mock(conn) => {
let db_backend = conn.get_database_backend();
let stmt = Statement::from_string(db_backend, sql.into());
conn.execute(stmt)
}
#[allow(unreachable_patterns)]
_ => unreachable!(),
}
}
#[instrument(level = "trace")]
#[allow(unused_variables)]
async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {

View File

@ -94,6 +94,21 @@ impl SqlxMySqlPoolConnection {
}
}
/// Execute an unprepared SQL statement on a MySQL backend
#[instrument(level = "trace")]
pub async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
debug_print!("{}", sql);
if let Ok(conn) = &mut self.pool.acquire().await {
match conn.execute(sql).await {
Ok(res) => Ok(res.into()),
Err(err) => Err(sqlx_error_to_exec_err(err)),
}
} else {
Err(DbErr::ConnectionAcquire)
}
}
/// Get one result from a SQL query. Returns [Option::None] if no match was found
#[instrument(level = "trace")]
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {

View File

@ -109,6 +109,21 @@ impl SqlxPostgresPoolConnection {
}
}
/// Execute an unprepared SQL statement on a PostgreSQL backend
#[instrument(level = "trace")]
pub async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
debug_print!("{}", sql);
if let Ok(conn) = &mut self.pool.acquire().await {
match conn.execute(sql).await {
Ok(res) => Ok(res.into()),
Err(err) => Err(sqlx_error_to_exec_err(err)),
}
} else {
Err(DbErr::ConnectionAcquire)
}
}
/// Get one result from a SQL query. Returns [Option::None] if no match was found
#[instrument(level = "trace")]
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {

View File

@ -4,7 +4,7 @@ use std::{future::Future, pin::Pin, sync::Arc};
use sqlx::{
pool::PoolConnection,
sqlite::{SqliteConnectOptions, SqliteQueryResult, SqliteRow},
Sqlite, SqlitePool,
Executor, Sqlite, SqlitePool,
};
use sea_query_binder::SqlxValues;
@ -101,6 +101,21 @@ impl SqlxSqlitePoolConnection {
}
}
/// Execute an unprepared SQL statement on a SQLite backend
#[instrument(level = "trace")]
pub async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
debug_print!("{}", sql);
if let Ok(conn) = &mut self.pool.acquire().await {
match conn.execute(sql).await {
Ok(res) => Ok(res.into()),
Err(err) => Err(sqlx_error_to_exec_err(err)),
}
} else {
Err(DbErr::ConnectionAcquire)
}
}
/// Get one result from a SQL query. Returns [Option::None] if no match was found
#[instrument(level = "trace")]
pub async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {

View File

@ -0,0 +1,41 @@
pub mod common;
pub use common::{features::*, setup::*, TestContext};
use pretty_assertions::assert_eq;
use sea_orm::{entity::prelude::*, ConnectionTrait, DatabaseConnection};
#[sea_orm_macros::test]
#[cfg(any(
feature = "sqlx-mysql",
feature = "sqlx-sqlite",
feature = "sqlx-postgres"
))]
async fn main() -> Result<(), DbErr> {
let ctx = TestContext::new("execute_unprepared_tests").await;
create_tables(&ctx.db).await?;
execute_unprepared(&ctx.db).await?;
ctx.delete().await;
Ok(())
}
pub async fn execute_unprepared(db: &DatabaseConnection) -> Result<(), DbErr> {
use insert_default::*;
db.execute_unprepared(
[
"INSERT INTO insert_default VALUES (1), (2), (3), (4), (5)",
"DELETE FROM insert_default WHERE id % 2 = 0",
]
.join(";")
.as_str(),
)
.await?;
assert_eq!(
Entity::find().all(db).await?,
vec![Model { id: 1 }, Model { id: 3 }, Model { id: 5 },]
);
Ok(())
}