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}