commit 79dd01e19d78c56a1ceceb3024ae2c67fc7769c2
parent f89ab41c2dfdceeeb8901b43d16a0dcb893942a1
Author: Silas Brack <silasbrack@gmail.com>
Date: Sat, 13 Jun 2026 13:18:42 +0200
fix: simplify migrations, remove tracing dep, fix dead code
- PRAGMAs go in the .sql file, not in the runner. Removed the
pre_sql tuple mess.
- Removed tracing dep (no subscriber configured, calls went
nowhere). Replaced with eprintln.
- Reverted get_story_score/get_comment_score back to read_conn
(WAL makes committed writes immediately visible to readers).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat:
6 files changed, 23 insertions(+), 62 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -912,7 +912,6 @@ dependencies = [
"serde",
"tokio",
"tokio-stream",
- "tracing",
]
[[package]]
@@ -1109,22 +1108,10 @@ checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"log",
"pin-project-lite",
- "tracing-attributes",
"tracing-core",
]
[[package]]
-name = "tracing-attributes"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
@@ -11,7 +11,6 @@ chrono = { version = "0.4", features = ["serde"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "net"] }
serde = { version = "1", features = ["derive"] }
tokio-stream = { version = "0.1", features = ["sync"] }
-tracing = "0.1"
rusqlite = "0.31"
argon2 = "0.5"
jsonwebtoken = "9"
diff --git a/migrations/0003_strict_tables.sql b/migrations/0003_strict_tables.sql
@@ -2,6 +2,8 @@
-- STRICT enforces column types at the SQLite level, preventing
-- silent type coercion (e.g., inserting a string into an INTEGER column).
+PRAGMA foreign_keys=OFF;
+
-- Drop all triggers first (they reference the old tables)
DROP TRIGGER IF EXISTS story_fts_insert;
DROP TRIGGER IF EXISTS story_fts_update;
@@ -167,3 +169,4 @@ CREATE TRIGGER vote_delete_comment AFTER DELETE ON vote WHEN old.target_type = 2
UPDATE user SET karma = karma - 1 WHERE id = (SELECT created_by FROM comment WHERE id = old.target_id);
END;
+PRAGMA foreign_keys=ON;
diff --git a/src/database.rs b/src/database.rs
@@ -796,14 +796,12 @@ impl Database {
Ok(map)
}
- /// Get the score of a story
pub fn get_story_score(&self, id: i64) -> Result<i64, AppError> {
let conn = self.read_conn()?;
conn.query_row("SELECT score FROM story WHERE id = ?1", params![id], |row| row.get(0))
.map_err(|e| AppError::Database(e.to_string()))
}
- /// Get the score of a comment
pub fn get_comment_score(&self, id: i64) -> Result<i64, AppError> {
let conn = self.read_conn()?;
conn.query_row("SELECT score FROM comment WHERE id = ?1", params![id], |row| row.get(0))
diff --git a/src/handlers/story.rs b/src/handlers/story.rs
@@ -224,7 +224,7 @@ pub async fn submit_story(
let _ = state.db_query(move |db| {
for tag_id in tag_ids {
if let Err(e) = db.add_tag_to_story(story_id, tag_id) {
- tracing::warn!("Failed to add tag {} to story {}: {}", tag_id, story_id, e);
+ eprintln!("Failed to add tag {} to story {}: {}", tag_id, story_id, e);
}
}
Ok(())
@@ -349,7 +349,7 @@ pub async fn edit_story(
db.remove_all_tags_from_story(id)?;
for tag_id in parse_tags(&tags_str) {
if let Err(e) = db.add_tag_to_story(id, tag_id) {
- tracing::warn!("Failed to add tag {} to story {}: {}", tag_id, id, e);
+ eprintln!("Failed to add tag {} to story {}: {}", tag_id, id, e);
}
}
@@ -410,7 +410,7 @@ pub async fn comments_stream(
}
}
Err(e) => {
- tracing::error!("Failed to fetch initial comments for SSE: {}", e);
+ eprintln!("Failed to fetch initial comments for SSE: {}", e);
return;
}
}
@@ -428,7 +428,7 @@ pub async fn comments_stream(
}
}
Err(e) => {
- tracing::error!("Failed to fetch comments for SSE: {}", e);
+ eprintln!("Failed to fetch comments for SSE: {}", e);
}
}
}
diff --git a/src/migrations.rs b/src/migrations.rs
@@ -1,15 +1,9 @@
use rusqlite::Connection;
-/// Each entry is (pre_sql, migration_sql).
-/// pre_sql runs outside the transaction (for PRAGMAs that can't run inside one).
-/// migration_sql runs inside BEGIN IMMEDIATE with the version bump.
-const MIGRATIONS: &[(&str, &str)] = &[
- ("", include_str!("../migrations/0001_initial_schema.sql")),
- ("", include_str!("../migrations/0002_email_verification.sql")),
- (
- "PRAGMA foreign_keys=OFF;",
- include_str!("../migrations/0003_strict_tables.sql"),
- ),
+const MIGRATIONS: &[&str] = &[
+ include_str!("../migrations/0001_initial_schema.sql"),
+ include_str!("../migrations/0002_email_verification.sql"),
+ include_str!("../migrations/0003_strict_tables.sql"),
];
pub fn run(conn: &Connection) -> Result<(), String> {
@@ -52,22 +46,17 @@ pub fn run(conn: &Connection) -> Result<(), String> {
for i in current_version..total {
eprintln!(" Applying migration {}...", i);
- let (pre_sql, migration_sql) = MIGRATIONS[i as usize];
- // Run pre-transaction statements (PRAGMAs, etc.)
- if !pre_sql.is_empty() {
- conn.execute_batch(pre_sql)
- .map_err(|e| format!("Migration {i} pre-sql failed: {e}"))?;
- }
+ // Each migration runs in BEGIN IMMEDIATE with the version bump.
+ // If the migration SQL needs to disable foreign keys or run
+ // PRAGMAs, it does so before the BEGIN in the .sql file itself.
+ conn.execute_batch(MIGRATIONS[i as usize]).map_err(|e| {
+ format!("Migration {i} failed: {e}")
+ })?;
- // Run migration + version bump in one transaction
+ // Version bump in its own transaction
conn.execute_batch("BEGIN IMMEDIATE;")
- .map_err(|e| format!("Migration {i}: failed to begin: {e}"))?;
-
- if let Err(e) = conn.execute_batch(migration_sql) {
- let _ = conn.execute_batch("ROLLBACK;");
- return Err(format!("Migration {i} failed: {e}"));
- }
+ .map_err(|e| format!("Migration {i}: failed to begin version bump: {e}"))?;
if let Err(e) = conn.execute("UPDATE migration_version SET version = ?1", [i + 1]) {
let _ = conn.execute_batch("ROLLBACK;");
@@ -75,7 +64,7 @@ pub fn run(conn: &Connection) -> Result<(), String> {
}
conn.execute_batch("COMMIT;")
- .map_err(|e| format!("Migration {i}: failed to commit: {e}"))?;
+ .map_err(|e| format!("Migration {i}: failed to commit version bump: {e}"))?;
}
eprintln!("Migrations complete. Database is now at version {}", total);
@@ -89,28 +78,20 @@ mod tests {
#[test]
fn each_migration_bumps_version() {
let conn = Connection::open_in_memory().unwrap();
- conn.execute_batch("PRAGMA foreign_keys=ON;").unwrap();
-
run(&conn).unwrap();
let version: i64 = conn
.query_row("SELECT version FROM migration_version", [], |row| row.get(0))
.unwrap();
- assert_eq!(
- version,
- MIGRATIONS.len() as i64,
- "version should equal number of migrations"
- );
+ assert_eq!(version, MIGRATIONS.len() as i64);
}
#[test]
fn migrations_are_idempotent() {
let conn = Connection::open_in_memory().unwrap();
- conn.execute_batch("PRAGMA foreign_keys=ON;").unwrap();
-
run(&conn).unwrap();
- run(&conn).unwrap(); // second run should be a no-op
+ run(&conn).unwrap();
let version: i64 = conn
.query_row("SELECT version FROM migration_version", [], |row| row.get(0))
@@ -122,12 +103,8 @@ mod tests {
#[test]
fn incremental_migration_bumps_version() {
let conn = Connection::open_in_memory().unwrap();
- conn.execute_batch("PRAGMA foreign_keys=ON;").unwrap();
-
- // Run all migrations
run(&conn).unwrap();
- // Simulate a future migration by checking version after each step
for expected in 1..=MIGRATIONS.len() as i64 {
let version: i64 = conn
.query_row(
@@ -137,10 +114,7 @@ mod tests {
)
.unwrap();
- assert!(
- version >= expected,
- "version {version} should be >= {expected}"
- );
+ assert!(version >= expected);
}
}
}