--- a/test/database.c Mon Dec 29 18:09:43 2025 +0100 +++ b/test/database.c Tue Dec 30 21:05:46 2025 +0100 @@ -90,16 +90,24 @@ static DBUContext *ctx; static DBUConnection *conn; +static DBUClass *country; static DBUClass *address; static DBUClass *person; static DBUClass *role; +typedef struct Country { + int64_t country_id; + cxmutstr name; +} Country; + typedef struct Address { int64_t address_id; cxmutstr street; cxmutstr zip; cxmutstr city; + + Country *country; } Address; typedef struct Person { @@ -125,10 +133,14 @@ int init_db_tests(void) { ctx = dbuContextCreate(); + country = dbuRegisterClass(ctx, "country", Country, country_id); + dbuClassAdd(country, Country, name); + address = dbuRegisterClass(ctx, "address", Address, address_id); dbuClassAdd(address, Address, street); dbuClassAdd(address, Address, zip); dbuClassAdd(address, Address, city); + dbuClassAddObj(address, "country_id", offsetof(Address, country), country); role = dbuRegisterClass(ctx, "role", Role, role_id); @@ -297,8 +309,46 @@ CX_TEST_ASSERT(!cx_strcmp(p0->address->city, "city 17")); CX_TEST_ASSERT(!cx_strcmp(p1->address->city, "city 18")); + dbuObjectBuilderDestroy(builder); - dbuObjectBuilderDestroy(builder); + const char *sql2 = "select p.*, " + "a.address_id as [__address__address_id], a.street, a.zip, a.city, " + "c.country_id as [__country__country_id], c.name " + "from Person p inner join Address a on p.address_id = a.address_id inner join Country c on a.country_id = c.country_id " + "order by p.person_id;"; + DBUQuery *query2 = dbuQueryCreate(conn, mp->allocator, sql2); + DBUObjectBuilder *builder2 = dbuObjectBuilder(person, query2, mp->allocator); + CxList *persons2 = dbuObjectBuilderGetList(builder2); + + CX_TEST_ASSERT(persons2); + CX_TEST_ASSERT(cxListSize(persons2) == 2); + + p0 = cxListAt(persons2, 0); + p1 = cxListAt(persons2, 1); + CX_TEST_ASSERT(p0); + CX_TEST_ASSERT(p1); + CX_TEST_ASSERT(!cx_strcmp(p0->name, "alice")); + CX_TEST_ASSERT(!cx_strcmp(p1->name, "bob")); + CX_TEST_ASSERT(!cx_strcmp(p0->email, "alice@example.com")); + CX_TEST_ASSERT(!cx_strcmp(p1->email, "bob@example.com")); + CX_TEST_ASSERT(p0->age == 30); + CX_TEST_ASSERT(p1->age == 25); + CX_TEST_ASSERT(p0->iscustomer == 0); + CX_TEST_ASSERT(p1->iscustomer == 1); + CX_TEST_ASSERT(p0->hash == 123456789); + CX_TEST_ASSERT(p1->hash == 987654321); + + CX_TEST_ASSERT(p0->address != NULL); + CX_TEST_ASSERT(p1->address != NULL); + + CX_TEST_ASSERT(!cx_strcmp(p0->address->street, "street 1")); + CX_TEST_ASSERT(!cx_strcmp(p1->address->street, "street 2")); + CX_TEST_ASSERT(!cx_strcmp(p0->address->zip, "12343")); + CX_TEST_ASSERT(!cx_strcmp(p1->address->zip, "23456")); + CX_TEST_ASSERT(!cx_strcmp(p0->address->city, "city 17")); + CX_TEST_ASSERT(!cx_strcmp(p1->address->city, "city 18")); + + dbuObjectBuilderDestroy(builder2); } cxMempoolFree(mp);