diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/hearthstoneAPIHandler.cpp | 2 | ||||
| -rw-r--r-- | src/main.cpp | 4 | ||||
| -rw-r--r-- | src/postgresHandler.cpp | 197 |
3 files changed, 125 insertions, 78 deletions
diff --git a/src/hearthstoneAPIHandler.cpp b/src/hearthstoneAPIHandler.cpp index ff8aa9b..8845b62 100644 --- a/src/hearthstoneAPIHandler.cpp +++ b/src/hearthstoneAPIHandler.cpp @@ -1,4 +1,4 @@ -#include "hearthstoneAPIHandler.h" +#include "hearthstoneAPIHandler.hpp" #include <chrono> #include <curl/curl.h> #include <format> diff --git a/src/main.cpp b/src/main.cpp index d0aa649..37c1525 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,9 @@ -#include "postgresHandler.h" +#include "postgresHandler.hpp" +#include "startMenu.hpp" #include <pqxx/pqxx> int main() { refresh_cards_table(); + launchFunction(refresh_cards_table); return 0; } 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) { |
