This commit is contained in:
Chris Tsang 2021-05-07 05:57:51 +08:00
parent 28b82fa6ed
commit 7d99d33aa2
8 changed files with 106 additions and 11 deletions

View File

@ -1,6 +1,7 @@
use async_trait::async_trait; use async_trait::async_trait;
use sqlx::{mysql::MySqlRow, MySqlPool}; use sqlx::{mysql::MySqlRow, MySqlPool};
use sea_query::MysqlQueryBuilder;
sea_query::sea_query_driver_mysql!(); sea_query::sea_query_driver_mysql!();
use sea_query_driver_mysql::bind_query; use sea_query_driver_mysql::bind_query;
@ -12,6 +13,8 @@ pub struct SqlxMySqlExecutor {
#[async_trait] #[async_trait]
impl Executor for SqlxMySqlExecutor { impl Executor for SqlxMySqlExecutor {
type QueryBuilder = MysqlQueryBuilder;
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, ExecErr> { async fn query_one(&self, stmt: Statement) -> Result<QueryResult, ExecErr> {
debug_print!("{}, {:?}", sql, values); debug_print!("{}, {:?}", sql, values);

View File

@ -1,4 +1,5 @@
use super::{Column, Identity, Relation}; use super::{Column, Identity, Relation};
use crate::Select;
use sea_query::Iden; use sea_query::Iden;
use std::fmt::Debug; use std::fmt::Debug;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -10,11 +11,13 @@ pub trait Entity: Iden + Default + Debug {
type Relation: Relation + IntoEnumIterator; type Relation: Relation + IntoEnumIterator;
fn table_name() -> Self;
fn primary_key() -> Identity; fn primary_key() -> Identity;
fn auto_increment() -> bool { fn auto_increment() -> bool {
true true
} }
fn find<'s>() -> Select<'s, Self> {
Select::new(Self::default())
}
} }

View File

@ -11,19 +11,19 @@ pub enum RelationType {
} }
pub trait Relation { pub trait Relation {
fn rel_def() -> RelationDef; fn rel_def(&self) -> RelationDef;
} }
pub struct RelationDef { pub struct RelationDef {
rel_type: RelationType, pub rel_type: RelationType,
from_tbl: Rc<dyn Iden>, pub to_tbl: Rc<dyn Iden>,
from_col: Identity, pub from_col: Identity,
to_col: Identity, pub to_col: Identity,
} }
pub struct RelationBuilder { pub struct RelationBuilder {
rel_type: RelationType, rel_type: RelationType,
from_tbl: Rc<dyn Iden>, to_tbl: Rc<dyn Iden>,
from_col: Option<Identity>, from_col: Option<Identity>,
to_col: Option<Identity>, to_col: Option<Identity>,
} }
@ -56,7 +56,7 @@ impl RelationBuilder {
{ {
Self { Self {
rel_type, rel_type,
from_tbl: entity.into_iden(), to_tbl: entity.into_iden(),
from_col: None, from_col: None,
to_col: None, to_col: None,
} }
@ -83,7 +83,7 @@ impl From<RelationBuilder> for RelationDef {
fn from(b: RelationBuilder) -> Self { fn from(b: RelationBuilder) -> Self {
RelationDef { RelationDef {
rel_type: b.rel_type, rel_type: b.rel_type,
from_tbl: b.from_tbl, to_tbl: b.to_tbl,
from_col: b.from_col.unwrap(), from_col: b.from_col.unwrap(),
to_col: b.to_col.unwrap(), to_col: b.to_col.unwrap(),
} }

View File

@ -1,6 +1,10 @@
mod query;
pub use query::*;
use crate::QueryResult; use crate::QueryResult;
use async_trait::async_trait; use async_trait::async_trait;
use sea_query::Values; use sea_query::{GenericBuilder, Values};
use std::{error::Error, fmt}; use std::{error::Error, fmt};
pub struct Statement { pub struct Statement {
@ -10,6 +14,8 @@ pub struct Statement {
#[async_trait] #[async_trait]
pub trait Executor { pub trait Executor {
type QueryBuilder: GenericBuilder;
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, ExecErr>; async fn query_one(&self, stmt: Statement) -> Result<QueryResult, ExecErr>;
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, ExecErr>; async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, ExecErr>;

1
src/executor/query.rs Normal file
View File

@ -0,0 +1 @@

5
src/query/mod.rs Normal file
View File

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

77
src/query/select.rs Normal file
View File

@ -0,0 +1,77 @@
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 std::rc::Rc;
use strum::IntoEnumIterator;
#[derive(Debug)]
pub struct Select<'s, E: 'static>
where
E: Entity,
{
select: SelectStatement,
entity: PhantomData<&'s E>,
}
impl<E: 'static> Select<'_, E>
where
E: Entity,
{
pub(crate) fn new(_: E) -> Self {
Self {
select: SelectStatement::new(),
entity: PhantomData,
}
.prepare_select()
.prepare_from()
}
fn prepare_select(mut self) -> Self {
let table = E::default().into_iden();
let columns: Vec<(Rc<dyn Iden>, E::Column)> =
E::Column::iter().map(|c| (Rc::clone(&table), c)).collect();
self.select.columns(columns);
self
}
fn prepare_from(mut self) -> Self {
self.select.from(E::default().into_iden());
self
}
fn prepare_join(mut self, join: JoinType, relation: RelationDef) -> Self {
let own_tbl = E::default().into_iden();
let to_tbl = &relation.to_tbl;
let owner_keys = relation.from_col;
let foreign_keys = relation.to_col;
let condition = match (owner_keys, foreign_keys) {
(Identity::Unary(o1), Identity::Unary(f1)) => {
Expr::tbl(Rc::clone(&own_tbl), o1).equals(Rc::clone(to_tbl), f1)
} // _ => panic!("Owner key and foreign key mismatch"),
};
self.select.join(join, Rc::clone(to_tbl), condition);
self
}
pub fn left_join(self, relation: RelationDef) -> Self {
self.prepare_join(JoinType::LeftJoin, relation)
}
pub fn right_join(self, relation: RelationDef) -> Self {
self.prepare_join(JoinType::RightJoin, relation)
}
pub fn inner_join(self, relation: RelationDef) -> Self {
self.prepare_join(JoinType::InnerJoin, relation)
}
pub fn query(&mut self) -> &mut SelectStatement {
&mut self.select
}
pub fn into_query(self) -> SelectStatement {
self.select
}
}