add testMultiTableQuery3 default tip

Wed, 04 Feb 2026 20:00:54 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 04 Feb 2026 20:00:54 +0100
changeset 52
8503be5eea49
parent 51
e3163dc41a80

add testMultiTableQuery3

dbutils/dbutils/dbutils.h file | annotate | diff | comparison | revisions
test/database.c file | annotate | diff | comparison | revisions
test/database.h file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
testdata.sql file | annotate | diff | comparison | revisions
--- a/dbutils/dbutils/dbutils.h	Wed Jan 21 18:19:31 2026 +0100
+++ b/dbutils/dbutils/dbutils.h	Wed Feb 04 20:00:54 2026 +0100
@@ -97,7 +97,7 @@
      * value: DBUField*
      */
     CxMap *fields;
-    
+     
     /*
      * object fields
      * 
--- a/test/database.c	Wed Jan 21 18:19:31 2026 +0100
+++ b/test/database.c	Wed Feb 04 20:00:54 2026 +0100
@@ -94,6 +94,8 @@
 static DBUClass *address;
 static DBUClass *person;
 static DBUClass *role;
+static DBUClass *resource;
+static DBUClass *note;
 
 typedef struct Country {
     int64_t country_id;
@@ -130,6 +132,23 @@
     cxmutstr name;
 } Role;
 
+typedef struct Resource {
+    int64_t resource_id;
+    int64_t parent_id;
+    char    *nodename;
+    char    *content;
+    bool    iscollection;
+} Resource;
+
+typedef struct Note {
+    int64_t note_id;
+    int64_t resource_id;
+    char    *tags;
+    int     type;
+    
+    Resource *resource;
+} Note;
+
 int init_db_tests(void) {
     ctx = dbuContextCreate();
     
@@ -140,7 +159,7 @@
     dbuClassAdd(address, Address, street);
     dbuClassAdd(address, Address, zip);
     dbuClassAdd(address, Address, city);
-    dbuClassAddObj(address, "country_id", offsetof(Address, country), country);
+    dbuClassAddObj(address, "country", offsetof(Address, country), country);
     
     role = dbuRegisterClass(ctx, "role", Role, role_id);
     dbuClassAdd(role, Role, person_id);
@@ -152,12 +171,25 @@
     dbuClassAdd(person, Person, age);
     dbuClassAdd(person, Person, iscustomer);
     dbuClassAdd(person, Person, hash);
-    dbuClassAddObj(person, "address_id", offsetof(Person, address), address);
+    dbuClassAddObj(person, "address", offsetof(Person, address), address);
     dbuClassAddCxLinkedList(person, "person_id", offsetof(Person, roles), role);
     
     dbuClassAddForeignKey(role, Role, person_id, person);
     dbuClassAdd(role, Role, name);
     
+    resource = dbuRegisterClass(ctx, "resource", Resource, resource_id);
+    dbuClassAdd(resource, Resource, parent_id);
+    dbuClassAdd(resource, Resource, nodename);
+    dbuClassAdd(resource, Resource, content);
+    dbuClassAdd(resource, Resource, iscollection);
+    
+    note = dbuRegisterClass(ctx, "note", Note, note_id);
+    dbuClassAdd(note, Note, resource_id);
+    dbuClassAdd(note, Note, tags);
+    dbuClassAdd(note, Note, type);
+    dbuClassAddObj(note, "resource", offsetof(Note, resource), resource);
+    
+    
     return 0;
 }
 
@@ -409,6 +441,55 @@
     cxMempoolFree(mp);
 }
 
+CX_TEST(testMultiTableQuery3) {
+    CxMempool *mp = cxMempoolCreateSimple(64);
+    
+    CX_TEST_DO {
+        const char *sql1 = 
+                "select n.*, r.resource_id as [__resource__resource_id], r.parent_id, " \
+                "r.nodename, r.content, r.iscollection " \
+                "from resource r inner join note n on r.resource_id = n.resource_id " \
+                "where parent_id = (select resource_id from resource where nodename = 'Collection1') ;";
+        DBUQuery *q = dbuQueryCreate(conn, mp->allocator, sql1);
+        DBUObjectBuilder *builder = dbuObjectBuilder(note, q, mp->allocator);
+        CxList *notes = dbuObjectBuilderGetList(builder);
+        dbuObjectBuilderDestroy(builder);
+        
+        CX_TEST_ASSERT(notes);
+        CX_TEST_ASSERT(cxListSize(notes) == 2);
+        
+        Note *n0 = cxListAt(notes, 0);
+        Note *n1 = cxListAt(notes, 1);
+        
+        CX_TEST_ASSERT(n0);
+        CX_TEST_ASSERT(n1);
+        
+        CX_TEST_ASSERT(n0->note_id > 0);
+        CX_TEST_ASSERT(n0->resource_id > 0);
+        CX_TEST_ASSERT(!cx_strcmp(n0->tags, "todo, test"));
+        CX_TEST_ASSERT(n0->type == 1);
+        CX_TEST_ASSERT(n0->resource);
+        CX_TEST_ASSERT(n0->resource_id == n0->resource->resource_id);
+        CX_TEST_ASSERT(!cx_strcmp(n0->resource->nodename, "note1"));
+        CX_TEST_ASSERT(!n0->resource->iscollection);
+        CX_TEST_ASSERT(n0->resource->parent_id > 0);
+        CX_TEST_ASSERT(!cx_strcmp(n0->resource->content, "Hello World!"));
+        
+        CX_TEST_ASSERT(n1->note_id > 0);
+        CX_TEST_ASSERT(n1->resource_id > 0);
+        CX_TEST_ASSERT(!cx_strcmp(n1->tags, "work, project2501, ai"));
+        CX_TEST_ASSERT(n1->type == 2);
+        CX_TEST_ASSERT(n1->resource);
+        CX_TEST_ASSERT(n1->resource_id == n1->resource->resource_id);
+        CX_TEST_ASSERT(!cx_strcmp(n1->resource->nodename, "note2"));
+        CX_TEST_ASSERT(!n1->resource->iscollection);
+        CX_TEST_ASSERT(n1->resource->parent_id > 0);
+        CX_TEST_ASSERT(!cx_strcmp(n1->resource->content, "Test String"));
+    }
+    
+    cxMempoolFree(mp);
+}
+
 CX_TEST(testMultiTableQueryUnknownResult1) {
     CxMempool *mp = cxMempoolCreateSimple(64);
     
--- a/test/database.h	Wed Jan 21 18:19:31 2026 +0100
+++ b/test/database.h	Wed Feb 04 20:00:54 2026 +0100
@@ -53,6 +53,7 @@
 CX_TEST(testMultiTableQuery);
 CX_TEST(testMultiTableQuery1);
 CX_TEST(testMultiTableQuery2);
+CX_TEST(testMultiTableQuery3);
 CX_TEST(testMultiTableQueryUnknownResult1);
 CX_TEST(testQuerySubListDense1);
 CX_TEST(testQuerySubListDenseWithMultiTable1);
--- a/test/main.c	Wed Jan 21 18:19:31 2026 +0100
+++ b/test/main.c	Wed Feb 04 20:00:54 2026 +0100
@@ -136,6 +136,7 @@
     cx_test_register(suite, testMultiTableQuery);
     cx_test_register(suite, testMultiTableQuery1);
     cx_test_register(suite, testMultiTableQuery2);
+    cx_test_register(suite, testMultiTableQuery3);
     cx_test_register(suite, testMultiTableQueryUnknownResult1);
     cx_test_register(suite, testQuerySubListDense1);
     cx_test_register(suite, testQuerySubListDenseWithMultiTable1);
--- a/testdata.sql	Wed Jan 21 18:19:31 2026 +0100
+++ b/testdata.sql	Wed Feb 04 20:00:54 2026 +0100
@@ -28,6 +28,21 @@
 	name text
 );
 
+create table Resource(
+	resource_id integer primary key autoincrement,
+	parent_id integer references Resource(resource_id),
+	nodename text,
+	content text,
+	iscollection integer default 0
+);
+
+create table Note(
+	note_id integer primary key autoincrement,
+	resource_id integer references Resource(resource_id),
+	tags text,
+	type int
+);
+
 insert into country (name) values ('Germany');
 
 insert into address (street, zip, city, country_id) 
@@ -46,3 +61,39 @@
 (1, 'manager'), 
 (2, 'extern');
 
+insert into Resource(nodename, iscollection)
+values
+('root', 1);
+
+insert into Resource(parent_id, nodename, iscollection)
+values
+((select resource_id from Resource where nodename = 'root'), 'Collection1', 1);
+
+insert into Resource(parent_id, nodename, iscollection)
+values
+((select resource_id from Resource where nodename = 'root'), 'Collection2', 1);
+
+insert into Resource(parent_id, nodename, content)
+values
+((select resource_id from Resource where nodename = 'Collection1'), 'note1', 'Hello World!');
+
+insert into Resource(parent_id, nodename, content)
+values
+((select resource_id from Resource where nodename = 'Collection1'), 'note2', 'Test String');
+
+insert into Resource(parent_id, nodename, content)
+values
+((select resource_id from Resource where nodename = 'Collection2'), 'note3', 'Content Text');
+
+insert into Note(resource_id, tags, type)
+values
+((select resource_id from Resource where nodename = 'note1'), 'todo, test', 1);
+
+insert into Note(resource_id, tags, type)
+values
+((select resource_id from Resource where nodename = 'note2'), 'work, project2501, ai', 2);
+
+insert into Note(resource_id, tags, type)
+values
+((select resource_id from Resource where nodename = 'note3'), 'finance', 3);
+

mercurial