use crate::data_err;
use crate::errors::Result;
use crate::mapper::IPage;
use crate::prelude::{AkitaError, GetFields, GetTableName, Params};
use akita_core::{
from_akita_value, from_akita_value_opt, AkitaValue, FromAkitaValue, IntoAkitaValue, Rows,
Wrapper,
};
pub trait AkitaMapper {
#[track_caller]
fn list<T>(&self, wrapper: Wrapper) -> Result<Vec<T>>
where
T: GetTableName + GetFields + FromAkitaValue;
#[track_caller]
fn select_one<T>(&self, wrapper: Wrapper) -> Result<Option<T>>
where
T: GetTableName + GetFields + FromAkitaValue;
#[track_caller]
fn select_by_id<T, I>(&self, id: I) -> Result<Option<T>>
where
T: GetTableName + GetFields + FromAkitaValue,
I: IntoAkitaValue;
#[track_caller]
fn page<T>(&self, page: u64, size: u64, wrapper: Wrapper) -> Result<IPage<T>>
where
T: GetTableName + GetFields + FromAkitaValue;
#[track_caller]
fn count<T>(&self, wrapper: Wrapper) -> Result<u64>
where
T: GetTableName + GetFields;
#[track_caller]
fn remove<T>(&self, wrapper: Wrapper) -> Result<u64>
where
T: GetTableName + GetFields;
#[track_caller]
fn remove_by_ids<T, I>(&self, ids: Vec<I>) -> Result<u64>
where
I: IntoAkitaValue,
T: GetTableName + GetFields;
#[track_caller]
fn remove_by_id<T, I>(&self, id: I) -> Result<u64>
where
I: IntoAkitaValue + Into<AkitaValue>,
T: GetTableName + GetFields;
#[track_caller]
fn update<T>(&self, entity: &T, wrapper: Wrapper) -> Result<u64>
where
T: GetTableName + GetFields + IntoAkitaValue;
#[track_caller]
fn update_by_id<T>(&self, entity: &T) -> Result<u64>
where
T: GetTableName + GetFields + IntoAkitaValue;
#[allow(unused_variables)]
#[track_caller]
fn update_batch_by_id<T>(&self, entities: &Vec<T>) -> Result<u64>
where
T: GetTableName + GetFields + IntoAkitaValue;
#[allow(unused_variables)]
#[track_caller]
fn save_batch<T, E>(&self, entities: E) -> Result<()>
where
T: GetTableName + GetFields + IntoAkitaValue,
E: IntoIterator<Item = T>;
#[track_caller]
fn save<T, I>(&self, entity: &T) -> Result<Option<I>>
where
T: GetTableName + GetFields + IntoAkitaValue,
I: FromAkitaValue;
#[track_caller]
fn save_or_update<T, I>(&self, entity: &T) -> Result<Option<I>>
where
T: GetTableName + GetFields + IntoAkitaValue,
I: FromAkitaValue;
#[track_caller]
fn simple_query<T, Q>(&self, query: Q) -> Result<Vec<T>>
where
Q: Into<String>,
T: FromAkitaValue,
{
self.query_map(query, from_akita_value)
}
#[track_caller]
fn query_opt<T, Q>(&self, query: Q) -> Result<Vec<Result<T>>>
where
Q: Into<String>,
T: FromAkitaValue,
{
self.query_map(query, from_akita_value_opt)
.map(|v| v.into_iter().map(|v| v.map_err(AkitaError::from)).collect())
}
#[track_caller]
fn query_first<S: Into<String>, R>(&self, sql: S) -> Result<R>
where
R: FromAkitaValue,
{
self.exec_first(sql, ())
}
#[track_caller]
fn query_first_opt<R, S: Into<String>>(&self, sql: S) -> Result<Option<R>>
where
R: FromAkitaValue,
{
self.exec_first_opt(sql, ())
}
#[track_caller]
fn query_map<T, F, Q, U>(&self, query: Q, mut f: F) -> Result<Vec<U>>
where
Q: Into<String>,
T: FromAkitaValue,
F: FnMut(T) -> U,
{
self.query_fold(query, Vec::new(), |mut acc, row| {
acc.push(f(row));
acc
})
}
#[track_caller]
fn query_fold<T, F, Q, U>(&self, query: Q, init: U, mut f: F) -> Result<U>
where
Q: Into<String>,
T: FromAkitaValue,
F: FnMut(U, T) -> U,
{
self.exec_iter::<_, _>(query, ()).map(|r| {
r.object_iter()
.map(|data| from_akita_value(data))
.fold(init, |acc, row| f(acc, row))
})
}
#[track_caller]
fn query_drop<Q>(&self, query: Q) -> Result<()>
where
Q: Into<String>,
{
self.query_iter(query).map(drop)
}
#[track_caller]
fn exec_map<T, F, Q, U>(&self, query: Q, mut f: F) -> Result<Vec<U>>
where
Q: Into<String>,
T: FromAkitaValue,
F: FnMut(T) -> U,
{
self.query_fold(query, Vec::new(), |mut acc, row| {
acc.push(f(row));
acc
})
}
#[track_caller]
fn query_iter<S: Into<String>>(&self, sql: S) -> Result<Rows> {
self.exec_iter(sql, ())
}
#[track_caller]
fn exec_iter<S: Into<String>, P: Into<Params>>(&self, sql: S, params: P) -> Result<Rows>;
#[allow(clippy::redundant_closure)]
#[track_caller]
fn exec_raw<R, S: Into<String>, P: Into<Params>>(&self, sql: S, params: P) -> Result<Vec<R>>
where
R: FromAkitaValue,
{
let rows = self.exec_iter(&sql.into(), params.into())?;
Ok(rows
.object_iter()
.map(|data| R::from_value(&data))
.collect::<Vec<R>>())
}
#[track_caller]
fn exec_first<R, S: Into<String>, P: Into<Params>>(&self, sql: S, params: P) -> Result<R>
where
R: FromAkitaValue,
{
let sql: String = sql.into();
let rows = self.exec_iter(&sql, params.into())?;
if rows.is_empty() {
return Err(data_err!("Empty record returned".to_string()));
}
if rows.len() > 1 {
return Err(data_err!("More than one record returned".to_string()));
}
let data = rows
.first()
.map(|row| row.as_object())
.ok_or_else(|| data_err!("Empty record returned".to_string()))?;
R::from_value_opt(&data).map_err(|e| {
data_err!(
"exec_first: Cannot divide the value {:? } to type {}: {}",
data,
std::any::type_name::<R>(),
e
)
})
}
#[track_caller]
fn exec_drop<S: Into<String>, P: Into<Params>>(&self, sql: S, params: P) -> Result<()> {
let sql: String = sql.into();
let _result: Vec<()> = self.exec_raw(&sql, params)?;
Ok(())
}
#[track_caller]
fn exec_first_opt<R, S: Into<String>, P: Into<Params>>(
&self,
sql: S,
params: P,
) -> Result<Option<R>>
where
R: FromAkitaValue,
{
let sql: String = sql.into();
let result: Result<Vec<R>> = self.exec_raw(&sql, params);
match result {
Ok(mut result) => match result.len() {
0 => Ok(None),
1 => Ok(Some(result.remove(0))),
_ => Err(data_err!("More than one record returned".to_string())),
},
Err(e) => Err(e),
}
}
}