use super::{
ExecError, FetcherPool, LoadRelated, MaybeMyFromRow, MaybeMyLoadRelated, MaybePgFromRow,
MaybeSqliteFromRow, MaybeSqliteLoadRelated,
};
use crate::core::Model;
use crate::sql::Pool;
pub async fn get_or_create<T, F, Fut>(
qs: crate::query::QuerySet<T>,
create_fn: F,
pool: &Pool,
) -> Result<(T, bool), ExecError>
where
T: Model
+ MaybePgFromRow
+ MaybeMyFromRow
+ MaybeSqliteFromRow
+ LoadRelated
+ MaybeMyLoadRelated
+ MaybeSqliteLoadRelated
+ Send
+ Unpin,
F: FnOnce(Pool) -> Fut,
Fut: std::future::Future<Output = Result<T, ExecError>>,
{
let mut rows = qs.fetch(pool).await?;
match rows.len() {
0 => Ok((create_fn(pool.clone()).await?, true)),
1 => Ok((rows.remove(0), false)),
n => Err(ExecError::MultipleRowsReturned {
op: "get_or_create",
table: T::SCHEMA.table,
count: n,
}),
}
}
pub async fn update_or_create<T, UF, UFut, CF, CFut>(
qs: crate::query::QuerySet<T>,
update_fn: UF,
create_fn: CF,
pool: &Pool,
) -> Result<(T, bool), ExecError>
where
T: Model
+ MaybePgFromRow
+ MaybeMyFromRow
+ MaybeSqliteFromRow
+ LoadRelated
+ MaybeMyLoadRelated
+ MaybeSqliteLoadRelated
+ Send
+ Unpin,
UF: FnOnce(Pool, T) -> UFut,
UFut: std::future::Future<Output = Result<T, ExecError>>,
CF: FnOnce(Pool) -> CFut,
CFut: std::future::Future<Output = Result<T, ExecError>>,
{
let mut rows = qs.fetch(pool).await?;
match rows.len() {
0 => Ok((create_fn(pool.clone()).await?, true)),
1 => {
let existing = rows.remove(0);
let updated = update_fn(pool.clone(), existing).await?;
Ok((updated, false))
}
n => Err(ExecError::MultipleRowsReturned {
op: "update_or_create",
table: T::SCHEMA.table,
count: n,
}),
}
}
impl<T> crate::query::QuerySet<T>
where
T: Model
+ MaybePgFromRow
+ MaybeMyFromRow
+ MaybeSqliteFromRow
+ LoadRelated
+ MaybeMyLoadRelated
+ MaybeSqliteLoadRelated
+ Send
+ Unpin,
{
pub async fn get_or_create<F, Fut>(
self,
create_fn: F,
pool: &Pool,
) -> Result<(T, bool), ExecError>
where
F: FnOnce(Pool) -> Fut,
Fut: std::future::Future<Output = Result<T, ExecError>>,
{
get_or_create(self, create_fn, pool).await
}
pub async fn first_or_create<F, Fut>(
self,
create_fn: F,
pool: &Pool,
) -> Result<(T, bool), ExecError>
where
F: FnOnce(Pool) -> Fut,
Fut: std::future::Future<Output = Result<T, ExecError>>,
{
self.get_or_create(create_fn, pool).await
}
pub async fn update_or_create<UF, UFut, CF, CFut>(
self,
update_fn: UF,
create_fn: CF,
pool: &Pool,
) -> Result<(T, bool), ExecError>
where
UF: FnOnce(Pool, T) -> UFut,
UFut: std::future::Future<Output = Result<T, ExecError>>,
CF: FnOnce(Pool) -> CFut,
CFut: std::future::Future<Output = Result<T, ExecError>>,
{
update_or_create(self, update_fn, create_fn, pool).await
}
}