pub struct Database { /* private fields */ }Expand description
The main entry point for database connection and management.
Database handles connection pooling, driver detection, and provides methods
for schema operations and query building. It uses sqlx’s AnyPool to support
multiple database backends with a unified interface.
§Fields
pool- The sqlx connection pool for executing queriesdriver- The detected database driver type
§Thread Safety
Database implements Clone and can be safely shared across threads.
The underlying connection pool is thread-safe and handles connection
distribution automatically.
§Example
use bottle_orm::Database;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to database
let db = Database::connect("postgres://localhost/mydb").await?;
// Create migrator
let migrator = db.migrator();
// Build queries
let query = db.model::<User>();
// Database can be cloned and shared
let db_clone = db.clone();
tokio::spawn(async move {
let users = db_clone.model::<User>().scan().await;
});
Ok(())
}Implementations§
Source§impl Database
impl Database
Sourcepub fn builder() -> DatabaseBuilder
pub fn builder() -> DatabaseBuilder
Sourcepub async fn connect(url: &str) -> Result<Self, Error>
pub async fn connect(url: &str) -> Result<Self, Error>
Connects to the database using a connection string (Database URL).
This method establishes a connection pool to the specified database and automatically detects the driver type based on the URL scheme. The connection pool is configured with a default maximum of 5 connections.
§Arguments
url- The database connection string with the format:<scheme>://<user>:<password>@<host>:<port>/<database>
§Supported URL Schemes
- PostgreSQL:
postgres://orpostgresql:// - MySQL:
mysql:// - SQLite:
sqlite://orsqlite::memory:(for in-memory databases)
§Connection Pool Configuration
- Maximum connections: 5
- Connection timeout: Default (30 seconds)
- Idle timeout: Default (10 minutes)
§Returns
Ok(Database)- Successfully connected database instanceErr(sqlx::Error)- Connection error (invalid URL, authentication failure, etc.)
§Examples
// PostgreSQL connection
let db = Database::connect("postgres://user:password@localhost:5432/mydb").await?;
// PostgreSQL with SSL
let db = Database::connect("postgres://user:password@localhost/mydb?sslmode=require").await?;
// SQLite in-memory database (great for testing)
let db = Database::connect("sqlite::memory:").await?;
// SQLite file-based database
let db = Database::connect("sqlite://./database.db").await?;
// MySQL connection
let db = Database::connect("mysql://user:password@localhost:3306/mydb").await?;§Error Handling
match Database::connect("postgres://localhost/mydb").await {
Ok(db) => println!("Connected successfully"),
Err(e) => eprintln!("Connection failed: {}", e),
}Sourcepub fn migrator(&self) -> Migrator<'_>
pub fn migrator(&self) -> Migrator<'_>
Creates a Migrator instance to manage schema migrations.
The migrator allows you to register multiple models and execute all necessary schema changes (table creation, foreign keys) in the correct order.
§Returns
A new Migrator instance associated with this database connection
§Example
let db = Database::connect("sqlite::memory:").await?;
db.migrator()
.register::<User>()
.register::<Post>()
.register::<Comment>()
.run()
.await?;§See Also
Migrator- For detailed migration documentationMigrator::register()- For registering modelsMigrator::run()- For executing migrations
Sourcepub fn model<T: Model + Send + Sync + Unpin>(&self) -> QueryBuilder<'_, T, Self>
pub fn model<T: Model + Send + Sync + Unpin>(&self) -> QueryBuilder<'_, T, Self>
Starts building a query for a specific Model.
This method creates a new QueryBuilder instance configured for the
specified model type. The query builder provides a fluent interface
for constructing SELECT and INSERT queries.
§Type Parameters
T- The Model type to query. Must implementModel + Send + Sync + Unpin
§Returns
A new QueryBuilder instance ready for query construction
§Example
// Simple query
let users: Vec<User> = db.model::<User>().scan().await?;
// Filtered query
let adults: Vec<User> = db.model::<User>()
.filter("age", ">=", 18)
.scan()
.await?;
// Insert operation
let new_user = User { /* ... */ };
db.model::<User>().insert(&new_user).await?;§See Also
QueryBuilder- For detailed query building documentationQueryBuilder::filter()- For adding WHERE clausesQueryBuilder::scan()- For executing SELECT queriesQueryBuilder::insert()- For INSERT operations
Sourcepub async fn create_table<T: Model>(&self) -> Result<&Self, Error>
pub async fn create_table<T: Model>(&self) -> Result<&Self, Error>
Creates the table for model T if it does not exist.
This method generates and executes SQL to create a table based on the model’s structure. It handles column definitions, primary keys, unique constraints, default values, and indexes.
§Type Parameters
T- The Model type representing the table
§Returns
Ok(&Self)- Reference to self for method chainingErr(sqlx::Error)- Database error during table creation
§Generated SQL Features
- Primary Keys: Automatically marked with
PRIMARY KEY - NOT NULL: Non-nullable fields get
NOT NULLconstraint - UNIQUE: Fields marked with
#[orm(unique)]getUNIQUEconstraint - DEFAULT: Fields marked with
#[orm(create_time)]getDEFAULT CURRENT_TIMESTAMP - Indexes: Fields marked with
#[orm(index)]get database indexes
§Example
use bottle_orm::Model;
use uuid::Uuid;
use chrono::{DateTime, Utc};
#[derive(Model)]
struct User {
#[orm(primary_key)]
id: Uuid,
#[orm(size = 50, unique)]
username: String,
#[orm(index)]
email: String,
age: i32,
#[orm(create_time)]
created_at: DateTime<Utc>,
}
// Creates table with:
// - UUID primary key
// - Unique username constraint
// - Index on email
// - created_at with DEFAULT CURRENT_TIMESTAMP
db.create_table::<User>().await?;§Generated SQL Example (PostgreSQL)
CREATE TABLE IF NOT EXISTS "user" (
"id" UUID PRIMARY KEY,
"username" VARCHAR(50) NOT NULL UNIQUE,
"email" TEXT NOT NULL,
"age" INTEGER NOT NULL,
"created_at" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS "idx_user_email" ON "user" ("email");Sourcepub async fn begin<'a>(&self) -> Result<Transaction<'a>, Error>
pub async fn begin<'a>(&self) -> Result<Transaction<'a>, Error>
Starts a new database transaction.
Returns a Transaction wrapper that can be used to execute multiple
queries atomically. The transaction must be explicitly committed
using commit(), otherwise it will be rolled back when dropped.
§Returns
Ok(Transaction)- A new transaction instanceErr(sqlx::Error)- Database error starting transaction
§Example
let mut tx = db.begin().await?;
// ... perform operations ...
tx.commit().await?;Sourcepub async fn assign_foreign_keys<T: Model>(&self) -> Result<&Self, Error>
pub async fn assign_foreign_keys<T: Model>(&self) -> Result<&Self, Error>
Checks for and assigns Foreign Keys for model T.
This method examines all columns marked with #[orm(foreign_key = "Table::Column")]
and creates the appropriate foreign key constraints. It verifies that constraints
don’t already exist before attempting to create them, preventing duplication errors.
§Type Parameters
T- The Model type to process for foreign keys
§Returns
Ok(&Self)- Reference to self for method chainingErr(sqlx::Error)- Database error during foreign key creation
§Constraint Naming
Foreign key constraints are named using the pattern:
fk_{table_name}_{column_name}
§Example
use bottle_orm::Model;
use uuid::Uuid;
#[derive(Model)]
struct User {
#[orm(primary_key)]
id: Uuid,
username: String,
}
#[derive(Model)]
struct Post {
#[orm(primary_key)]
id: Uuid,
#[orm(foreign_key = "User::id")]
user_id: Uuid,
title: String,
}
// Create tables first
db.create_table::<User>().await?;
db.create_table::<Post>().await?;
// Then assign foreign keys
db.assign_foreign_keys::<Post>().await?;§Generated SQL Example
ALTER TABLE "post"
ADD CONSTRAINT "fk_post_user_id"
FOREIGN KEY ("user_id")
REFERENCES "user" ("id");§Important Notes
- Foreign key assignment should be done after all tables are created
- The referenced table and column must exist before creating the foreign key
- Use the
Migratorto handle the correct order automatically - Currently optimized for PostgreSQL (uses
information_schema)
§See Also
Migrator- For automatic migration order management
Trait Implementations§
Source§impl<'a> Connection for &'a mut Database
Implementation of Connection for a mutable reference to Database.
impl<'a> Connection for &'a mut Database
Implementation of Connection for a mutable reference to Database.
Source§impl Connection for Database
Implementation of Connection for the main Database struct.
impl Connection for Database
Implementation of Connection for the main Database struct.
Uses the internal connection pool to execute queries.
Auto Trait Implementations§
impl Freeze for Database
impl !RefUnwindSafe for Database
impl Send for Database
impl Sync for Database
impl Unpin for Database
impl !UnwindSafe for Database
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more