Decouple as ModelSelect

This commit is contained in:
Chris Tsang 2021-05-09 23:32:54 +08:00
parent e1504c6743
commit e2c7722d84
3 changed files with 83 additions and 11 deletions

View File

@ -1,22 +1,79 @@
use crate::{Connection, Database, EntityTrait, ModelTrait, QueryErr, Select}; use crate::{Connection, Database, EntityTrait, FromQueryResult, QueryErr, Select, Statement};
use sea_query::{QueryBuilder, SelectStatement};
use std::marker::PhantomData;
#[derive(Clone, Debug)]
pub struct ModelSelect<M>
where
M: FromQueryResult,
{
query: SelectStatement,
model: PhantomData<M>,
}
impl<E: 'static> Select<E> impl<E: 'static> Select<E>
where where
E: EntityTrait, E: EntityTrait,
{ {
pub async fn one(mut self, db: &Database) -> Result<E::Model, QueryErr> { pub fn into_model<M>(self) -> ModelSelect<M>
let builder = db.get_query_builder_backend(); where
self.query().limit(1); M: FromQueryResult,
let row = db.get_connection().query_one(self.build(builder)).await?; {
Ok(<E as EntityTrait>::Model::from_query_result(row)?) ModelSelect {
query: self.query,
model: PhantomData,
}
}
pub async fn one(self, db: &Database) -> Result<E::Model, QueryErr> {
self.into_model::<E::Model>().one(db).await
} }
pub async fn all(self, db: &Database) -> Result<Vec<E::Model>, QueryErr> { pub async fn all(self, db: &Database) -> Result<Vec<E::Model>, QueryErr> {
self.into_model::<E::Model>().all(db).await
}
}
impl<M> ModelSelect<M>
where
M: FromQueryResult,
{
/// Get a mutable ref to the query builder
pub fn query(&mut self) -> &mut SelectStatement {
&mut self.query
}
/// Get an immutable ref to the query builder
pub fn as_query(&self) -> &SelectStatement {
&self.query
}
/// Take ownership of the query builder
pub fn into_query(self) -> SelectStatement {
self.query
}
/// Build the query as [`Statement`]
pub fn build<B>(&self, builder: B) -> Statement
where
B: QueryBuilder,
{
self.as_query().build(builder).into()
}
pub async fn one(mut self, db: &Database) -> Result<M, QueryErr> {
let builder = db.get_query_builder_backend();
self.query().limit(1);
let row = db.get_connection().query_one(self.build(builder)).await?;
Ok(M::from_query_result(row)?)
}
pub async fn all(self, db: &Database) -> Result<Vec<M>, QueryErr> {
let builder = db.get_query_builder_backend(); let builder = db.get_query_builder_backend();
let rows = db.get_connection().query_all(self.build(builder)).await?; let rows = db.get_connection().query_all(self.build(builder)).await?;
let mut models = Vec::new(); let mut models = Vec::new();
for row in rows.into_iter() { for row in rows.into_iter() {
models.push(<E as EntityTrait>::Model::from_query_result(row)?); models.push(M::from_query_result(row)?);
} }
Ok(models) Ok(models)
} }

View File

@ -11,5 +11,20 @@ pub trait ModelTrait: Clone + Debug + Default {
fn from_query_result(row: QueryResult) -> Result<Self, TypeErr> fn from_query_result(row: QueryResult) -> Result<Self, TypeErr>
where where
Self: std::marker::Sized; Self: Sized;
}
pub trait FromQueryResult {
fn from_query_result(row: QueryResult) -> Result<Self, TypeErr>
where
Self: Sized;
}
impl<M> FromQueryResult for M
where
M: ModelTrait + Sized,
{
fn from_query_result(row: QueryResult) -> Result<M, TypeErr> {
<Self as ModelTrait>::from_query_result(row)
}
} }

View File

@ -13,8 +13,8 @@ pub struct Select<E: 'static>
where where
E: EntityTrait, E: EntityTrait,
{ {
query: SelectStatement, pub(crate) query: SelectStatement,
entity: PhantomData<E>, pub(crate) entity: PhantomData<E>,
} }
impl<E: 'static> Select<E> impl<E: 'static> Select<E>
@ -162,7 +162,7 @@ where
&mut self.query &mut self.query
} }
/// Get a immutable ref to the query builder /// Get an immutable ref to the query builder
pub fn as_query(&self) -> &SelectStatement { pub fn as_query(&self) -> &SelectStatement {
&self.query &self.query
} }