Skip to content

Commit c946736

Browse files
committed
feat: add database wipe methods for activity and blocktank modules
- Add activity_wipe_all() to clear all activities and tags - Add blocktank_remove_all_orders() to clear order history - Add blocktank_remove_all_cjit_entries() to clear CJIT entries - Add blocktank_wipe_all() to clear all blocktank tables - Add wipe_all_databases() for global database reset - Update tests accordingly
1 parent 436a67a commit c946736

File tree

5 files changed

+619
-29
lines changed

5 files changed

+619
-29
lines changed

src/lib.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,4 +1244,95 @@ pub fn trezor_compose_transaction(
12441244
Ok(result) => Ok(result),
12451245
Err(e) => Err(TrezorConnectError::ClientError { error_details: e.to_string() }),
12461246
}
1247+
}
1248+
1249+
#[uniffi::export]
1250+
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();
1255+
let db = guard.activity_db.as_mut().ok_or(ActivityError::ConnectionError {
1256+
error_details: "Database not initialized. Call init_db first.".to_string()
1257+
})?;
1258+
db.wipe_all()
1259+
}
1260+
1261+
#[uniffi::export]
1262+
pub async fn blocktank_remove_all_orders() -> Result<(), BlocktankError> {
1263+
let rt = ensure_runtime();
1264+
rt.spawn(async move {
1265+
let cell = ASYNC_DB.get().ok_or(BlocktankError::ConnectionError {
1266+
error_details: "Database not initialized. Call init_db first.".to_string()
1267+
})?;
1268+
let guard = cell.lock().await;
1269+
let db = guard.blocktank_db.as_ref().ok_or(BlocktankError::ConnectionError {
1270+
error_details: "Database not initialized. Call init_db first.".to_string()
1271+
})?;
1272+
db.remove_all_orders().await
1273+
}).await.unwrap()
1274+
}
1275+
1276+
#[uniffi::export]
1277+
pub async fn blocktank_remove_all_cjit_entries() -> Result<(), BlocktankError> {
1278+
let rt = ensure_runtime();
1279+
rt.spawn(async move {
1280+
let cell = ASYNC_DB.get().ok_or(BlocktankError::ConnectionError {
1281+
error_details: "Database not initialized. Call init_db first.".to_string()
1282+
})?;
1283+
let guard = cell.lock().await;
1284+
let db = guard.blocktank_db.as_ref().ok_or(BlocktankError::ConnectionError {
1285+
error_details: "Database not initialized. Call init_db first.".to_string()
1286+
})?;
1287+
db.remove_all_cjit_entries().await
1288+
}).await.unwrap()
1289+
}
1290+
1291+
#[uniffi::export]
1292+
pub async fn blocktank_wipe_all() -> Result<(), BlocktankError> {
1293+
let rt = ensure_runtime();
1294+
rt.spawn(async move {
1295+
let cell = ASYNC_DB.get().ok_or(BlocktankError::ConnectionError {
1296+
error_details: "Database not initialized. Call init_db first.".to_string()
1297+
})?;
1298+
let guard = cell.lock().await;
1299+
let db = guard.blocktank_db.as_ref().ok_or(BlocktankError::ConnectionError {
1300+
error_details: "Database not initialized. Call init_db first.".to_string()
1301+
})?;
1302+
db.wipe_all().await
1303+
}).await.unwrap()
1304+
}
1305+
1306+
#[uniffi::export]
1307+
pub async fn wipe_all_databases() -> Result<String, DbError> {
1308+
let rt = ensure_runtime();
1309+
1310+
// Wipe activity database
1311+
{
1312+
let cell = DB.get().ok_or(DbError::InitializationError {
1313+
error_details: "Database not initialized. Call init_db first.".to_string()
1314+
})?;
1315+
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+
}
1321+
}
1322+
1323+
// Wipe blocktank database
1324+
rt.spawn(async move {
1325+
let cell = ASYNC_DB.get().ok_or(DbError::InitializationError {
1326+
error_details: "Database not initialized. Call init_db first.".to_string()
1327+
})?;
1328+
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+
}
1334+
Ok::<(), DbError>(())
1335+
}).await.unwrap()?;
1336+
1337+
Ok("All databases wiped successfully".to_string())
12471338
}

src/modules/activity/implementation.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,4 +1019,38 @@ impl ActivityDB {
10191019
SortDirection::Desc => "DESC"
10201020
}
10211021
}
1022+
1023+
/// Removes all activities from the database
1024+
pub fn remove_all(&mut self) -> Result<(), ActivityError> {
1025+
let tx = self.conn.transaction().map_err(|e| ActivityError::DataError {
1026+
error_details: format!("Failed to start transaction: {}", e),
1027+
})?;
1028+
1029+
// Delete from activities table (this will cascade to other tables due to foreign key constraints)
1030+
tx.execute("DELETE FROM activities", [])
1031+
.map_err(|e| ActivityError::DataError {
1032+
error_details: format!("Failed to delete all activities: {}", e),
1033+
})?;
1034+
1035+
tx.commit().map_err(|e| ActivityError::DataError {
1036+
error_details: format!("Failed to commit transaction: {}", e),
1037+
})?;
1038+
1039+
Ok(())
1040+
}
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+
}
10221056
}

src/modules/activity/tests.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,4 +1280,127 @@ mod tests {
12801280

12811281
cleanup(&db_path);
12821282
}
1283+
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+
}
1358+
1359+
#[test]
1360+
fn test_wipe_all() {
1361+
let (mut db, db_path) = setup();
1362+
1363+
// Insert various activities
1364+
let activity1 = create_test_onchain_activity();
1365+
let mut activity2 = create_test_lightning_activity();
1366+
activity2.id = "test_lightning_2".to_string();
1367+
let mut activity3 = create_test_onchain_activity();
1368+
activity3.id = "test_onchain_3".to_string();
1369+
let mut activity4 = create_test_lightning_activity();
1370+
activity4.id = "test_lightning_4".to_string();
1371+
1372+
db.insert_onchain_activity(&activity1).unwrap();
1373+
db.insert_lightning_activity(&activity2).unwrap();
1374+
db.insert_onchain_activity(&activity3).unwrap();
1375+
db.insert_lightning_activity(&activity4).unwrap();
1376+
1377+
// Add tags
1378+
db.add_tags(&activity1.id, &["payment".to_string()]).unwrap();
1379+
db.add_tags(&activity2.id, &["invoice".to_string()]).unwrap();
1380+
db.add_tags(&activity3.id, &["transfer".to_string()]).unwrap();
1381+
db.add_tags(&activity4.id, &["payment".to_string(), "invoice".to_string()]).unwrap();
1382+
1383+
// Verify data exists
1384+
let activities = db.get_activities(None, None, None, None, None, None, None, None).unwrap();
1385+
assert_eq!(activities.len(), 4);
1386+
let tags = db.get_all_unique_tags().unwrap();
1387+
assert_eq!(tags.len(), 3);
1388+
1389+
// Wipe all data
1390+
db.wipe_all().unwrap();
1391+
1392+
// Verify everything is deleted
1393+
let activities_after = db.get_activities(None, None, None, None, None, None, None, None).unwrap();
1394+
assert_eq!(activities_after.len(), 0);
1395+
let tags_after = db.get_all_unique_tags().unwrap();
1396+
assert_eq!(tags_after.len(), 0);
1397+
1398+
// Verify we can still insert new data after wipe
1399+
let new_activity = create_test_onchain_activity();
1400+
db.insert_onchain_activity(&new_activity).unwrap();
1401+
let activities_new = db.get_activities(None, None, None, None, None, None, None, None).unwrap();
1402+
assert_eq!(activities_new.len(), 1);
1403+
1404+
cleanup(&db_path);
1405+
}
12831406
}

src/modules/blocktank/db.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,4 +821,70 @@ impl BlocktankDB {
821821

822822
Ok(entries)
823823
}
824+
825+
/// Removes all orders from the database
826+
pub async fn remove_all_orders(&self) -> Result<(), BlocktankError> {
827+
let conn = self.conn.lock().await;
828+
829+
conn.execute("DELETE FROM orders", [])
830+
.map_err(|e| BlocktankError::DatabaseError {
831+
error_details: format!("Failed to delete all orders: {}", e),
832+
})?;
833+
834+
Ok(())
835+
}
836+
837+
/// Removes all CJIT entries from the database
838+
pub async fn remove_all_cjit_entries(&self) -> Result<(), BlocktankError> {
839+
let conn = self.conn.lock().await;
840+
841+
conn.execute("DELETE FROM cjit_entries", [])
842+
.map_err(|e| BlocktankError::DatabaseError {
843+
error_details: format!("Failed to delete all CJIT entries: {}", e),
844+
})?;
845+
846+
Ok(())
847+
}
848+
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+
861+
/// Removes all data from all Blocktank tables
862+
pub async fn wipe_all(&self) -> Result<(), BlocktankError> {
863+
let mut conn = self.conn.lock().await;
864+
865+
let tx = conn.transaction().map_err(|e| BlocktankError::DatabaseError {
866+
error_details: format!("Failed to start transaction: {}", e),
867+
})?;
868+
869+
tx.execute("DELETE FROM orders", [])
870+
.map_err(|e| BlocktankError::DatabaseError {
871+
error_details: format!("Failed to delete orders: {}", e),
872+
})?;
873+
874+
tx.execute("DELETE FROM cjit_entries", [])
875+
.map_err(|e| BlocktankError::DatabaseError {
876+
error_details: format!("Failed to delete CJIT entries: {}", e),
877+
})?;
878+
879+
tx.execute("DELETE FROM info", [])
880+
.map_err(|e| BlocktankError::DatabaseError {
881+
error_details: format!("Failed to delete info entries: {}", e),
882+
})?;
883+
884+
tx.commit().map_err(|e| BlocktankError::DatabaseError {
885+
error_details: format!("Failed to commit transaction: {}", e),
886+
})?;
887+
888+
Ok(())
889+
}
824890
}

0 commit comments

Comments
 (0)