feat(db): add migration 028 for discussions.merge_request_id FK constraint
Add foreign key constraint on discussions.merge_request_id to prevent orphaned discussions when MRs are deleted. SQLite doesn't support ALTER TABLE ADD CONSTRAINT, so this migration recreates the table with: 1. New table with FK: REFERENCES merge_requests(id) ON DELETE CASCADE 2. Data copy with FK validation (only copies rows with valid MR references) 3. Table swap (DROP old, RENAME new) 4. Full index recreation (all 10 indexes from migrations 002-022) The migration also includes a CHECK constraint ensuring mutual exclusivity: - Issue discussions have issue_id NOT NULL and merge_request_id NULL - MR discussions have merge_request_id NOT NULL and issue_id NULL Also fixes run_migrations() to properly propagate query errors instead of silently returning unwrap_or defaults, improving error diagnostics. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,10 @@ const MIGRATIONS: &[(&str, &str)] = &[
|
||||
"027",
|
||||
include_str!("../../migrations/027_surgical_sync_runs.sql"),
|
||||
),
|
||||
(
|
||||
"028",
|
||||
include_str!("../../migrations/028_discussions_mr_fk.sql"),
|
||||
),
|
||||
];
|
||||
|
||||
pub fn create_connection(db_path: &Path) -> Result<Connection> {
|
||||
@@ -130,21 +134,20 @@ pub fn create_connection(db_path: &Path) -> Result<Connection> {
|
||||
}
|
||||
|
||||
pub fn run_migrations(conn: &Connection) -> Result<()> {
|
||||
let has_version_table: bool = conn
|
||||
.query_row(
|
||||
"SELECT COUNT(*) > 0 FROM sqlite_master WHERE type='table' AND name='schema_version'",
|
||||
[],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.unwrap_or(false);
|
||||
// Note: sqlite_master always exists, so errors here indicate real DB problems
|
||||
// (corruption, locked, etc.) - we must not silently treat them as "fresh DB"
|
||||
let has_version_table: bool = conn.query_row(
|
||||
"SELECT COUNT(*) > 0 FROM sqlite_master WHERE type='table' AND name='schema_version'",
|
||||
[],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
|
||||
let current_version: i32 = if has_version_table {
|
||||
conn.query_row(
|
||||
"SELECT COALESCE(MAX(version), 0) FROM schema_version",
|
||||
[],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.unwrap_or(0)
|
||||
)?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user