Skip to content

Commit 35d48e8

Browse files
committed
refactor: improve database wipe methods based on PR feedback
- Add get_activity_db() helper to reduce code duplication - Ensure wipe_all_databases() requires initialized DBs - Remove unused methods: remove_all_tags(), remove_all_info() - Consolidate remove_all() into wipe_all() to remove the wrapper - Document that enum state tables persist across wipes
1 parent ecd065d commit 35d48e8

File tree

5 files changed

+45
-193
lines changed

5 files changed

+45
-193
lines changed

src/lib.rs

Lines changed: 34 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ fn ensure_runtime() -> &'static Runtime {
4545
})
4646
}
4747

48+
/// Helper function to get a reference to the activity database connections
49+
fn get_activity_db() -> Result<std::sync::MutexGuard<'static, DatabaseConnections>, ActivityError> {
50+
let cell = DB.get().ok_or(ActivityError::ConnectionError {
51+
error_details: "Database not initialized. Call init_db first.".to_string()
52+
})?;
53+
Ok(cell.lock().unwrap())
54+
}
55+
4856
#[uniffi::export]
4957
pub async fn decode(invoice: String) -> Result<Scanner, DecodingError> {
5058
let rt = ensure_runtime();
@@ -290,10 +298,7 @@ pub fn get_activities(
290298
limit: Option<u32>,
291299
sort_direction: Option<SortDirection>
292300
) -> Result<Vec<Activity>, ActivityError> {
293-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
294-
error_details: "Database not initialized. Call init_db first.".to_string()
295-
})?;
296-
let guard = cell.lock().unwrap();
301+
let guard = get_activity_db()?;
297302
let db = guard.activity_db.as_ref().ok_or(ActivityError::ConnectionError {
298303
error_details: "Database not initialized. Call init_db first.".to_string()
299304
})?;
@@ -302,10 +307,7 @@ pub fn get_activities(
302307

303308
#[uniffi::export]
304309
pub fn upsert_activity(activity: Activity) -> Result<(), ActivityError> {
305-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
306-
error_details: "Database not initialized. Call init_db first.".to_string()
307-
})?;
308-
let mut guard = cell.lock().unwrap();
310+
let mut guard = get_activity_db()?;
309311
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
310312
error_details: "Database not initialized. Call init_db first.".to_string()
311313
})?;
@@ -314,10 +316,7 @@ pub fn upsert_activity(activity: Activity) -> Result<(), ActivityError> {
314316

315317
#[uniffi::export]
316318
pub fn insert_activity(activity: Activity) -> Result<(), ActivityError> {
317-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
318-
error_details: "Database not initialized. Call init_db first.".to_string()
319-
})?;
320-
let mut guard = cell.lock().unwrap();
319+
let mut guard = get_activity_db()?;
321320
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
322321
error_details: "Database not initialized. Call init_db first.".to_string()
323322
})?;
@@ -329,10 +328,7 @@ pub fn insert_activity(activity: Activity) -> Result<(), ActivityError> {
329328

330329
#[uniffi::export]
331330
pub fn update_activity(activity_id: String, activity: Activity) -> Result<(), ActivityError> {
332-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
333-
error_details: "Database not initialized. Call init_db first.".to_string()
334-
})?;
335-
let mut guard = cell.lock().unwrap();
331+
let mut guard = get_activity_db()?;
336332
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
337333
error_details: "Database not initialized. Call init_db first.".to_string()
338334
})?;
@@ -344,10 +340,7 @@ pub fn update_activity(activity_id: String, activity: Activity) -> Result<(), Ac
344340

345341
#[uniffi::export]
346342
pub fn get_activity_by_id(activity_id: String) -> Result<Option<Activity>, ActivityError> {
347-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
348-
error_details: "Database not initialized. Call init_db first.".to_string()
349-
})?;
350-
let guard = cell.lock().unwrap();
343+
let guard = get_activity_db()?;
351344
let db = guard.activity_db.as_ref().ok_or(ActivityError::ConnectionError {
352345
error_details: "Database not initialized. Call init_db first.".to_string()
353346
})?;
@@ -356,10 +349,7 @@ pub fn get_activity_by_id(activity_id: String) -> Result<Option<Activity>, Activ
356349

357350
#[uniffi::export]
358351
pub fn delete_activity_by_id(activity_id: String) -> Result<bool, ActivityError> {
359-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
360-
error_details: "Database not initialized. Call init_db first.".to_string()
361-
})?;
362-
let mut guard = cell.lock().unwrap();
352+
let mut guard = get_activity_db()?;
363353
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
364354
error_details: "Database not initialized. Call init_db first.".to_string()
365355
})?;
@@ -368,10 +358,7 @@ pub fn delete_activity_by_id(activity_id: String) -> Result<bool, ActivityError>
368358

369359
#[uniffi::export]
370360
pub fn add_tags(activity_id: String, tags: Vec<String>) -> Result<(), ActivityError> {
371-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
372-
error_details: "Database not initialized. Call init_db first.".to_string()
373-
})?;
374-
let mut guard = cell.lock().unwrap();
361+
let mut guard = get_activity_db()?;
375362
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
376363
error_details: "Database not initialized. Call init_db first.".to_string()
377364
})?;
@@ -380,10 +367,7 @@ pub fn add_tags(activity_id: String, tags: Vec<String>) -> Result<(), ActivityEr
380367

381368
#[uniffi::export]
382369
pub fn remove_tags(activity_id: String, tags: Vec<String>) -> Result<(), ActivityError> {
383-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
384-
error_details: "Database not initialized. Call init_db first.".to_string()
385-
})?;
386-
let mut guard = cell.lock().unwrap();
370+
let mut guard = get_activity_db()?;
387371
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
388372
error_details: "Database not initialized. Call init_db first.".to_string()
389373
})?;
@@ -392,10 +376,7 @@ pub fn remove_tags(activity_id: String, tags: Vec<String>) -> Result<(), Activit
392376

393377
#[uniffi::export]
394378
pub fn get_tags(activity_id: String) -> Result<Vec<String>, ActivityError> {
395-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
396-
error_details: "Database not initialized. Call init_db first.".to_string()
397-
})?;
398-
let guard = cell.lock().unwrap();
379+
let guard = get_activity_db()?;
399380
let db = guard.activity_db.as_ref().ok_or(ActivityError::ConnectionError {
400381
error_details: "Database not initialized. Call init_db first.".to_string()
401382
})?;
@@ -404,10 +385,7 @@ pub fn get_tags(activity_id: String) -> Result<Vec<String>, ActivityError> {
404385

405386
#[uniffi::export]
406387
pub fn get_activities_by_tag(tag: String, limit: Option<u32>, sort_direction: Option<SortDirection>) -> Result<Vec<Activity>, ActivityError> {
407-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
408-
error_details: "Database not initialized. Call init_db first.".to_string()
409-
})?;
410-
let guard = cell.lock().unwrap();
388+
let guard = get_activity_db()?;
411389
let db = guard.activity_db.as_ref().ok_or(ActivityError::ConnectionError {
412390
error_details: "Database not initialized. Call init_db first.".to_string()
413391
})?;
@@ -416,10 +394,7 @@ pub fn get_activities_by_tag(tag: String, limit: Option<u32>, sort_direction: Op
416394

417395
#[uniffi::export]
418396
pub fn get_all_unique_tags() -> Result<Vec<String>, ActivityError> {
419-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
420-
error_details: "Database not initialized. Call init_db first.".to_string()
421-
})?;
422-
let guard = cell.lock().unwrap();
397+
let guard = get_activity_db()?;
423398
let db = guard.activity_db.as_ref().ok_or(ActivityError::ConnectionError {
424399
error_details: "Database not initialized. Call init_db first.".to_string()
425400
})?;
@@ -1248,10 +1223,7 @@ pub fn trezor_compose_transaction(
12481223

12491224
#[uniffi::export]
12501225
pub fn activity_wipe_all() -> Result<(), ActivityError> {
1251-
let cell = DB.get().ok_or(ActivityError::ConnectionError {
1252-
error_details: "Database not initialized. Call init_db first.".to_string()
1253-
})?;
1254-
let mut guard = cell.lock().unwrap();
1226+
let mut guard = get_activity_db()?;
12551227
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
12561228
error_details: "Database not initialized. Call init_db first.".to_string()
12571229
})?;
@@ -1307,30 +1279,32 @@ pub async fn blocktank_wipe_all() -> Result<(), BlocktankError> {
13071279
pub async fn wipe_all_databases() -> Result<String, DbError> {
13081280
let rt = ensure_runtime();
13091281

1310-
// Wipe activity database
1282+
// Wipe activity database - require it to be initialized
13111283
{
13121284
let cell = DB.get().ok_or(DbError::InitializationError {
13131285
error_details: "Database not initialized. Call init_db first.".to_string()
13141286
})?;
13151287
let mut guard = cell.lock().unwrap();
1316-
if let Some(db) = guard.activity_db.as_mut() {
1317-
db.wipe_all().map_err(|e| DbError::InitializationError {
1318-
error_details: format!("Failed to wipe activity database: {}", e)
1319-
})?;
1320-
}
1288+
let db = guard.activity_db.as_mut().ok_or(DbError::InitializationError {
1289+
error_details: "Activity database not initialized. Call init_db first.".to_string()
1290+
})?;
1291+
db.wipe_all().map_err(|e| DbError::InitializationError {
1292+
error_details: format!("Failed to wipe activity database: {}", e)
1293+
})?;
13211294
}
13221295

1323-
// Wipe blocktank database
1296+
// Wipe blocktank database - require it to be initialized
13241297
rt.spawn(async move {
13251298
let cell = ASYNC_DB.get().ok_or(DbError::InitializationError {
13261299
error_details: "Database not initialized. Call init_db first.".to_string()
13271300
})?;
13281301
let guard = cell.lock().await;
1329-
if let Some(db) = guard.blocktank_db.as_ref() {
1330-
db.wipe_all().await.map_err(|e| DbError::InitializationError {
1331-
error_details: format!("Failed to wipe blocktank database: {}", e)
1332-
})?;
1333-
}
1302+
let db = guard.blocktank_db.as_ref().ok_or(DbError::InitializationError {
1303+
error_details: "Blocktank database not initialized. Call init_db first.".to_string()
1304+
})?;
1305+
db.wipe_all().await.map_err(|e| DbError::InitializationError {
1306+
error_details: format!("Failed to wipe blocktank database: {}", e)
1307+
})?;
13341308
Ok::<(), DbError>(())
13351309
}).await.unwrap()?;
13361310

src/modules/activity/implementation.rs

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,8 +1020,9 @@ impl ActivityDB {
10201020
}
10211021
}
10221022

1023-
/// Removes all activities from the database
1024-
pub fn remove_all(&mut self) -> Result<(), ActivityError> {
1023+
/// Wipes all activity data from the database
1024+
/// This deletes all activities, which cascades to delete all tags due to foreign key constraints
1025+
pub fn wipe_all(&mut self) -> Result<(), ActivityError> {
10251026
let tx = self.conn.transaction().map_err(|e| ActivityError::DataError {
10261027
error_details: format!("Failed to start transaction: {}", e),
10271028
})?;
@@ -1038,19 +1039,4 @@ impl ActivityDB {
10381039

10391040
Ok(())
10401041
}
1041-
1042-
/// Removes all tags from the database
1043-
pub fn remove_all_tags(&mut self) -> Result<(), ActivityError> {
1044-
self.conn.execute("DELETE FROM activity_tags", [])
1045-
.map_err(|e| ActivityError::DataError {
1046-
error_details: format!("Failed to delete all tags: {}", e),
1047-
})?;
1048-
1049-
Ok(())
1050-
}
1051-
1052-
/// Wipes all activity data from the database
1053-
pub fn wipe_all(&mut self) -> Result<(), ActivityError> {
1054-
self.remove_all()
1055-
}
10561042
}

src/modules/activity/tests.rs

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,80 +1281,6 @@ mod tests {
12811281
cleanup(&db_path);
12821282
}
12831283

1284-
#[test]
1285-
fn test_remove_all() {
1286-
let (mut db, db_path) = setup();
1287-
1288-
// Insert multiple activities
1289-
let activity1 = create_test_onchain_activity();
1290-
let mut activity2 = create_test_lightning_activity();
1291-
activity2.id = "test_lightning_2".to_string();
1292-
let mut activity3 = create_test_onchain_activity();
1293-
activity3.id = "test_onchain_3".to_string();
1294-
1295-
db.insert_onchain_activity(&activity1).unwrap();
1296-
db.insert_lightning_activity(&activity2).unwrap();
1297-
db.insert_onchain_activity(&activity3).unwrap();
1298-
1299-
// Add tags to verify cascade deletion
1300-
db.add_tags(&activity1.id, &["tag1".to_string(), "tag2".to_string()]).unwrap();
1301-
db.add_tags(&activity2.id, &["tag3".to_string()]).unwrap();
1302-
1303-
// Verify activities exist
1304-
let activities = db.get_activities(None, None, None, None, None, None, None, None).unwrap();
1305-
assert_eq!(activities.len(), 3);
1306-
1307-
// Verify tags exist
1308-
let tags = db.get_all_unique_tags().unwrap();
1309-
assert_eq!(tags.len(), 3);
1310-
1311-
// Remove all activities
1312-
db.remove_all().unwrap();
1313-
1314-
// Verify all activities are deleted
1315-
let activities_after = db.get_activities(None, None, None, None, None, None, None, None).unwrap();
1316-
assert_eq!(activities_after.len(), 0);
1317-
1318-
// Verify tags are also deleted (cascade)
1319-
let tags_after = db.get_all_unique_tags().unwrap();
1320-
assert_eq!(tags_after.len(), 0);
1321-
1322-
cleanup(&db_path);
1323-
}
1324-
1325-
#[test]
1326-
fn test_remove_all_tags() {
1327-
let (mut db, db_path) = setup();
1328-
1329-
// Insert activities
1330-
let activity1 = create_test_onchain_activity();
1331-
let mut activity2 = create_test_lightning_activity();
1332-
activity2.id = "test_lightning_2".to_string();
1333-
1334-
db.insert_onchain_activity(&activity1).unwrap();
1335-
db.insert_lightning_activity(&activity2).unwrap();
1336-
1337-
// Add multiple tags
1338-
db.add_tags(&activity1.id, &["tag1".to_string(), "tag2".to_string(), "tag3".to_string()]).unwrap();
1339-
db.add_tags(&activity2.id, &["tag4".to_string(), "tag5".to_string()]).unwrap();
1340-
1341-
// Verify tags exist
1342-
let tags = db.get_all_unique_tags().unwrap();
1343-
assert_eq!(tags.len(), 5);
1344-
1345-
// Remove all tags
1346-
db.remove_all_tags().unwrap();
1347-
1348-
// Verify all tags are deleted
1349-
let tags_after = db.get_all_unique_tags().unwrap();
1350-
assert_eq!(tags_after.len(), 0);
1351-
1352-
// Verify activities still exist
1353-
let activities = db.get_activities(None, None, None, None, None, None, None, None).unwrap();
1354-
assert_eq!(activities.len(), 2);
1355-
1356-
cleanup(&db_path);
1357-
}
13581284

13591285
#[test]
13601286
fn test_wipe_all() {

src/modules/blocktank/db.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -846,19 +846,15 @@ impl BlocktankDB {
846846
Ok(())
847847
}
848848

849-
/// Removes all info entries from the database
850-
pub async fn remove_all_info(&self) -> Result<(), BlocktankError> {
851-
let conn = self.conn.lock().await;
852-
853-
conn.execute("DELETE FROM info", [])
854-
.map_err(|e| BlocktankError::DatabaseError {
855-
error_details: format!("Failed to delete all info entries: {}", e),
856-
})?;
857-
858-
Ok(())
859-
}
860-
861849
/// Removes all data from all Blocktank tables
850+
///
851+
/// This wipes:
852+
/// - All orders
853+
/// - All CJIT entries
854+
/// - All info entries
855+
///
856+
/// Note: This does NOT delete the enum state tables (order_states, payment_states, cjit_states)
857+
/// as these contain static reference data that should persist across wipes.
862858
pub async fn wipe_all(&self) -> Result<(), BlocktankError> {
863859
let mut conn = self.conn.lock().await;
864860

src/modules/blocktank/tests.rs

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,36 +1533,6 @@ mod tests {
15331533
assert_eq!(entries_new.len(), 1);
15341534
}
15351535

1536-
#[tokio::test]
1537-
async fn test_remove_all_info() {
1538-
let temp_dir = tempfile::tempdir().expect("Failed to create temp directory");
1539-
let db_path = format!("{}/test_blocktank.db", temp_dir.path().display());
1540-
1541-
let db = BlocktankDB::new(&db_path, None).await
1542-
.expect("Failed to create BlocktankDB");
1543-
1544-
// Create and insert test info
1545-
let info = create_test_info();
1546-
db.upsert_info(&info).await.expect("Failed to insert info");
1547-
1548-
// Verify info exists
1549-
let retrieved_info = db.get_info().await.expect("Failed to get info");
1550-
assert!(retrieved_info.is_some());
1551-
1552-
// Remove all info
1553-
db.remove_all_info().await.expect("Failed to remove all info");
1554-
1555-
// Verify info is deleted
1556-
let info_after = db.get_info().await.expect("Failed to get info");
1557-
assert!(info_after.is_none());
1558-
1559-
// Verify we can still insert new info after wipe
1560-
let new_info = create_test_info();
1561-
db.upsert_info(&new_info).await.expect("Failed to insert new info");
1562-
let info_new = db.get_info().await.expect("Failed to get info");
1563-
assert!(info_new.is_some());
1564-
}
1565-
15661536
#[tokio::test]
15671537
async fn test_wipe_all() {
15681538
let temp_dir = tempfile::tempdir().expect("Failed to create temp directory");

0 commit comments

Comments
 (0)