package lib import ( "log" "regexp" ) // MigrateDOB encrypts plain-text date_of_birth values (YYYY-MM-DD format) func MigrateDOB() error { rows, err := db.Query(`SELECT dossier_id, date_of_birth FROM dossiers WHERE date_of_birth != ''`) if err != nil { return err } defer rows.Close() datePattern := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`) updated := 0 for rows.Next() { var dossierID, dob string if err := rows.Scan(&dossierID, &dob); err != nil { continue } // If it looks like a plain date, encrypt it if datePattern.MatchString(dob) { encrypted := CryptoEncrypt(dob) _, err := db.Exec(`UPDATE dossiers SET date_of_birth = ? WHERE dossier_id = ?`, encrypted, dossierID) if err != nil { log.Printf("update error for dossier %s: %v", dossierID, err) continue } log.Printf("Encrypted DOB for dossier %s: %s", dossierID, dob) updated++ } } log.Printf("DOB migration complete: %d encrypted", updated) return nil } // MigrateCategory populates category from encrypted category strings. // Run once, then drop the old category column. func MigrateCategory() error { rows, err := db.Query(`SELECT entry_id, category FROM entries WHERE category IS NULL`) if err != nil { return err } defer rows.Close() updated := 0 unknown := 0 for rows.Next() { var entryID int64 var encCategory string if err := rows.Scan(&entryID, &encCategory); err != nil { log.Printf("scan error: %v", err) continue } catStr := CryptoDecrypt(encCategory) catInt, ok := CategoryFromString[catStr] if !ok { log.Printf("unknown category %q for entry %d", catStr, entryID) unknown++ continue } _, err := db.Exec(`UPDATE entries SET category = ? WHERE entry_id = ?`, catInt, entryID) if err != nil { log.Printf("update error for entry %d: %v", entryID, err) continue } updated++ } log.Printf("Migration complete: %d updated, %d unknown", updated, unknown) return nil }