kit_rs/database/
mod.rs

1//! Database module for Kit framework
2//!
3//! Provides a SeaORM-based ORM with Laravel-like API.
4//!
5//! # Quick Start
6//!
7//! ```rust,ignore
8//! use kit::{Config, DB, DatabaseConfig};
9//!
10//! // 1. Register database config (in config/mod.rs)
11//! Config::register(DatabaseConfig::from_env());
12//!
13//! // 2. Initialize connection (in bootstrap.rs)
14//! DB::init().await.expect("Failed to connect to database");
15//!
16//! // 3. Use in controllers
17//! let conn = DB::connection()?;
18//! let users = User::find().all(conn.inner()).await?;
19//! ```
20//!
21//! # Configuration
22//!
23//! Set these environment variables:
24//!
25//! ```env
26//! DATABASE_URL=postgres://user:pass@localhost:5432/mydb
27//! # or for SQLite:
28//! DATABASE_URL=sqlite://./database.db
29//!
30//! # Optional:
31//! DB_MAX_CONNECTIONS=10
32//! DB_MIN_CONNECTIONS=1
33//! DB_CONNECT_TIMEOUT=30
34//! DB_LOGGING=false
35//! ```
36
37pub mod config;
38pub mod connection;
39pub mod model;
40
41pub use config::{DatabaseConfig, DatabaseConfigBuilder, DatabaseType};
42pub use connection::DbConnection;
43pub use model::{Model, ModelMut};
44
45/// Injectable database connection type
46///
47/// This is an alias for `DbConnection` that can be used with dependency injection.
48/// Use with the `#[inject]` attribute in actions and services for cleaner database access.
49///
50/// # Example
51///
52/// ```rust,ignore
53/// use kit::{injectable, Database};
54///
55/// #[injectable]
56/// pub struct CreateUserAction {
57///     #[inject]
58///     db: Database,
59/// }
60///
61/// impl CreateUserAction {
62///     pub async fn execute(&self) {
63///         let users = User::find().all(self.db.conn()).await?;
64///     }
65/// }
66/// ```
67pub type Database = DbConnection;
68
69use crate::error::FrameworkError;
70use crate::{App, Config};
71
72/// Database facade - main entry point for database operations
73///
74/// Provides static methods for initializing and accessing the database connection.
75/// The connection is stored in the application container as a singleton.
76///
77/// # Example
78///
79/// ```rust,ignore
80/// use kit::{DB, DatabaseConfig, Config};
81///
82/// // Initialize (usually in bootstrap.rs)
83/// Config::register(DatabaseConfig::from_env());
84/// DB::init().await?;
85///
86/// // Use anywhere in your app
87/// let conn = DB::connection()?;
88/// ```
89pub struct DB;
90
91impl DB {
92    /// Initialize the database connection
93    ///
94    /// Reads configuration from `DatabaseConfig` (must be registered via Config system)
95    /// and establishes a connection pool. The connection is stored in the App container.
96    ///
97    /// # Errors
98    ///
99    /// Returns an error if:
100    /// - `DatabaseConfig` is not registered
101    /// - Connection to the database fails
102    ///
103    /// # Example
104    ///
105    /// ```rust,ignore
106    /// // In bootstrap.rs
107    /// pub async fn register() {
108    ///     DB::init().await.expect("Failed to connect to database");
109    /// }
110    /// ```
111    pub async fn init() -> Result<(), FrameworkError> {
112        let config = Config::get::<DatabaseConfig>().ok_or_else(|| {
113            FrameworkError::internal(
114                "DatabaseConfig not registered. Call Config::register(DatabaseConfig::from_env()) first.",
115            )
116        })?;
117
118        let connection = DbConnection::connect(&config).await?;
119        App::singleton(connection);
120        Ok(())
121    }
122
123    /// Initialize with a custom config
124    ///
125    /// Useful for testing or when you need to connect to a different database.
126    ///
127    /// # Example
128    ///
129    /// ```rust,ignore
130    /// let config = DatabaseConfig::builder()
131    ///     .url("sqlite::memory:")
132    ///     .build();
133    /// DB::init_with(config).await?;
134    /// ```
135    pub async fn init_with(config: DatabaseConfig) -> Result<(), FrameworkError> {
136        let connection = DbConnection::connect(&config).await?;
137        App::singleton(connection);
138        Ok(())
139    }
140
141    /// Get the database connection
142    ///
143    /// Returns the connection from the App container. The connection is wrapped
144    /// in a `DbConnection` which provides convenient access to the underlying
145    /// SeaORM `DatabaseConnection`.
146    ///
147    /// # Errors
148    ///
149    /// Returns an error if `DB::init()` was not called.
150    ///
151    /// # Example
152    ///
153    /// ```rust,ignore
154    /// let conn = DB::connection()?;
155    ///
156    /// // Use with SeaORM queries
157    /// let users = User::find()
158    ///     .all(conn.inner())
159    ///     .await?;
160    /// ```
161    pub fn connection() -> Result<DbConnection, FrameworkError> {
162        App::resolve::<DbConnection>()
163    }
164
165    /// Check if the database connection is initialized
166    ///
167    /// # Example
168    ///
169    /// ```rust,ignore
170    /// if DB::is_connected() {
171    ///     let conn = DB::connection()?;
172    ///     // ...
173    /// }
174    /// ```
175    pub fn is_connected() -> bool {
176        App::has::<DbConnection>()
177    }
178
179    /// Get the database connection for use with SeaORM
180    ///
181    /// This is a convenience alias for `DB::connection()`. The returned
182    /// `DbConnection` implements `Deref<Target=DatabaseConnection>`, so you
183    /// can use it directly with SeaORM methods.
184    ///
185    /// # Example
186    ///
187    /// ```rust,ignore
188    /// use kit::database::DB;
189    /// use sea_orm::{Set, ActiveModelTrait};
190    ///
191    /// let new_todo = todos::ActiveModel {
192    ///     title: Set("My Todo".to_string()),
193    ///     ..Default::default()
194    /// };
195    ///
196    /// // Use &* to dereference to &DatabaseConnection
197    /// let inserted = new_todo.insert(&*DB::get()?).await?;
198    ///
199    /// // Or use .inner() method
200    /// let inserted = new_todo.insert(DB::get()?.inner()).await?;
201    /// ```
202    pub fn get() -> Result<DbConnection, FrameworkError> {
203        Self::connection()
204    }
205}
206
207// Re-export sea_orm types that users commonly need
208pub use sea_orm;