use thiserror::Error;
#[derive(Debug, Clone)]
pub struct EventRow {
pub persistence_id: String,
pub sequence_nr: u64,
pub payload: Vec<u8>,
pub manifest: String,
pub writer_uuid: String,
}
#[derive(Debug, Clone)]
pub struct OutboxRow {
pub topic: String,
pub payload: Vec<u8>,
}
#[derive(Debug, Error)]
pub enum OutboxError {
#[error("backend error: {0}")]
Backend(String),
}
impl OutboxError {
pub fn backend(e: impl std::fmt::Display) -> Self {
Self::Backend(e.to_string())
}
}
pub struct TxOutbox;
impl TxOutbox {
pub async fn persist_with(
&self,
tx: &mut sqlx::Transaction<'_, sqlx::Any>,
event: EventRow,
outbox: OutboxRow,
) -> Result<(), OutboxError> {
let created_at = now_millis();
sqlx::query(
"INSERT INTO event_journal \
(persistence_id, sequence_nr, payload, manifest, writer_uuid, deleted, created_at) \
VALUES (?, ?, ?, ?, ?, 0, ?)",
)
.bind(&event.persistence_id)
.bind(event.sequence_nr as i64)
.bind(event.payload)
.bind(&event.manifest)
.bind(&event.writer_uuid)
.bind(created_at)
.execute(&mut **tx)
.await
.map_err(OutboxError::backend)?;
sqlx::query("INSERT INTO outbox (topic, payload, created_at) VALUES (?, ?, ?)")
.bind(&outbox.topic)
.bind(outbox.payload)
.bind(created_at)
.execute(&mut **tx)
.await
.map_err(OutboxError::backend)?;
Ok(())
}
}
fn now_millis() -> i64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as i64).unwrap_or(0)
}