# SQLx 0.7 to 0.8 Migration Guide for Owlen ## Executive Summary The Owlen project has been successfully upgraded from SQLx 0.7 to SQLx 0.8. The migration was straightforward as Owlen uses SQLite, which is not affected by the security vulnerability CVE-2024-0363. ## Key Changes Made ### 1. Cargo.toml Update **Before (SQLx 0.7):** ```toml sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "sqlite", "macros", "uuid", "chrono", "migrate"] } ``` **After (SQLx 0.8):** ```toml sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "tls-rustls", "sqlite", "macros", "uuid", "chrono", "migrate"] } ``` **Key change:** Split `runtime-tokio-rustls` into `runtime-tokio` and `tls-rustls` ## Important Notes for Owlen ### 1. Security Status - **CVE-2024-0363 (Binary Protocol Misinterpretation)**: This vulnerability **DOES NOT AFFECT SQLite users** - Only affects PostgreSQL and MySQL that use binary network protocols - SQLite uses an in-process C API, not a network protocol - No security risk for Owlen's SQLite implementation ### 2. Date/Time Handling Owlen uses `chrono` types directly, not through SQLx's query macros for datetime columns. The current implementation: - Uses `INTEGER` columns for timestamps (Unix epoch seconds) - Converts between `SystemTime` and epoch seconds manually - No changes needed for datetime handling ### 3. Database Schema The existing migrations work without modification: - `/crates/owlen-core/migrations/0001_create_conversations.sql` - `/crates/owlen-core/migrations/0002_create_secure_items.sql` ### 4. Offline Mode Changes For CI/CD pipelines: - Offline mode is now always enabled (no separate flag needed) - Use `SQLX_OFFLINE=true` environment variable to force offline builds - Run `cargo sqlx prepare --workspace` to regenerate query metadata - The `.sqlx` directory should be committed to version control ## Testing Checklist After the upgrade, perform these tests: - [ ] Run all unit tests: `cargo test --all` - [ ] Test database operations: - [ ] Create new conversation - [ ] Save existing conversation - [ ] Load conversation by ID - [ ] List all conversations - [ ] Search conversations - [ ] Delete conversation - [ ] Test migrations: `cargo sqlx migrate run` - [ ] Test offline compilation (CI simulation): ```bash rm -rf .sqlx cargo sqlx prepare --workspace SQLX_OFFLINE=true cargo build --release ``` ## Migration Code Patterns ### Connection Pool Setup (No Changes Required) The connection pool setup remains identical: ```rust use sqlx::sqlite::{SqlitePool, SqlitePoolOptions, SqliteConnectOptions}; let options = SqliteConnectOptions::from_str(&format!("sqlite://{}", path))? .create_if_missing(true) .journal_mode(SqliteJournalMode::Wal) .synchronous(SqliteSynchronous::Normal); let pool = SqlitePoolOptions::new() .max_connections(5) .connect_with(options) .await?; ``` ### Query Execution (No Changes Required) Standard queries work the same: ```rust sqlx::query( r#" INSERT INTO conversations (id, name, description, model, message_count, created_at, updated_at, data) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) ON CONFLICT(id) DO UPDATE SET name = excluded.name, description = excluded.description, model = excluded.model, message_count = excluded.message_count, updated_at = excluded.updated_at, data = excluded.data "# ) .bind(&id) .bind(&name) .bind(&description) .bind(&model) .bind(message_count) .bind(created_at) .bind(updated_at) .bind(&data) .execute(&self.pool) .await?; ``` ### Transaction Handling (No Changes Required) ```rust let mut tx = pool.begin().await?; sqlx::query("INSERT INTO users (name) VALUES (?)") .bind("Alice") .execute(&mut *tx) .await?; tx.commit().await?; ``` ## Performance Improvements in 0.8 1. **SQLite-specific fixes**: Version 0.8.6 fixed a performance regression for SQLite 2. **Better connection pooling**: More efficient connection reuse 3. **Improved compile-time checking**: Faster query validation ## Common Pitfalls to Avoid 1. **Feature flag splitting**: Don't forget to split `runtime-tokio-rustls` into two separate features 2. **Dependency conflicts**: Check for `libsqlite3-sys` version conflicts with `cargo tree -i libsqlite3-sys` 3. **Offline mode**: Remember that offline mode is always on - no need to enable it separately ## Future Considerations ### If Moving to query! Macro If you decide to use compile-time checked queries in the future: ```rust // Instead of manual query building let row = sqlx::query("SELECT * FROM conversations WHERE id = ?") .bind(&id) .fetch_one(&pool) .await?; // Use compile-time checked queries let conversation = sqlx::query_as!( ConversationRow, "SELECT * FROM conversations WHERE id = ?", id ) .fetch_one(&pool) .await?; ``` ### If Adding DateTime Columns If you add proper DATETIME columns in the future (instead of INTEGER timestamps): ```rust // With SQLx 0.8 + chrono feature, you'll use time crate types use time::PrimitiveDateTime; // Instead of chrono::NaiveDateTime #[derive(sqlx::FromRow)] struct MyModel { created_at: PrimitiveDateTime, // Not chrono::NaiveDateTime } ``` ## Verification Steps 1. **Build successful**: ✅ SQLx 0.8 compiles without errors 2. **Tests pass**: Run `cargo test -p owlen-core` to verify 3. **Migrations work**: Run `cargo sqlx migrate info` to check migration status 4. **Runtime works**: Start the application and perform basic operations ## Resources - [SQLx 0.8 Release Notes](https://github.com/launchbadge/sqlx/releases/tag/v0.8.0) - [SQLx Migration Guide](https://github.com/launchbadge/sqlx/blob/main/CHANGELOG.md) - [CVE-2024-0363 Details](https://rustsec.org/advisories/RUSTSEC-2024-0363)