dbutils/dbutils/dbutils.h

Thu, 11 Dec 2025 22:58:02 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 11 Dec 2025 22:58:02 +0100
changeset 29
b8c826c720f3
parent 28
e46f9f254fcd
permissions
-rw-r--r--

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 */

mercurial