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(&self, db: &C) -> Result>, DbErr> where C: ConnectionTrait, R: EntityTrait, R::Model: Send + Sync, <::Column as FromStr>::Err: Debug, <::Model as ModelTrait>::Entity: Related, <<<::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::Err: Debug; async fn load_many(&self, db: &C) -> Result>, DbErr> where C: ConnectionTrait, R: EntityTrait, R::Model: Send + Sync, <::Column as FromStr>::Err: Debug, <::Model as ModelTrait>::Entity: Related, <<<::Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::Err: Debug; } #[async_trait::async_trait] impl LoaderTrait for Vec where M: ModelTrait, Vec: Sync, { type Model = M; async fn load_one(&self, db: &C) -> Result>, DbErr> where C: ConnectionTrait, R: EntityTrait, R::Model: Send + Sync, <::Column as FromStr>::Err: Debug, <::Model as ModelTrait>::Entity: Related, <<::Entity as EntityTrait>::Column as FromStr>::Err: Debug, { let rel_def = <<::Model as ModelTrait>::Entity as Related>::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(target_col: &Identity, model: &Model) -> Vec where Model: ModelTrait, <<::Entity as EntityTrait>::Column as FromStr>::Err: Debug, { match target_col { Identity::Unary(a) => { let column_a = <<::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap(); vec![model.get(column_a)] }, Identity::Binary(a, b) => { let column_a = <<::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap(); let column_b = <<::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 = <<::Entity as EntityTrait>::Column as FromStr>::from_str(&a.to_string()).unwrap(); let column_b = <<::Entity as EntityTrait>::Column as FromStr>::from_str(&b.to_string()).unwrap(); let column_c = <<::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> = 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: ::Column = <<<::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::>(), )) } Identity::Binary(a, b) => { let column_a: <<::Model as ModelTrait>::Entity as EntityTrait>::Column = <<<::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 = <<<::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::>()) // ) // TODO Condition::all().add(ColumnTrait::is_in( &column_a, keys.iter().map(|key| key[0].clone()).collect::>(), )) } 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(); // TODO Condition::all().add(ColumnTrait::is_in( &column_a, keys.iter().map(|key| key[0].clone()).collect::>(), )) } }; let stmt = ::find(); let stmt = as QueryFilter>::filter(stmt, condition); let data = stmt.all(db).await?; let mut hashmap: BTreeMap::::Model> = data .into_iter() .fold(BTreeMap::::Model>::new(), |mut acc: BTreeMap::::Model>, value: ::Model| { { let key = extract_key(&rel_def.to_col, &value); acc.insert(format!("{:?}", key), value); } acc }); let result: Vec::Model>> = keys .iter() .map(|key| { let model = hashmap.remove(&format!("{:?}", key)); model }) .collect(); Ok(result) } async fn load_many(&self, db: &C) -> Result>, DbErr> where C: ConnectionTrait, R: EntityTrait, R::Model: Send + Sync, <::Column as FromStr>::Err: Debug, <::Model as ModelTrait>::Entity: Related, <<::Entity as EntityTrait>::Column as FromStr>::Err: Debug, { // we should verify this is a has_many relation Ok(vec![]) } }