diff --git a/src/driver/sqlx_mysql.rs b/src/driver/sqlx_mysql.rs index c4de4d5e..eee999d0 100644 --- a/src/driver/sqlx_mysql.rs +++ b/src/driver/sqlx_mysql.rs @@ -1,6 +1,7 @@ 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; @@ -12,6 +13,8 @@ pub struct SqlxMySqlExecutor { #[async_trait] impl Executor for SqlxMySqlExecutor { + type QueryBuilder = MysqlQueryBuilder; + async fn query_one(&self, stmt: Statement) -> Result { debug_print!("{}, {:?}", sql, values); diff --git a/src/entity/base.rs b/src/entity/base.rs index 6fdf8720..a3162103 100644 --- a/src/entity/base.rs +++ b/src/entity/base.rs @@ -1,4 +1,5 @@ use super::{Column, Identity, Relation}; +use crate::Select; use sea_query::Iden; use std::fmt::Debug; use strum::IntoEnumIterator; @@ -10,11 +11,13 @@ pub trait Entity: Iden + Default + Debug { type Relation: Relation + IntoEnumIterator; - fn table_name() -> Self; - fn primary_key() -> Identity; fn auto_increment() -> bool { true } + + fn find<'s>() -> Select<'s, Self> { + Select::new(Self::default()) + } } diff --git a/src/entity/relation.rs b/src/entity/relation.rs index d1268919..a97972fb 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -11,19 +11,19 @@ pub enum RelationType { } pub trait Relation { - fn rel_def() -> RelationDef; + fn rel_def(&self) -> RelationDef; } pub struct RelationDef { - rel_type: RelationType, - from_tbl: Rc, - from_col: Identity, - to_col: Identity, + pub rel_type: RelationType, + pub to_tbl: Rc, + pub from_col: Identity, + pub to_col: Identity, } pub struct RelationBuilder { rel_type: RelationType, - from_tbl: Rc, + to_tbl: Rc, from_col: Option, to_col: Option, } @@ -56,7 +56,7 @@ impl RelationBuilder { { Self { rel_type, - from_tbl: entity.into_iden(), + to_tbl: entity.into_iden(), from_col: None, to_col: None, } @@ -83,7 +83,7 @@ impl From for RelationDef { fn from(b: RelationBuilder) -> Self { RelationDef { rel_type: b.rel_type, - from_tbl: b.from_tbl, + to_tbl: b.to_tbl, from_col: b.from_col.unwrap(), to_col: b.to_col.unwrap(), } diff --git a/src/executor.rs b/src/executor/mod.rs similarity index 87% rename from src/executor.rs rename to src/executor/mod.rs index 49df09b8..88e549bb 100644 --- a/src/executor.rs +++ b/src/executor/mod.rs @@ -1,6 +1,10 @@ +mod query; + +pub use query::*; + use crate::QueryResult; use async_trait::async_trait; -use sea_query::Values; +use sea_query::{GenericBuilder, Values}; use std::{error::Error, fmt}; pub struct Statement { @@ -10,6 +14,8 @@ pub struct Statement { #[async_trait] pub trait Executor { + type QueryBuilder: GenericBuilder; + async fn query_one(&self, stmt: Statement) -> Result; async fn query_all(&self, stmt: Statement) -> Result, ExecErr>; diff --git a/src/executor/query.rs b/src/executor/query.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/executor/query.rs @@ -0,0 +1 @@ + diff --git a/src/query/mod.rs b/src/query/mod.rs new file mode 100644 index 00000000..b44778cd --- /dev/null +++ b/src/query/mod.rs @@ -0,0 +1,5 @@ +mod select; +mod types; + +pub use select::*; +pub use types::*; diff --git a/src/query/select.rs b/src/query/select.rs new file mode 100644 index 00000000..783a2bcd --- /dev/null +++ b/src/query/select.rs @@ -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 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, 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 + } +} diff --git a/src/query.rs b/src/query/types.rs similarity index 100% rename from src/query.rs rename to src/query/types.rs