eventuary_sqlite/
writer.rs1use std::sync::Arc;
2
3use eventuary_core::io::Writer;
4use eventuary_core::{Error, Event, Result, SerializedEvent};
5
6use crate::database::SqliteConn;
7use crate::relation::SqliteRelationName;
8
9#[derive(Debug, Clone)]
10pub struct SqliteWriterConfig {
11 pub events_relation: SqliteRelationName,
12}
13
14impl Default for SqliteWriterConfig {
15 fn default() -> Self {
16 Self {
17 events_relation: SqliteRelationName::new("events").expect("default events relation"),
18 }
19 }
20}
21
22pub struct SqliteWriter {
23 conn: SqliteConn,
24 insert_sql: Arc<String>,
25}
26
27impl SqliteWriter {
28 pub fn new(conn: SqliteConn) -> Self {
29 Self::new_with_config(conn, SqliteWriterConfig::default())
30 }
31
32 pub fn new_with_config(conn: SqliteConn, config: SqliteWriterConfig) -> Self {
33 let insert_sql = format!(
34 "INSERT INTO {events} (id, organization, namespace, topic, event_key, payload, content_type, metadata, timestamp, version, parent_id, correlation_id, causation_id)
35 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)",
36 events = config.events_relation.render(),
37 );
38 Self {
39 conn,
40 insert_sql: Arc::new(insert_sql),
41 }
42 }
43}
44
45impl Writer for SqliteWriter {
46 async fn write(&self, event: &Event) -> Result<()> {
47 let conn = Arc::clone(&self.conn);
48 let event = event.clone();
49 let sql = Arc::clone(&self.insert_sql);
50 tokio::task::spawn_blocking(move || {
51 let guard = conn.lock().map_err(|e| Error::Store(e.to_string()))?;
52 insert_event(&guard, &sql, &event)
53 })
54 .await
55 .map_err(|e| Error::Store(format!("blocking task panicked: {e}")))?
56 }
57
58 async fn write_all(&self, events: &[Event]) -> Result<()> {
59 if events.is_empty() {
60 return Ok(());
61 }
62 let conn = Arc::clone(&self.conn);
63 let events = events.to_vec();
64 let sql = Arc::clone(&self.insert_sql);
65 tokio::task::spawn_blocking(move || {
66 let mut guard = conn.lock().map_err(|e| Error::Store(e.to_string()))?;
67 let tx = guard
68 .transaction()
69 .map_err(|e| Error::Store(e.to_string()))?;
70 for event in &events {
71 insert_event(&tx, &sql, event)?;
72 }
73 tx.commit().map_err(|e| Error::Store(e.to_string()))?;
74 Ok(())
75 })
76 .await
77 .map_err(|e| Error::Store(format!("blocking task panicked: {e}")))?
78 }
79}
80
81fn insert_event(conn: &rusqlite::Connection, sql: &str, event: &Event) -> Result<()> {
82 let serialized = SerializedEvent::from_event(event)?;
83 let content_type = serialized.payload.content_type().to_string();
84 let payload = serde_json::to_string(&serialized.payload)
85 .map_err(|e| Error::Store(format!("encode payload: {e}")))?;
86 let metadata = serde_json::to_string(&serialized.metadata)
87 .map_err(|e| Error::Store(format!("encode metadata: {e}")))?;
88 conn.execute(
89 sql,
90 rusqlite::params![
91 serialized.id.to_string(),
92 serialized.organization,
93 serialized.namespace,
94 serialized.topic,
95 serialized.key,
96 payload,
97 content_type,
98 metadata,
99 serialized.timestamp.to_rfc3339(),
100 serialized.version as i64,
101 serialized.parent_id.map(|id| id.to_string()),
102 serialized.correlation_id,
103 serialized.causation_id,
104 ],
105 )
106 .map_err(|e| Error::Store(e.to_string()))?;
107 Ok(())
108}