sqlx_utils/traits/repository/
mod.rs

1//! [`Repository`] Trait to define a database repository
2
3mod_def! {!export
4    pub(crate) mod insert;
5    pub(crate) mod update;
6    pub(crate) mod save;
7    pub(crate) mod select;
8    pub(crate) mod delete;
9    pub(crate) mod transactions;
10}
11
12use crate::mod_def;
13use crate::prelude::Pool;
14use crate::traits::model::Model;
15use tracing::{debug_span, Span};
16
17/// A trait that provides a standardized interface for database operations, implementing the Repository pattern.
18///
19/// This trait serves as a foundation for all repository implementations in the system,
20/// offering both basic access to database connections and advanced batch processing capabilities.
21/// It centralizes the logic for database access patterns and promotes consistent error handling
22/// across the application.
23///
24/// # Type Parameters
25///
26/// * `M` - The model type that this repository manages. Must implement the [`Model`] trait.
27///
28/// # Design Philosophy
29///
30/// This trait follows several key design principles:
31///
32/// 1. **Separation of Concerns**: The repository isolates database access logic from business logic
33/// 2. **Type Safety**: Uses generics and associated types to maintain compile-time type checking
34/// 3. **Instrumentation Support**: Built-in tracing for debugging and monitoring
35/// 4. **Extensibility**: Serves as a base for more specialized repository traits
36///
37/// # Core Methods
38///
39/// Repositories must implement:
40///
41/// ```no_compile
42/// fn pool(&self) -> &Pool;  // Access to database connection pool
43/// ```
44///
45/// # Usage Example
46///
47/// Basic repository implementation:
48/// ```rust
49/// # use sqlx_utils::prelude::*;
50/// # use sqlx_utils::types::Pool;
51/// # struct User { id: i32, name: String }
52/// # impl Model for User {
53/// #     type Id = i32;
54/// #     fn get_id(&self) -> Option<Self::Id> { Some(self.id) }
55/// # }
56///
57/// struct UserRepository {
58///     pool: Pool
59/// }
60///
61/// impl Repository<User> for UserRepository {
62///     fn pool(&self) -> &Pool {
63///         &self.pool
64///     }
65/// }
66///
67/// // Adding specialized capabilities through extension traits
68/// impl InsertableRepository<User> for UserRepository {
69///     fn insert_query(user: &User) -> Query<'_> {
70///         sqlx::query("INSERT INTO users (name) VALUES ($1)")
71///             .bind(&user.name)
72///     }
73/// }
74/// ```
75///
76/// # Error Handling
77///
78/// Repository methods return [`crate::Result<T>`], providing consistent error handling across
79/// the application. This includes database errors, validation errors, and transactions errors.
80///
81/// # Implementation Notes
82///
83/// 1. The trait is intended to be extended by more specialized traits that provide
84///    concrete CRUD operations (like [`InsertableRepository`], [`UpdatableRepository`], etc.)
85/// 2. The static `repository_span()` method provides consistent tracing instrumentation
86///    across all repositories
87/// 3. Use the included macros ([`repository!`](crate::repository), [`repository_insert!`](crate::repository_insert), etc.) to reduce
88///    boilerplate when implementing repositories
89#[diagnostic::on_unimplemented(
90    note = "Type `{Self}` does not implement the `Repository<{M}>` trait",
91    label = "this type does not implement `Repository` for model type `{M}`",
92    message = "`{Self}` must implement `Repository<{M}>` to provide database operations for `{M}`"
93)]
94pub trait Repository<M>: Sync
95where
96    M: Model,
97{
98    /// Gets a reference to the database connection pool used by this repository.
99    ///
100    /// The pool is a fundamental component that manages database connections efficiently,
101    /// handling connection pooling, timeouts, and reconnection strategies. Each repository
102    /// instance maintains its own reference to a pool, but multiple repositories can share
103    /// the same underlying pool to optimize resource usage.
104    ///
105    /// # Returns
106    ///
107    /// * `&`[`Pool`] - A reference to the Database connection pool
108    fn pool(&self) -> &Pool;
109
110    /// Creates a tracing span for repository operations.
111    ///
112    /// This method provides a consistent way to create spans for tracing and
113    /// debugging repository operations. All repository methods should use this
114    /// span as their parent span to ensure proper hierarchical tracing.
115    ///
116    /// # Returns
117    ///
118    /// * [`Span`] - A tracing span for repository operations
119    #[inline]
120    fn repository_span() -> Span {
121        debug_span!("Repository")
122    }
123}