SQLite with sqlx

Migrations, a connection pool in state, and queries verified at compile time.

Part 2 of 3Updated
cargo add sqlx --features runtime-tokio,sqlite,macros
cargo sqlx migrate add create_tasks
let tasks = sqlx::query_as!(
    Task,
    "SELECT id, title, done FROM tasks ORDER BY id DESC LIMIT ?",
    limit
)
.fetch_all(&pool)
.await?;

query_as! connects to your database at compile time, checks the SQL, and verifies that the returned columns match the struct. A typo in a column name is a build failure. This is the main reason to pick sqlx over an ORM.

Share the pool with State:

let app = Router::new().route("/tasks", get(list)).with_state(pool);

async fn list(State(pool): State<SqlitePool>) -> Result<Json<Vec<Task>>, AppError> { /* ... */ }

Set DATABASE_URL in .env, and run cargo sqlx prepare so CI can build without a live database.