From: Olaf Wintermann Date: Tue, 20 Jan 2026 19:48:14 +0000 (+0100) Subject: implement sub-tree deletion in note_store_delete_collection_async X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=63995160d86a8d450d2f55e130e673b54b0b8da1;p=note.git implement sub-tree deletion in note_store_delete_collection_async --- diff --git a/application/store.c b/application/store.c index e7f6773..3f6525a 100644 --- a/application/store.c +++ b/application/store.c @@ -84,6 +84,14 @@ #define SQL_RESOURCE_DELETE_CHILDREN "delete from resources where parent_id = ? ;" +#define SQL_RESOURCE_DELETE_ALL \ + "with recursive cte as ( " \ + " select resource_id, parent_id, nodename from resources where resource_id = ? " \ + " union all " \ + " select r.resource_id, r.parent_id, r.nodename from resources r join cte on r.parent_id = cte.resource_id " \ + ") " \ + "delete from resources where resource_id in (select resource_id from cte);" + #define SQL_RESOURCE_UPDATE_PARENT "update resources set parent_id = ? where parent_id = ? ;" #define SQL_RESOURCE_COUNT_CHILDREN "select count(*) from resources where parent_id = ? ;" @@ -1208,7 +1216,7 @@ static void uithr_execjob_finished(UiEvent *event, ExecJob *job) { static int qthr_delete_collection(ExecJob *job) { if(job->flag == NOTESTORE_COLLECTION_DELETE_ALL) { - DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_RESOURCE_DELETE_CHILDREN, job->id1); + DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_RESOURCE_DELETE_ALL, job->id1); if(!result) { job->error = 3; return 0; @@ -1230,16 +1238,16 @@ static int qthr_delete_collection(ExecJob *job) { job->error = 2; // db error return 0; } - } - - DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_RESOURCE_DELETE, job->id1); - if(!result) { - job->error = 5; - } - int ok = dbuResultIsOk(result); - dbuResultFree(result); - if(!ok) { - job->error = 6; + + DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_RESOURCE_DELETE, job->id1); + if(!result) { + job->error = 5; + } + int ok = dbuResultIsOk(result); + dbuResultFree(result); + if(!ok) { + job->error = 6; + } } return 0; diff --git a/application/store_sqlite.c b/application/store_sqlite.c index 79c8d86..8ecf6ca 100644 --- a/application/store_sqlite.c +++ b/application/store_sqlite.c @@ -67,7 +67,7 @@ "creationdate integer, " \ "etag text, " \ "content blob, " \ - "foreign key (parent_id) references resources(resource_id), " \ + "foreign key (parent_id) references resources(resource_id) on delete cascade, " \ "unique (parent_id, nodename) " \ ");" #define SQL_CREATE_TABLE_NOTES "create table notes( " \ @@ -92,8 +92,8 @@ "attachment_resource_id integer, " \ "parent_resource_id integer, " \ "type integer , " \ - "foreign key (attachment_resource_id) references resources(resource_id), " \ - "foreign key (parent_resource_id) references resources(resource_id) " \ + "foreign key (attachment_resource_id) references resources(resource_id) on delete cascade, " \ + "foreign key (parent_resource_id) references resources(resource_id) on delete cascade" \ ");" int store_sqlite_init_db(DBUConnection *connection) { diff --git a/application/tests/test-store.c b/application/tests/test-store.c index c548621..665507c 100644 --- a/application/tests/test-store.c +++ b/application/tests/test-store.c @@ -558,10 +558,32 @@ CX_TEST(test_note_store_delete_collection_async) { ui_exec_buffered_mainthread_calls_wait(3); CX_TEST_ASSERT(error == 0); - CX_TEST_ASSERT(res1->resource_id != 0); + CX_TEST_ASSERT(res1_child->resource_id != 0); + + Resource *res1_child_collection = cxZalloc(store->mp->allocator, sizeof(Resource)); + res1_child_collection->parent_id = res1->resource_id; + res1_child_collection->nodename = cx_strdup_a(store->mp->allocator, "child2_collection").ptr; + + error = -1; + note_store_save_notebook_async(obj, res1_child_collection, 0, test_save_notebook_result, &error); + ui_exec_buffered_mainthread_calls_wait(3); + + CX_TEST_ASSERT(error == 0); + CX_TEST_ASSERT(res1_child_collection->resource_id != 0); + + Resource *res1_sub_child = cxZalloc(store->mp->allocator, sizeof(Resource)); + res1_sub_child->parent_id = res1_child_collection->resource_id; + res1_sub_child->nodename = cx_strdup_a(store->mp->allocator, "subchild1").ptr; + + error = -1; + note_store_save_notebook_async(obj, res1_sub_child, 0, test_save_notebook_result, &error); + ui_exec_buffered_mainthread_calls_wait(3); + + CX_TEST_ASSERT(error == 0); + CX_TEST_ASSERT(res1_sub_child->resource_id != 0); int64_t res1_id = res1->resource_id; - int64_t res1_child_id = res1_child->resource_id; + int64_t res1_child_collection_id = res1_child_collection->resource_id; // test delete int result = -1; @@ -581,6 +603,9 @@ CX_TEST(test_note_store_delete_collection_async) { int64_t nchildren = note_store_count_children(res1_id); CX_TEST_ASSERT(nchildren == 0); + int64_t nsubchildren = note_store_count_children(res1_child_collection_id); + CX_TEST_ASSERT(nsubchildren == 0); + // cleanup ui_close(obj); }