1use std::ops::{Deref, DerefMut};
4
5#[cfg(feature = "mysql")]
6use sea_query::MysqlQueryBuilder;
7#[cfg(feature = "postgres")]
8use sea_query::PostgresQueryBuilder;
9#[cfg(feature = "sqlite")]
10use sea_query::SqliteQueryBuilder;
11use sea_query::{
12 Cond, Expr, ExprTrait, Func, Iden, IntoColumnRef, OnConflict, Query, SelectStatement,
13};
14use sea_query_sqlx::SqlxBinder;
15use sqlx::{Database, Pool};
16use ulid::Ulid;
17
18use evento_core::{
19 cursor::{self, Args, Cursor, Edge, PageInfo, ReadResult, Value},
20 Executor, ReadAggregator, WriteError,
21};
22
23#[derive(Iden, Clone)]
40pub enum Event {
41 Table,
43 Id,
45 Name,
47 AggregatorType,
49 AggregatorId,
51 Version,
53 Data,
55 Metadata,
57 RoutingKey,
59 Timestamp,
61 TimestampSubsec,
63}
64
65#[derive(Iden)]
71pub enum Snapshot {
72 Table,
74 Id,
76 Type,
78 Cursor,
80 Revision,
82 Data,
84 CreatedAt,
86 UpdatedAt,
88}
89
90#[derive(Iden)]
103pub enum Subscriber {
104 Table,
106 Key,
108 WorkerId,
110 Cursor,
112 Lag,
114 Enabled,
116 CreatedAt,
118 UpdatedAt,
120}
121
122#[cfg(feature = "mysql")]
126pub type MySql = Sql<sqlx::MySql>;
127
128#[cfg(feature = "mysql")]
132pub type RwMySql = evento_core::Rw<MySql, MySql>;
133
134#[cfg(feature = "postgres")]
138pub type Postgres = Sql<sqlx::Postgres>;
139
140#[cfg(feature = "postgres")]
144pub type RwPostgres = evento_core::Rw<Postgres, Postgres>;
145
146#[cfg(feature = "sqlite")]
150pub type Sqlite = Sql<sqlx::Sqlite>;
151
152#[cfg(feature = "sqlite")]
156pub type RwSqlite = evento_core::Rw<Sqlite, Sqlite>;
157
158pub struct Sql<DB: Database>(Pool<DB>);
196
197impl<DB: Database> Sql<DB> {
198 fn build_sqlx<S: SqlxBinder>(statement: S) -> (String, sea_query_sqlx::SqlxValues) {
199 match DB::NAME {
200 #[cfg(feature = "sqlite")]
201 "SQLite" => statement.build_sqlx(SqliteQueryBuilder),
202 #[cfg(feature = "mysql")]
203 "MySQL" => statement.build_sqlx(MysqlQueryBuilder),
204 #[cfg(feature = "postgres")]
205 "PostgreSQL" => statement.build_sqlx(PostgresQueryBuilder),
206 name => panic!("'{name}' not supported, consider using SQLite, PostgreSQL or MySQL"),
207 }
208 }
209}
210
211#[async_trait::async_trait]
212impl<DB> Executor for Sql<DB>
213where
214 DB: Database,
215 for<'c> &'c mut DB::Connection: sqlx::Executor<'c, Database = DB>,
216 sea_query_sqlx::SqlxValues: sqlx::IntoArguments<DB>,
217 String: for<'r> sqlx::Decode<'r, DB> + sqlx::Type<DB>,
218 bool: for<'r> sqlx::Decode<'r, DB> + sqlx::Type<DB>,
219 Vec<u8>: for<'r> sqlx::Decode<'r, DB> + sqlx::Type<DB>,
220 i64: for<'r> sqlx::Decode<'r, DB> + sqlx::Type<DB>,
221 usize: sqlx::ColumnIndex<DB::Row>,
222 SqlEvent: for<'r> sqlx::FromRow<'r, DB::Row>,
223{
224 async fn read(
225 &self,
226 aggregators: Option<Vec<ReadAggregator>>,
227 routing_key: Option<evento_core::RoutingKey>,
228 args: Args,
229 ) -> anyhow::Result<ReadResult<evento_core::Event>> {
230 let statement = Query::select()
231 .columns([
232 Event::Id,
233 Event::Name,
234 Event::AggregatorType,
235 Event::AggregatorId,
236 Event::Version,
237 Event::Data,
238 Event::Metadata,
239 Event::RoutingKey,
240 Event::Timestamp,
241 Event::TimestampSubsec,
242 ])
243 .from(Event::Table)
244 .conditions(
245 aggregators.is_some(),
246 |q| {
247 let Some(aggregators) = aggregators else {
248 return;
249 };
250
251 let mut cond = Cond::any();
252
253 for aggregator in aggregators {
254 let mut aggregator_cond = Cond::all()
255 .add(Expr::col(Event::AggregatorType).eq(aggregator.aggregator_type));
256
257 if let Some(id) = aggregator.aggregator_id {
258 aggregator_cond =
259 aggregator_cond.add(Expr::col(Event::AggregatorId).eq(id));
260 }
261
262 if let Some(name) = aggregator.name {
263 aggregator_cond = aggregator_cond.add(Expr::col(Event::Name).eq(name));
264 }
265
266 cond = cond.add(aggregator_cond);
267 }
268
269 q.and_where(cond.into());
270 },
271 |_| {},
272 )
273 .conditions(
274 matches!(routing_key, Some(evento_core::RoutingKey::Value(_))),
275 |q| {
276 if let Some(evento_core::RoutingKey::Value(Some(ref routing_key))) = routing_key
277 {
278 q.and_where(Expr::col(Event::RoutingKey).eq(routing_key));
279 }
280
281 if let Some(evento_core::RoutingKey::Value(None)) = routing_key {
282 q.and_where(Expr::col(Event::RoutingKey).is_null());
283 }
284 },
285 |_q| {},
286 )
287 .to_owned();
288
289 Ok(Reader::new(statement)
290 .args(args)
291 .execute::<_, SqlEvent, _>(&self.0)
292 .await?
293 .map(|e| e.0))
294 }
295
296 async fn latest_timestamp(
297 &self,
298 aggregators: Option<Vec<ReadAggregator>>,
299 routing_key: Option<evento_core::RoutingKey>,
300 ) -> anyhow::Result<u64> {
301 let statement = Query::select()
302 .expr(Func::max(Expr::col(Event::Timestamp)))
303 .from(Event::Table)
304 .conditions(
305 aggregators.is_some(),
306 |q| {
307 let Some(aggregators) = aggregators else {
308 return;
309 };
310
311 let mut cond = Cond::any();
312
313 for aggregator in aggregators {
314 let mut aggregator_cond = Cond::all()
315 .add(Expr::col(Event::AggregatorType).eq(aggregator.aggregator_type));
316
317 if let Some(id) = aggregator.aggregator_id {
318 aggregator_cond =
319 aggregator_cond.add(Expr::col(Event::AggregatorId).eq(id));
320 }
321
322 if let Some(name) = aggregator.name {
323 aggregator_cond = aggregator_cond.add(Expr::col(Event::Name).eq(name));
324 }
325
326 cond = cond.add(aggregator_cond);
327 }
328
329 q.and_where(cond.into());
330 },
331 |_| {},
332 )
333 .conditions(
334 matches!(routing_key, Some(evento_core::RoutingKey::Value(_))),
335 |q| {
336 if let Some(evento_core::RoutingKey::Value(Some(ref routing_key))) = routing_key
337 {
338 q.and_where(Expr::col(Event::RoutingKey).eq(routing_key));
339 }
340
341 if let Some(evento_core::RoutingKey::Value(None)) = routing_key {
342 q.and_where(Expr::col(Event::RoutingKey).is_null());
343 }
344 },
345 |_q| {},
346 )
347 .to_owned();
348
349 let (sql, values) = Self::build_sqlx(statement);
350
351 let (ts,): (Option<i64>,) =
352 sqlx::query_as_with::<DB, (Option<i64>,), _>(sqlx::AssertSqlSafe(sql.as_str()), values)
353 .fetch_one(&self.0)
354 .await?;
355
356 Ok(ts.map(|v| if v < 0 { 0 } else { v as u64 }).unwrap_or(0))
357 }
358
359 async fn get_subscriber_cursor(&self, key: String) -> anyhow::Result<Option<Value>> {
360 let statement = Query::select()
361 .columns([Subscriber::Cursor])
362 .from(Subscriber::Table)
363 .and_where(Expr::col(Subscriber::Key).eq(Expr::value(key)))
364 .limit(1)
365 .to_owned();
366
367 let (sql, values) = Self::build_sqlx(statement);
368
369 let Some((cursor,)) = sqlx::query_as_with::<DB, (Option<String>,), _>(
370 sqlx::AssertSqlSafe(sql.as_str()),
371 values,
372 )
373 .fetch_optional(&self.0)
374 .await?
375 else {
376 return Ok(None);
377 };
378
379 Ok(cursor.map(|c| c.into()))
380 }
381
382 async fn is_subscriber_running(&self, key: String, worker_id: Ulid) -> anyhow::Result<bool> {
383 let statement = Query::select()
384 .columns([Subscriber::WorkerId, Subscriber::Enabled])
385 .from(Subscriber::Table)
386 .and_where(Expr::col(Subscriber::Key).eq(Expr::value(key)))
387 .limit(1)
388 .to_owned();
389
390 let (sql, values) = Self::build_sqlx(statement);
391
392 let (id, enabled) =
393 sqlx::query_as_with::<DB, (String, bool), _>(sqlx::AssertSqlSafe(sql.as_str()), values)
394 .fetch_one(&self.0)
395 .await?;
396
397 Ok(worker_id.to_string() == id && enabled)
398 }
399
400 async fn upsert_subscriber(&self, key: String, worker_id: Ulid) -> anyhow::Result<()> {
401 let statement = Query::insert()
402 .into_table(Subscriber::Table)
403 .columns([Subscriber::Key, Subscriber::WorkerId, Subscriber::Lag])
404 .values_panic([key.into(), worker_id.to_string().into(), 0.into()])
405 .on_conflict(
406 OnConflict::column(Subscriber::Key)
407 .update_columns([Subscriber::WorkerId])
408 .value(Subscriber::UpdatedAt, Expr::current_timestamp())
409 .to_owned(),
410 )
411 .to_owned();
412
413 let (sql, values) = Self::build_sqlx(statement);
414
415 sqlx::query_with::<DB, _>(sqlx::AssertSqlSafe(sql.as_str()), values)
416 .execute(&self.0)
417 .await?;
418
419 Ok(())
420 }
421
422 async fn write(&self, events: Vec<evento_core::Event>) -> Result<(), WriteError> {
423 let mut statement = Query::insert()
424 .into_table(Event::Table)
425 .columns([
426 Event::Id,
427 Event::Name,
428 Event::Data,
429 Event::Metadata,
430 Event::AggregatorType,
431 Event::AggregatorId,
432 Event::Version,
433 Event::RoutingKey,
434 Event::Timestamp,
435 Event::TimestampSubsec,
436 ])
437 .to_owned();
438
439 for event in events {
440 let metadata = bitcode::encode(&event.metadata);
441 statement.values_panic([
442 event.id.to_string().into(),
443 event.name.into(),
444 event.data.into(),
445 metadata.into(),
446 event.aggregator_type.into(),
447 event.aggregator_id.into(),
448 event.version.into(),
449 event.routing_key.into(),
450 event.timestamp.into(),
451 event.timestamp_subsec.into(),
452 ]);
453 }
454
455 let (sql, values) = Self::build_sqlx(statement);
456
457 sqlx::query_with::<DB, _>(sqlx::AssertSqlSafe(sql.as_str()), values)
458 .execute(&self.0)
459 .await
460 .map_err(|err| {
461 let err_str = err.to_string();
462 if err_str.contains("(code: 2067)") {
463 return WriteError::InvalidOriginalVersion;
464 }
465 if err_str.contains("1062 (23000): Duplicate entry") {
466 return WriteError::InvalidOriginalVersion;
467 }
468 if err_str.contains("duplicate key value violates unique constraint") {
469 return WriteError::InvalidOriginalVersion;
470 }
471 WriteError::Unknown(err.into())
472 })?;
473
474 Ok(())
475 }
476
477 async fn acknowledge(&self, key: String, cursor: Value, lag: u64) -> anyhow::Result<()> {
478 let statement = Query::update()
479 .table(Subscriber::Table)
480 .values([
481 (Subscriber::Cursor, cursor.0.into()),
482 (Subscriber::Lag, lag.into()),
483 (Subscriber::UpdatedAt, Expr::current_timestamp()),
484 ])
485 .and_where(Expr::col(Subscriber::Key).eq(key))
486 .to_owned();
487
488 let (sql, values) = Self::build_sqlx(statement);
489
490 sqlx::query_with::<DB, _>(sqlx::AssertSqlSafe(sql.as_str()), values)
491 .execute(&self.0)
492 .await?;
493
494 Ok(())
495 }
496
497 async fn get_snapshot(
498 &self,
499 aggregator_type: String,
500 aggregator_revision: String,
501 id: String,
502 ) -> anyhow::Result<Option<(Vec<u8>, Value)>> {
503 let statement = Query::select()
504 .columns([Snapshot::Data, Snapshot::Cursor])
505 .from(Snapshot::Table)
506 .and_where(Expr::col(Snapshot::Type).eq(Expr::value(aggregator_type)))
507 .and_where(Expr::col(Snapshot::Id).eq(Expr::value(id)))
508 .and_where(Expr::col(Snapshot::Revision).eq(Expr::value(aggregator_revision)))
509 .limit(1)
510 .to_owned();
511
512 let (sql, values) = Self::build_sqlx(statement);
513
514 Ok(sqlx::query_as_with::<DB, (Vec<u8>, String), _>(
515 sqlx::AssertSqlSafe(sql.as_str()),
516 values,
517 )
518 .fetch_optional(&self.0)
519 .await
520 .map(|res| res.map(|(data, cursor)| (data, cursor.into())))?)
521 }
522
523 async fn save_snapshot(
524 &self,
525 aggregator_type: String,
526 aggregator_revision: String,
527 id: String,
528 data: Vec<u8>,
529 cursor: Value,
530 ) -> anyhow::Result<()> {
531 let statement = Query::insert()
532 .into_table(Snapshot::Table)
533 .columns([
534 Snapshot::Type,
535 Snapshot::Id,
536 Snapshot::Cursor,
537 Snapshot::Revision,
538 Snapshot::Data,
539 ])
540 .values_panic([
541 aggregator_type.into(),
542 id.to_string().into(),
543 cursor.to_string().into(),
544 aggregator_revision.into(),
545 data.into(),
546 ])
547 .on_conflict(
548 OnConflict::columns([Snapshot::Type, Snapshot::Id])
549 .update_columns([Snapshot::Data, Snapshot::Cursor, Snapshot::Revision])
550 .value(Snapshot::UpdatedAt, Expr::current_timestamp())
551 .to_owned(),
552 )
553 .to_owned();
554
555 let (sql, values) = Self::build_sqlx(statement);
556
557 sqlx::query_with::<DB, _>(sqlx::AssertSqlSafe(sql.as_str()), values)
558 .execute(&self.0)
559 .await?;
560
561 Ok(())
562 }
563}
564
565impl<D: Database> Clone for Sql<D> {
566 fn clone(&self) -> Self {
567 Self(self.0.clone())
568 }
569}
570
571impl<D: Database> From<Pool<D>> for Sql<D> {
572 fn from(value: Pool<D>) -> Self {
573 Self(value)
574 }
575}
576
577pub struct Reader {
618 statement: SelectStatement,
619 args: Args,
620 order: cursor::Order,
621}
622
623impl Reader {
624 pub fn new(statement: SelectStatement) -> Self {
626 Self {
627 statement,
628 args: Args::default(),
629 order: cursor::Order::Asc,
630 }
631 }
632
633 pub fn order(&mut self, order: cursor::Order) -> &mut Self {
635 self.order = order;
636
637 self
638 }
639
640 pub fn desc(&mut self) -> &mut Self {
642 self.order(cursor::Order::Desc)
643 }
644
645 pub fn args(&mut self, args: Args) -> &mut Self {
647 self.args = args;
648
649 self
650 }
651
652 pub fn backward(&mut self, last: u16, before: Option<Value>) -> &mut Self {
659 self.args(Args {
660 last: Some(last),
661 before,
662 ..Default::default()
663 })
664 }
665
666 pub fn forward(&mut self, first: u16, after: Option<Value>) -> &mut Self {
673 self.args(Args {
674 first: Some(first),
675 after,
676 ..Default::default()
677 })
678 }
679
680 pub async fn execute<'e, 'c: 'e, DB, O, E>(
693 &mut self,
694 executor: E,
695 ) -> anyhow::Result<ReadResult<O>>
696 where
697 DB: Database,
698 E: 'e + sqlx::Executor<'c, Database = DB>,
699 O: for<'r> sqlx::FromRow<'r, DB::Row>,
700 O: Cursor,
701 O: Send + Unpin,
702 O: Bind<Cursor = O>,
703 <<O as Bind>::I as IntoIterator>::IntoIter: DoubleEndedIterator,
704 <<O as Bind>::V as IntoIterator>::IntoIter: DoubleEndedIterator,
705 sea_query_sqlx::SqlxValues: sqlx::IntoArguments<DB>,
706 {
707 let limit = self.build_reader::<O, O>()?;
708
709 let (sql, values) = match DB::NAME {
710 #[cfg(feature = "sqlite")]
711 "SQLite" => self.statement.build_sqlx(SqliteQueryBuilder),
712 #[cfg(feature = "mysql")]
713 "MySQL" => self.build_sqlx(MysqlQueryBuilder),
714 #[cfg(feature = "postgres")]
715 "PostgreSQL" => self.build_sqlx(PostgresQueryBuilder),
716 name => panic!("'{name}' not supported, consider using SQLite, PostgreSQL or MySQL"),
717 };
718
719 let mut rows = sqlx::query_as_with::<DB, O, _>(sqlx::AssertSqlSafe(sql.as_str()), values)
720 .fetch_all(executor)
721 .await?;
722
723 let has_more = rows.len() > limit as usize;
724 if has_more {
725 rows.pop();
726 }
727
728 let mut edges = vec![];
729 for node in rows.into_iter() {
730 edges.push(Edge {
731 cursor: node.serialize_cursor()?,
732 node,
733 });
734 }
735
736 if self.args.is_backward() {
737 edges = edges.into_iter().rev().collect();
738 }
739
740 let page_info = if self.args.is_backward() {
741 let start_cursor = edges.first().map(|e| e.cursor.clone());
742
743 PageInfo {
744 has_previous_page: has_more,
745 has_next_page: false,
746 start_cursor,
747 end_cursor: None,
748 }
749 } else {
750 let end_cursor = edges.last().map(|e| e.cursor.clone());
751 PageInfo {
752 has_previous_page: false,
753 has_next_page: has_more,
754 start_cursor: None,
755 end_cursor,
756 }
757 };
758
759 Ok(ReadResult { edges, page_info })
760 }
761
762 fn build_reader<O: Cursor, B: Bind<Cursor = O>>(&mut self) -> Result<u16, cursor::CursorError>
763 where
764 B::T: Clone,
765 <<B as Bind>::I as IntoIterator>::IntoIter: DoubleEndedIterator,
766 <<B as Bind>::V as IntoIterator>::IntoIter: DoubleEndedIterator,
767 {
768 let (limit, cursor) = self.args.get_info();
769
770 if let Some(cursor) = cursor.as_ref() {
771 self.build_reader_where::<O, B>(cursor)?;
772 }
773
774 self.build_reader_order::<B>();
775 self.limit((limit + 1).into());
776
777 Ok(limit)
778 }
779
780 fn build_reader_where<O, B>(&mut self, cursor: &Value) -> Result<(), cursor::CursorError>
781 where
782 O: Cursor,
783 B: Bind<Cursor = O>,
784 B::T: Clone,
785 <<B as Bind>::I as IntoIterator>::IntoIter: DoubleEndedIterator,
786 <<B as Bind>::V as IntoIterator>::IntoIter: DoubleEndedIterator,
787 {
788 let is_order_desc = self.is_order_desc();
789 let cursor = O::deserialize_cursor(cursor)?;
790 let colums = B::columns().into_iter().rev();
791 let values = B::values(cursor).into_iter().rev();
792
793 let mut expr = None::<Expr>;
794 for (col, value) in colums.zip(values) {
795 let current_expr = if is_order_desc {
796 Expr::col(col.clone()).lt(value.clone())
797 } else {
798 Expr::col(col.clone()).gt(value.clone())
799 };
800
801 let Some(ref prev_expr) = expr else {
802 expr = Some(current_expr.clone());
803 continue;
804 };
805
806 expr = Some(current_expr.or(Expr::col(col).eq(value).and(prev_expr.clone())));
807 }
808
809 self.and_where(expr.unwrap());
810
811 Ok(())
812 }
813
814 fn build_reader_order<O: Bind>(&mut self) {
815 let order = if self.is_order_desc() {
816 sea_query::Order::Desc
817 } else {
818 sea_query::Order::Asc
819 };
820
821 let colums = O::columns();
822 for col in colums {
823 self.order_by(col, order.clone());
824 }
825 }
826
827 fn is_order_desc(&self) -> bool {
828 matches!(
829 (&self.order, self.args.is_backward()),
830 (cursor::Order::Asc, true) | (cursor::Order::Desc, false)
831 )
832 }
833}
834
835impl Deref for Reader {
836 type Target = SelectStatement;
837
838 fn deref(&self) -> &Self::Target {
839 &self.statement
840 }
841}
842
843impl DerefMut for Reader {
844 fn deref_mut(&mut self) -> &mut Self::Target {
845 &mut self.statement
846 }
847}
848
849pub trait Bind {
867 type T: IntoColumnRef + Clone;
869 type I: IntoIterator<Item = Self::T>;
871 type V: IntoIterator<Item = Expr>;
873 type Cursor: Cursor;
875
876 fn columns() -> Self::I;
878 fn values(cursor: <<Self as Bind>::Cursor as Cursor>::T) -> Self::V;
880}
881
882impl evento_core::cursor::Cursor for SqlEvent {
883 type T = evento_core::EventCursor;
884
885 fn serialize(&self) -> Self::T {
886 evento_core::EventCursor {
887 i: self.0.id.to_string(),
888 v: self.0.version,
889 t: self.0.timestamp,
890 s: self.0.timestamp_subsec,
891 }
892 }
893}
894
895impl Bind for SqlEvent {
896 type T = Event;
897 type I = [Self::T; 4];
898 type V = [Expr; 4];
899 type Cursor = Self;
900
901 fn columns() -> Self::I {
902 [
903 Event::Timestamp,
904 Event::TimestampSubsec,
905 Event::Version,
906 Event::Id,
907 ]
908 }
909
910 fn values(cursor: <<Self as Bind>::Cursor as Cursor>::T) -> Self::V {
911 [
912 cursor.t.into(),
913 cursor.s.into(),
914 cursor.v.into(),
915 cursor.i.into(),
916 ]
917 }
918}
919
920#[cfg(feature = "sqlite")]
921impl From<Sqlite> for evento_core::Evento {
922 fn from(value: Sqlite) -> Self {
923 evento_core::Evento::new(value)
924 }
925}
926
927#[cfg(feature = "sqlite")]
928impl From<&Sqlite> for evento_core::Evento {
929 fn from(value: &Sqlite) -> Self {
930 evento_core::Evento::new(value.clone())
931 }
932}
933
934#[cfg(feature = "mysql")]
935impl From<MySql> for evento_core::Evento {
936 fn from(value: MySql) -> Self {
937 evento_core::Evento::new(value)
938 }
939}
940
941#[cfg(feature = "mysql")]
942impl From<&MySql> for evento_core::Evento {
943 fn from(value: &MySql) -> Self {
944 evento_core::Evento::new(value.clone())
945 }
946}
947
948#[cfg(feature = "postgres")]
949impl From<Postgres> for evento_core::Evento {
950 fn from(value: Postgres) -> Self {
951 evento_core::Evento::new(value)
952 }
953}
954
955#[cfg(feature = "postgres")]
956impl From<&Postgres> for evento_core::Evento {
957 fn from(value: &Postgres) -> Self {
958 evento_core::Evento::new(value.clone())
959 }
960}
961
962#[derive(Debug, Clone, PartialEq, Default)]
963pub struct SqlEvent(pub evento_core::Event);
964
965impl<R: sqlx::Row> sqlx::FromRow<'_, R> for SqlEvent
966where
967 i32: sqlx::Type<R::Database> + for<'r> sqlx::Decode<'r, R::Database>,
968 Vec<u8>: sqlx::Type<R::Database> + for<'r> sqlx::Decode<'r, R::Database>,
969 String: sqlx::Type<R::Database> + for<'r> sqlx::Decode<'r, R::Database>,
970 i64: sqlx::Type<R::Database> + for<'r> sqlx::Decode<'r, R::Database>,
971 for<'r> &'r str: sqlx::Type<R::Database> + sqlx::Decode<'r, R::Database>,
972 for<'r> &'r str: sqlx::ColumnIndex<R>,
973{
974 fn from_row(row: &R) -> Result<Self, sqlx::Error> {
975 let timestamp: i64 = sqlx::Row::try_get(row, "timestamp")?;
976 let timestamp_subsec: i64 = sqlx::Row::try_get(row, "timestamp_subsec")?;
977 let version: i32 = sqlx::Row::try_get(row, "version")?;
978 let metadata: Vec<u8> = sqlx::Row::try_get(row, "metadata")?;
979 let metadata: evento_core::metadata::Metadata =
980 bitcode::decode(&metadata).map_err(|e| sqlx::Error::Decode(e.into()))?;
981
982 Ok(SqlEvent(evento_core::Event {
983 id: Ulid::from_string(sqlx::Row::try_get(row, "id")?)
984 .map_err(|err| sqlx::Error::InvalidArgument(err.to_string()))?,
985 aggregator_id: sqlx::Row::try_get(row, "aggregator_id")?,
986 aggregator_type: sqlx::Row::try_get(row, "aggregator_type")?,
987 version: version as u16,
988 name: sqlx::Row::try_get(row, "name")?,
989 routing_key: sqlx::Row::try_get(row, "routing_key")?,
990 data: sqlx::Row::try_get(row, "data")?,
991 timestamp: timestamp as u64,
992 timestamp_subsec: timestamp_subsec as u32,
993 metadata,
994 }))
995 }
996}