Thu, 11 Dec 2025 22:58:02 +0100
implement list to json serialization
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2024 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef LIB_DBU_H #define LIB_DBU_H #include <stdbool.h> #include <stdlib.h> #include <inttypes.h> #include <sys/types.h> #include <cx/allocator.h> #include <cx/string.h> #include <cx/list.h> #include <cx/map.h> #ifdef __cplusplus extern "C" { #endif typedef struct DBUContext DBUContext; typedef struct DBUClass DBUClass; typedef struct DBUField DBUField; typedef struct DBUObjectBuilder DBUObjectBuilder; typedef struct DBUForeignKeyField DBUForeignKeyField; typedef char* DBUObject; typedef int(*DBUFieldDefInitFunc)(DBUField *f, const CxAllocator *a, DBUObject obj); typedef int(*DBUFieldInitFunc)(DBUField *f, const CxAllocator *a, DBUObject obj, const char *value, size_t length); typedef bool(*DBUFieldToBoolFunc)(DBUField *f, DBUObject obj); typedef int64_t(*DBUFieldToInt64Func)(DBUField *f, DBUObject obj); typedef uint64_t(*DBUFieldToUInt64Func)(DBUField *f, DBUObject obj); typedef uint64_t(*DBUFieldToUInt64Func)(DBUField *f, DBUObject obj); typedef cxmutstr(*DBUFieldToStringFunc)(DBUField *f, DBUObject obj, const CxAllocator *a); typedef double(*DBUFieldToDoubleFunc)(DBUField *f, DBUObject obj); struct DBUContext { /* * key: class name * value: DBUClass* */ CxMap *classes; }; struct DBUClass { /* * context, that contains this class */ DBUContext *context; /* * class/table name */ cxmutstr name; /* * primary key column name */ cxmutstr primary_key_column; /* * primary key struct member initializer */ DBUField *primary_key; /* * primitive fields * * key: field name * value: DBUField* */ CxMap *fields; /* * object fields * * key: type name * value: DBUField* */ CxMap *obj_fields; /* * foreign keys * * key: field name * value: DBUForeignKeyField */ CxMap *foreign_keys; /* * object size used for allocation, typically sizeof(some_struct) */ size_t obj_size; /* * optional initializer function * */ int (*init)(void *obj, const CxAllocator *a); }; typedef struct DBUObjectResult DBUObjectResult; struct DBUObjectResult { void *userdata1; void *userdata2; int int1; int int2; DBUObject (*create)(DBUObjectResult *result, DBUClass *type, const CxAllocator *a); int (*add)(DBUObjectResult *result, DBUObject parent, DBUClass *type, void *obj, CxList *fk, const CxAllocator *a); void (*free)(DBUObjectResult *result); }; struct DBUForeignKeyField { DBUField *field; DBUClass *cls; }; /* * list abstraction for accessing elements */ typedef struct DBUAbstractList DBUAbstractList; struct DBUAbstractList { /* * List pointer (for example a C array or CxList*) */ void *list; /* * Get the list size */ size_t (*length)(DBUAbstractList *ls); /* * Get the element at the specified index */ void* (*get)(DBUAbstractList *ls, size_t index); /* * Get an DBUField for an list element. The DBUField pointer is only * valid until another elementField call. */ DBUField* (*elementField)(DBUAbstractList *ls, void *elm); /* * Optional function for getting an list iterator */ CxIterator (*iterator)(DBUAbstractList *ls); /* * Free the DBUAbstractList abstraction layer. The actual list is * not freed. */ void (*free)(DBUAbstractList *ls); }; /* * abstract field */ struct DBUField { /* * field name */ cxmutstr name; /* * field object type */ DBUClass *objType; /* * called, if the field is null (optional) */ int (*initDefaultValue)(DBUField *f, const CxAllocator *a, DBUObject obj); /* * called, if a field was not requested in a query (optional) */ int (*initExcluded)(DBUField *f, const CxAllocator *a, DBUObject obj); /* * init primitve type (required) * * This must be implemented */ int (*initValue)(DBUField *f, const CxAllocator *a, DBUObject obj, const char *value, size_t length); /* * integer initialization function (optional) * * if a result columns contains an integer and this pointer is * non-null, this function is called */ int (*initIntValue)(DBUField *f, const CxAllocator *a, DBUObject obj, int64_t value); /* * double initialization function (optional) */ int (*initDoubleValue)(DBUField *f, const CxAllocator *a, DBUObject obj, double value); /* * set/add an child to obj */ int (*initObjValue)(DBUField *f, const CxAllocator *a, DBUObject obj, void *child); /* * get the field value as a boolean * * This should only be implemented, if the field is a boolean */ bool (*toBool)(DBUField *f, DBUObject obj); /* * get the field value as an int64 (optional) * * This should only be implemented, if the field is a signed integer */ int64_t (*toInt64)(DBUField *f, DBUObject obj); /* * get the field value as an int64 (optional) * * This should only be implemented, if the field is a unsigned integer */ uint64_t (*toUInt64)(DBUField *f, DBUObject obj); /* * get the field value as a string(optional) * * This should only be implemented, if the field is represented as a string */ cxmutstr (*toString)(DBUField *f, DBUObject obj, const CxAllocator *a); /* * get the field value as a binary (optional) * * This should only be implemented, if the field contains binary data */ cxmutstr (*toBinary)(DBUField *f, DBUObject obj, const CxAllocator *a); /* * get the field value as double (optional) * * This should only be implemented, if the field is a float/double */ double (*toDouble)(DBUField *f, DBUObject obj); /* * get the field value as object (optional) * * This should only be implemented, if the field has a compley type * and objType is set. */ DBUObject (*toObject)(DBUField *f, DBUObject obj); /* * get the field value as a list/iterator (optional) * * This should only be implemented, if the field is a list. */ DBUAbstractList* (*toList)(DBUField *f, DBUObject obj); /* * destructor (optional) * * this callback must not free the DBUField* ptr */ void (*destructor)(DBUField *f); /* * object result builder callback struct (optional for list/array types) * * DBUObjectResult contains callback for adding objects to * list/array-fields */ DBUObjectResult builder; DBUClass *foreignKeyClass; /* * if true, null values are not accepted and result in an error */ bool nonnull; bool query_length; // TODO: remove }; DBUContext* dbuContextCreate(void); void dbuContextFree(DBUContext *context); void dbuContextAddClass(DBUContext *context, DBUClass *cls); /* * incomplete constructor for a DBUClass * * To complete the class definition, either obj_size or constructor must be set. */ DBUClass* dbuClassCreate(const char *name); #define dbuRegisterClass(context, name, type, primarykey) \ dbuRegisterClassWithPKName(context, name, type, primarykey, #primarykey) #define dbuRegisterClassWithPKName(context, name, type, primarykey, column) \ _Generic(((type*)0)->primarykey, \ int32_t: dbuRegisterClassWithPrimaryKeyInt32, \ uint32_t: dbuRegisterClassWithPrimaryKeyUInt32, \ int64_t: dbuRegisterClassWithPrimaryKeyInt64, \ uint64_t: dbuRegisterClassWithPrimaryKeyUInt64, \ char*: dbuRegisterClassWithPrimaryKeyString, \ cxmutstr: dbuRegisterClassWithPrimaryKeyCxMutStr) \ (context, name, sizeof(type), column, offsetof(type, primarykey)) DBUClass* dbuRegisterClassWithPrimaryKeyInt32( DBUContext *context, const char *name, size_t obj_size, const char *primary_key_column, off_t primary_key_offset); DBUClass* dbuRegisterClassWithPrimaryKeyUInt32( DBUContext *context, const char *name, size_t obj_size, const char *primary_key_column, off_t primary_key_offset); DBUClass* dbuRegisterClassWithPrimaryKeyInt64( DBUContext *context, const char *name, size_t obj_size, const char *primary_key_column, off_t primary_key_offset); DBUClass* dbuRegisterClassWithPrimaryKeyUInt64( DBUContext *context, const char *name, size_t obj_size, const char *primary_key_column, off_t primary_key_offset); DBUClass* dbuRegisterClassWithPrimaryKeyString( DBUContext *context, const char *name, size_t obj_size, const char *primary_key_column, off_t primary_key_offset); DBUClass* dbuRegisterClassWithPrimaryKeyCxMutStr( DBUContext *context, const char *name, size_t obj_size, const char *primary_key_column, off_t primary_key_offset); DBUClass* dbuRegisterClassWithoutPK( DBUContext *context, const char *name, size_t obj_size); void dbuClassSetPrimaryKeyInt32(DBUClass *cls, const char *column_name, off_t offset); void dbuClassSetPrimaryKeyUInt32(DBUClass *cls, const char *column_name, off_t offset); void dbuClassSetPrimaryKeyInt64(DBUClass *cls, const char *column_name, off_t offset); void dbuClassSetPrimaryKeyUInt64(DBUClass *cls, const char *column_name, off_t offset); void dbuClassSetPrimaryKeyString(DBUClass *cls, const char *column_name, off_t offset); void dbuClassSetPrimaryKeyCxMutStr(DBUClass *cls, const char *column_name, off_t offset); void dbuClassAddField(DBUClass *cls, const char *name, DBUField *field); void dbuClassAddFKField(DBUClass *cls, const char *name, DBUField *field, DBUClass *fkcls); void dbuClassAddObjField(DBUClass *cls, const char *name, DBUField *field, DBUClass *foreign_cls); #define dbuClassAdd(cls, type, member) \ dbuClassAddWithName(cls, type, member, #member) #define dbuClassAddWithName(cls, type, member, member_name) \ _Generic(((type*)0)->member, \ int8_t: dbuClassAddInt8, \ uint8_t: dbuClassAddUInt8, \ int16_t: dbuClassAddInt16, \ uint16_t: dbuClassAddUInt16, \ int32_t: dbuClassAddInt32, \ uint32_t: dbuClassAddUInt32, \ int64_t: dbuClassAddInt64, \ uint64_t: dbuClassAddUInt64, \ bool: dbuClassAddBool, \ float: dbuClassAddFloat, \ double: dbuClassAddDouble, \ char*: dbuClassAddString, \ cxmutstr: dbuClassAddCXMutStr) \ (cls, member_name, offsetof(type, member), 0) #define dbuClassAddForeignKey(cls, type, member, foreigncls) \ _Generic(((type*)0)->member, \ int32_t: dbuClassAddInt32FK, \ uint32_t: dbuClassAddUInt32FK, \ int64_t: dbuClassAddInt64FK, \ uint64_t: dbuClassAddUInt64FK, \ char*: dbuClassAddStringFK, \ cxmutstr: dbuClassAddCXMutStrFK) \ (cls, #member, offsetof(type, member), foreigncls, 0) void dbuClassAddInt(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddUInt(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddInt8(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddUInt8(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddInt16(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddUInt16(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddInt32(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddUInt32(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddInt64(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddUInt64(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddSize(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddSSize(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddBool(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddFloat(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddDouble(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddString(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddCXMutStr(DBUClass *cls, const char *name, off_t offset, bool nonnull); void dbuClassAddStringSize(DBUClass *cls, const char *name, off_t offset, off_t size_offset, bool nonnull); void dbuClassAddStringIntLen(DBUClass *cls, const char *name, off_t offset, off_t int_offset, bool nonnull); void dbuClassAddBuf(DBUClass *cls, const char *name, off_t offset, off_t size_offset, bool nonnull); void dbuClassAddBufIntLen(DBUClass *cls, const char *name, off_t offset, off_t int_offset, bool nonnull); void dbuClassAddInt32FK(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls, bool nonnull); void dbuClassAddUInt32FK(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls, bool nonnull); void dbuClassAddInt64FK(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls, bool nonnull); void dbuClassAddUInt64FK(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls, bool nonnull); void dbuClassAddStringFK(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls, bool nonnull); void dbuClassAddCXMutStrFK(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls, bool nonnull); void dbuClassAddIntDef(DBUClass *cls, const char *name, off_t offset, int def); void dbuClassAddUIntDef(DBUClass *cls, const char *name, off_t offset, unsigned int def); void dbuClassAddInt16Def(DBUClass *cls, const char *name, off_t offset, int16_t def); void dbuClassAddUInt16Def(DBUClass *cls, const char *name, off_t offset, uint16_t def); void dbuClassAddInt32Def(DBUClass *cls, const char *name, off_t offset, int32_t def); void dbuClassAddUInt32Def(DBUClass *cls, const char *name, off_t offset, uint32_t def); void dbuClassAddInt64Def(DBUClass *cls, const char *name, off_t offset, int64_t def); void dbuClassAddUInt64Def(DBUClass *cls, const char *name, off_t offset, uint64_t def); void dbuClassAddSizeDef(DBUClass *cls, const char *name, off_t offset, size_t def); void dbuClassAddSSizeDef(DBUClass *cls, const char *name, off_t offset, ssize_t def); void dbuClassAddFloatDef(DBUClass *cls, const char *name, off_t offset, float def); void dbuClassAddDoubleDef(DBUClass *cls, const char *name, off_t offset, double def); void dbuClassAddObj(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls); void dbuClassAddCxLinkedList(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls); void dbuClassAddValueCxLinkedList(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls); void dbuClassAddCxArrayList(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_clst); void dbuClassAddValueCxArrayList(DBUClass *cls, const char *name, off_t offset, DBUClass *foreign_cls); void dbuClassAddArray(DBUClass *cls, const char *name, off_t array_offset, off_t size_offset, DBUClass *foreign_cls); void dbuClassAddValueArray(DBUClass *cls, const char *name, off_t array_offset, off_t size_offset, DBUClass *foreign_cls); #ifdef __cplusplus } #endif #endif /* LIB_DBU_H */