Database

Struct Database 

Source
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 queries
  • driver - 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

Source

pub fn builder() -> DatabaseBuilder

Creates a builder to configure the database connection options.

Returns a DatabaseBuilder which allows setting pool options like max_connections, timeouts, etc.

§Example
let db = Database::builder()
    .max_connections(20)
    .connect("postgres://...")
    .await?;
Source

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:// or postgresql://
  • MySQL: mysql://
  • SQLite: sqlite:// or sqlite::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 instance
  • Err(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),
}
Source

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
Source

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 implement Model + 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
Source

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 chaining
  • Err(sqlx::Error) - Database error during table creation
§Generated SQL Features
  • Primary Keys: Automatically marked with PRIMARY KEY
  • NOT NULL: Non-nullable fields get NOT NULL constraint
  • UNIQUE: Fields marked with #[orm(unique)] get UNIQUE constraint
  • DEFAULT: Fields marked with #[orm(create_time)] get DEFAULT 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");
Source

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 instance
  • Err(sqlx::Error) - Database error starting transaction
§Example
let mut tx = db.begin().await?;
// ... perform operations ...
tx.commit().await?;
Source

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 chaining
  • Err(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 Migrator to handle the correct order automatically
  • Currently optimized for PostgreSQL (uses information_schema)
§See Also
  • Migrator - For automatic migration order management

Trait Implementations§

Source§

impl Clone for Database

Source§

fn clone(&self) -> Database

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'a> Connection for &'a mut Database

Implementation of Connection for a mutable reference to Database.

Source§

type Exec<'c> = &'c Pool<Any> where Self: 'c

The type of the executor returned by this connection. Read more
Source§

fn executor<'c>(&'c mut self) -> Self::Exec<'c>

Returns a mutable reference to the SQLx executor. Read more
Source§

impl Connection for Database

Implementation of Connection for the main Database struct.

Uses the internal connection pool to execute queries.

Source§

type Exec<'c> = &'c Pool<Any>

The type of the executor returned by this connection. Read more
Source§

fn executor<'c>(&'c mut self) -> Self::Exec<'c>

Returns a mutable reference to the SQLx executor. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more