use std::convert::Infallible;
use std::error::Error;
use std::future::Future;
use eventcore_types::{AttemptNumber, DeliveryPosition, PersistedEventEnvelope, ProjectorName};
use serde::de::DeserializeOwned;
use sqlx::{Postgres, Transaction};
use super::error::BoxedProjectionError;
pub trait AfterCommit: Send + 'static {
type Error: Error + Send + Sync + 'static;
fn execute(self) -> impl Future<Output = Result<(), Self::Error>> + Send;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NoopAfterCommit;
impl AfterCommit for NoopAfterCommit {
type Error = Infallible;
async fn execute(self) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ProjectionFailureDecision {
Retry,
Skip,
Stop,
Fatal,
}
#[derive(Debug)]
pub struct ProjectionFailureContext<'a, E> {
position: DeliveryPosition,
error: &'a E,
attempt: AttemptNumber,
}
impl<'a, E> ProjectionFailureContext<'a, E> {
pub fn new(position: DeliveryPosition, error: &'a E, attempt: AttemptNumber) -> Self {
Self {
position,
error,
attempt,
}
}
pub fn position(&self) -> DeliveryPosition {
self.position
}
pub fn error(&self) -> &'a E {
self.error
}
pub fn attempt(&self) -> AttemptNumber {
self.attempt
}
}
pub trait PostgresProjector: Send {
type Event: DeserializeOwned + Send + Sync;
type Error: Error + Send + Sync + 'static;
type AfterCommit: AfterCommit;
fn name(&self) -> &ProjectorName;
fn decode(
&self,
envelope: &PersistedEventEnvelope,
) -> Result<Self::Event, BoxedProjectionError> {
serde_json::from_str(envelope.payload().get())
.map_err(|error| -> BoxedProjectionError { Box::new(error) })
}
fn apply<'a, 'c>(
&'a mut self,
event: &'a Self::Event,
position: DeliveryPosition,
tx: &'a mut Transaction<'c, Postgres>,
) -> impl Future<Output = Result<Self::AfterCommit, Self::Error>> + Send + 'a
where
'c: 'a;
fn on_error(
&mut self,
failure: ProjectionFailureContext<'_, Self::Error>,
) -> ProjectionFailureDecision {
let _ = failure;
ProjectionFailureDecision::Fatal
}
}
pub trait PostgresProjectionReset: Send {
type Error: Error + Send + Sync + 'static;
fn reset<'a, 'c>(
&'a mut self,
tx: &'a mut Transaction<'c, Postgres>,
) -> impl Future<Output = Result<(), Self::Error>> + Send + 'a
where
'c: 'a;
}