summaryrefslogtreecommitdiff
path: root/src/postgresHandler.cpp
diff options
context:
space:
mode:
authorAotrix <[email protected]>2025-06-29 02:16:13 +0200
committerAotrix <[email protected]>2025-06-29 02:16:13 +0200
commit4167f92f3d36b7384c4c5f8bf7501bba52e91a0c (patch)
tree7cbccb75c24ddb1d256a1e3b78d05c0ca7dcbd7c /src/postgresHandler.cpp
parenta61305a4f779d72ebf01bf1c4b0d4c9244d23236 (diff)
refactoring and added start menu
Diffstat (limited to 'src/postgresHandler.cpp')
-rw-r--r--src/postgresHandler.cpp197
1 files changed, 121 insertions, 76 deletions
diff --git a/src/postgresHandler.cpp b/src/postgresHandler.cpp
index 662a6a3..dc8451d 100644
--- a/src/postgresHandler.cpp
+++ b/src/postgresHandler.cpp
@@ -1,5 +1,5 @@
-#include "postgresHandler.h"
-#include "hearthstoneAPIHandler.h"
+#include "postgresHandler.hpp"
+#include "hearthstoneAPIHandler.hpp"
#include <cctype>
#include <cstddef>
#include <cstdint>
@@ -8,63 +8,74 @@
#include <regex>
#include <stdexcept>
-#define KEY_INDEX 1
-#define INT_INDEX 3
-#define STRING_INDEX 4
-#define LIST_OF_INT_INDEX 5
-#define NULL_INDEX 6
-#define BOOL_INDEX 7
+#define KEY_ID 1
-const pqxx::result execute_query(pqxx::work &t_transaction,
- std::string_view t_query) {
- return t_transaction.exec(t_query);
+// TODO: create a list/array which contains CardTypeHandlerInfo struct objects
+// and fill these info in a single function
+struct CardTypeHandlerInfo {
+ std::string aCardType;
+ std::string aCardRegex;
+ std::function<const std::string(const std::string &)> aJSONToSQLConverter;
+};
+
+const std::map<std::string, std::string> aCardValueTypeToRegex = {
+ {"INT", "[0-9]+"},
+ {"STRING", "\"[^\"?]*\""},
+ {"LIST_OF_INT", "\\[[0-9,]*\\]"},
+ {"NULL", "null"},
+ {"BOOL", "true|false"}};
+
+const pqxx::result executeQuery(pqxx::work &aTransaction,
+ std::string_view aQuery) {
+ return aTransaction.exec(aQuery);
}
-std::ostream &operator<<(std::ostream &t_ostream, const pqxx::result &t_r) {
- const int nb_columns = t_r.columns();
- t_ostream << "| ";
- for (const auto &row : t_r) {
- for (int i = 0; i < nb_columns; i++) {
- t_ostream << row[i].c_str() << " | ";
+std::ostream &operator<<(std::ostream &aOstream, const pqxx::result &kResult) {
+ const int kNbColumnsInResult = kResult.columns();
+ aOstream << "| ";
+ for (const auto &kResultRow : kResult) {
+ for (int i = 0; i < kNbColumnsInResult; i++) {
+ aOstream << kResultRow[i].c_str() << " | ";
}
}
- return t_ostream;
+ return aOstream;
}
-static const unsigned int
-get_type_of_regex_iterator(const std::sregex_iterator &t_sregex_it) {
- std::array<int, 5> types{INT_INDEX, STRING_INDEX, LIST_OF_INT_INDEX,
- NULL_INDEX, BOOL_INDEX};
- for (const int &type : types) {
- if ((*t_sregex_it)[type] != "") {
- return type;
+const unsigned int
+getTypeIndexOfRegexIterator(const std::sregex_iterator &kSregexIt) {
+ // TODO: remove hardcoded variable because it is... weird.
+ // The input should already be the "value" part?
+ const unsigned int offset = 2;
+ for (size_t aCardInfoType = 0; aCardInfoType < aCardValueTypeToRegex.size();
+ aCardInfoType++) {
+ if ((*kSregexIt)[aCardInfoType] != "") {
+ return offset + aCardInfoType;
}
}
throw std::invalid_argument("regex iterator input is invalid");
}
-const std::string format_json_value_to_sql(const unsigned int &t_type_index,
- const std::string &t_json_value) {
- switch (t_type_index) {
- case BOOL_INDEX:
- case INT_INDEX:
- return t_json_value;
- case STRING_INDEX: {
- std::string json_copy = t_json_value;
- *json_copy.begin() = '\'';
- *std::prev(json_copy.end()) = '\'';
- return json_copy;
- }
- case NULL_INDEX:
+const std::string format_json_value_to_sql(const std::string &kTypeOfValue,
+ const std::string &kValueFromJSON) {
+ // TODO: show an error if a type is no longer here,
+ // to avoid having useless conditions
+ // FIXME: it does not scale well, a bit ugly... should be a single line
+ if (kTypeOfValue == "BOOL" || kTypeOfValue == "INT") {
+ return kValueFromJSON;
+ } else if (kTypeOfValue == "STRING") {
+ std::string aCopyOfJSONValue = kValueFromJSON;
+ *aCopyOfJSONValue.begin() = '\'';
+ *std::prev(aCopyOfJSONValue.end()) = '\'';
+ return aCopyOfJSONValue;
+ } else if (kTypeOfValue == "NULL") {
return "NULL";
- case LIST_OF_INT_INDEX: {
- std::string json_copy = t_json_value;
- json_copy.append("\'");
- json_copy.insert(json_copy.begin(), '\'');
- return json_copy;
- }
- default:
- throw std::invalid_argument("type index is invalid: ");
+ } else if (kTypeOfValue == "LIST_OF_INT") {
+ std::string aCopyOfJSONValue = kValueFromJSON;
+ aCopyOfJSONValue.append("\'");
+ aCopyOfJSONValue.insert(aCopyOfJSONValue.begin(), '\'');
+ return aCopyOfJSONValue;
+ } else {
+ throw std::invalid_argument("ERROR: type of value is invalid");
}
}
@@ -97,12 +108,18 @@ add_single_card_to_database(const std::string &t_cards, pqxx::work &t_tx,
if (words_begin != words_end) {
std::string insert_columns("INSERT INTO cards (");
std::string values(" VALUES (");
- for (auto it = words_begin; it != words_end; ++it) {
- insert_columns.append(format_key((*it)[KEY_INDEX].str()) +
+ for (std::sregex_iterator kSregexIt = words_begin;
+ kSregexIt != words_end; ++kSregexIt) {
+ insert_columns.append(format_key((*kSregexIt)[KEY_ID].str()) +
","); // key
- const unsigned int type_index = get_type_of_regex_iterator(it);
+ const unsigned int kTypeIndexOfValue =
+ getTypeIndexOfRegexIterator(kSregexIt);
+ const std::string kTypeNameOfValue =
+ std::next(aCardValueTypeToRegex.begin(), kTypeIndexOfValue)
+ ->first;
values.append(
- format_json_value_to_sql(type_index, (*it)[type_index].str()) +
+ format_json_value_to_sql(
+ kTypeNameOfValue, (*kSregexIt)[kTypeIndexOfValue].str()) +
",");
}
*std::prev(insert_columns.end()) = ')';
@@ -110,37 +127,65 @@ add_single_card_to_database(const std::string &t_cards, pqxx::work &t_tx,
insert_columns.append(values);
insert_columns.append(" ON CONFLICT (id) DO NOTHING;");
- execute_query(t_tx, insert_columns);
+ executeQuery(t_tx, insert_columns);
}
}
-void add_cards_to_database(const std::string &t_cards, pqxx::work &t_tx) {
- std::regex key_regex("\"([^\"?]+)\":(([0-9]+)|(\"[^\"?]*\")|(\\[[0-9,]*\\])"
- "|(null)|(true|false))");
-
- std::string::size_type id_pos = t_cards.find("{\"id");
- std::string::size_type closing_bracket_pos = t_cards.find("}");
- while (id_pos != std::string::npos &&
- closing_bracket_pos != std::string::npos) {
- add_single_card_to_database(t_cards, t_tx, key_regex, id_pos,
- closing_bracket_pos);
- id_pos = t_cards.find("{\"id", id_pos + 1);
- closing_bracket_pos = t_cards.find("}", closing_bracket_pos + 1);
+const std::regex keyValueJSONRegex() {
+ std::string aRegexString = "\"([^\"?]+)\":(";
+ for (auto &[fieldName, regex] : aCardValueTypeToRegex) {
+ aRegexString += "(" + regex + ")|";
}
+ aRegexString[aRegexString.length() - 1] = ')';
+ return std::regex(aRegexString);
}
-void refresh_cards_table() {
- HearthstoneAPIHandler hs_handler;
- pqxx::connection cx{
- "postgresql://aotrix@localhost:5432/hearthstonegameinfo"};
- pqxx::work tx{cx};
+const std::string::size_type
+startPosOfCardJSON(const std::string &kCardsPageJSON,
+ const std::string::size_type kSearchStartPos = 0) {
+ return kCardsPageJSON.find("{\"id", kSearchStartPos);
+}
+
+const std::string::size_type
+endPosOfCardJSON(const std::string &kCardsPageJSON,
+ const std::string::size_type kSearchStartPos = 0) {
+ return kCardsPageJSON.find("}", kSearchStartPos);
+}
+void addCardsToDatabase(HearthstoneAPIHandler &aAPIIntermediate,
+ pqxx::work &aTransaction,
+ const std::string &kURLOfCardsPage) {
+ const std::regex aKeyValueJSONRegex = keyValueJSONRegex();
+ const std::string &kCardsPageJSON =
+ aAPIIntermediate.get_cards(kURLOfCardsPage);
+ std::string::size_type aCardStartPos = startPosOfCardJSON(kCardsPageJSON);
+ std::string::size_type aCardEndPos = endPosOfCardJSON(kCardsPageJSON);
+ while (aCardStartPos != std::string::npos &&
+ aCardEndPos != std::string::npos) {
+ add_single_card_to_database(kCardsPageJSON, aTransaction,
+ aKeyValueJSONRegex, aCardStartPos,
+ aCardEndPos);
+ aCardStartPos = startPosOfCardJSON(kCardsPageJSON, aCardStartPos + 1);
+ aCardEndPos = endPosOfCardJSON(kCardsPageJSON, aCardEndPos + 1);
+ }
+}
+
+void clearCardDatabase(pqxx::work &tx) {
+ executeQuery(tx, "DELETE FROM cards");
+}
+
+void refresh_cards_table() {
try {
- execute_query(tx, "DELETE FROM cards");
- std::regex key_regex("\"pageCount\":([0-9]+)");
+ pqxx::connection cx{
+ "postgresql://aotrix@localhost:5432/hearthstonegameinfo"};
+ pqxx::work tx{cx};
+ HearthstoneAPIHandler aAPIIntermediate;
std::string cards =
- hs_handler.get_cards("/?locale=fr_FR&gameMode=constructed");
- add_cards_to_database(cards, tx);
+ aAPIIntermediate.get_cards("/?locale=fr_FR&gameMode=constructed");
+ clearCardDatabase(tx);
+ addCardsToDatabase(aAPIIntermediate, tx,
+ "/?locale=fr_FR&gameMode=constructed");
+ std::regex key_regex("\"pageCount\":([0-9]+)");
auto nb_pages_begin =
std::sregex_iterator(cards.begin(), cards.end(), key_regex);
auto nb_pages_end = std::sregex_iterator();
@@ -150,13 +195,13 @@ void refresh_cards_table() {
// FIXME: [Process exited 139]
// for (int i = 2; i < nb_pages; i++) {
for (uint32_t i = 2; i < 3; i++) {
- cards = hs_handler.get_cards(std::format(
- "/?locale=fr_FR&gameMode=constructed&page={}", i));
- add_cards_to_database(cards, tx);
+ const std::string kCardsPageURL{std::format(
+ "/?locale=fr_FR&gameMode=constructed&page={}", i)};
+ addCardsToDatabase(aAPIIntermediate, tx, kCardsPageURL);
}
}
std::cout << "number of cards in database: "
- << execute_query(tx, "SELECT COUNT(*) FROM cards")
+ << executeQuery(tx, "SELECT COUNT(*) FROM cards")
<< std::endl;
tx.commit();
} catch (pqxx::sql_error const &e) {