@@ -70,12 +70,14 @@ CREATE TABLE IF NOT EXISTS messages (
7070 at INTEGER NOT NULL,
7171 mine INTEGER NOT NULL,
7272 user_id INTEGER,
73+ wrapper_event_id TEXT,
7374 FOREIGN KEY (chat_id) REFERENCES chats(id) ON DELETE CASCADE,
7475 FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE SET NULL
7576);
7677CREATE INDEX IF NOT EXISTS idx_messages_chat ON messages(chat_id, at);
7778CREATE INDEX IF NOT EXISTS idx_messages_time ON messages(at DESC);
7879CREATE INDEX IF NOT EXISTS idx_messages_user ON messages(user_id);
80+ CREATE INDEX IF NOT EXISTS idx_messages_wrapper ON messages(wrapper_event_id);
7981
8082-- Settings table (key-value pairs)
8183CREATE TABLE IF NOT EXISTS settings (
@@ -354,6 +356,10 @@ pub fn get_db_connection<R: Runtime>(handle: &AppHandle<R>) -> Result<rusqlite::
354356 conn. execute_batch ( "PRAGMA journal_mode=WAL;" )
355357 . map_err ( |e| format ! ( "Failed to set WAL mode: {}" , e) ) ?;
356358
359+ // Run migrations to ensure schema is up to date
360+ // This is important for existing databases that may not have new columns
361+ run_migrations ( & conn) ?;
362+
357363 Ok ( conn)
358364}
359365
@@ -406,11 +412,45 @@ pub async fn init_profile_database<R: Runtime>(
406412 conn. execute_batch ( SQL_SCHEMA )
407413 . map_err ( |e| format ! ( "Failed to create database schema: {}" , e) ) ?;
408414
415+ // Run migrations for existing databases
416+ run_migrations ( & conn) ?;
417+
409418 println ! ( "[Account Manager] Database schema created successfully" ) ;
410419
411420 Ok ( ( ) )
412421}
413422
423+ /// Run database migrations for schema updates
424+ /// This handles adding new columns to existing tables
425+ fn run_migrations ( conn : & rusqlite:: Connection ) -> Result < ( ) , String > {
426+ // Migration 1: Add wrapper_event_id column to messages table
427+ // This column stores the public giftwrap event ID for fast duplicate detection
428+ let has_wrapper_column: bool = conn. query_row (
429+ "SELECT COUNT(*) FROM pragma_table_info('messages') WHERE name = 'wrapper_event_id'" ,
430+ [ ] ,
431+ |row| row. get :: < _ , i32 > ( 0 )
432+ ) . map ( |count| count > 0 )
433+ . unwrap_or ( false ) ;
434+
435+ if !has_wrapper_column {
436+ println ! ( "[Migration] Adding wrapper_event_id column to messages table..." ) ;
437+ conn. execute (
438+ "ALTER TABLE messages ADD COLUMN wrapper_event_id TEXT" ,
439+ [ ]
440+ ) . map_err ( |e| format ! ( "Failed to add wrapper_event_id column: {}" , e) ) ?;
441+
442+ // Create index for fast lookups
443+ conn. execute (
444+ "CREATE INDEX IF NOT EXISTS idx_messages_wrapper ON messages(wrapper_event_id)" ,
445+ [ ]
446+ ) . map_err ( |e| format ! ( "Failed to create wrapper_event_id index: {}" , e) ) ?;
447+
448+ println ! ( "[Migration] wrapper_event_id column added successfully" ) ;
449+ }
450+
451+ Ok ( ( ) )
452+ }
453+
414454/// Switch to a different account
415455#[ tauri:: command]
416456pub async fn switch_account < R : Runtime > (
0 commit comments