add support for list members to the object builder

Sat, 14 Dec 2024 17:03:31 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 14 Dec 2024 17:03:31 +0100
changeset 8
bd08116b8af4
parent 7
c98ff52cd806
child 9
5785a693834c

add support for list members to the object builder

dbutils/class.c file | annotate | diff | comparison | revisions
dbutils/dbutils/dbutils.h file | annotate | diff | comparison | revisions
dbutils/field.c file | annotate | diff | comparison | revisions
dbutils/object.c file | annotate | diff | comparison | revisions
dbutils/object.h file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
--- a/dbutils/class.c	Fri Dec 13 11:24:55 2024 +0100
+++ b/dbutils/class.c	Sat Dec 14 17:03:31 2024 +0100
@@ -74,6 +74,7 @@
     val.cls = fkcls;
     field->foreignKeyClass = fkcls;
     cxMapPut(cls->foreign_keys, name, &val);
+    dbuClassAddField(cls, name, field);
 }
 
 void dbuClassAddObjField(DBUClass *cls, const char *name, DBUField *field, DBUClass *foreign_cls) {
--- a/dbutils/dbutils/dbutils.h	Fri Dec 13 11:24:55 2024 +0100
+++ b/dbutils/dbutils/dbutils.h	Sat Dec 14 17:03:31 2024 +0100
@@ -127,7 +127,7 @@
     int int1;
     int int2;
     DBUObject (*create)(DBUObjectResult *result, DBUClass *type, const CxAllocator *a);
-    int (*add)(DBUObjectResult *result, DBUObject parent, void *obj, CxList *fk, const CxAllocator *a);
+    int (*add)(DBUObjectResult *result, DBUObject parent, DBUClass *tye, void *obj, CxList *fk, const CxAllocator *a);
     void (*free)(DBUObjectResult *result);
 };
 
--- a/dbutils/field.c	Fri Dec 13 11:24:55 2024 +0100
+++ b/dbutils/field.c	Sat Dec 14 17:03:31 2024 +0100
@@ -1089,11 +1089,11 @@
     }
     return obj;
 }
-static int linkedlist_add(DBUObjectResult *result, DBUObject parent, void *obj, CxList *fk, const CxAllocator *a) {
+static int linkedlist_add(DBUObjectResult *result, DBUObject parent, DBUClass *type, void *obj, CxList *fk, const CxAllocator *a) {
     DBUOffsetField *field  = result->userdata1;
     DBUClass *cls = result->userdata2;
     CxList **list = (CxList**)(parent+field->offset);
-    if(*list) {
+    if(!*list) {
         *list = cxLinkedListCreate(a, NULL, CX_STORE_POINTERS);
         if(!(*list)) {
             return 1;
--- a/dbutils/object.c	Fri Dec 13 11:24:55 2024 +0100
+++ b/dbutils/object.c	Sat Dec 14 17:03:31 2024 +0100
@@ -96,7 +96,7 @@
     return result->userdata2;
 }
 
-static int list_result_add(DBUObjectResult *result, DBUObject parent, void *obj, CxList *fk, const CxAllocator *a) {
+static int list_result_add(DBUObjectResult *result, DBUObject parent, DBUClass *type, void *obj, CxList *fk, const CxAllocator *a) {
     return cxListAdd(result->userdata1, obj);
 }
 
@@ -159,9 +159,27 @@
 
 /* ------------------------- Object Builder -----------------------------*/
 
-static int add_to_parent(DBUObjectResult *result, DBUObject parent, void *obj, CxList *fk, const CxAllocator *a) {
+static int add_to_parent(DBUObjectResult *result, DBUObject parent, DBUClass *type, void *obj, CxList *fklist, const CxAllocator *a) {
     DBUBuilderQuery *query = result->userdata1;
-    
+    DBUObjectBuilder *builder = result->userdata2;
+    CxIterator i = cxListIterator(fklist);
+    cx_foreach(DBUFK*, fk, i) {
+        // check if the elm can be added
+        DBUField *field = cxMapGet(fk->cls->obj_fields, type->name);
+        if(!field) {
+            continue;
+        }
+        
+        // find cached object for all foreign keys
+        DBUBuilderObjCache *parent_cached = cxMapGet(builder->cache, fk->cache_key);
+        if(!parent_cached) {
+            continue;
+        }
+        
+        if(field->builder.add) {
+            field->builder.add(&field->builder, parent_cached->obj, type, obj, NULL, a);
+        }
+    }
     
     return 0;
 }
@@ -180,7 +198,7 @@
         cx_foreach(DBUBuilderQuery *, q, i) {
             DBUObjectResult result = { 
                 .userdata1 = q,
-                .userdata2 = NULL,
+                .userdata2 = builder,
                 .int1 = CX_STORE_POINTERS,
                 .create = result_create_obj,
                 .add = add_to_parent
@@ -200,6 +218,10 @@
     return ret;
 }
 
+void dbufkelm_free(DBUFK *elm) {
+    free(elm->cache_key);
+}
+
 int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult) {
     DBUClass *cls = type;
     
@@ -270,12 +292,13 @@
     
     const CxAllocator *a = builder->allocator;
     
-    CxList *fklist = cxArrayListCreateSimple(CX_STORE_POINTERS, 4);
-    fklist->collection.simple_destructor = free;
+    CxList *fklist = cxArrayListCreateSimple(sizeof(DBUFK), 4);
+    fklist->collection.simple_destructor = (cx_destructor_func)dbufkelm_free;
     
      // get result
     int err = 0;
     while(result->hasData(result)) {
+        
         // create main result obj
         void *obj = objresult->create(objresult, cls, a);
         if(!obj) {
@@ -326,7 +349,7 @@
                     
                     // if obj caching is enabled and the current field contains
                     // the primary key, add this object to the cache
-                    if(builder->cache && field.field == current_cls->primary_key) {
+                    if(builder->cache) {
                         if(field.field == current_cls->primary_key) {
                             cxmutstr cache_key = cx_asprintf("%.*s::%.*s",
                                     (int)current_cls->name.length, current_cls->name.ptr,
@@ -335,7 +358,10 @@
                                 err = 1;
                                 break;
                             }
-                            int r = cxMapPut(builder->cache, cache_key, current_obj);
+                            DBUBuilderObjCache cache_elm;
+                            cache_elm.class = current_cls;
+                            cache_elm.obj = current_obj;
+                            int r = cxMapPut(builder->cache, cache_key, &cache_elm);
                             free(cache_key.ptr);
                             if(r) {
                                 err = 1;
@@ -343,9 +369,12 @@
                             }
                         } else if(field.field->foreignKeyClass) {
                             cxmutstr fkey = cx_asprintf("%.*s::%.*s",
-                                    (int)field.field->foreignKeyClass->name.length, current_cls->name.ptr,
+                                    (int)field.field->foreignKeyClass->name.length, field.field->foreignKeyClass->name.ptr,
                                     (int)text.length, text.ptr);
-                            cxListAdd(fklist, fkey.ptr);
+                            DBUFK fkelm;
+                            fkelm.cache_key = fkey.ptr;
+                            fkelm.cls = field.field->foreignKeyClass;
+                            cxListAdd(fklist, &fkelm);
                         }
                     }
                 }
@@ -356,7 +385,7 @@
             break;
         }
         
-        objresult->add(objresult, NULL, obj, fklist, a);
+        objresult->add(objresult, NULL, cls, obj, fklist, a);
         
         cxListClear(fklist);
         
--- a/dbutils/object.h	Fri Dec 13 11:24:55 2024 +0100
+++ b/dbutils/object.h	Sat Dec 14 17:03:31 2024 +0100
@@ -102,6 +102,11 @@
     CxMap *cache;
 };
 
+typedef struct DBUFK {
+    char *cache_key;
+    DBUClass *cls;
+} DBUFK;
+
 int dbuObjectExec(DBUObjectBuilder *builder, DBUObjectResult *objresult);
 
 int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult);
--- a/test/main.c	Fri Dec 13 11:24:55 2024 +0100
+++ b/test/main.c	Sat Dec 14 17:03:31 2024 +0100
@@ -33,6 +33,9 @@
 #include <dbutils/sqlite.h>
 #include <dbutils/db.h>
 
+#include <cx/buffer.h>
+#include <cx/printf.h>
+
 const char *sql_create_table_person =
 "create table if not exists Person ("
 "person_id integer primary key autoincrement, "
@@ -161,8 +164,23 @@
     if(persons) {
         CxIterator i = cxListIterator(persons);
         cx_foreach(Person *, p, i) {
-            printf("{ person_id = %" PRId64 ", name = \"%s\", email = \"%s\", age = %d, iscustomer = %s, hash = %" PRIu64 " }\n",
-                    p->person_id, p->name.ptr, p->email.ptr, p->age, p->iscustomer ? "true" : "false", p->hash);
+            CxBuffer rolebuffer;
+            cxBufferInit(&rolebuffer, NULL, 256, 0, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS);
+            cxBufferPut(&rolebuffer, '[');
+            if(p->roles) {
+                CxIterator r = cxListIterator(p->roles);
+                char *addseparator = "";
+                cx_foreach(Role *, role, r) {
+                    cx_bprintf(&rolebuffer, "%s{ role_id = %d, name = \"%s\"}", addseparator, role->role_id, role->name.ptr);
+                    addseparator = ", ";
+                }
+            }
+            cxBufferPut(&rolebuffer, ']');
+            cxBufferPut(&rolebuffer, 0);
+            printf("{ person_id = %" PRId64 ", name = \"%s\", email = \"%s\", age = %d, iscustomer = %s, hash = %" PRIu64 " roles = %s }\n",
+                    p->person_id, p->name.ptr, p->email.ptr, p->age, p->iscustomer ? "true" : "false", p->hash, rolebuffer.space);
+            
+            cxBufferDestroy(&rolebuffer);
         }
     } else {
         fprintf(stderr, "Error\n");

mercurial