Skip to main content
Annie Mei uses SQLx for PostgreSQL database access and PostgreSQL for data storage. The bot uses an async connection pool for queries and runs its own SQLx migrations at startup.
The bot owns settings tables in the annie_mei schema and reads OAuth-linked account data from auth-service-owned tables in the shared database. Keep bot and auth migrations coordinated when changing shared behavior.

Overview

SQLx provides:
  • Async queries — Non-blocking database access compatible with the Tokio runtime
  • Compile-time query checking — Optional query! macro that verifies SQL at build time
  • Connection pooling — Reusable database connections via sqlx::PgPoolOptions
  • Type-safe models#[derive(FromRow)] for mapping query results to Rust structs

Configuration

The database connection pool is configured in src/utils/database.rs:

Connection pool settings

Migration ownership

The bot service runs migrations from its own migrations/ directory during startup. The current bot-owned migration creates settings tables in the annie_mei schema:
These migrations create:
  • annie_mei.user_settings for per-member preferences
  • annie_mei.guild_settings for Discord server preferences
The bot still connects to a database that already contains the auth-service-owned OAuth schema. The current OAuth schema migrations live in the companion auth service repo under migrations/. The auth service runs them on startup with sqlx::migrate!("./migrations").
Do not use the bot repo’s migrations to prepare the OAuth schema. The bot migrations only create bot-owned settings tables and do not create oauth_credentials or oauth_sessions.

Bot repo migrations

Auth repo schema migrations

Creating auth schema migrations

Create new OAuth schema migrations from the auth service repo:
This creates reversible SQLx migration files:
Coordinate schema changes with the bot repo when you add, rename, or remove columns that the bot reads or deletes.

Running migrations

The auth service runs migrations during startup. To run them manually from the auth service repo:
To inspect migration state:

Querying with SQLx

The bot reads from the auth-service-owned oauth_credentials table using sqlx::query_as with FromRow structs:
src/models/db/oauth_credential.rs
Key points:
  • FromRow — Derives sqlx::FromRow to map query columns to struct fields by name
  • query_as — Executes raw SQL and maps results to a typed struct
  • fetch_optional — Returns Ok(None) when no row matches instead of an error
  • Async — All queries are async and compatible with the Tokio runtime
  • Pool reference — Pass &DbPool rather than acquiring a connection manually

Batch lookups

The get_by_discord_ids method queries multiple users at once for guild member status:

Writing data

The /unregister command demonstrates writing data using SQLx transactions:
Transactions are started from the pool:

Accessing the pool in commands

The connection pool is stored in Serenity’s TypeMap and accessed in command handlers:

Setup

Install SQLx CLI for auth schema work

Create the database

Or using psql:

Run auth migrations manually

Check migration status

Troubleshooting

Verify environment variables:
Test connection:
For bot startup migration failures, check the cargo run startup output for the failing SQLx migration and verify the database user can create the annie_mei schema and tables.Inspect the bot migration table from the bot repo database connection:
For auth service OAuth migration failures, check migration state from the auth repo:
For persistent auth issues, inspect the auth service _sqlx_migrations table directly.
If you see connection timeout errors:
  • Check max_connections in create_pool() (default: 10)
  • Ensure PostgreSQL’s max_connections is higher than the pool limit
  • Look for long-running queries or missing await points

Next Steps

Architecture

Understand how database fits in the architecture

Adding Commands

Use database connections in commands

SQLx Documentation

Official SQLx repository and docs