Possible to load basic data from the database
This commit is contained in:
parent
69f7f625f8
commit
397189c259
99
.vscode/settings.json
vendored
99
.vscode/settings.json
vendored
@ -1,6 +1,103 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"text_encoding": "cpp",
|
"text_encoding": "cpp",
|
||||||
"thread": "cpp"
|
"thread": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"any": "cpp",
|
||||||
|
"array": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"hash_map": "cpp",
|
||||||
|
"strstream": "cpp",
|
||||||
|
"barrier": "cpp",
|
||||||
|
"bit": "cpp",
|
||||||
|
"bitset": "cpp",
|
||||||
|
"cctype": "cpp",
|
||||||
|
"cfenv": "cpp",
|
||||||
|
"charconv": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"cinttypes": "cpp",
|
||||||
|
"clocale": "cpp",
|
||||||
|
"cmath": "cpp",
|
||||||
|
"codecvt": "cpp",
|
||||||
|
"compare": "cpp",
|
||||||
|
"complex": "cpp",
|
||||||
|
"concepts": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"coroutine": "cpp",
|
||||||
|
"csetjmp": "cpp",
|
||||||
|
"csignal": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstdlib": "cpp",
|
||||||
|
"cstring": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cuchar": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"forward_list": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"unordered_set": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"expected": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"memory_resource": "cpp",
|
||||||
|
"numeric": "cpp",
|
||||||
|
"optional": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"regex": "cpp",
|
||||||
|
"source_location": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"system_error": "cpp",
|
||||||
|
"tuple": "cpp",
|
||||||
|
"type_traits": "cpp",
|
||||||
|
"utility": "cpp",
|
||||||
|
"flat_map": "cpp",
|
||||||
|
"flat_set": "cpp",
|
||||||
|
"format": "cpp",
|
||||||
|
"fstream": "cpp",
|
||||||
|
"future": "cpp",
|
||||||
|
"generator": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"iomanip": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"latch": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"numbers": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"print": "cpp",
|
||||||
|
"queue": "cpp",
|
||||||
|
"ranges": "cpp",
|
||||||
|
"scoped_allocator": "cpp",
|
||||||
|
"semaphore": "cpp",
|
||||||
|
"shared_mutex": "cpp",
|
||||||
|
"span": "cpp",
|
||||||
|
"spanstream": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"stack": "cpp",
|
||||||
|
"stacktrace": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"stdfloat": "cpp",
|
||||||
|
"stop_token": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"syncstream": "cpp",
|
||||||
|
"typeindex": "cpp",
|
||||||
|
"typeinfo": "cpp",
|
||||||
|
"valarray": "cpp",
|
||||||
|
"variant": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +67,8 @@ add_executable(${TARGET_NAME}
|
|||||||
src/shadowrun/ShadowrunCharacterForm.cpp
|
src/shadowrun/ShadowrunCharacterForm.cpp
|
||||||
src/shadowrun/ShadowrunApi.cpp
|
src/shadowrun/ShadowrunApi.cpp
|
||||||
src/shadowrun/ShadowrunApi.hpp
|
src/shadowrun/ShadowrunApi.hpp
|
||||||
|
src/shadowrun/ShadowrunDb.cpp
|
||||||
|
src/shadowrun/ShadowrunDb.hpp
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#include "crow.h"
|
#include "crow.h"
|
||||||
#include "database.hpp"
|
#include "database.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
Database::Database() :
|
Database::Database() :
|
||||||
m_db(nullptr)
|
m_db(nullptr)
|
||||||
{}
|
{}
|
||||||
@ -9,6 +11,15 @@ Database::~Database() {
|
|||||||
sqlite3_close(m_db);
|
sqlite3_close(m_db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* Database::prepareStmt(const string& sql){
|
||||||
|
sqlite3_stmt* stmt = nullptr;
|
||||||
|
if (sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
|
||||||
|
CROW_LOG_ERROR << "Failed to prepare statement: " << sqlite3_errmsg(m_db);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
|
||||||
bool Database::exec(const char* sqlQuery) {
|
bool Database::exec(const char* sqlQuery) {
|
||||||
char* errmsg = nullptr;
|
char* errmsg = nullptr;
|
||||||
int rc = sqlite3_exec(m_db, sqlQuery, nullptr, nullptr, &errmsg);
|
int rc = sqlite3_exec(m_db, sqlQuery, nullptr, nullptr, &errmsg);
|
||||||
@ -20,13 +31,72 @@ bool Database::exec(const char* sqlQuery) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::exec(const std::string& sqlQuery)
|
bool Database::exec(const std::string& sqlQuery){
|
||||||
{
|
return exec(sqlQuery.c_str());
|
||||||
exec(sqlQuery.c_str());
|
}
|
||||||
|
|
||||||
|
map<string, string> Database::getStrMap(const string& sql){
|
||||||
|
sqlite3_stmt* stmt = prepareStmt(sql);
|
||||||
|
map<string, string> map;
|
||||||
|
if (stmt == nullptr)
|
||||||
|
return map;
|
||||||
|
|
||||||
|
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
string key = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
|
||||||
|
string value = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||||
|
map[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
set<string> Database::getStrSet(const string& sql){
|
||||||
|
sqlite3_stmt* stmt = prepareStmt(sql);
|
||||||
|
set<string> vec;
|
||||||
|
if (stmt == nullptr)
|
||||||
|
return vec;
|
||||||
|
|
||||||
|
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
string s = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
|
||||||
|
vec.insert(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int64_t> Database::getInt(const char* sql) {
|
||||||
|
sqlite3_stmt* stmt = prepareStmt(sql);
|
||||||
|
if (stmt == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::optional<int64_t> id;
|
||||||
|
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
id = sqlite3_column_int64(stmt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int64_t> Database::insert(const char* sql) {
|
||||||
|
sqlite3_stmt* stmt = prepareStmt(sql);
|
||||||
|
if (stmt == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||||
|
CROW_LOG_ERROR << "Insert failed: " << sqlite3_errmsg(m_db);
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return sqlite3_last_insert_rowid(m_db);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::open(){
|
bool Database::open(){
|
||||||
int rc = sqlite3_open("example.db", &m_db);
|
int rc = sqlite3_open("app.db", &m_db);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
CROW_LOG_ERROR << "Can't open database: " << sqlite3_errmsg(m_db);
|
CROW_LOG_ERROR << "Can't open database: " << sqlite3_errmsg(m_db);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include <set>
|
||||||
class Database {
|
class Database {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -14,7 +15,18 @@ public:
|
|||||||
bool exec(const char* sqlQuery);
|
bool exec(const char* sqlQuery);
|
||||||
bool exec(const std::string& sqlQuery);
|
bool exec(const std::string& sqlQuery);
|
||||||
|
|
||||||
|
/// returns true if the sql statment returns at least one row
|
||||||
|
std::optional<int64_t> getInt(const char* sql);
|
||||||
|
|
||||||
|
std::optional<int64_t> insert(const char* sql);
|
||||||
|
|
||||||
|
std::set<std::string> getStrSet(const std::string& sql);
|
||||||
|
|
||||||
|
std::map<std::string, std::string> Database::getStrMap(const std::string& sql);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
sqlite3_stmt* prepareStmt(const std::string& sql);
|
||||||
|
|
||||||
sqlite3* m_db;
|
sqlite3* m_db;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const vector<str
|
|||||||
html += format("<h2>{}</h2>", id);
|
html += format("<h2>{}</h2>", id);
|
||||||
html += "<div class='grid'>";
|
html += "<div class='grid'>";
|
||||||
for (auto& item : itemList){
|
for (auto& item : itemList){
|
||||||
string item_id = utils::to_id_format(id + "_" + item);
|
string item_id = utils::to_id_format(format("{}_{}", id, item));
|
||||||
|
|
||||||
html += format("<label>{}:<input type='text' name='{}'></label>", item, item_id);
|
html += format("<label>{}:<input type='text' name='{}'></label>", item, item_id);
|
||||||
}
|
}
|
||||||
@ -19,8 +19,15 @@ HtmxShAttributeList::HtmxShAttributeList(const std::string& id, const std::vecto
|
|||||||
html += format("<h2>{}</h2>", id);
|
html += format("<h2>{}</h2>", id);
|
||||||
html += "<div class='grid'>";
|
html += "<div class='grid'>";
|
||||||
for (auto& item : itemValueList){
|
for (auto& item : itemValueList){
|
||||||
string item_id = utils::to_id_format(id + "_" + item.first);
|
string item_id = utils::to_id_format(format("{}_{}", id, item));
|
||||||
html += format("<label>{}:<input type='text' name='{}' value='{}'></label>", item, item_id, item.second);
|
html += format("<label>{}:<input type='text' name='{}' value='{}'></label>", item, item_id, item.second);
|
||||||
}
|
}
|
||||||
html += "</div>";
|
html += "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HtmxShAttributeList::genIds(std::vector<std::string>& vec, const std::string& id, const std::vector<std::string>& itemList)
|
||||||
|
{
|
||||||
|
for (auto& item : itemList){
|
||||||
|
vec.push_back(utils::to_id_format(format("{}_{}", id, item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,6 +13,8 @@ public:
|
|||||||
|
|
||||||
// create new item list where each item as a value
|
// create new item list where each item as a value
|
||||||
HtmxShAttributeList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
HtmxShAttributeList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
||||||
|
|
||||||
|
static void genIds(std::vector<std::string>& vec, const std::string& id, const std::vector<std::string>& itemList);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HTMXSHATTRIBUTELIST_H
|
#endif // HTMXSHATTRIBUTELIST_H
|
||||||
@ -26,3 +26,10 @@ HtmxShCondition::HtmxShCondition(std::string id, size_t nbrOfBoxes)
|
|||||||
}
|
}
|
||||||
html += "</div></div>";
|
html += "</div></div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HtmxShCondition::genIds(std::vector<std::string>& vec, std::string id, size_t nbrOfBoxes)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < nbrOfBoxes; i++){
|
||||||
|
vec.push_back(utils::to_id_format(format("{}_{}",id, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,12 +2,15 @@
|
|||||||
#define __HTMXSHCONDITION_H__
|
#define __HTMXSHCONDITION_H__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include "HtmxObject.h"
|
#include "HtmxObject.h"
|
||||||
|
|
||||||
class HtmxShCondition : public HtmxObject {
|
class HtmxShCondition : public HtmxObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HtmxShCondition(std::string id, size_t nbrOfBoxes);
|
HtmxShCondition(std::string id, size_t nbrOfBoxes);
|
||||||
|
|
||||||
|
static void genIds(std::vector<std::string>& vec, std::string id, size_t nbrOfBoxes);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __HTMXSHCONDITION_H__
|
#endif // __HTMXSHCONDITION_H__
|
||||||
@ -41,3 +41,12 @@ HtmxShItemList::HtmxShItemList(const std::string& id, const std::vector<std::pai
|
|||||||
html += "</div></div>";
|
html += "</div></div>";
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void HtmxShItemList::genIds(std::vector<std::string>& vec, const std::string& id, const std::vector<std::string>& columns, size_t size)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size; i++){
|
||||||
|
for (auto& col : columns){
|
||||||
|
vec.push_back(utils::to_id_format(format("{}_{}_{}", id, i, col)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -13,6 +13,8 @@ public:
|
|||||||
|
|
||||||
// create new item list where each item as a value
|
// create new item list where each item as a value
|
||||||
HtmxShItemList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
HtmxShItemList(const std::string& id, const std::vector<std::pair<std::string, std::string>>& itemValueList);
|
||||||
|
|
||||||
|
static void genIds(std::vector<std::string>& vec, const std::string& id, const std::vector<std::string>& columns, size_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HTMXSHITEMLIST_H
|
#endif // HTMXSHITEMLIST_H
|
||||||
@ -2,66 +2,71 @@
|
|||||||
|
|
||||||
#include "ShadowrunApi.hpp"
|
#include "ShadowrunApi.hpp"
|
||||||
#include "ShadowrunCharacterForm.hpp"
|
#include "ShadowrunCharacterForm.hpp"
|
||||||
#include "database.hpp"
|
#include "ShadowrunDb.hpp"
|
||||||
|
#include <format>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
namespace shadowrun
|
namespace shadowrun
|
||||||
{
|
{
|
||||||
|
|
||||||
bool initDb() {
|
static std::unordered_map<std::string, std::string> parse_query_string(const std::string& query) {
|
||||||
auto db = Database();
|
std::unordered_map<std::string, std::string> params;
|
||||||
|
std::istringstream stream(query);
|
||||||
|
std::string pair;
|
||||||
|
|
||||||
if (!db.open()){
|
while (std::getline(stream, pair, '&')) {
|
||||||
return false;
|
auto pos = pair.find('=');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
std::string key = pair.substr(0, pos);
|
||||||
|
std::string value = pair.substr(pos + 1);
|
||||||
|
params[key] = value; // You may want to URL-decode here
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a tables
|
return params;
|
||||||
const char* create_sql_chars = "CREATE TABLE IF NOT EXISTS shadowrun_characters ("
|
|
||||||
"id INTEGER PRIMARY KEY,"
|
|
||||||
"name TEXT,"
|
|
||||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP);";
|
|
||||||
|
|
||||||
if (!db.exec(create_sql_chars)){
|
|
||||||
CROW_LOG_ERROR << "Failed to create shadowrun_characters table";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* create_sql_data = "CREATE TABLE IF NOT EXISTS shadowrun_data ("
|
static crow::response rsp(const std::string& msg){
|
||||||
"id INTEGER PRIMARY KEY,"
|
auto str = format("<div class='alert alert-success'>"
|
||||||
"character_id INTEGER NOT NULL,"
|
"{} </div>", msg);
|
||||||
"name TEXT NOT NULL,"
|
return crow::response{str};
|
||||||
"value TEXT,"
|
|
||||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
|
||||||
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
|
||||||
"FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE);";
|
|
||||||
|
|
||||||
if (!db.exec(create_sql_data)){
|
|
||||||
CROW_LOG_ERROR << "Failed to create shadowrun_data table";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initApi(crow::SimpleApp& app)
|
void initApi(crow::SimpleApp& app)
|
||||||
{
|
{
|
||||||
CROW_ROUTE(app, "/api/shadowrun/submit-character").methods("POST"_method)(
|
CROW_ROUTE(app, "/api/shadowrun/submit-character").methods("POST"_method)(
|
||||||
[](const crow::request& req) {
|
[](const crow::request& req) {
|
||||||
auto params = crow::query_string(req.body);
|
auto params = parse_query_string(req.body);
|
||||||
|
|
||||||
std::string name = params.get("name") ? params.get("name") : "";
|
auto name_data = params["Character-Info_Name"];
|
||||||
std::string metatype = params.get("metatype") ? params.get("metatype") : "";
|
if (name_data.empty()){
|
||||||
std::string age = params.get("age") ? params.get("age") : "";
|
CROW_LOG_WARNING << "Character without name submited, will not be saved";
|
||||||
// ... extract more fields as needed
|
return rsp("Failed : Character without name submited, will not be saved");
|
||||||
|
}
|
||||||
|
|
||||||
// Optionally save to a DB or do logic here
|
auto key = getKeyOfCharacter(name_data);
|
||||||
|
if (key < 0){
|
||||||
|
CROW_LOG_ERROR << "Failed to create id of character : " << name_data;
|
||||||
|
return rsp("Failed to create id of character");
|
||||||
|
}
|
||||||
|
|
||||||
// Return response HTML
|
vector<pair<const string&, const string&>> idValues;
|
||||||
std::ostringstream out;
|
idValues.reserve(ShadowrunCharacterForm::m_formIds.size());
|
||||||
out << "<div class='alert alert-success'>"
|
|
||||||
<< "Character " << name << " submitted successfully!"
|
|
||||||
<< "</div>";
|
|
||||||
|
|
||||||
return crow::response{out.str()};
|
for (auto& id : ShadowrunCharacterForm::m_formIds) {
|
||||||
|
auto data = params[id];
|
||||||
|
if(!
|
||||||
|
data.empty()){
|
||||||
|
idValues.push_back(make_pair(id, data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!storeCharacterData(key, idValues)){
|
||||||
|
CROW_LOG_ERROR << "Failed to store character data of " << name_data;
|
||||||
|
return rsp("Failed to store character data");
|
||||||
|
};
|
||||||
|
return rsp(format("Character {} submitted successfully", name_data));
|
||||||
});
|
});
|
||||||
|
|
||||||
CROW_ROUTE(app, "/api/shadowrun/character-form")
|
CROW_ROUTE(app, "/api/shadowrun/character-form")
|
||||||
@ -69,9 +74,7 @@ void initApi(crow::SimpleApp& app)
|
|||||||
auto query = crow::query_string(req.url_params);
|
auto query = crow::query_string(req.url_params);
|
||||||
std::string name = query.get("name") ? query.get("name") : "";
|
std::string name = query.get("name") ? query.get("name") : "";
|
||||||
|
|
||||||
// TODO: Load data from file or DB using `name`
|
auto data = getCharacterData(getKeyOfCharacter(name));
|
||||||
std::string metatype = "Troll";
|
|
||||||
int age = 28;
|
|
||||||
|
|
||||||
return crow::response{ShadowrunCharacterForm().htmx()};
|
return crow::response{ShadowrunCharacterForm().htmx()};
|
||||||
});
|
});
|
||||||
@ -81,7 +84,7 @@ void initApi(crow::SimpleApp& app)
|
|||||||
std::ostringstream html;
|
std::ostringstream html;
|
||||||
|
|
||||||
// Simulated character database
|
// Simulated character database
|
||||||
std::vector<std::string> characters = { "Trogdor", "Alice", "Zigzag" };
|
auto characters = getCharacters();
|
||||||
|
|
||||||
html << "<form hx-get='/api/shadowrun/character-form' hx-target='#form-container' hx-params='*'>"
|
html << "<form hx-get='/api/shadowrun/character-form' hx-target='#form-container' hx-params='*'>"
|
||||||
<< "<label>Character Name: "
|
<< "<label>Character Name: "
|
||||||
@ -98,7 +101,7 @@ void initApi(crow::SimpleApp& app)
|
|||||||
return crow::response{html.str()};
|
return crow::response{html.str()};
|
||||||
});
|
});
|
||||||
|
|
||||||
if(initDb()){
|
if(!shadowrun::initDb()){
|
||||||
CROW_LOG_ERROR << "Failed to Init shadowrun database";
|
CROW_LOG_ERROR << "Failed to Init shadowrun database";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,6 +76,31 @@ static const vector<string> cArmorParamters = {
|
|||||||
"Notes",
|
"Notes",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const vector<string> genFormIds(){
|
||||||
|
vector<string> vec;
|
||||||
|
vec.reserve(200);
|
||||||
|
|
||||||
|
// OBS make sure to update both here and in ShadowrunCharacterForm()
|
||||||
|
HtmxShAttributeList::genIds(vec, "Character Info", cCharacterInfo);
|
||||||
|
HtmxShAttributeList::genIds(vec, "Attributes", cAttributes);
|
||||||
|
HtmxShItemList::genIds(vec, "Active Skills", cSkillParameters, 6);
|
||||||
|
HtmxShItemList::genIds(vec, "Knowledge Skills", cSkillParameters, 6);
|
||||||
|
vec.push_back("positive_qualities");
|
||||||
|
vec.push_back("negative_qualities");
|
||||||
|
vec.push_back("datapack_notes");
|
||||||
|
HtmxShCondition::genIds(vec, "Physical Condition", 18);
|
||||||
|
HtmxShCondition::genIds(vec, "Stun Condition", 12);
|
||||||
|
HtmxShItemList::genIds(vec, "Contacts", cContactsParameters, 6);
|
||||||
|
HtmxShItemList::genIds(vec, "Ranged Weapons", cRangedWeaponsParameters, 7);
|
||||||
|
HtmxShItemList::genIds(vec, "Cyberware and Bioware", cImplantParameters, 7);
|
||||||
|
HtmxShItemList::genIds(vec, "Melee Weapons", cMeleeWeaponParameters, 7);
|
||||||
|
HtmxShItemList::genIds(vec, "Armor", cArmorParamters , 3);
|
||||||
|
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> ShadowrunCharacterForm::m_formIds = genFormIds();
|
||||||
|
|
||||||
ShadowrunCharacterForm::ShadowrunCharacterForm() {
|
ShadowrunCharacterForm::ShadowrunCharacterForm() {
|
||||||
html.reserve(30000);
|
html.reserve(30000);
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class ShadowrunCharacterForm : public HtmxObject {
|
|||||||
public:
|
public:
|
||||||
ShadowrunCharacterForm();
|
ShadowrunCharacterForm();
|
||||||
|
|
||||||
private:
|
static const std::vector<std::string> m_formIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHADOWRUN_CHARACTER_FORM_HPP
|
#endif // SHADOWRUN_CHARACTER_FORM_HPP
|
||||||
110
src/shadowrun/ShadowrunDb.cpp
Normal file
110
src/shadowrun/ShadowrunDb.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include <format>
|
||||||
|
#include "database.hpp"
|
||||||
|
#include "crow.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace shadowrun {
|
||||||
|
|
||||||
|
bool initDb() {
|
||||||
|
auto db = Database();
|
||||||
|
|
||||||
|
if (!db.open()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a tables
|
||||||
|
const char* create_sql_chars = "CREATE TABLE IF NOT EXISTS shadowrun_characters ("
|
||||||
|
"id INTEGER PRIMARY KEY,"
|
||||||
|
"name TEXT NOT NULL,"
|
||||||
|
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP);";
|
||||||
|
|
||||||
|
if (!db.exec(create_sql_chars)){
|
||||||
|
CROW_LOG_ERROR << "Failed to create shadowrun_characters table";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* create_sql_data = "CREATE TABLE IF NOT EXISTS shadowrun_data ("
|
||||||
|
"id INTEGER PRIMARY KEY,"
|
||||||
|
"character_id INTEGER NOT NULL,"
|
||||||
|
"name TEXT NOT NULL,"
|
||||||
|
"value TEXT,"
|
||||||
|
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
||||||
|
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
|
||||||
|
"FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE);";
|
||||||
|
|
||||||
|
if (!db.exec(create_sql_data)){
|
||||||
|
CROW_LOG_ERROR << "Failed to create shadowrun_data table";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t getKeyOfCharacter(const string& name){
|
||||||
|
auto sql = format("SELECT 1 FROM shadowrun_characters WHERE name = '{}' LIMIT 1;", name);
|
||||||
|
auto db = Database();
|
||||||
|
|
||||||
|
if (!db.open())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
auto opt_int = db.getInt(sql.c_str());
|
||||||
|
if (opt_int.has_value()) {
|
||||||
|
return opt_int.value();
|
||||||
|
} else {
|
||||||
|
sql = format("INSERT INTO shadowrun_characters (name) VALUES ('{}');", name);
|
||||||
|
auto key = db.insert(sql.c_str());
|
||||||
|
|
||||||
|
if(key.has_value()){
|
||||||
|
return key.value();
|
||||||
|
} else {
|
||||||
|
CROW_LOG_ERROR << "Failed to insert character " << name;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storeCharacterData(int64_t characterKey, vector<pair<const string&, const string&>>& idValues){
|
||||||
|
auto sql = format("SELECT name FROM shadowrun_data WHERE character_id = {};", characterKey);
|
||||||
|
auto db = Database();
|
||||||
|
if (!db.open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto set = db.getStrSet(sql);
|
||||||
|
|
||||||
|
for (auto& idValue : idValues) {
|
||||||
|
// update if already exist
|
||||||
|
if(set.contains(idValue.first)){
|
||||||
|
auto sql = format("UPDATE shadowrun_data SET value = {}, updated_at = CURRENT_TIMESTAMP WHERE name = {} AND character_id = {}", idValue.second, idValue.first, characterKey);
|
||||||
|
if (!db.exec(sql)){
|
||||||
|
CROW_LOG_WARNING << "Failed to update " << idValue.first << " with " << idValue.second;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto sql = format("INSERT INTO shadowrun_data (character_id, name, value)"
|
||||||
|
"VALUES ({}, {}, {})", characterKey, idValue.first, idValue.second);
|
||||||
|
if (!db.exec(sql)){
|
||||||
|
CROW_LOG_WARNING << "Failed to insert " << idValue.first << " with " << idValue.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> getCharacters(){
|
||||||
|
string sql = "SELECT name FROM shadowrun_characters;";
|
||||||
|
auto db = Database();
|
||||||
|
if (!db.open())
|
||||||
|
return std::set<std::string>();
|
||||||
|
|
||||||
|
return db.getStrSet(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string> getCharacterData(int64_t characterKey) {
|
||||||
|
auto sql = format("SELECT name, value FROM shadowrun_data WHERE character_id = {};", characterKey);
|
||||||
|
auto db = Database();
|
||||||
|
if (!db.open())
|
||||||
|
return std::map<std::string, std::string>();
|
||||||
|
|
||||||
|
return db.getStrMap(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/shadowrun/ShadowrunDb.hpp
Normal file
20
src/shadowrun/ShadowrunDb.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef __SHADOWRUNDB_H__
|
||||||
|
#define __SHADOWRUNDB_H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace shadowrun{
|
||||||
|
|
||||||
|
bool initDb();
|
||||||
|
int64_t getKeyOfCharacter(const std::string& name);
|
||||||
|
bool storeCharacterData(int64_t characterKey, std::vector<std::pair<const std::string&, const std::string&>>& idValues);
|
||||||
|
std::set<std::string> getCharacters();
|
||||||
|
|
||||||
|
std::map<std::string, std::string> getCharacterData(int64_t characterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __SHADOWRUNDB_H__
|
||||||
Loading…
x
Reference in New Issue
Block a user