diff --git a/crates/cli/src/app_state.rs b/crates/cli/src/app_state.rs index 3355559e..59aeb0a9 100644 --- a/crates/cli/src/app_state.rs +++ b/crates/cli/src/app_state.rs @@ -30,7 +30,7 @@ use mas_matrix::BoxHomeserverConnection; use mas_matrix_synapse::SynapseConnection; use mas_policy::{Policy, PolicyFactory}; use mas_router::UrlBuilder; -use mas_storage::{BoxClock, BoxRepository, BoxRng, Repository, SystemClock}; +use mas_storage::{BoxClock, BoxRepository, BoxRng, SystemClock}; use mas_storage_pg::PgRepository; use mas_templates::Templates; use opentelemetry::{ @@ -351,8 +351,6 @@ impl FromRequestParts for BoxRepository { histogram.record(duration_ms, &[]); } - Ok(repo - .map_err(mas_storage::RepositoryError::from_error) - .boxed()) + Ok(repo.boxed()) } } diff --git a/crates/handlers/src/activity_tracker/worker.rs b/crates/handlers/src/activity_tracker/worker.rs index 6c12a528..d02221ba 100644 --- a/crates/handlers/src/activity_tracker/worker.rs +++ b/crates/handlers/src/activity_tracker/worker.rs @@ -15,7 +15,7 @@ use std::{collections::HashMap, net::IpAddr}; use chrono::{DateTime, Utc}; -use mas_storage::{user::BrowserSessionRepository, Repository, RepositoryAccess}; +use mas_storage::{user::BrowserSessionRepository, RepositoryAccess}; use opentelemetry::{ metrics::{Counter, Histogram}, Key, diff --git a/crates/handlers/src/graphql/mod.rs b/crates/handlers/src/graphql/mod.rs index 0768af06..f56d5094 100644 --- a/crates/handlers/src/graphql/mod.rs +++ b/crates/handlers/src/graphql/mod.rs @@ -40,9 +40,7 @@ use mas_axum_utils::{ use mas_data_model::{BrowserSession, Session, SiteConfig, User}; use mas_matrix::HomeserverConnection; use mas_policy::{InstantiateError, Policy, PolicyFactory}; -use mas_storage::{ - BoxClock, BoxRepository, BoxRng, Clock, Repository, RepositoryError, SystemClock, -}; +use mas_storage::{BoxClock, BoxRepository, BoxRng, Clock, RepositoryError, SystemClock}; use mas_storage_pg::PgRepository; use opentelemetry_semantic_conventions::trace::{GRAPHQL_DOCUMENT, GRAPHQL_OPERATION_NAME}; use rand::{thread_rng, SeedableRng}; @@ -82,7 +80,7 @@ impl state::State for GraphQLState { .await .map_err(RepositoryError::from_error)?; - Ok(repo.map_err(RepositoryError::from_error).boxed()) + Ok(repo.boxed()) } async fn policy(&self) -> Result { diff --git a/crates/handlers/src/test_utils.rs b/crates/handlers/src/test_utils.rs index 8d7ea37c..dd8eaa1a 100644 --- a/crates/handlers/src/test_utils.rs +++ b/crates/handlers/src/test_utils.rs @@ -43,7 +43,7 @@ use mas_keystore::{Encrypter, JsonWebKey, JsonWebKeySet, Keystore, PrivateKey}; use mas_matrix::{BoxHomeserverConnection, HomeserverConnection, MockHomeserverConnection}; use mas_policy::{InstantiateError, Policy, PolicyFactory}; use mas_router::{SimpleRoute, UrlBuilder}; -use mas_storage::{clock::MockClock, BoxClock, BoxRepository, BoxRng, Repository}; +use mas_storage::{clock::MockClock, BoxClock, BoxRepository, BoxRng}; use mas_storage_pg::{DatabaseError, PgRepository}; use mas_templates::{SiteConfigExt, Templates}; use rand::SeedableRng; @@ -272,9 +272,7 @@ impl TestState { pub async fn repository(&self) -> Result { let repo = PgRepository::from_pool(&self.pool).await?; - Ok(repo - .map_err(mas_storage::RepositoryError::from_error) - .boxed()) + Ok(repo.boxed()) } /// Returns a new random number generator. @@ -330,9 +328,7 @@ impl graphql::State for TestGraphQLState { .await .map_err(mas_storage::RepositoryError::from_error)?; - Ok(repo - .map_err(mas_storage::RepositoryError::from_error) - .boxed()) + Ok(repo.boxed()) } async fn policy(&self) -> Result { @@ -500,9 +496,7 @@ impl FromRequestParts for BoxRepository { state: &TestState, ) -> Result { let repo = PgRepository::from_pool(&state.pool).await?; - Ok(repo - .map_err(mas_storage::RepositoryError::from_error) - .boxed()) + Ok(repo.boxed()) } } diff --git a/crates/storage-pg/src/compat/mod.rs b/crates/storage-pg/src/compat/mod.rs index 45073667..48f72d4f 100644 --- a/crates/storage-pg/src/compat/mod.rs +++ b/crates/storage-pg/src/compat/mod.rs @@ -36,7 +36,7 @@ mod tests { CompatSessionRepository, CompatSsoLoginFilter, }, user::UserRepository, - Clock, Pagination, Repository, RepositoryAccess, + Clock, Pagination, RepositoryAccess, }; use rand::SeedableRng; use rand_chacha::ChaChaRng; diff --git a/crates/storage-pg/src/oauth2/mod.rs b/crates/storage-pg/src/oauth2/mod.rs index fe66cff4..a386e094 100644 --- a/crates/storage-pg/src/oauth2/mod.rs +++ b/crates/storage-pg/src/oauth2/mod.rs @@ -36,7 +36,7 @@ mod tests { use mas_storage::{ clock::MockClock, oauth2::{OAuth2DeviceCodeGrantParams, OAuth2SessionFilter, OAuth2SessionRepository}, - Clock, Pagination, Repository, + Clock, Pagination, }; use oauth2_types::{ requests::{GrantType, ResponseMode}, diff --git a/crates/storage-pg/src/repository.rs b/crates/storage-pg/src/repository.rs index 6e951051..96ac2ef9 100644 --- a/crates/storage-pg/src/repository.rs +++ b/crates/storage-pg/src/repository.rs @@ -31,7 +31,7 @@ use mas_storage::{ UpstreamOAuthSessionRepository, }, user::{BrowserSessionRepository, UserEmailRepository, UserPasswordRepository, UserRepository}, - Repository, RepositoryAccess, RepositoryTransaction, + BoxRepository, MapErr, Repository, RepositoryAccess, RepositoryError, RepositoryTransaction, }; use sqlx::{PgConnection, PgPool, Postgres, Transaction}; use tracing::Instrument; @@ -76,6 +76,11 @@ impl PgRepository { let txn = pool.begin().await?; Ok(Self::from_conn(txn)) } + + /// Transform the repository into a type-erased [`BoxRepository`] + pub fn boxed(self) -> BoxRepository { + Box::new(MapErr::new(self, RepositoryError::from_error)) + } } impl PgRepository { diff --git a/crates/storage-pg/src/user/tests.rs b/crates/storage-pg/src/user/tests.rs index 789e9b4c..0d0c1d5b 100644 --- a/crates/storage-pg/src/user/tests.rs +++ b/crates/storage-pg/src/user/tests.rs @@ -19,7 +19,7 @@ use mas_storage::{ BrowserSessionFilter, BrowserSessionRepository, UserEmailFilter, UserEmailRepository, UserFilter, UserPasswordRepository, UserRepository, }, - Pagination, Repository, RepositoryAccess, + Pagination, RepositoryAccess, }; use rand::SeedableRng; use rand_chacha::ChaChaRng; diff --git a/crates/storage/src/pagination.rs b/crates/storage/src/pagination.rs index e3efcf0b..b6e91eb3 100644 --- a/crates/storage/src/pagination.rs +++ b/crates/storage/src/pagination.rs @@ -104,6 +104,13 @@ impl Pagination { self } + /// Clear the before cursor + #[must_use] + pub const fn clear_before(mut self) -> Self { + self.before = None; + self + } + /// Get items after the given cursor #[must_use] pub const fn after(mut self, id: Ulid) -> Self { @@ -111,6 +118,13 @@ impl Pagination { self } + /// Clear the after cursor + #[must_use] + pub const fn clear_after(mut self) -> Self { + self.after = None; + self + } + /// Process a page returned by a paginated query #[must_use] pub fn process(&self, mut edges: Vec) -> Page { diff --git a/crates/storage/src/repository.rs b/crates/storage/src/repository.rs index dae46e9a..86dc1566 100644 --- a/crates/storage/src/repository.rs +++ b/crates/storage/src/repository.rs @@ -34,7 +34,6 @@ use crate::{ BrowserSessionRepository, UserEmailRepository, UserPasswordRepository, UserRecoveryRepository, UserRepository, UserTermsRepository, }, - MapErr, }; /// A [`Repository`] helps interacting with the underlying storage backend. @@ -43,21 +42,6 @@ pub trait Repository: where E: std::error::Error + Send + Sync + 'static, { - /// Construct a (boxed) typed-erased repository - fn boxed(self) -> BoxRepository - where - Self: Sync + Sized + 'static, - { - Box::new(self) - } - - /// Map the error type of all the methods of a [`Repository`] - fn map_err(self, mapper: Mapper) -> MapErr - where - Self: Sized, - { - MapErr::new(self, mapper) - } } /// An opaque, type-erased error @@ -80,7 +64,7 @@ impl RepositoryError { } /// A type-erased [`Repository`] -pub type BoxRepository = Box + Send + Sync + 'static>; +pub type BoxRepository = Box + Send + Sync + 'static>; /// A [`RepositoryTransaction`] can be saved or cancelled, after a series /// of operations. @@ -113,7 +97,7 @@ pub trait RepositoryTransaction { /// repository is used at a time. /// /// When adding a new repository, you should add a new method to this trait, and -/// update the implementations for [`MapErr`] and [`Box`] below. +/// update the implementations for [`crate::MapErr`] and [`Box`] below. /// /// Note: this used to have generic associated types to avoid boxing all the /// repository traits, but that was removed because it made almost impossible to @@ -218,7 +202,7 @@ pub trait RepositoryAccess: Send { } /// Implementations of the [`RepositoryAccess`], [`RepositoryTransaction`] and -/// [`Repository`] for the [`MapErr`] wrapper and [`Box`] +/// [`Repository`] for the [`crate::MapErr`] wrapper and [`Box`] mod impls { use futures_util::{future::BoxFuture, FutureExt, TryFutureExt}; diff --git a/crates/storage/src/utils.rs b/crates/storage/src/utils.rs index 44caa23e..56eca026 100644 --- a/crates/storage/src/utils.rs +++ b/crates/storage/src/utils.rs @@ -26,7 +26,10 @@ pub struct MapErr { } impl MapErr { - pub(crate) fn new(inner: R, mapper: F) -> Self { + /// Create a new [`MapErr`] wrapper from an inner repository and a mapper + /// function + #[must_use] + pub fn new(inner: R, mapper: F) -> Self { Self { inner, mapper, diff --git a/crates/tasks/src/lib.rs b/crates/tasks/src/lib.rs index f84e321e..20a47137 100644 --- a/crates/tasks/src/lib.rs +++ b/crates/tasks/src/lib.rs @@ -18,7 +18,7 @@ use apalis_core::{executor::TokioExecutor, layers::extensions::Extension, monito use mas_email::Mailer; use mas_matrix::HomeserverConnection; use mas_router::UrlBuilder; -use mas_storage::{BoxClock, BoxRepository, Repository, SystemClock}; +use mas_storage::{BoxClock, BoxRepository, SystemClock}; use mas_storage_pg::{DatabaseError, PgRepository}; use rand::SeedableRng; use sqlx::{Pool, Postgres}; @@ -83,10 +83,7 @@ impl State { } pub async fn repository(&self) -> Result { - let repo = PgRepository::from_pool(self.pool()) - .await? - .map_err(mas_storage::RepositoryError::from_error) - .boxed(); + let repo = PgRepository::from_pool(self.pool()).await?.boxed(); Ok(repo) }