From 9e96151a42b10e8c123eb69645b818bfd6d459e4 Mon Sep 17 00:00:00 2001 From: chris bell Date: Wed, 5 Aug 2026 22:38:13 -0500 Subject: [PATCH] getting more database stuff hooked up --- assets/main.rml | 15 +++++-- src/critter.hpp | 12 ++++++ src/database.hpp | 104 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 83 ++++++++++++++++--------------------- 4 files changed, 163 insertions(+), 51 deletions(-) create mode 100644 src/database.hpp diff --git a/assets/main.rml b/assets/main.rml index f976d9d..26742e9 100644 --- a/assets/main.rml +++ b/assets/main.rml @@ -1,5 +1,4 @@ - Critterfolio @@ -7,7 +6,15 @@

{{page_title}}

-

Hello world!

+ +

Critter Roster

+
+
+

#{{entry.key}} - {{entry.value.name}}

+

Species: {{entry.value.species}}

+

Gender: {{entry.value.gender}}

+

Notes: {{entry.value.notes}}

+
+
- -
+ \ No newline at end of file diff --git a/src/critter.hpp b/src/critter.hpp index 6b385a6..9143055 100644 --- a/src/critter.hpp +++ b/src/critter.hpp @@ -31,4 +31,16 @@ class Critter { int father_id; std::string gender; std::string species; + + Critter() = default; + + Critter(int id, std::string name, std::string gender, int mother_id, int father_id, std::string notes, std::string species) : + id(id), name(std::move(name)), gender(std::move(gender)), + mother_id(mother_id), father_id(father_id), + notes(std::move(notes)), species(std::move(species)) {} +}; + +struct CritterEntry { + int key; + Critter value; }; diff --git a/src/database.hpp b/src/database.hpp new file mode 100644 index 0000000..bc22b5e --- /dev/null +++ b/src/database.hpp @@ -0,0 +1,104 @@ +#include "critter.hpp" +#include +#include +#include + +inline static bool db_get_all_critters(std::map &critters) { + try { + SQLite::Database db("./assets/local.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); + SQLite::Statement q(db, "SELECT * FROM critters"); + + critters.clear(); + + while (q.executeStep()) { + int id = q.getColumn(0); + + critters.try_emplace( + id, + id, + q.getColumn(1).getText(), + q.getColumn(2).getText(), + q.getColumn(3).getInt(), + q.getColumn(4).getInt(), + q.getColumn(5).getText(), + q.getColumn(6).getText() + ); + } + } + catch (const std::exception &e) { + std::cout << "[ERROR] DB exception: " << e.what() << std::endl; + return false; + } + + return true; +} + +inline static void db_print_all_critters(std::map &critters) { + std::cout << "Current loaded critters:"; + for (auto c : critters) { + std::cout << "\nCritter " << c.first << "\n"; + std::cout << "ID: " << c.second.id << std::endl; + std::cout << "Name:" << c.second.name << std::endl; + std::cout << "Gender: " << c.second.gender << std::endl; + std::cout << "Mother ID: " << c.second.mother_id << std::endl; + std::cout << "Father ID: " << c.second.father_id << std::endl; + std::cout << "Notes: " << c.second.notes << std::endl; + std::cout << "Species: " << c.second.species << std::endl; + } + std::cout << "\n"; +} + +inline static bool validate_critter(const Critter &c, std::map &all_critters, std::string &out_error) { + if (c.mother_id != 0 && c.father_id != 0 && c.mother_id == c.father_id) { + out_error = "Mother ID and Father ID cannot be the same."; + return false; + } + + // Mother Validation + if (c.mother_id != 0) { + auto it = all_critters.find(c.mother_id); + if (it == all_critters.end()) { + out_error = "Mother ID " + std::to_string(c.mother_id) + " does not exist."; + return false; + } + + const Critter& mother = it->second; + + if (mother.gender != "F" && mother.gender != "Female") { + out_error = "Mother must have female gender ('F' or 'Female')."; + return false; + } + + if (mother.species != c.species) { + out_error = "Mother species ('" + mother.species + "') must match critter species ('" + c.species + "')."; + return false; + } + } + + // Father Validation + if (c.father_id != 0) { + auto it = all_critters.find(c.father_id); + if (it == all_critters.end()) { + out_error = "Father ID " + std::to_string(c.father_id) + " does not exist."; + return false; + } + + const Critter& father = it->second; + + if (father.gender != "M" && father.gender != "Male") { + out_error = "Father must have male gender ('M' or 'Male')."; + return false; + } + + if (father.species != c.species) { + out_error = "Father species ('" + father.species + "') must match critter species ('" + c.species + "')."; + return false; + } + } + + return true; +} + +inline static bool db_try_add_critter() { + +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1a98982..b8da5f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -15,19 +14,28 @@ #include #include #include "critter.hpp" -#include #include #include +#include +#include "database.hpp" static bool is_initalized = false; static bool is_running = false; static Rml::Context *ctx; static std::map critters = {}; +static std::vector critter_list = {}; struct AppData { Rml::String page_title = "Main"; } app_data; +void SyncMapToList() { + critter_list.clear(); + for (const auto &[id, critter] : critters) { + critter_list.push_back({id, critter}); + } +} + void Shutdown() { Rml::Shutdown(); Backend::Shutdown(); @@ -40,10 +48,27 @@ bool SetupDataBinding(Rml::Context *context, Rml::DataModelHandle &model_handle) return false; } + if (auto handle = dmc.RegisterStruct()) { + handle.RegisterMember("id", &Critter::id); + handle.RegisterMember("name", &Critter::name); + handle.RegisterMember("gender", &Critter::gender); + handle.RegisterMember("species", &Critter::species); + handle.RegisterMember("notes", &Critter::notes); + handle.RegisterMember("mother_id", &Critter::mother_id); + handle.RegisterMember("father_id", &Critter::father_id); + } + + if (auto handle = dmc.RegisterStruct()) { + handle.RegisterMember("key", &CritterEntry::key); + handle.RegisterMember("value", &CritterEntry::value); + } + + dmc.RegisterArray>(); + dmc.Bind("critters", &critter_list); + dmc.Bind("page_title", &app_data.page_title); model_handle = dmc.GetModelHandle(); - return true; } @@ -62,53 +87,17 @@ bool Initalize() { // TODO: Add more error handling for initalization std::cout << "[INFO] Loading local DB...\n"; - try { - SQLite::Database db = SQLite::Database("./assets/local.db", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - - SQLite::Statement q(db, "SELECT * FROM critters"); - - while(q.executeStep()) { - int id = q.getColumn(0); - std::string name = q.getColumn(1); - std::string gender = q.getColumn(2); - int mother_id = q.getColumn(3); - int father_id = q.getColumn(4); - std::string notes = q.getColumn(5); - std::string species = q.getColumn(6); - - Critter c; - c.id = id; - c.name = name; - c.gender = gender; - c.mother_id = mother_id; - c.father_id = father_id; - c.notes = notes; - c.species = species; - - critters[c.id] = c; - } - - std::cout << "[INFO] Loaded " << critters.size() << " critters from local db.\n"; - } - catch (std::exception &e){ - std::cout << "[ERROR] DB exception: " << e.what() << std::endl; - return false; + bool db_result = db_get_all_critters(critters); + if (!db_result) { + std::cout << "[ERROR] Local DB failed to initalize.\n"; + return false; } std::cout << "[INFO] Local DB initalized.\n"; + SyncMapToList(); + // ------- DB TESTING - std::cout << "\n"; - for (auto c : critters) { - std::cout << "\nCritter " << c.first << "\n"; - std::cout << "ID: " << c.second.id << std::endl; - std::cout << "Name:" << c.second.name << std::endl; - std::cout << "Gender: " << c.second.gender << std::endl; - std::cout << "Mother ID: " << c.second.mother_id << std::endl; - std::cout << "Father ID: " << c.second.father_id << std::endl; - std::cout << "Notes: " << c.second.notes << std::endl; - std::cout << "Species: " << c.second.species << std::endl; - } - std::cout << "\n"; + // db_print_all_critters(critters); // ------- END DB TESTING ctx = Rml::CreateContext("main", Rml::Vector2i(800, 600)); @@ -120,7 +109,7 @@ bool Initalize() { Rml::Debugger::Initialise(ctx); - // lua_State *L = Rml::Lua::Interpreter::GetLuaState(); + // lua_State *L = Rml::Lua::Interpreter::GetLuaState(); return true; }