DatabaseConnection

This commit is contained in:
Chris Tsang 2021-05-07 15:09:07 +08:00
parent 7d99d33aa2
commit 6ffed93b46
11 changed files with 181 additions and 79 deletions

View File

@ -24,7 +24,7 @@ path = "src/lib.rs"
async-trait = "^0.1"
async-std = { version = "^1.9", features = [ "attributes" ] }
futures = { version = "^0.3" }
sea-query = { version = "^0.10", features = [ "sqlx-mysql" ] }
sea-query = { path = "../sea-query", version = "^0.10", features = [ "sqlx-mysql" ] }
# sea-schema = { path = "../sea-schema" }
serde = { version = "^1.0", features = [ "derive" ] }
sqlx = { version = "^0.5", features = [ "runtime-async-std-native-tls", "mysql", "any", "chrono", "time", "bigdecimal", "decimal", "uuid", "json" ] }

68
src/connector/mod.rs Normal file
View File

@ -0,0 +1,68 @@
use crate::{DatabaseConnection, QueryResult};
use async_trait::async_trait;
use sea_query::{inject_parameters, MySqlQueryBuilder, Values};
use std::{error::Error, fmt};
pub struct Statement {
pub sql: String,
pub values: Values,
}
#[async_trait]
pub trait Connector {
fn accepts(string: &str) -> bool;
async fn connect(string: &str) -> Result<DatabaseConnection, ConnectionErr>;
}
#[async_trait]
pub trait Connection {
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, QueryErr>;
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, QueryErr>;
}
#[derive(Debug)]
pub struct QueryErr;
#[derive(Debug)]
pub struct ConnectionErr;
// Statement //
impl From<(String, Values)> for Statement {
fn from(stmt: (String, Values)) -> Statement {
Statement {
sql: stmt.0,
values: stmt.1,
}
}
}
impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let builder = MySqlQueryBuilder::default();
let string = inject_parameters(&self.sql, self.values.0.clone(), &builder);
write!(f, "{}", &string)
}
}
// QueryErr //
impl Error for QueryErr {}
impl fmt::Display for QueryErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
// ConnectionErr //
impl Error for ConnectionErr {}
impl fmt::Display for ConnectionErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}

51
src/database/mod.rs Normal file
View File

@ -0,0 +1,51 @@
use crate::{Connection, ConnectionErr, Connector, SqlxMySqlConnector, SqlxMySqlPoolConnection};
#[derive(Debug, Default)]
pub struct Database {
connection: DatabaseConnection,
}
pub enum DatabaseConnection {
SqlxMySqlPoolConnection(SqlxMySqlPoolConnection),
Disconnected,
}
// DatabaseConnection //
impl Default for DatabaseConnection {
fn default() -> Self {
Self::Disconnected
}
}
impl std::fmt::Debug for DatabaseConnection {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::SqlxMySqlPoolConnection(_) => "SqlxMySqlPoolConnection",
Self::Disconnected => "Disconnected",
}
)
}
}
// Database //
impl Database {
pub async fn connect(&mut self, string: &str) -> Result<(), ConnectionErr> {
if SqlxMySqlConnector::accepts(string) {
self.connection = SqlxMySqlConnector::connect(string).await?;
return Ok(());
}
Err(ConnectionErr)
}
pub fn get_connection(&self) -> impl Connection + '_ {
match &self.connection {
DatabaseConnection::SqlxMySqlPoolConnection(conn) => conn,
DatabaseConnection::Disconnected => panic!("Disconnected"),
}
}
}

View File

@ -1 +1,3 @@
pub mod sqlx_mysql;
mod sqlx_mysql;
pub use sqlx_mysql::*;

View File

@ -1,47 +1,59 @@
use async_trait::async_trait;
use sqlx::{mysql::MySqlRow, MySqlPool};
use sea_query::MysqlQueryBuilder;
sea_query::sea_query_driver_mysql!();
use sea_query_driver_mysql::bind_query;
use crate::{debug_print, executor::*, query::*};
use crate::{connector::*, debug_print, query::*, DatabaseConnection};
pub struct SqlxMySqlExecutor {
pub struct SqlxMySqlConnector;
pub struct SqlxMySqlPoolConnection {
pool: MySqlPool,
}
#[async_trait]
impl Executor for SqlxMySqlExecutor {
type QueryBuilder = MysqlQueryBuilder;
impl Connector for SqlxMySqlConnector {
fn accepts(string: &str) -> bool {
string.starts_with("mysql://")
}
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, ExecErr> {
debug_print!("{}, {:?}", sql, values);
async fn connect(string: &str) -> Result<DatabaseConnection, ConnectionErr> {
if let Ok(conn) = MySqlPool::connect(string).await {
Ok(DatabaseConnection::SqlxMySqlPoolConnection(
SqlxMySqlPoolConnection { pool: conn },
))
} else {
Err(ConnectionErr)
}
}
}
#[async_trait]
impl Connection for &SqlxMySqlPoolConnection {
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, QueryErr> {
debug_print!("{}", stmt);
let query = bind_query(sqlx::query(&stmt.sql), &stmt.values);
if let Ok(row) = query
.fetch_one(&mut self.pool.acquire().await.unwrap())
.await
{
Ok(row.into())
} else {
Err(ExecErr)
if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(row) = query.fetch_one(conn).await {
return Ok(row.into());
}
}
Err(QueryErr)
}
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, ExecErr> {
debug_print!("{}, {:?}", sql, values);
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, QueryErr> {
debug_print!("{}", stmt);
let query = bind_query(sqlx::query(&stmt.sql), &stmt.values);
if let Ok(rows) = query
.fetch_all(&mut self.pool.acquire().await.unwrap())
.await
{
Ok(rows.into_iter().map(|r| r.into()).collect())
} else {
Err(ExecErr)
if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(rows) = query.fetch_all(conn).await {
return Ok(rows.into_iter().map(|r| r.into()).collect());
}
}
Err(QueryErr)
}
}
impl From<MySqlRow> for QueryResult {

View File

@ -1,44 +0,0 @@
mod query;
pub use query::*;
use crate::QueryResult;
use async_trait::async_trait;
use sea_query::{GenericBuilder, Values};
use std::{error::Error, fmt};
pub struct Statement {
pub sql: String,
pub values: Values,
}
#[async_trait]
pub trait Executor {
type QueryBuilder: GenericBuilder;
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, ExecErr>;
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, ExecErr>;
}
#[derive(Debug)]
pub struct ExecErr;
// ----- //
impl From<(String, Values)> for Statement {
fn from(stmt: (String, Values)) -> Statement {
Statement {
sql: stmt.0,
values: stmt.1,
}
}
}
impl Error for ExecErr {}
impl fmt::Display for ExecErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}

View File

@ -1 +0,0 @@

View File

@ -1,10 +1,12 @@
mod connector;
mod database;
mod driver;
mod entity;
mod executor;
mod query;
mod util;
pub use connector::*;
pub use database::*;
pub use driver::*;
pub use entity::*;
pub use executor::*;
pub use query::*;

View File

@ -1,5 +1,5 @@
mod result;
mod select;
mod types;
pub use result::*;
pub use select::*;
pub use types::*;

View File

@ -1,8 +1,9 @@
use crate::Statement;
use crate::{entity::*, RelationDef};
use core::fmt::Debug;
use core::marker::PhantomData;
pub use sea_query::JoinType;
use sea_query::{Expr, Iden, IntoIden, SelectStatement};
use sea_query::{Expr, Iden, IntoIden, QueryBuilder, SelectStatement};
use std::rc::Rc;
use strum::IntoEnumIterator;
@ -71,7 +72,18 @@ where
&mut self.select
}
pub fn as_query(&self) -> &SelectStatement {
&self.select
}
pub fn into_query(self) -> SelectStatement {
self.select
}
pub fn build<B>(&self, builder: B) -> Statement
where
B: QueryBuilder,
{
self.as_query().build(builder).into()
}
}