WIP add loader skeleton
This commit is contained in:
parent
9e77760376
commit
f87f6a8e71
161
src/entity/loader.rs
Normal file
161
src/entity/loader.rs
Normal file
@ -0,0 +1,161 @@
|
||||
use crate::{DbErr, EntityTrait, ModelTrait, QueryFilter, Select, Related, RelationType, Identity, Condition, Value, ColumnTrait, ConnectionTrait};
|
||||
use std::{fmt::Debug, str::FromStr, collections::BTreeMap};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait LoaderTrait {
|
||||
type Model: ModelTrait;
|
||||
|
||||
async fn load_one<R, C>(&self, db: &C) -> Result<Vec<Option<R::Model>>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait,
|
||||
R: EntityTrait,
|
||||
R::Model: Send + Sync,
|
||||
<<R as EntityTrait>::Column as FromStr>::Err: Debug,
|
||||
<<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
|
||||
<<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::Err: Debug;
|
||||
|
||||
async fn load_many<R, C>(&self, db: &C) -> Result<Vec<Vec<R::Model>>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait,
|
||||
R: EntityTrait,
|
||||
R::Model: Send + Sync,
|
||||
<<R as EntityTrait>::Column as FromStr>::Err: Debug,
|
||||
<<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
|
||||
<<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::Err: Debug;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<M> LoaderTrait for Vec<M>
|
||||
where
|
||||
M: ModelTrait,
|
||||
Vec<M>: Sync,
|
||||
{
|
||||
type Model = M;
|
||||
|
||||
async fn load_one<R, C>(&self, db: &C) -> Result<Vec<Option<R::Model>>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait,
|
||||
R: EntityTrait,
|
||||
R::Model: Send + Sync,
|
||||
<<R as EntityTrait>::Column as FromStr>::Err: Debug,
|
||||
<<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
|
||||
<<<M as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::Err: Debug,
|
||||
{
|
||||
let rel_def =
|
||||
<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as Related<R>>::to();
|
||||
|
||||
// we verify that is has_one relation
|
||||
match (&rel_def).rel_type {
|
||||
RelationType::HasOne => (),
|
||||
RelationType::HasMany => {
|
||||
return Err(DbErr::Type("Relation is HasMany instead of HasOne".into()))
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_key<Model>(target_col: &Identity, model: &Model) -> Vec<Value>
|
||||
where
|
||||
Model: ModelTrait,
|
||||
<<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::Err: Debug,
|
||||
{
|
||||
match target_col {
|
||||
Identity::Unary(a) => {
|
||||
let column_a = <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap();
|
||||
vec![model.get(column_a)]
|
||||
},
|
||||
Identity::Binary(a, b) => {
|
||||
let column_a = <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap();
|
||||
let column_b = <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&b.to_string()).unwrap();
|
||||
vec![model.get(column_a), model.get(column_b)]
|
||||
},
|
||||
Identity::Ternary(a, b, c) => {
|
||||
let column_a = <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap();
|
||||
let column_b = <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&b.to_string()).unwrap();
|
||||
let column_c = <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&c.to_string()).unwrap();
|
||||
vec![model.get(column_a), model.get(column_b), model.get(column_c)]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let keys: Vec<Vec<Value>> = self
|
||||
.iter()
|
||||
.map(|model: &M| {
|
||||
extract_key(&rel_def.from_col, model)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let condition = match &rel_def.to_col {
|
||||
Identity::Unary(a) => {
|
||||
let column_a: <M::Entity as EntityTrait>::Column = <<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap();
|
||||
Condition::all().add(ColumnTrait::is_in(
|
||||
&column_a,
|
||||
keys.iter().map(|key| key[0].clone()).collect::<Vec<Value>>(),
|
||||
))
|
||||
}
|
||||
Identity::Binary(a, b) => {
|
||||
let column_a: <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column = <<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap();
|
||||
let column_b: <<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column = <<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&b.to_string()).unwrap();
|
||||
// TODO
|
||||
// Condition::all().add(
|
||||
// sea_query::Expr::tuple([column_a.to_string(), column_b]).is_in(keys.iter().map(|key| (key[0].clone(), key[1].clone())).collect::<Vec<(Value, Value)>>())
|
||||
// )
|
||||
// TODO
|
||||
Condition::all().add(ColumnTrait::is_in(
|
||||
&column_a,
|
||||
keys.iter().map(|key| key[0].clone()).collect::<Vec<Value>>(),
|
||||
))
|
||||
}
|
||||
Identity::Ternary(a, b, c) => {
|
||||
let column_a = <<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap();
|
||||
let column_b = <<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&b.to_string()).unwrap();
|
||||
let column_c = <<<<Self as LoaderTrait>::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(&c.to_string()).unwrap();
|
||||
// TODO
|
||||
Condition::all().add(ColumnTrait::is_in(
|
||||
&column_a,
|
||||
keys.iter().map(|key| key[0].clone()).collect::<Vec<Value>>(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let stmt = <R as EntityTrait>::find();
|
||||
|
||||
let stmt = <Select<R> as QueryFilter>::filter(stmt, condition);
|
||||
|
||||
let data = stmt.all(db).await?;
|
||||
|
||||
let mut hashmap: BTreeMap::<String, <R as EntityTrait>::Model> = data
|
||||
.into_iter()
|
||||
.fold(BTreeMap::<String, <R as EntityTrait>::Model>::new(), |mut acc: BTreeMap::<String, <R as EntityTrait>::Model>, value: <R as EntityTrait>::Model| {
|
||||
{
|
||||
let key = extract_key(&rel_def.to_col, &value);
|
||||
|
||||
acc.insert(format!("{:?}", key), value);
|
||||
}
|
||||
|
||||
acc
|
||||
});
|
||||
|
||||
let result: Vec<Option<<R as EntityTrait>::Model>> = keys
|
||||
.iter()
|
||||
.map(|key| {
|
||||
let model = hashmap.remove(&format!("{:?}", key));
|
||||
|
||||
model
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn load_many<R, C>(&self, db: &C) -> Result<Vec<Vec<R::Model>>, DbErr>
|
||||
where
|
||||
C: ConnectionTrait,
|
||||
R: EntityTrait,
|
||||
R::Model: Send + Sync,
|
||||
<<R as EntityTrait>::Column as FromStr>::Err: Debug,
|
||||
<<Self as LoaderTrait>::Model as ModelTrait>::Entity: Related<R>,
|
||||
<<<M as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::Err: Debug,
|
||||
{
|
||||
// we should verify this is a has_many relation
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
@ -106,6 +106,7 @@ mod model;
|
||||
pub mod prelude;
|
||||
mod primary_key;
|
||||
mod relation;
|
||||
mod loader;
|
||||
|
||||
pub use active_enum::*;
|
||||
pub use active_model::*;
|
||||
@ -117,3 +118,4 @@ pub use model::*;
|
||||
// pub use prelude::*;
|
||||
pub use primary_key::*;
|
||||
pub use relation::*;
|
||||
pub use loader::*;
|
||||
|
Loading…
x
Reference in New Issue
Block a user