]> uap-core.de Git - note.git/commitdiff
update dbutils, simplify delete_collection main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 21 Jan 2026 17:26:47 +0000 (18:26 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 21 Jan 2026 17:26:47 +0000 (18:26 +0100)
13 files changed:
application/store.c
application/store_sqlite.c
application/tests/test-store.c
dbutils/class.c
dbutils/db.c
dbutils/dbutils/db.h
dbutils/dbutils/dbutils.h
dbutils/dbutils/json.h
dbutils/field.c
dbutils/json.c
dbutils/json.h
dbutils/object.c
dbutils/sqlite.c

index 3f6525af758a54bb17a6cfee7be730dd3cbdb296..5fb698000a9ac75f4b1820e3cce3b79c7b8c19ab 100644 (file)
@@ -84,6 +84,7 @@
 
 #define SQL_RESOURCE_DELETE_CHILDREN "delete from resources where parent_id = ? ;"
 
+// unused
 #define SQL_RESOURCE_DELETE_ALL \
     "with recursive cte as ( " \
     "    select resource_id, parent_id, nodename from resources where resource_id = ? " \
@@ -367,7 +368,7 @@ int note_store_create_default(const char *host, const char *user) {
     if(!q->exec(q)) {
         err = dbuResultAsValue(q->getResult(q), &notebooks_id);
         if(!err) {
-            DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, notebooks_id);
+            DBUResult *result = dbuSqlExecQueryParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, notebooks_id);
             int64_t unused;
             err = dbuResultAsInt64(result, &unused);
         }
@@ -381,7 +382,7 @@ int note_store_create_default(const char *host, const char *user) {
         if(!q->exec(q)) {
             err = dbuResultAsValue(q->getResult(q), &mynotes_id);
             if(!err) {
-                DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, mynotes_id);
+                DBUResult *result = dbuSqlExecQueryParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, mynotes_id);
                 int64_t unused;
                 err = dbuResultAsInt64(result, &unused);
             }
@@ -1173,7 +1174,7 @@ typedef struct CountJob {
 } CountJob;
 
 static int qthr_collection_get_size(CountJob *job) {
-    DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_NOTEBOOK_COUNT_CHILDREN, job->id1);
+    DBUResult *result = dbuSqlExecQueryParamInt64(connection, NULL, SQL_NOTEBOOK_COUNT_CHILDREN, job->id1);
     if(!result) {
         job->error = 1;
         return 0;
@@ -1216,17 +1217,10 @@ 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_ALL, job->id1);
-        if(!result) {
+        if(dbuSqlExecParamInt64(connection, SQL_RESOURCE_DELETE, job->id1)) {
             job->error = 3;
             return 0;
         }
-        int ok = dbuResultIsOk(result);
-        dbuResultFree(result);
-        if(!ok) {
-            job->error = 4;
-            return 0;
-        }
     } else {
         // only delete the resource when there are no children
         int64_t nchildren = note_store_count_children(job->id1);
@@ -1239,14 +1233,8 @@ static int qthr_delete_collection(ExecJob *job) {
             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;
+        if(dbuSqlExecParamInt64(connection, SQL_RESOURCE_DELETE, job->id1)) {
+            job->error = 3;
         }
     }
     
index 8ecf6ca483597810724f923650ebb18f798a0f40..7ec45c2a52f57b675eb3c9d193395cb78622dc8f 100644 (file)
@@ -109,7 +109,7 @@ int store_sqlite_init_db(DBUConnection *connection) {
     int nsql = sizeof(sql) / sizeof(char*);
     
     for(int i=0;i<nsql;i++) {
-        if(dbuConnectionExec(connection, sql[i])) {
+        if(dbuSqlExec(connection, sql[i])) {
             fprintf(stderr, "sqlite error: query failed\n%s\n", sql[i]);
             return 1;
         }
index 665507c3f414be1bf39a31f7a687167f92a17bd5..06ce0c9052e49a25c978da4234e77fbfb46d4cfd 100644 (file)
@@ -63,7 +63,7 @@ CX_TEST(test_note_store_create_default) {
         int ret = note_store_create_default("testhost", "testuser");
         CX_TEST_ASSERT(ret == 0);
         
-        DBUResult *result = dbuSqlExec(conn, NULL,
+        DBUResult *result = dbuSqlExecQuery(conn, NULL,
                 "select r.repository_id, c.resource_id from user_settings u "
                 "inner join repositories r on u.default_repository_id = r.repository_id "
                 "inner join resources c on u.default_collection_id = c.resource_id "
index fcd2751a862fcdb83b65084514fbc038f4040631..c15def273d28379e90a28a8d3f23669986efbed2 100644 (file)
@@ -81,6 +81,7 @@ void dbuClassAddObjField(DBUClass *cls, const char *name, DBUField *field, DBUCl
     free(field->name.ptr);
     field->name = name ? cx_strdup(cx_str(name)) : (cxmutstr){NULL,0};
     cxMapPut(cls->obj_fields, foreign_cls->name, field);
+    cxMapPut(cls->fields, name, field);
 }
 
 
index 0dbea991aaac2ba7e852b463861324cc68788f21..4d3f7aa2334b1ae98c0b4b5cab9bf5bb52d2b3fd 100644 (file)
 #include "db.h"
 #include "dbutils/db.h"
 
-int dbuConnectionExec(DBUConnection *conn, const char *sql) {
-    DBUQuery *q = conn->createQuery(conn, NULL);
-    int err = 1;
-    if(!dbuQuerySetSQL(q, sql)) {
-        err = dbuQueryExec(q);
-    } 
-    dbuQueryFree(q);
-    return err;
-}
-
 int dbuConnectionIsActive(DBUConnection *conn) {
     return conn->isActive ? conn->isActive(conn) : 1;
 }
@@ -246,7 +236,7 @@ static DBUQuery* execStringParamQuery(DBUConnection *conn, const char *sql, cxst
     return q;
 }
 
-DBUResult* dbuSqlExec(DBUConnection *conn, const CxAllocator *a, const char *sql) {
+DBUResult* dbuSqlExecQuery(DBUConnection *conn, const CxAllocator *a, const char *sql) {
     DBUQuery *q = dbuQueryCreate(conn, a, sql);
     if(!q) {
         return NULL;
@@ -260,7 +250,7 @@ DBUResult* dbuSqlExec(DBUConnection *conn, const CxAllocator *a, const char *sql
     return result;
 }
 
-DBUResult* dbuSqlExecParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param) {
+DBUResult* dbuSqlExecQueryParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param) {
     DBUQuery *q = execInt64ParamQuery(conn, sql, param);
     if(!q) return NULL;
     DBUResult *r = dbuQueryGetResult(q);
@@ -268,7 +258,7 @@ DBUResult* dbuSqlExecParamInt32(DBUConnection *conn, const CxAllocator *a, const
     return r;
 }
 
-DBUResult* dbuSqlExecParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param) {
+DBUResult* dbuSqlExecQueryParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param) {
     DBUQuery *q = execInt64ParamQuery(conn, sql, param);
     if(!q) return NULL;
     DBUResult *r = dbuQueryGetResult(q);
@@ -276,7 +266,7 @@ DBUResult* dbuSqlExecParamInt64(DBUConnection *conn, const CxAllocator *a, const
     return r;
 }
 
-DBUResult* dbuSqlExecParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param) {
+DBUResult* dbuSqlExecQueryParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param) {
     DBUQuery *q = execInt64ParamQuery(conn, sql, param);
     if(!q) return NULL;
     DBUResult *r = dbuQueryGetResult(q);
@@ -284,7 +274,7 @@ DBUResult* dbuSqlExecParamUInt32(DBUConnection *conn, const CxAllocator *a, cons
     return r;
 }
 
-DBUResult* dbuSqlExecParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param) {
+DBUResult* dbuSqlExecQueryParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint64_t param) {
     DBUQuery *q = execInt64ParamQuery(conn, sql, param);
     if(!q) return NULL;
     DBUResult *r = dbuQueryGetResult(q);
@@ -292,7 +282,7 @@ DBUResult* dbuSqlExecParamUInt64(DBUConnection *conn, const CxAllocator *a, cons
     return r;
 }
 
-DBUResult* dbuSqlExecParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param) {
+DBUResult* dbuSqlExecQueryParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param) {
     DBUQuery *q = execStringParamQuery(conn, sql, cx_str(param));
     if(!q) return NULL;
     DBUResult *r = dbuQueryGetResult(q);
@@ -300,7 +290,7 @@ DBUResult* dbuSqlExecParamString(DBUConnection *conn, const CxAllocator *a, cons
     return r;
 }
 
-DBUResult* dbuSqlExecParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param) {
+DBUResult* dbuSqlExecQueryParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param) {
     DBUQuery *q = execStringParamQuery(conn, sql, param);
     if(!q) return NULL;
     DBUResult *r = dbuQueryGetResult(q);
@@ -308,7 +298,7 @@ DBUResult* dbuSqlExecParamCxString(DBUConnection *conn, const CxAllocator *a, co
     return r;
 }
 
-DBUResult* dbuSqlExecParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param) {
+DBUResult* dbuSqlExecQueryParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param) {
     DBUQuery *q = execStringParamQuery(conn, sql, cx_strcast(param));
     if(!q) return NULL;
     DBUResult *r = dbuQueryGetResult(q);
@@ -378,3 +368,83 @@ CxList* dbuSimpleGetListWithStringParam(DBUConnection *conn, const char *sql, cx
     dbuObjectBuilderDestroy(builder);
     return list;
 }
+
+int dbuSqlExec(DBUConnection *conn, const char *sql) {
+    DBUResult *result = dbuSqlExecQuery(conn, NULL, sql);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
+
+int dbuSqlExecParamInt32(DBUConnection *conn, const char *sql, int32_t param) {
+    DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
+
+int dbuSqlExecParamInt64(DBUConnection *conn, const char *sql, int64_t param) {
+    DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
+
+int dbuSqlExecParamUInt32(DBUConnection *conn, const char *sql, uint32_t param) {
+    DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
+
+int dbuSqlExecParamUInt64(DBUConnection *conn, const char *sql, uint64_t param) {
+    DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
+
+int dbuSqlExecParamString(DBUConnection *conn, const char *sql, const char *param) {
+    DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
+
+int dbuSqlExecParamCxString(DBUConnection *conn, const char *sql, cxstring param) {
+    DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
+
+int dbuSqlExecParamCxMutStr(DBUConnection *conn, const char *sql, cxmutstr param) {
+    DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+    if(!result) {
+        return 1;
+    }
+    int ret = dbuResultIsOk(result);
+    dbuResultFree(result);
+    return !ret;
+}
index 3162704ef2e496f20e4755d20eb3a865c8716c2a..0074a1f7d74791e9a5ca90471cfd21de7f922d71 100644 (file)
@@ -96,7 +96,6 @@ struct DBUResult {
     int rowIndex;
 };
 
-int dbuConnectionExec(DBUConnection *conn, const char *sql);
 int dbuConnectionIsActive(DBUConnection *conn);
 void dbuConnectionFree(DBUConnection *conn);
 DBUQuery* dbuConnectionQuery(DBUConnection *conn, const CxAllocator *a);
@@ -152,27 +151,25 @@ void dbuObjectBuilderDestroy(DBUObjectBuilder *builder);
 // TODO: implement
 int dbuObjectBuilderAddSubquery(DBUObjectBuilder *builder, DBUClass *type, DBUQuery *subquery);
 
-#define dbuSqlExecParam(conn, a, sql, param) \
+#define dbuSqlExecQueryParam(conn, a, sql, param) \
     _Generic(param, \
-    int32_t    : dbuSqlExecParamInt32, \
-    int64_t    : dbuSqlExecParamInt64, \
-    uint32_t   : dbuSqlExecParamUInt32, \
-    uint64_t   : dbuSqlExecParamUInt64, \
-    char*      : dbuSqlExecParamString, \
-    const char*: dbuSqlExecParamString, \
-    cxstring   : dbuSqlExecParamCxString, \
-    cxmutstr   : dbuSqlExecParamCxMutStr)(conn, a, sql, param)
-
-DBUResult* dbuSqlExec(DBUConnection *conn, const CxAllocator *a, const char *sql);
-DBUResult* dbuSqlExecParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param);
-DBUResult* dbuSqlExecParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param);
-DBUResult* dbuSqlExecParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param);
-DBUResult* dbuSqlExecParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param);
-DBUResult* dbuSqlExecParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param);
-DBUResult* dbuSqlExecParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param);
-DBUResult* dbuSqlExecParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param);
-
-
+    int32_t    : dbuSqlExecQueryParamInt32, \
+    int64_t    : dbuSqlExecQueryParamInt64, \
+    uint32_t   : dbuSqlExecQueryParamUInt32, \
+    uint64_t   : dbuSqlExecQueryParamUInt64, \
+    char*      : dbuSqlExecQueryParamString, \
+    const char*: dbuSqlExecQueryParamString, \
+    cxstring   : dbuSqlExecQueryParamCxString, \
+    cxmutstr   : dbuSqlExecQueryParamCxMutStr)(conn, a, sql, param)
+
+DBUResult* dbuSqlExecQuery(DBUConnection *conn, const CxAllocator *a, const char *sql);
+DBUResult* dbuSqlExecQueryParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param);
+DBUResult* dbuSqlExecQueryParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param);
+DBUResult* dbuSqlExecQueryParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param);
+DBUResult* dbuSqlExecQueryParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint64_t param);
+DBUResult* dbuSqlExecQueryParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param);
+DBUResult* dbuSqlExecQueryParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param);
+DBUResult* dbuSqlExecQueryParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param);
 
 int dbuSimpleGetInt64WithIntParam(DBUConnection *conn, const char *sql, int64_t param, int64_t *result);
 int dbuSimpleGetInt64WithStringParam(DBUConnection *conn, const char *sql, cxstring param, int64_t *result);
@@ -181,6 +178,26 @@ int dbuSimpleGetStringWithStringParam(DBUConnection *conn, const char *sql, cxst
 CxList* dbuSimpleGetListWithIntParam(DBUConnection *conn, const char *sql, int64_t param, const CxAllocator *a, DBUClass *type);
 CxList* dbuSimpleGetListWithStringParam(DBUConnection *conn, const char *sql, cxstring param, const CxAllocator *a, DBUClass *type);
 
+#define dbuSqlExecParam(conn, sql, param) \
+    _Generic(param, \
+    int32_t    : dbuSqlExecParamInt32, \
+    int64_t    : dbuSqlExecParamInt64, \
+    uint32_t   : dbuSqlExecParamUInt32, \
+    uint64_t   : dbuSqlExecParamUInt64, \
+    char*      : dbuSqlExecParamString, \
+    const char*: dbuSqlExecParamString, \
+    cxstring   : dbuSqlExecParamCxString, \
+    cxmutstr   : dbuSqlExecParamCxMutStr)(conn, sql, param)
+
+int dbuSqlExec(DBUConnection *conn, const char *sql);
+int dbuSqlExecParamInt32(DBUConnection *conn, const char *sql, int32_t param);
+int dbuSqlExecParamInt64(DBUConnection *conn, const char *sql, int64_t param);
+int dbuSqlExecParamUInt32(DBUConnection *conn, const char *sql, uint32_t param);
+int dbuSqlExecParamUInt64(DBUConnection *conn, const char *sql, uint64_t param);
+int dbuSqlExecParamString(DBUConnection *conn, const char *sql, const char *param);
+int dbuSqlExecParamCxString(DBUConnection *conn, const char *sql, cxstring param);
+int dbuSqlExecParamCxMutStr(DBUConnection *conn, const char *sql, cxmutstr param);
+
 #ifdef __cplusplus
 }
 #endif
index c75740149ff683402f5a33337caa88e8d97fa364..12eb671d862b9f55570890e3222e12b29973f1f7 100644 (file)
@@ -130,6 +130,7 @@ typedef struct DBUObjectResult DBUObjectResult;
 struct DBUObjectResult {
     void *userdata1;
     void *userdata2;
+    DBUClass *type;
     int int1;
     int int2;
     DBUObject (*create)(DBUObjectResult *result, DBUClass *type, const CxAllocator *a);
index 0617ef89f4f11350c246a1e7fb4d63f6f8c556d4..46ce0f8114336366e777159a9d2995a8343a4e08 100644 (file)
@@ -47,6 +47,9 @@ cxmutstr dbuArrayToJsonString(DBUClass *type, void **objArray, size_t size, cons
 
 CxJsonValue* dbuObjectToJson2(DBUClass *type, void *obj, const CxAllocator *a, bool setNull, bool forceString);
 
+void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value);
+CxList* dbuJsonToList(DBUClass *type, const CxAllocator *a, CxJsonValue *value);
+
 
 #ifdef __cplusplus
 }
index bebf2211216628ccbe088657d03f9a5be31ada7f..8a5656e33b0d84047077e9119e65f1abff41da9d 100644 (file)
@@ -1238,7 +1238,7 @@ static DBUObject linkedlist_create_obj(DBUObjectResult *result, DBUClass *type,
 }
 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;
+    DBUClass *cls = result->type;
     CxList **list = (CxList**)(parent+field->offset);
     if(!*list) {
         *list = cxLinkedListCreate(a, CX_STORE_POINTERS);
@@ -1294,13 +1294,14 @@ void dbuClassAddCxLinkedList(DBUClass *cls, const char *name, off_t offset, DBUC
     memset(field, 0, sizeof(DBUOffsetField));
     field->offset = offset;
     field->def.def = 0;
+    field->field.builder.type = foreign_cls;
     field->field.builder.userdata1 = field;
     field->field.builder.userdata2 = foreign_cls;
     field->field.builder.create = linkedlist_create_obj;
     field->field.builder.add = linkedlist_add;
     field->field.toList = cxlist_tolist;
     // TODO: can we pass name to dbuClassAddObjField?
-    dbuClassAddObjField(cls, NULL, (DBUField*)field, foreign_cls);
+    dbuClassAddObjField(cls, name, (DBUField*)field, foreign_cls);
     field->field.name = name ? cx_strdup(cx_str(name)) : (cxmutstr){NULL,0};
     //dbuClassAddParentObjField(foreign_cls, name, cls, (DBUField*)field);
 }
index 52cdc8a53013b89afa8d27da5f73646a89fae7a9..55339b3402e943b6e9a9f2141b059fbb13c570c5 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <stdio.h>
+
 #include "json.h"
 
+/* ---------------- Obj to JSON serialization functions ---------------------*/
+
 CxJsonValue* dbuObjectToJson(DBUClass *type, void *obj, const CxAllocator *a) {
     return dbuObjectToJson2(type, obj, a, false, false);
 }
@@ -123,3 +127,186 @@ CxJsonValue* dbuObjectToJson2(DBUClass *type, void *obj, const CxAllocator *a, b
     
     return value;
 }
+
+
+/* --------------- Json to Obj deserialization functions --------------------*/
+
+static void* jsonToObj(DBUClass *type, const CxAllocator *a, CxJsonValue *value, int depth, int *error) {
+    if(!cxJsonIsObject(value)) {
+        *error = 1;
+        return NULL;
+    }
+    if(depth > DBU_JSON_MAX_DEPTH) {
+        *error = 2;
+        return NULL;
+    }
+    if(!a) {
+        a = cxDefaultAllocator;
+    }
+     
+    void *obj = cxMalloc(a, type->obj_size);
+    if(obj) {
+        memset(obj, 0, type->obj_size);
+    } else {
+        *error = 3;
+        return NULL;
+    }
+    
+    char buf[64];
+    int len = 0;
+    
+    CxMapIterator i = cxMapIterator(value->object);
+    cx_foreach(CxMapEntry *, entry, i) {
+        DBUField *field = cxMapGet(type->fields, entry->key);
+        if(!field) {
+            field = cxMapGet(type->obj_fields, entry->key);
+            if(!field) {
+                continue;
+            }
+        }
+        
+        len = 0;
+        
+        CxJsonValue *child = entry->value;
+        switch(child->type) {
+            case CX_JSON_LITERAL: {
+                if(child->literal == CX_JSON_NULL) {
+                    if(field->initObjValue) {
+                        field->initObjValue(field, a, obj, NULL);
+                    }
+                    break;
+                } else {
+                    int b = child->literal == CX_JSON_TRUE;
+                    if(field->initIntValue) {
+                        field->initIntValue(field, a, obj, b);
+                        continue;
+                    } else {
+                        len = snprintf(buf, 64, "%d", b);
+                    }
+                }
+                break;
+            }
+            case CX_JSON_INTEGER: {
+                if(field->initIntValue) {
+                    field->initIntValue(field, a, obj, child->integer);
+                } else {
+                    len = snprintf(buf, 64, "%" PRId64, child->integer);
+                }
+                break;
+            }
+            case CX_JSON_NUMBER: {
+                if(field->initDoubleValue) {
+                    field->initDoubleValue(field, a, obj, child->number);
+                } else {
+                    len = snprintf(buf, 64, "%f", child->number);
+                }
+                break;
+            }
+            case CX_JSON_STRING: {
+                cxmutstr str = child->string;
+                if(field->initValue(field, a, obj, str.ptr, str.length)) {
+                    *error = 3;
+                    free(obj); // TODO: improve obj cleanup
+                    return NULL;
+                }
+                break;
+            }
+            case CX_JSON_OBJECT: {
+                if(field->objType && field->initObjValue) {
+                    void *child_obj = jsonToObj(field->objType, a, child, depth+1, error);
+                    if(child_obj) {
+                        field->initObjValue(field, a, obj, child_obj);
+                    } else {
+                        free(obj); // TODO: improve obj cleanup
+                        return NULL;
+                    }
+                }
+                break;
+            }
+            case CX_JSON_ARRAY: {
+                if(field->builder.add) {
+                    for(int i=0;i<child->array.size;i++) {
+                        CxJsonValue *elm = child->array.data[i];
+                        void *elm_obj = NULL;
+                        bool add_elm = false;
+                        if(cxJsonIsObject(elm)) {
+                            elm_obj = jsonToObj(field->builder.type, a, elm, depth+1, error);
+                            if(!elm_obj) {
+                                free(obj); // TODO: improve obj cleanup
+                                return NULL;
+                            }
+                            add_elm = true;
+                            
+                        } else if(cxJsonIsLiteral(elm) && elm->literal == CX_JSON_NULL) {
+                            add_elm = true;
+                        }
+                        
+                        if(add_elm) {
+                            if(field->builder.add(&field->builder, obj, field->builder.type, elm_obj, NULL, a)) {
+                                free(obj); // TODO: improve obj cleanup
+                                free(elm_obj);
+                                *error = 3;
+                                return NULL;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+            default: break;
+        }
+        
+        if(len > 0) {
+            if(field->initValue(field, a, obj, buf, len)) {
+                // TODO: completely cleanup obj
+                free(obj);
+                *error = 3;
+                return NULL;
+            }
+        }
+    }
+    
+    *error = 0;
+    return obj;
+}
+
+void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value) {
+    int error;
+    return jsonToObj(type, a, value, 0, &error);
+}
+
+static CxList* jsonToArray(DBUClass *type, const CxAllocator *a, CxJsonValue *value, size_t elmSize, int *error) {
+    if(!cxJsonIsArray(value)) {
+        *error = 1;
+        return NULL;
+    }
+    
+    CxList *list = cxArrayListCreate(a, elmSize, value->array.size);
+    if(!list) {
+        *error = 3;
+    }
+    
+    for(size_t i=0;i<value->array.size;i++) {
+        CxJsonValue *elm = value->array.data[i];
+        void *elm_obj = NULL;
+        if(cxJsonIsObject(elm)) {
+            elm_obj = jsonToObj(type, a, elm, 1, error);
+            if(!elm_obj) {
+                cxListFree(list);
+                return NULL;
+            }
+        }
+        if(cxListAdd(list, elm_obj)) {
+            *error = 3;
+            cxListFree(list);
+            return NULL;
+        }
+    }
+    
+    return list;
+}
+
+CxList* dbuJsonToList(DBUClass *type, const CxAllocator *a, CxJsonValue *value) {
+    int error;
+    return jsonToArray(type, a, value, CX_STORE_POINTERS, &error);
+}
index debdad3ee6c2406dc8e1fb71703720417afc4804..93570c2be55db251e8e3c332d3ecdef5e46ee37b 100644 (file)
@@ -35,7 +35,7 @@
 extern "C" {
 #endif
 
-
+#define DBU_JSON_MAX_DEPTH 512
 
 
 #ifdef __cplusplus
index 6c25e662eef652671b472d3571790113057c45dd..6c3a7ad9f7dc92a5acbcb8fb7e44c5500cba1dbf 100644 (file)
@@ -133,7 +133,8 @@ CxList* dbuObjectBuilderGetValueList(DBUObjectBuilder *builder) {
     }
     // TODO: the class needs a obj destructor func, because we need to be able
     //       to destroy partialy created lists
-    DBUObjectResult result = { 
+    DBUObjectResult result = {
+        .type = builder->resultType,
         .userdata1 = result_list,
         .userdata2 = malloc(builder->resultType->obj_size),
         .int1 = builder->resultType->obj_size,
@@ -241,6 +242,10 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
     DBUClass *cls = type;
     
     // execute sql
+    if(!query) {
+        return 1;
+    }
+    
     if(query->exec(query)) {
         query->free(query);
         return 1;
@@ -269,14 +274,13 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
     // list of all classes returned by the result
     // used when dense == true, to check, if a new result row contains
     // the same objects (primary keys haven't changed)
-    size_t result_types_capacity = 16;
-    size_t result_types_size = 0;
     CX_ARRAY(DBUResultType, result_types);
     cx_array_init(result_types, 16);
     
     DBUResultType mainResult = { .cls = cls };
     cx_array_add(result_types, mainResult);
     
+    // analyse columns: create a column-field mapping
     for(int i=0;i<numcols;i++) {
         cxstring fieldname = cx_str(result->fieldName(result, i));
         DBUField *field = NULL;
@@ -303,12 +307,19 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
                 }
                 if(remaining.length > 2) {
                     field = cxMapGet(fcls->fields, cx_strsubs(remaining, 2));
+                    // make sure the field is a normal field and not an obj/list field
+                    if(!field->initValue) {
+                        field = NULL;
+                    }
                 }
                 field_mapping[i].cls = fcls;
                 field_class = fcls;
             }
         } else {
             field = cxMapGet(field_class->fields, fieldname);
+            if(field && !field->initValue) {
+                field = NULL;
+            }
         }
         
         if(field) {
@@ -342,7 +353,7 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
     CxList *fklist = cxArrayListCreate(NULL, sizeof(DBUFK), 4);
     fklist->collection.simple_destructor = (cx_destructor_func)dbufkelm_free;
       
-     // get result
+    // get result
     int err = 0;
     while(result->hasData(result)) {       
         // create main result obj
@@ -351,12 +362,15 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
         int skip_fields = 0;
         int cls_index = 0;
         if(dense) {
+            // if the primary key in this row is the same as in the previous
+            // row, we don't create a new obj for this row, but reuse the
+            // previous obj ptr.
             cxstring text = result->getText(result, main_pk_index);
             cxmutstr prev_pk = result_types.data[0].prev_key;
-            if(prev_pk.ptr && !cx_strcmp(text, cx_strcast(prev_pk))) {
+            if(prev_pk.ptr && !cx_strcmp(text, prev_pk)) {
                 obj = result_types.data[0].prev_obj;
                 addobj = false;
-                if(1 < result_types_size) {
+                if(1 < result_types.size) {
                     skip_fields = result_types.data[1].pk_col;
                 }
             }
@@ -391,12 +405,12 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
                 
                 if(dense) {
                     // check if this object was already added
-                    if(cls_index < result_types_size) {
+                    if(cls_index < result_types.size) {
                         cxstring text = result->getText(result, result_types.data[cls_index].pk_col);
                         cxmutstr prev_pk = result_types.data[cls_index].prev_key;
                         if(prev_pk.ptr && !cx_strcmp(text, cx_strcast(prev_pk))) {
                             //printf("already added -> skip\n");
-                            if(cls_index+1 < result_types_size) {
+                            if(cls_index+1 < result_types.size) {
                                 i = result_types.data[cls_index+1].pk_col-1; // -1 because i++ by loop
                                 //printf("next col %d\n", i);
                                 continue;
@@ -438,7 +452,7 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
                         //printf("list field\n");
                         
                         DBUField *parent_field = NULL;
-                        for(int c=0;c<result_types_size;c++) {
+                        for(int c=0;c<result_types.size;c++) {
                             DBUResultType parentType = result_types.data[c];
                             DBUField *f = cxMapGet(parentType.cls->obj_fields, field.cls->name);
                             if(f && f->builder.create) {
@@ -514,7 +528,7 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
         cxListClear(fklist);
         
         if(dense) {
-            for(int i=0;i<result_types_size;i++) {
+            for(int i=0;i<result_types.size;i++) {
                 cxstring text = result->getText(result, result_types.data[i].pk_col);
                 free(result_types.data[i].prev_key.ptr);
                 result_types.data[i].prev_key = cx_strdup(text);
@@ -528,7 +542,7 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *
     
     cxListFree(fklist);
     
-    for(int i=0;i<result_types_size;i++) {
+    for(int i=0;i<result_types.size;i++) {
         free(result_types.data[i].prev_key.ptr);
     }
     free(result_types.data);
index ea1716c0170a38ce09a74760e190ac01b3f08ec1..265da9ca29364a9687c8d3f2500917c198cb8319 100644 (file)
@@ -47,7 +47,13 @@ DBUConnection* dbuSQLiteConnection(const char *filename) {
     DBUConnection *conn = dbuSQLiteConnectionFromDB(db, true);
     if(!conn) {
         sqlite3_close(db);
+    } else {
+        if(dbuSqlExec(conn, "PRAGMA foreign_keys = ON;")) {
+            dbuConnectionFree(conn);
+            return NULL;
+        }
     }
+    
     return conn;
 }