diff --git a/Cargo.lock b/Cargo.lock index e6709a0..f880270 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2519,6 +2519,7 @@ dependencies = [ "rustical_carddav", "rustical_frontend", "rustical_store", + "rustical_store_sqlite", "serde", "sqlx", "tokio", @@ -2632,16 +2633,25 @@ dependencies = [ "lazy_static", "password-auth", "pbkdf2", - "rand_core", "regex", "rstest", "rstest_reuse", "serde", "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "rustical_store_sqlite" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "rustical_store", + "serde", "sqlx", "thiserror", - "tokio", - "toml", "tracing", ] diff --git a/Cargo.toml b/Cargo.toml index c78a9c7..34be00a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,7 @@ ical = { version = "0.11", features = ["generator", "serde"] } toml = "0.8" rustical_dav = { path = "./crates/dav/" } rustical_store = { path = "./crates/store/" } +rustical_store_sqlite = { path = "./crates/store_sqlite/" } rustical_caldav = { path = "./crates/caldav/" } rustical_carddav = { path = "./crates/carddav/" } rustical_frontend = { path = "./crates/frontend/" } @@ -80,6 +81,7 @@ chrono-tz = "0.10.0" [dependencies] rustical_store = { workspace = true } +rustical_store_sqlite = { workspace = true } rustical_caldav = { workspace = true } rustical_carddav = { workspace = true } rustical_frontend = { workspace = true } diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 298b5f9..7805306 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -11,15 +11,10 @@ anyhow = { workspace = true } async-trait = { workspace = true } serde = { workspace = true } sha2 = { workspace = true } -sqlx = { workspace = true } -tokio = { workspace = true } -toml = { workspace = true } ical = { workspace = true } chrono = { workspace = true } regex = { workspace = true } lazy_static = { workspace = true } -rstest = { workspace = true } -rstest_reuse = { workspace = true } thiserror = { workspace = true } password-auth = { workspace = true } actix-web = { workspace = true } @@ -27,6 +22,9 @@ actix-session = { workspace = true } actix-web-httpauth = { workspace = true } tracing = { workspace = true } pbkdf2 = { workspace = true } -rand_core = { workspace = true } chrono-tz = { workspace = true } derive_more = { workspace = true } + +[dev-dependencies] +rstest = { workspace = true } +rstest_reuse = { workspace = true } diff --git a/crates/store/src/error.rs b/crates/store/src/error.rs index 33d400f..7217717 100644 --- a/crates/store/src/error.rs +++ b/crates/store/src/error.rs @@ -1,4 +1,5 @@ #[derive(Debug, thiserror::Error)] + pub enum Error { #[error("Not found")] NotFound, @@ -9,21 +10,9 @@ pub enum Error { #[error("Invalid ics/vcf input: {0}")] InvalidData(String), - #[error(transparent)] - SqlxError(sqlx::Error), - #[error(transparent)] Other(#[from] anyhow::Error), #[error(transparent)] ParserError(#[from] ical::parser::ParserError), } - -impl From for Error { - fn from(value: sqlx::Error) -> Self { - match value { - sqlx::Error::RowNotFound => Error::NotFound, - err => Error::SqlxError(err), - } - } -} diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index ca3a682..b515654 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -2,7 +2,6 @@ pub mod addressbook_store; pub mod calendar_store; pub mod error; pub mod model; -pub mod sqlite_store; pub mod timestamp; pub use error::Error; pub mod auth; diff --git a/crates/store_sqlite/Cargo.toml b/crates/store_sqlite/Cargo.toml new file mode 100644 index 0000000..6ebb140 --- /dev/null +++ b/crates/store_sqlite/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rustical_store_sqlite" +version.workspace = true +edition.workspace = true +description.workspace = true +repository.workspace = true +publish = false + +[dependencies] +rustical_store = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +serde = { workspace = true } +sqlx = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } diff --git a/crates/store/migrations/1_init.sql b/crates/store_sqlite/migrations/1_init.sql similarity index 100% rename from crates/store/migrations/1_init.sql rename to crates/store_sqlite/migrations/1_init.sql diff --git a/crates/store/migrations/2_addressbook.sql b/crates/store_sqlite/migrations/2_addressbook.sql similarity index 100% rename from crates/store/migrations/2_addressbook.sql rename to crates/store_sqlite/migrations/2_addressbook.sql diff --git a/crates/store/src/sqlite_store/addressbook_store.rs b/crates/store_sqlite/src/addressbook_store.rs similarity index 77% rename from crates/store/src/sqlite_store/addressbook_store.rs rename to crates/store_sqlite/src/addressbook_store.rs index 98bfba5..80b2afb 100644 --- a/crates/store/src/sqlite_store/addressbook_store.rs +++ b/crates/store_sqlite/src/addressbook_store.rs @@ -1,10 +1,10 @@ use super::{ChangeOperation, SqliteStore}; use crate::Error; -use crate::{ +use async_trait::async_trait; +use rustical_store::{ model::{AddressObject, Addressbook}, AddressbookStore, }; -use async_trait::async_trait; use sqlx::{Sqlite, Transaction}; use tracing::instrument; @@ -18,7 +18,7 @@ impl TryFrom for AddressObject { type Error = Error; fn try_from(value: AddressObjectRow) -> Result { - Self::from_vcf(value.id, value.vcf) + Ok(Self::from_vcf(value.id, value.vcf)?) } } @@ -60,7 +60,11 @@ async fn log_object_operation( #[async_trait] impl AddressbookStore for SqliteStore { #[instrument] - async fn get_addressbook(&self, principal: &str, id: &str) -> Result { + async fn get_addressbook( + &self, + principal: &str, + id: &str, + ) -> Result { let addressbook = sqlx::query_as!( Addressbook, r#"SELECT principal, id, synctoken, displayname, description, deleted_at @@ -70,12 +74,16 @@ impl AddressbookStore for SqliteStore { id ) .fetch_one(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; Ok(addressbook) } #[instrument] - async fn get_addressbooks(&self, principal: &str) -> Result, Error> { + async fn get_addressbooks( + &self, + principal: &str, + ) -> Result, rustical_store::Error> { let addressbooks = sqlx::query_as!( Addressbook, r#"SELECT principal, id, synctoken, displayname, description, deleted_at @@ -84,7 +92,8 @@ impl AddressbookStore for SqliteStore { principal ) .fetch_all(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; Ok(addressbooks) } @@ -94,7 +103,7 @@ impl AddressbookStore for SqliteStore { principal: String, id: String, addressbook: Addressbook, - ) -> Result<(), Error> { + ) -> Result<(), rustical_store::Error> { let result = sqlx::query!( r#"UPDATE addressbooks SET principal = ?, id = ?, displayname = ?, description = ? WHERE (principal, id) = (?, ?)"#, @@ -106,15 +115,19 @@ impl AddressbookStore for SqliteStore { id ) .execute(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; if result.rows_affected() == 0 { - return Err(Error::NotFound); + return Err(rustical_store::Error::NotFound); } Ok(()) } #[instrument] - async fn insert_addressbook(&self, addressbook: Addressbook) -> Result<(), Error> { + async fn insert_addressbook( + &self, + addressbook: Addressbook, + ) -> Result<(), rustical_store::Error> { sqlx::query!( r#"INSERT INTO addressbooks (principal, id, displayname, description) VALUES (?, ?, ?, ?)"#, @@ -124,7 +137,8 @@ impl AddressbookStore for SqliteStore { addressbook.description, ) .execute(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; Ok(()) } @@ -134,7 +148,7 @@ impl AddressbookStore for SqliteStore { principal: &str, addressbook_id: &str, use_trashbin: bool, - ) -> Result<(), Error> { + ) -> Result<(), rustical_store::Error> { match use_trashbin { true => { sqlx::query!( @@ -142,7 +156,7 @@ impl AddressbookStore for SqliteStore { principal, addressbook_id ) .execute(&self.db) - .await?; + .await.map_err(Error::SqlxError)?; } false => { sqlx::query!( @@ -151,7 +165,8 @@ impl AddressbookStore for SqliteStore { addressbook_id ) .execute(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; } }; Ok(()) @@ -162,14 +177,15 @@ impl AddressbookStore for SqliteStore { &self, principal: &str, addressbook_id: &str, - ) -> Result<(), Error> { + ) -> Result<(), rustical_store::Error> { sqlx::query!( r"UPDATE addressbooks SET deleted_at = NULL WHERE (principal, id) = (?, ?)", principal, addressbook_id ) .execute(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; Ok(()) } @@ -179,7 +195,7 @@ impl AddressbookStore for SqliteStore { principal: &str, addressbook_id: &str, synctoken: i64, - ) -> Result<(Vec, Vec, i64), Error> { + ) -> Result<(Vec, Vec, i64), rustical_store::Error> { struct Row { object_id: String, synctoken: i64, @@ -194,7 +210,7 @@ impl AddressbookStore for SqliteStore { synctoken ) .fetch_all(&self.db) - .await?; + .await.map_err(Error::SqlxError)?; let mut objects = vec![]; let mut deleted_objects = vec![]; @@ -207,7 +223,7 @@ impl AddressbookStore for SqliteStore { for Row { object_id, .. } in changes { match self.get_object(principal, addressbook_id, &object_id).await { Ok(object) => objects.push(object), - Err(Error::NotFound) => deleted_objects.push(object_id), + Err(rustical_store::Error::NotFound) => deleted_objects.push(object_id), Err(err) => return Err(err), } } @@ -220,7 +236,7 @@ impl AddressbookStore for SqliteStore { &self, principal: &str, addressbook_id: &str, - ) -> Result, Error> { + ) -> Result, rustical_store::Error> { sqlx::query_as!( AddressObjectRow, "SELECT id, vcf FROM addressobjects WHERE principal = ? AND addressbook_id = ? AND deleted_at IS NULL", @@ -228,9 +244,9 @@ impl AddressbookStore for SqliteStore { addressbook_id ) .fetch_all(&self.db) - .await? + .await.map_err(Error::SqlxError)? .into_iter() - .map(|row| row.try_into()) + .map(|row| row.try_into().map_err(rustical_store::Error::from)) .collect() } @@ -240,7 +256,7 @@ impl AddressbookStore for SqliteStore { principal: &str, addressbook_id: &str, object_id: &str, - ) -> Result { + ) -> Result { Ok(sqlx::query_as!( AddressObjectRow, "SELECT id, vcf FROM addressobjects WHERE (principal, addressbook_id, id) = (?, ?, ?)", @@ -249,7 +265,8 @@ impl AddressbookStore for SqliteStore { object_id ) .fetch_one(&self.db) - .await? + .await + .map_err(Error::SqlxError)? .try_into()?) } @@ -261,8 +278,8 @@ impl AddressbookStore for SqliteStore { object: AddressObject, // TODO: implement overwrite: bool, - ) -> Result<(), Error> { - let mut tx = self.db.begin().await?; + ) -> Result<(), rustical_store::Error> { + let mut tx = self.db.begin().await.map_err(Error::SqlxError)?; let (object_id, vcf) = (object.get_id(), object.get_vcf()); @@ -274,7 +291,8 @@ impl AddressbookStore for SqliteStore { vcf ) .execute(&mut *tx) - .await?; + .await + .map_err(Error::SqlxError)?; log_object_operation( &mut tx, @@ -283,9 +301,10 @@ impl AddressbookStore for SqliteStore { object_id, ChangeOperation::Add, ) - .await?; + .await + .map_err(rustical_store::Error::from)?; - tx.commit().await?; + tx.commit().await.map_err(Error::SqlxError)?; Ok(()) } @@ -296,8 +315,8 @@ impl AddressbookStore for SqliteStore { addressbook_id: &str, object_id: &str, use_trashbin: bool, - ) -> Result<(), Error> { - let mut tx = self.db.begin().await?; + ) -> Result<(), rustical_store::Error> { + let mut tx = self.db.begin().await.map_err(Error::SqlxError)?; match use_trashbin { true => { @@ -308,7 +327,7 @@ impl AddressbookStore for SqliteStore { object_id ) .execute(&mut *tx) - .await?; + .await.map_err(Error::SqlxError)?; } false => { sqlx::query!( @@ -317,7 +336,8 @@ impl AddressbookStore for SqliteStore { object_id ) .execute(&mut *tx) - .await?; + .await + .map_err(Error::SqlxError)?; } }; log_object_operation( @@ -327,8 +347,9 @@ impl AddressbookStore for SqliteStore { object_id, ChangeOperation::Delete, ) - .await?; - tx.commit().await?; + .await + .map_err(rustical_store::Error::from)?; + tx.commit().await.map_err(Error::SqlxError)?; Ok(()) } @@ -338,8 +359,8 @@ impl AddressbookStore for SqliteStore { principal: &str, addressbook_id: &str, object_id: &str, - ) -> Result<(), Error> { - let mut tx = self.db.begin().await?; + ) -> Result<(), rustical_store::Error> { + let mut tx = self.db.begin().await.map_err(Error::SqlxError)?; sqlx::query!( r#"UPDATE addressobjects SET deleted_at = NULL, updated_at = datetime() WHERE (principal, addressbook_id, id) = (?, ?, ?)"#, @@ -348,7 +369,7 @@ impl AddressbookStore for SqliteStore { object_id ) .execute(&mut *tx) - .await?; + .await.map_err(Error::SqlxError)?; log_object_operation( &mut tx, @@ -357,8 +378,9 @@ impl AddressbookStore for SqliteStore { object_id, ChangeOperation::Add, ) - .await?; - tx.commit().await?; + .await + .map_err(rustical_store::Error::from)?; + tx.commit().await.map_err(Error::SqlxError)?; Ok(()) } } diff --git a/crates/store/src/sqlite_store/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs similarity index 76% rename from crates/store/src/sqlite_store/calendar_store.rs rename to crates/store_sqlite/src/calendar_store.rs index 04178c3..2935703 100644 --- a/crates/store/src/sqlite_store/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -1,9 +1,10 @@ use super::{ChangeOperation, SqliteStore}; -use crate::model::object::CalendarObject; -use crate::model::Calendar; -use crate::{CalendarStore, Error}; +use crate::Error; use anyhow::Result; use async_trait::async_trait; +use rustical_store::model::object::CalendarObject; +use rustical_store::model::Calendar; +use rustical_store::CalendarStore; use sqlx::Sqlite; use sqlx::Transaction; use tracing::instrument; @@ -15,9 +16,9 @@ struct CalendarObjectRow { } impl TryFrom for CalendarObject { - type Error = Error; + type Error = rustical_store::Error; - fn try_from(value: CalendarObjectRow) -> Result { + fn try_from(value: CalendarObjectRow) -> Result { CalendarObject::from_ics(value.id, value.ics) } } @@ -29,7 +30,7 @@ async fn log_object_operation( cal_id: &str, object_id: &str, operation: ChangeOperation, -) -> Result<(), Error> { +) -> Result<(), rustical_store::Error> { sqlx::query!( r#" UPDATE calendars @@ -39,7 +40,8 @@ async fn log_object_operation( cal_id ) .execute(&mut **tx) - .await?; + .await + .map_err(Error::SqlxError)?; sqlx::query!( r#" @@ -53,14 +55,19 @@ async fn log_object_operation( operation ) .execute(&mut **tx) - .await?; + .await + .map_err(Error::SqlxError)?; Ok(()) } #[async_trait] impl CalendarStore for SqliteStore { #[instrument] - async fn get_calendar(&self, principal: &str, id: &str) -> Result { + async fn get_calendar( + &self, + principal: &str, + id: &str, + ) -> Result { let cal = sqlx::query_as!( Calendar, r#"SELECT principal, id, synctoken, "order", displayname, description, color, timezone, deleted_at @@ -70,12 +77,12 @@ impl CalendarStore for SqliteStore { id ) .fetch_one(&self.db) - .await?; + .await.map_err(Error::SqlxError)?; Ok(cal) } #[instrument] - async fn get_calendars(&self, principal: &str) -> Result, Error> { + async fn get_calendars(&self, principal: &str) -> Result, rustical_store::Error> { let cals = sqlx::query_as!( Calendar, r#"SELECT principal, id, synctoken, displayname, "order", description, color, timezone, deleted_at @@ -84,12 +91,12 @@ impl CalendarStore for SqliteStore { principal ) .fetch_all(&self.db) - .await?; + .await.map_err(Error::SqlxError)?; Ok(cals) } #[instrument] - async fn insert_calendar(&self, calendar: Calendar) -> Result<(), Error> { + async fn insert_calendar(&self, calendar: Calendar) -> Result<(), rustical_store::Error> { sqlx::query!( r#"INSERT INTO calendars (principal, id, displayname, description, "order", color, timezone) VALUES (?, ?, ?, ?, ?, ?, ?)"#, @@ -102,7 +109,7 @@ impl CalendarStore for SqliteStore { calendar.timezone ) .execute(&self.db) - .await?; + .await.map_err(Error::SqlxError)?; Ok(()) } @@ -112,7 +119,7 @@ impl CalendarStore for SqliteStore { principal: String, id: String, calendar: Calendar, - ) -> Result<(), Error> { + ) -> Result<(), rustical_store::Error> { let result = sqlx::query!( r#"UPDATE calendars SET principal = ?, id = ?, displayname = ?, description = ?, "order" = ?, color = ?, timezone = ? WHERE (principal, id) = (?, ?)"#, @@ -125,9 +132,9 @@ impl CalendarStore for SqliteStore { calendar.timezone, principal, id - ).execute(&self.db).await?; + ).execute(&self.db).await.map_err(Error::SqlxError)?; if result.rows_affected() == 0 { - return Err(Error::NotFound); + return Err(rustical_store::Error::NotFound); } Ok(()) } @@ -139,7 +146,7 @@ impl CalendarStore for SqliteStore { principal: &str, id: &str, use_trashbin: bool, - ) -> Result<(), Error> { + ) -> Result<(), rustical_store::Error> { match use_trashbin { true => { sqlx::query!( @@ -147,7 +154,7 @@ impl CalendarStore for SqliteStore { principal, id ) .execute(&self.db) - .await?; + .await.map_err(Error::SqlxError)?; } false => { sqlx::query!( @@ -156,21 +163,27 @@ impl CalendarStore for SqliteStore { id ) .execute(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; } }; Ok(()) } #[instrument] - async fn restore_calendar(&self, principal: &str, id: &str) -> Result<(), Error> { + async fn restore_calendar( + &self, + principal: &str, + id: &str, + ) -> Result<(), rustical_store::Error> { sqlx::query!( r"UPDATE calendars SET deleted_at = NULL WHERE (principal, id) = (?, ?)", principal, id ) .execute(&self.db) - .await?; + .await + .map_err(Error::SqlxError)?; Ok(()) } @@ -179,7 +192,7 @@ impl CalendarStore for SqliteStore { &self, principal: &str, cal_id: &str, - ) -> Result, Error> { + ) -> Result, rustical_store::Error> { sqlx::query_as!( CalendarObjectRow, "SELECT id, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL", @@ -187,9 +200,9 @@ impl CalendarStore for SqliteStore { cal_id ) .fetch_all(&self.db) - .await? + .await.map_err(Error::SqlxError)? .into_iter() - .map(|row| row.try_into()) + .map(|row| row.try_into().map_err(rustical_store::Error::from)) .collect() } @@ -199,7 +212,7 @@ impl CalendarStore for SqliteStore { principal: &str, cal_id: &str, object_id: &str, - ) -> Result { + ) -> Result { Ok(sqlx::query_as!( CalendarObjectRow, "SELECT id, ics FROM calendarobjects WHERE (principal, cal_id, id) = (?, ?, ?)", @@ -208,7 +221,8 @@ impl CalendarStore for SqliteStore { object_id ) .fetch_one(&self.db) - .await? + .await + .map_err(Error::SqlxError)? .try_into()?) } @@ -220,8 +234,8 @@ impl CalendarStore for SqliteStore { object: CalendarObject, // TODO: implement overwrite: bool, - ) -> Result<(), Error> { - let mut tx = self.db.begin().await?; + ) -> Result<(), rustical_store::Error> { + let mut tx = self.db.begin().await.map_err(Error::SqlxError)?; let (object_id, ics) = (object.get_id(), object.get_ics()); @@ -233,7 +247,8 @@ impl CalendarStore for SqliteStore { ics ) .execute(&mut *tx) - .await?; + .await + .map_err(Error::SqlxError)?; log_object_operation( &mut tx, @@ -244,7 +259,7 @@ impl CalendarStore for SqliteStore { ) .await?; - tx.commit().await?; + tx.commit().await.map_err(Error::SqlxError)?; Ok(()) } @@ -255,8 +270,8 @@ impl CalendarStore for SqliteStore { cal_id: &str, id: &str, use_trashbin: bool, - ) -> Result<(), Error> { - let mut tx = self.db.begin().await?; + ) -> Result<(), rustical_store::Error> { + let mut tx = self.db.begin().await.map_err(Error::SqlxError)?; match use_trashbin { true => { @@ -267,7 +282,7 @@ impl CalendarStore for SqliteStore { id ) .execute(&mut *tx) - .await?; + .await.map_err(Error::SqlxError)?; } false => { sqlx::query!( @@ -276,11 +291,12 @@ impl CalendarStore for SqliteStore { id ) .execute(&mut *tx) - .await?; + .await + .map_err(Error::SqlxError)?; } }; log_object_operation(&mut tx, principal, cal_id, id, ChangeOperation::Delete).await?; - tx.commit().await?; + tx.commit().await.map_err(Error::SqlxError)?; Ok(()) } @@ -290,8 +306,8 @@ impl CalendarStore for SqliteStore { principal: &str, cal_id: &str, object_id: &str, - ) -> Result<(), Error> { - let mut tx = self.db.begin().await?; + ) -> Result<(), rustical_store::Error> { + let mut tx = self.db.begin().await.map_err(Error::SqlxError)?; sqlx::query!( r#"UPDATE calendarobjects SET deleted_at = NULL, updated_at = datetime() WHERE (principal, cal_id, id) = (?, ?, ?)"#, @@ -300,10 +316,10 @@ impl CalendarStore for SqliteStore { object_id ) .execute(&mut *tx) - .await?; + .await.map_err(Error::SqlxError)?; log_object_operation(&mut tx, principal, cal_id, object_id, ChangeOperation::Add).await?; - tx.commit().await?; + tx.commit().await.map_err(Error::SqlxError)?; Ok(()) } @@ -313,7 +329,7 @@ impl CalendarStore for SqliteStore { principal: &str, cal_id: &str, synctoken: i64, - ) -> Result<(Vec, Vec, i64), Error> { + ) -> Result<(Vec, Vec, i64), rustical_store::Error> { struct Row { object_id: String, synctoken: i64, @@ -328,7 +344,7 @@ impl CalendarStore for SqliteStore { synctoken ) .fetch_all(&self.db) - .await?; + .await.map_err(Error::SqlxError)?; let mut objects = vec![]; let mut deleted_objects = vec![]; @@ -341,7 +357,7 @@ impl CalendarStore for SqliteStore { for Row { object_id, .. } in changes { match self.get_object(principal, cal_id, &object_id).await { Ok(object) => objects.push(object), - Err(Error::NotFound) => deleted_objects.push(object_id), + Err(rustical_store::Error::NotFound) => deleted_objects.push(object_id), Err(err) => return Err(err), } } diff --git a/crates/store_sqlite/src/error.rs b/crates/store_sqlite/src/error.rs new file mode 100644 index 0000000..26f4889 --- /dev/null +++ b/crates/store_sqlite/src/error.rs @@ -0,0 +1,51 @@ +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Not found")] + NotFound, + + #[error("Resource already exists and overwrite=false")] + AlreadyExists, + + #[error("Invalid ics/vcf input: {0}")] + InvalidData(String), + + #[error(transparent)] + SqlxError(sqlx::Error), + + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +impl From for Error { + fn from(value: sqlx::Error) -> Self { + match value { + sqlx::Error::RowNotFound => Error::NotFound, + err => Error::SqlxError(err), + } + } +} + +// TODO: clean up error types +impl From for rustical_store::Error { + fn from(value: Error) -> Self { + match value { + Error::NotFound => Self::NotFound, + Error::AlreadyExists => Self::AlreadyExists, + Error::InvalidData(b) => Self::InvalidData(b), + Error::SqlxError(err) => Self::Other(err.into()), + Error::Other(err) => Self::Other(err), + } + } +} + +impl From for Error { + fn from(value: rustical_store::Error) -> Self { + match value { + rustical_store::Error::NotFound => Self::NotFound, + rustical_store::Error::AlreadyExists => Self::AlreadyExists, + rustical_store::Error::InvalidData(b) => Self::InvalidData(b), + rustical_store::Error::Other(err) => Self::Other(err), + rustical_store::Error::ParserError(err) => Self::Other(err.into()), + } + } +} diff --git a/crates/store/src/sqlite_store/mod.rs b/crates/store_sqlite/src/lib.rs similarity index 96% rename from crates/store/src/sqlite_store/mod.rs rename to crates/store_sqlite/src/lib.rs index 6d8d1fa..7410dd6 100644 --- a/crates/store/src/sqlite_store/mod.rs +++ b/crates/store_sqlite/src/lib.rs @@ -3,6 +3,9 @@ use sqlx::{sqlite::SqliteConnectOptions, Pool, Sqlite, SqlitePool}; pub mod addressbook_store; pub mod calendar_store; +pub mod error; + +pub use error::Error; #[derive(Debug, Clone, Serialize, sqlx::Type)] #[serde(rename_all = "kebab-case")] diff --git a/src/main.rs b/src/main.rs index d9db7a4..9cc9cb1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,8 +14,8 @@ use opentelemetry_sdk::{runtime, Resource}; use opentelemetry_semantic_conventions::resource::{SERVICE_NAME, SERVICE_VERSION}; use opentelemetry_semantic_conventions::SCHEMA_URL; use rustical_store::auth::StaticUserStore; -use rustical_store::sqlite_store::{create_db_pool, SqliteStore}; use rustical_store::{AddressbookStore, CalendarStore}; +use rustical_store_sqlite::{create_db_pool, SqliteStore}; use std::fs; use std::sync::Arc; use std::time::Duration;