diff --git a/Application/ApplicationAbstract.h b/Application/ApplicationAbstract.h new file mode 100644 index 0000000..99de669 --- /dev/null +++ b/Application/ApplicationAbstract.h @@ -0,0 +1,29 @@ +/** + * Karaka + * + * @package Utils + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef APPLICATION_ABSTRACT_H +#define APPLICATION_ABSTRACT_H + +#include +#include + +#include "../DataStorage/Database/Connection/ConnectionAbstract.h" +#include "../Utils/Parser/Json.h" +#include "../Threads/Thread.h" + +namespace Application +{ + typedef struct { + DataStorage::Database::ConnectionAbstract *db; + nlohmann::json config; + Threads::ThreadPool *pool; + } ApplicationAbstract; +} + +#endif diff --git a/DataStorage/Database/Connection/ConnectionAbstract.h b/DataStorage/Database/Connection/ConnectionAbstract.h index 366ef13..cac4e23 100755 --- a/DataStorage/Database/Connection/ConnectionAbstract.h +++ b/DataStorage/Database/Connection/ConnectionAbstract.h @@ -21,6 +21,12 @@ namespace DataStorage { namespace Database { + typedef struct { + size_t rows = 0; + size_t columns = 0; + char **results = NULL; + } QueryResult; + struct ConnectionAbstract { void *con = NULL; @@ -44,6 +50,11 @@ namespace DataStorage this->con = NULL; this->status = DatabaseStatus::CLOSED; } + + virtual QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + return QueryResult(); + } }; } } diff --git a/DataStorage/Database/Connection/MysqlConnection.h b/DataStorage/Database/Connection/MysqlConnection.h index ab29eff..95c92bc 100755 --- a/DataStorage/Database/Connection/MysqlConnection.h +++ b/DataStorage/Database/Connection/MysqlConnection.h @@ -85,6 +85,64 @@ namespace DataStorage this->con = NULL; this->status = DatabaseStatus::CLOSED; } + + QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + QueryResult result; + + MYSQL_RES *res; + int status = 0; + + if (paramValues != NULL) { + return result; + } else { + status = mysql_query((::MYSQL *) this->con, stmt); + res = mysql_store_result((::MYSQL *) this->con); + } + + if (res == NULL) { + return result; + } + + result.rows = mysql_num_rows(res); + result.columns = mysql_num_fields(res); + + if (result.rows == 0 || result.columns == 0) { + return result; + } + + result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); + + char *temp = NULL; + size_t valLen = 0; + size_t *lengths; + + ::MYSQL_ROW row; + size_t i = 0; + + while ((row = mysql_fetch_row(res)) != NULL) { + lengths = mysql_fetch_lengths(res); + for (int j = 0; j < result.columns; ++j) { + temp = row[j]; + + if (temp == NULL) { + result.results[i * result.columns + j] = NULL; + + continue; + } + + valLen = lengths[j]; + + result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); + memcpy(result.results[i * result.columns + j], temp, valLen); + result.results[i * result.columns + j][valLen] = '\0'; + } + + ++i; + } + + return result; + } }; } } diff --git a/DataStorage/Database/Connection/PostgresqlConnection.h b/DataStorage/Database/Connection/PostgresqlConnection.h index 27eb542..83cbd1e 100755 --- a/DataStorage/Database/Connection/PostgresqlConnection.h +++ b/DataStorage/Database/Connection/PostgresqlConnection.h @@ -89,6 +89,54 @@ namespace DataStorage this->con = NULL; this->status = DatabaseStatus::CLOSED; } + + QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + QueryResult result; + + PGresult *res; + if (paramValues != NULL) { + res = PQexecParams((PGconn *) this->con, stmt, 1, NULL, (const char* const*) paramValues, NULL, NULL, 0); + } else { + res = PQexec((PGconn *) this->con, stmt); + } + + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + PQclear(res); + + return result; + } + + result.rows = PQntuples(res); + result.columns = PQnfields(res); + + result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); + + char *temp = NULL; + size_t valLen = 0; + + for (size_t i = 0; i < result.rows; ++i) { + for (size_t j = 0; j < result.columns; ++j) { + temp = PQgetvalue(res, i, j); + + if (temp == NULL) { + result.results[i * result.columns + j] = NULL; + + continue; + } + + valLen = strlen(temp); + + result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); + memcpy(result.results[i * result.columns + j], temp, valLen); + result.results[i * result.columns + j][valLen] = '\0'; + } + } + + PQclear(res); + + return result; + } }; } } diff --git a/DataStorage/Database/Connection/SQLiteConnection.h b/DataStorage/Database/Connection/SQLiteConnection.h index edc9f76..a549800 100755 --- a/DataStorage/Database/Connection/SQLiteConnection.h +++ b/DataStorage/Database/Connection/SQLiteConnection.h @@ -71,6 +71,89 @@ namespace DataStorage this->con = NULL; this->status = DatabaseStatus::CLOSED; } + + QueryResult query_execute(char *stmt, char *paramValues = NULL) + { + QueryResult result; + + sqlite3_stmt *res; + int status = 0; + + if (paramValues != NULL) { + status = sqlite3_prepare_v2((sqlite3 *) this->con, stmt, -1, &res, 0); + + // @todo: sqlite3_bind_int(res, 1, 3); + } else { + status = sqlite3_prepare_v2((sqlite3 *) this->con, stmt, -1, &res, 0); + } + + if (res == NULL) { + return result; + } + + status = sqlite3_step(res); + + result.rows = 100; + result.columns = sqlite3_column_count(res); + + if (result.rows == 0 || result.columns == 0) { + return result; + } + + result.results = (char **) malloc(result.rows * result.columns * sizeof(char*)); + + char *temp = NULL; + size_t valLen = 0; + char ** tempStorage = NULL; + + size_t i = 0; + while (status == SQLITE_ROW) { + if (i == result.rows) { + tempStorage = (char **) malloc((result.rows + 100) * result.columns * sizeof(char*)); + memcpy(tempStorage, result.results, result.rows * result.columns * sizeof(char*)); + + free(result.results); + result.results = tempStorage; + + result.rows += 100; + } + + for (int j = 0; j < result.columns; ++j) { + temp = (char *) sqlite3_column_text(res, j); + + if (temp == NULL) { + result.results[i * result.columns + j] = NULL; + + continue; + } + + valLen = strlen(temp); + + result.results[i * result.columns + j] = (char *) malloc((valLen + 1) * sizeof(char)); + memcpy(result.results[i * result.columns + j], temp, valLen); + result.results[i * result.columns + j][valLen] = '\0'; + } + + status = sqlite3_step(res); + + ++i; + } + + --i; + if (i != result.rows) { + tempStorage = (char **) malloc(i * result.columns * sizeof(char*)); + memcpy(tempStorage, result.results, i * result.columns * sizeof(char*)); + + free(result.results); + result.results = tempStorage; + + result.rows = i; + } + + sqlite3_finalize(res); + + return result; + } }; } } diff --git a/DataStorage/Database/Mapper/DataMapperFactory.h b/DataStorage/Database/Mapper/DataMapperFactory.h new file mode 100644 index 0000000..de7adb1 --- /dev/null +++ b/DataStorage/Database/Mapper/DataMapperFactory.h @@ -0,0 +1,59 @@ +/** + * Karaka + * + * @package Models + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef DATASTORAGE_DATBASE_MAPPER_FACTORY_H +#define DATASTORAGE_DATBASE_MAPPER_FACTORY_H + +#include +#include +#include + +#include "../Connection/ConnectionAbstract.h" +#include "ReadMapper.h" +#include "MapperAbstract.h" + +namespace DataStorage +{ + namespace Database + { + static DataStorage::Database::ConnectionAbstract *db; + static const char *dateTimeFormat = "Y-m-d H:i:s"; + + struct DataMapperFactory { + static ReadMapper *reader(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) + { + ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); + readMapper->mapper = mapper; + readMapper->db = db == NULL ? DataStorage::Database::db : db; + + return readMapper; + } + + static ReadMapper *get(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) + { + ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); + readMapper->mapper = mapper; + readMapper->db = db == NULL ? DataStorage::Database::db : db; + + return readMapper->get(); + } + + static ReadMapper *getAll(const DataStorage::Database::MapperData *mapper, DataStorage::Database::ConnectionAbstract *db = NULL) + { + ReadMapper *readMapper = (ReadMapper *) malloc(sizeof(ReadMapper)); + readMapper->mapper = mapper; + readMapper->db = db == NULL ? DataStorage::Database::db : db; + + return readMapper->getAll(); + } + }; + } +} + +#endif diff --git a/DataStorage/Database/Mapper/DataMapperTypes.h b/DataStorage/Database/Mapper/DataMapperTypes.h new file mode 100644 index 0000000..1643112 --- /dev/null +++ b/DataStorage/Database/Mapper/DataMapperTypes.h @@ -0,0 +1,222 @@ +/** + * Karaka + * + * @package Models + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef DATASTORAGE_DATBASE_MAPPER_TYPES_H +#define DATASTORAGE_DATBASE_MAPPER_TYPES_H + +#include +#include + +namespace DataStorage +{ + namespace Database + { + typedef enum { + MAPPER_DEFAULT = 0, + MAPPER_GET = 1, + MAPPER_GET_ALL = 4, + MAPPER_FIND = 7, + MAPPER_GET_RAW = 8, + MAPPER_GET_RANDOM = 11, + MAPPER_COUNT_MODELS = 12, + MAPPER_CREATE = 1001, + MAPPER_UPDATE = 2001, + MAPPER_DELETE = 3001 + } MapperType; + + typedef enum { + FIELD_TYPE_INT = 1, + FIELD_TYPE_FLOAT = 2, + FIELD_TYPE_STRING = 3, + FIELD_TYPE_BOOL = 4 + } FieldType; + + typedef struct { + const char *name = NULL; + size_t size = 0; + } ModelStructure; + + void free_ModelStructure(ModelStructure *data) + { + /* Not necessary + if (data->name != NULL) { + free((void *) data->name); + } + */ + } + + typedef struct { + const char *name = NULL; + int type = FieldType::FIELD_TYPE_INT; + const char *internal = NULL; + bool readonly = false; + bool autocomplete = false; + } DataMapperColumn; + + void free_DataMapperColumn(DataMapperColumn *data) + { + if (data->name != NULL) { + free((void *) data->name); + } + + if (data->internal != NULL) { + free((void *) data->internal); + } + } + + typedef struct { + const char *member = NULL; + const char *mapper = NULL; + const char *external = NULL; + const char *table = NULL; + const char *self = NULL; + const char *column = NULL; + bool conditional = false; + const char *by = NULL; + } TableRelation; + + void free_TableRelation(TableRelation *data) + { + /* Not necessary + if (data->member != NULL) { + free((void *) data->member); + } + + if (data->mapper != NULL) { + free((void *) data->mapper); + } + + if (data->external != NULL) { + free((void *) data->external); + } + + if (data->table != NULL) { + free((void *) data->table); + } + + if (data->self != NULL) { + free((void *) data->self); + } + + if (data->column != NULL) { + free((void *) data->column); + } + + if (data->self != NULL) { + free((void *) data->self); + } + + if (data->by != NULL) { + free((void *) data->by); + } + */ + } + + typedef struct { + const char *TABLE = NULL; + const char *PRIMARYFIELD = NULL; + const char *CREATED_AT = NULL; + const char *PARENT = NULL; + void *MODEL = NULL; + + int MEMBER_COUNT = 0; + DataStorage::Database::ModelStructure *MODEL_STRUCTURE = NULL; + + int COLUMN_COUNT = 0; + DataStorage::Database::DataMapperColumn *COLUMNS = NULL; + + int OWNS_ONE_COUNT = 0; + DataStorage::Database::TableRelation *OWNS_ONE = NULL; + + int HAS_MANY_COUNT = 0; + DataStorage::Database::TableRelation *HAS_MANY = NULL; + + int BELONGS_TO_COUNT = 0; + DataStorage::Database::TableRelation *BELONGS_TO = NULL; + } MapperData; + + void free_MapperData(DataStorage::Database::MapperData *data) + { + /* Not necessary + if (data->TABLE != NULL) { + free((void *) data->TABLE); + } + + if (data->PRIMARYFIELD != NULL) { + free((void *) data->PRIMARYFIELD); + } + + if (data->CREATED_AT != NULL) { + free((void *) data->CREATED_AT); + } + + if (data->PARENT != NULL) { + free((void *) data->PARENT); + } + + if (data->MODEL != NULL) { + free(data->MODEL); + } + */ + + int i = 0; + if (data->MODEL_STRUCTURE != NULL) { + /* not neccessary + for (i = 0; i < data->MEMBER_COUNT; ++i) { + free_ModelStructure(&data->MODEL_STRUCTURE[i]); + } + */ + + free(data->MODEL_STRUCTURE); + } + + if (data->COLUMNS != NULL) { + /* not neccessary + for (i = 0; i < data->COLUMN_COUNT; ++i) { + free_DataMapperColumn(&data->COLUMNS[i]); + } + */ + + free(data->COLUMNS); + } + + if (data->OWNS_ONE != NULL) { + /* not neccessary + for (i = 0; i < data->OWNS_ONE_COUNT; ++i) { + free_TableRelation(&data->OWNS_ONE[i]); + } + */ + + free(data->OWNS_ONE); + } + + if (data->HAS_MANY != NULL) { + /* not neccessary + for (i = 0; i < data->HAS_MANY_COUNT; ++i) { + free_TableRelation(&data->HAS_MANY[i]); + } + */ + + free(data->HAS_MANY); + } + + if (data->BELONGS_TO != NULL) { + /* not neccessary + for (i = 0; i < data->BELONGS_TO_COUNT; ++i) { + free_TableRelation(&data->BELONGS_TO[i]); + } + */ + + free(data->BELONGS_TO); + } + } + } +} + +#endif diff --git a/DataStorage/Database/Mapper/MapperAbstract.h b/DataStorage/Database/Mapper/MapperAbstract.h new file mode 100644 index 0000000..443995c --- /dev/null +++ b/DataStorage/Database/Mapper/MapperAbstract.h @@ -0,0 +1,107 @@ +/** + * Karaka + * + * @package Models + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef DATASTORAGE_DATBASE_MAPPER_ABSTRACT_H +#define DATASTORAGE_DATBASE_MAPPER_ABSTRACT_H + +#include +#include + +#include "../Connection/ConnectionAbstract.h" +#include "DataMapperTypes.h" + +namespace DataStorage +{ + namespace Database + { + struct MapperAbstract { + const DataStorage::Database::MapperData *mapper = NULL; + + const DataStorage::Database::ConnectionAbstract *db = NULL; + + DataStorage::Database::MapperType type = DataStorage::Database::MapperType::MAPPER_DEFAULT; + + int MEMBERS = 0; + + int COLUMN_COUNT = 0; + + DataStorage::Database::ModelStructure *MODEL_STRUCTURE = NULL; + + char *PRIMARYFIELD = NULL; + + bool AUTOINCREMENT = true; + + char *CREATE_AT = NULL; + + char *TABLE = NULL; + + char *PARENT = NULL; + + char *MODEL = NULL; + + DataStorage::Database::DataMapperColumn *COLUMNS = NULL; + + DataStorage::Database::TableRelation *HAS_MANY = NULL; + + DataStorage::Database::TableRelation *OWNS_ONE = NULL; + + DataStorage::Database::TableRelation *BELONGS_TO = NULL; + + void *address(uintptr_t objPos, char *name) + { + uintptr_t pos = objPos; + for (int i = 0; i < this->MEMBERS; ++i) { + if (strcmp(this->MODEL_STRUCTURE[i].name, name) == 0) { + return (void *) pos; + } + + pos += this->MODEL_STRUCTURE[i].size; + } + + return NULL; + } + + DataMapperColumn *findByColumnName(char *column) + { + for (int i = 0; i < this->COLUMN_COUNT; ++i) { + if (strcmp(this->COLUMNS[i].name, column) == 0) { + return &this->COLUMNS[i]; + } + } + + return NULL; + } + + DataMapperColumn *findByMemberName(char *member) + { + for (int i = 0; i < this->COLUMN_COUNT; ++i) { + if (strcmp(this->COLUMNS[i].internal, member) == 0) { + return &this->COLUMNS[i]; + } + } + + return NULL; + } + + MapperAbstract *where( + char *member, + void *value, + int valueType, + const char *logic = "=", + const char *connector = "AND" + ) { + return this; + } + + virtual void *execute(void *options = NULL); + }; + } +} + +#endif diff --git a/DataStorage/Database/Mapper/ReadMapper.h b/DataStorage/Database/Mapper/ReadMapper.h new file mode 100644 index 0000000..cf68a09 --- /dev/null +++ b/DataStorage/Database/Mapper/ReadMapper.h @@ -0,0 +1,70 @@ +/** + * Karaka + * + * @package Models + * @copyright Dennis Eichhorn + * @license OMS License 1.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef DATASTORAGE_DATBASE_MAPPER_READ_H +#define DATASTORAGE_DATBASE_MAPPER_READ_H + +#include +#include + +#include "../Connection/ConnectionAbstract.h" +#include "DataMapperFactory.h" +#include "MapperAbstract.h" + +namespace DataStorage +{ + namespace Database + { + struct ReadMapper : MapperAbstract { + ReadMapper *get() + { + return this; + } + + ReadMapper *getAll() + { + return this; + } + + void *execute(void *options = NULL) + { + switch(this->type) { + case DataStorage::Database::MapperType::MAPPER_GET: + return this->executeGet(options); + case DataStorage::Database::MapperType::MAPPER_GET_RAW: + return this->executeGetRaw(options); + case DataStorage::Database::MapperType::MAPPER_GET_ALL: + return this->executeGetAll(options); + default: + return NULL; + }; + } + + void *executeGet(void *options) + { + int *primaryKeys = NULL; + const char *memberOfPrimaryField = findByColumnName((char *) this->mapper->PRIMARYFIELD)->internal; + + return NULL; + } + + void *executeGetRaw(void *options) + { + return NULL; + } + + void *executeGetAll(void *options) + { + return NULL; + } + }; + } +} + +#endif diff --git a/Utils/Parser/Json.h b/Utils/Parser/Json.h index c43fdbb..2448bf2 100755 --- a/Utils/Parser/Json.h +++ b/Utils/Parser/Json.h @@ -6,30 +6,6 @@ // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann // SPDX-License-Identifier: MIT -/* -MIT License - -Copyright (c) 2013-2022 Niels Lohmann - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - /****************************************************************************\ * Note on documentation: The source files contain links to the online * * documentation of the public API at https://json.nlohmann.me. This URL * @@ -64,6 +40,8 @@ SOFTWARE. // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann // SPDX-License-Identifier: MIT + + #include // #include @@ -2793,8 +2771,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP // it allows using the detected idiom to retrieve the return type // of such an expression #define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ - namespace detail - { \ + namespace detail { \ using std::std_name; \ \ template \ @@ -4192,28 +4169,28 @@ inline std::size_t concat_length() } template -inline std::size_t concat_length(const char* cstr, Args&& ... rest); +inline std::size_t concat_length(const char* cstr, const Args& ... rest); template -inline std::size_t concat_length(const StringType& str, Args&& ... rest); +inline std::size_t concat_length(const StringType& str, const Args& ... rest); template -inline std::size_t concat_length(const char /*c*/, Args&& ... rest) +inline std::size_t concat_length(const char /*c*/, const Args& ... rest) { - return 1 + concat_length(std::forward(rest)...); + return 1 + concat_length(rest...); } template -inline std::size_t concat_length(const char* cstr, Args&& ... rest) +inline std::size_t concat_length(const char* cstr, const Args& ... rest) { // cppcheck-suppress ignoredReturnValue - return ::strlen(cstr) + concat_length(std::forward(rest)...); + return ::strlen(cstr) + concat_length(rest...); } template -inline std::size_t concat_length(const StringType& str, Args&& ... rest) +inline std::size_t concat_length(const StringType& str, const Args& ... rest) { - return str.size() + concat_length(std::forward(rest)...); + return str.size() + concat_length(rest...); } template @@ -4304,7 +4281,7 @@ template inline OutStringType concat(Args && ... args) { OutStringType str; - str.reserve(concat_length(std::forward(args)...)); + str.reserve(concat_length(args...)); concat_into(str, std::forward(args)...); return str; } @@ -11254,7 +11231,7 @@ class binary_reader } if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimentional vector is not allowed", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr)); } std::vector dim; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) @@ -18872,7 +18849,7 @@ class serializer : (0xFFu >> type) & (byte); const std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); - JSON_ASSERT(index < 400); + JSON_ASSERT(index < utf8d.size()); state = utf8d[index]; return state; } diff --git a/Utils/StringUtils.h b/Utils/StringUtils.h index 6b44618..11d2e0b 100755 --- a/Utils/StringUtils.h +++ b/Utils/StringUtils.h @@ -125,7 +125,7 @@ namespace Utils char *token; int i = 0; - while ((token = strsep(&str, &delim)) != NULL) { + while ((token = strsep(&str, (char *) &delim)) != NULL) { list[i] = (char *) malloc(strlen(token + 1) * sizeof(char)); memcpy(list[i], token, (strlen(token) + 1) * sizeof(char));