Sun, 04 Jan 2026 18:09:59 +0100
implement deserialization of json objects that contain arrays
| 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/json.c | file | annotate | diff | comparison | revisions | |
| dbutils/object.c | file | annotate | diff | comparison | revisions | |
| test/json.c | file | annotate | diff | comparison | revisions | |
| test/json.h | file | annotate | diff | comparison | revisions | |
| test/main.c | file | annotate | diff | comparison | revisions |
--- a/dbutils/class.c Sun Jan 04 17:45:50 2026 +0100 +++ b/dbutils/class.c Sun Jan 04 18:09:59 2026 +0100 @@ -81,6 +81,7 @@ 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); }
--- a/dbutils/dbutils/dbutils.h Sun Jan 04 17:45:50 2026 +0100 +++ b/dbutils/dbutils/dbutils.h Sun Jan 04 18:09:59 2026 +0100 @@ -130,6 +130,7 @@ struct DBUObjectResult { void *userdata1; void *userdata2; + DBUClass *type; int int1; int int2; DBUObject (*create)(DBUObjectResult *result, DBUClass *type, const CxAllocator *a);
--- a/dbutils/field.c Sun Jan 04 17:45:50 2026 +0100 +++ b/dbutils/field.c Sun Jan 04 18:09:59 2026 +0100 @@ -1238,7 +1238,7 @@ } 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 @@ 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); }
--- a/dbutils/json.c Sun Jan 04 17:45:50 2026 +0100 +++ b/dbutils/json.c Sun Jan 04 18:09:59 2026 +0100 @@ -220,15 +220,27 @@ free(obj); // TODO: improve obj cleanup return NULL; } - } else { - *error = 4; - free(obj); // TODO: improve obj cleanup - return NULL; } break; } case CX_JSON_ARRAY: { - // TODO + if(field->builder.add) { + for(int i=0;i<child->array.size;i++) { + CxJsonValue *elm = child->array.data[i]; + if(cxJsonIsObject(elm)) { + void *elm_obj = jsonToObj(field->builder.type, a, elm, depth+1, error); + if(!elm_obj) { + free(obj); // TODO: improve obj cleanup + return NULL; + } + if(field->builder.add(&field->builder, obj, field->builder.type, elm_obj, NULL, a)) { + free(obj); // TODO: improve obj cleanup + *error = 3; + return NULL; + } + } + } + } break; } default: break;
--- a/dbutils/object.c Sun Jan 04 17:45:50 2026 +0100 +++ b/dbutils/object.c Sun Jan 04 18:09:59 2026 +0100 @@ -133,7 +133,8 @@ } // 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, @@ -306,12 +307,19 @@ } 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) {
--- a/test/json.c Sun Jan 04 17:45:50 2026 +0100 +++ b/test/json.c Sun Jan 04 18:09:59 2026 +0100 @@ -381,3 +381,37 @@ free(obj); } } + +CX_TEST(testJsonToObjectWithArray) { + const char *jsonStr = + "{" + "\"test\":\"hello world\"," + "\"test2List\":[ {\"name\":\"elm0\", \"i\":0}, {\"name\":\"elm1\", \"i\":1} ]" + "}"; + + CxJsonValue *json; + cxJsonFromString(NULL, jsonStr, &json); + + CX_TEST_DO { + Test5 *obj = dbuJsonToObject(test5_class, NULL, json); + + CX_TEST_ASSERT(obj); + CX_TEST_ASSERT(!cx_strcmp(obj->test, "hello world")); + CX_TEST_ASSERT(obj->test2List); + CX_TEST_ASSERT(cxListSize(obj->test2List) == 2); + + Test2 *elm0 = cxListAt(obj->test2List, 0); + Test2 *elm1 = cxListAt(obj->test2List, 1); + + CX_TEST_ASSERT(elm0); + CX_TEST_ASSERT(elm1); + + CX_TEST_ASSERT(!cx_strcmp(elm0->name, "elm0")); + CX_TEST_ASSERT(elm0->i == 0); + + CX_TEST_ASSERT(!cx_strcmp(elm1->name, "elm1")); + CX_TEST_ASSERT(elm1->i == 1); + + free(obj); + } +}
--- a/test/json.h Sun Jan 04 17:45:50 2026 +0100 +++ b/test/json.h Sun Jan 04 18:09:59 2026 +0100 @@ -46,6 +46,7 @@ CX_TEST(testJsonToSimpleObject); CX_TEST(testJsonToObjectWithObjChild); +CX_TEST(testJsonToObjectWithArray); #ifdef __cplusplus
--- a/test/main.c Sun Jan 04 17:45:50 2026 +0100 +++ b/test/main.c Sun Jan 04 18:09:59 2026 +0100 @@ -146,6 +146,7 @@ cx_test_register(suite, testObjectToJsonChildList); cx_test_register(suite, testJsonToSimpleObject); cx_test_register(suite, testJsonToObjectWithObjChild); + cx_test_register(suite, testJsonToObjectWithArray); cx_test_run_stdout(suite);