use std::future::Future;
use topcoat::{context::Cx, router::error::see_other, view::BoxView};
use super::gate::landing_url;
use crate::{
notification::{Notification, notify_write_failure, set_notification},
resource::{Committed, Mounted, Resource},
};
pub(crate) async fn commit_write<'a, R: Resource, T>(
cx: &'a Cx,
resource: &Mounted<R>,
tx: toasty::Transaction<'_>,
written: Result<T, topcoat::Error>,
committed: impl FnOnce(T) -> Committed<R::Model>,
note: impl Into<String>,
failure: &'static str,
) -> Result<BoxView<'a>, topcoat::Error> {
commit_then(
cx,
tx,
written,
|value| crate::resource::run_after_commit::<R>(cx, committed(value)),
note,
failure,
&resource.url,
)
.await
}
pub(crate) async fn commit_then<'a, T, F: Future<Output = ()>>(
cx: &'a Cx,
tx: toasty::Transaction<'_>,
written: Result<T, topcoat::Error>,
after: impl FnOnce(T) -> F,
note: impl Into<String>,
failure: &'static str,
home: &str,
) -> Result<BoxView<'a>, topcoat::Error> {
match written {
Ok(value) => match tx.commit().await {
Ok(()) => {
after(value).await;
Err(redirect_after_write(cx, home, note))
}
Err(error) => {
notify_write_failure(cx, failure);
Err(crate::error::unavailable(error))
}
},
Err(error) => {
notify_write_failure(cx, failure);
Err(crate::error::driver_failure(
error,
crate::error::DATABASE_UNAVAILABLE,
))
}
}
}
fn redirect_after_write(cx: &Cx, home: &str, note: impl Into<String>) -> topcoat::Error {
set_notification(cx, Notification::success(note));
see_other(landing_url(cx, home)).into()
}