juk3n/fluffypublic Fork
⑂ c5330a4
Commits
⬇ Clone ▾
git clone https://git.rickub.com/juk3n/fluffy.git
git clone ssh://git@rickub.com/juk3n/fluffy.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Merge pull request #20 from Juk3n/19-create-separate-class-to-handle-database-operationsUnverified

19 create separate class to handle database operations
Adrian Duraj committed 2024-07-04T13:43:55+02:00 Browse files
c5330a4 parents: 27755dd f664e09
added app/include/database.hpp +92 -0
new file mode 100644
@@ -0,0 +1,92 @@
1+#pragma once
2+
3+#include <sqlite3.h>
4+#include <string>
5+
6+#include <game.hpp>
7+
8+class Database
9+{
10+private:
11+ sqlite3 *database;
12+
13+ std::string database_initialization_command =
14+ "CREATE TABLE games("
15+ "GAME_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
16+ "GAME_NAME TEXT NOT NULL, "
17+ "GAME_PATH TEXT NOT NULL);";
18+ std::string select_all_games_command = "SELECT * FROM games;";
19+
20+ auto initializeDatabase() -> void {
21+ executeSqlCommand(database_initialization_command);
22+ //printMessage("Database Initialized");
23+ }
24+
25+public:
26+
27+ Database(std::filesystem::path databasePath) {
28+ loadDatabase(databasePath);
29+ }
30+
31+ ~Database() {
32+ sqlite3_close(database);
33+ }
34+
35+ auto executeSqlCommand(std::string command) -> void {
36+ int exit = 0;
37+ char *messageError;
38+ exit = sqlite3_exec(database, command.c_str(), nullptr, nullptr, &messageError);
39+
40+ if (exit != SQLITE_OK) {
41+ //printMessage("Error with command: " + command + " " + messageError);
42+ sqlite3_free(messageError);
43+ throw std::exception();
44+ }
45+ }
46+
47+
48+
49+ auto loadDatabase(std::filesystem::path databasePath) -> void {
50+ bool newCreation = not std::filesystem::exists(databasePath.string());
51+
52+ int exit = 0;
53+ exit = sqlite3_open(databasePath.c_str(), &database);
54+
55+ if (exit) {
56+ std::cerr << "Error opening database" << sqlite3_errmsg(database)
57+ << std::endl;
58+ throw std::exception();
59+ }
60+
61+ //printMessage("Opened database successfully!");
62+
63+ if (newCreation) {
64+ initializeDatabase();
65+ }
66+ }
67+
68+ auto getGames() -> std::vector<Game> {
69+ sqlite3_stmt *stmt;
70+ int exit = 0;
71+ exit = sqlite3_prepare_v2(database, select_all_games_command.c_str(), -1, &stmt, nullptr);
72+
73+ if (exit) {
74+ std::cerr << "Error retrieving data" << sqlite3_errmsg(database)
75+ << std::endl;
76+ sqlite3_close(database);
77+ return {};
78+ }
79+
80+ std::vector<Game> games;
81+ while (sqlite3_step(stmt) == SQLITE_ROW) {
82+ int id = sqlite3_column_int(stmt, 0);
83+ const unsigned char *gameName = sqlite3_column_text(stmt, 1);
84+ const unsigned char *gamePath = sqlite3_column_text(stmt, 2);
85+
86+ games.emplace_back(Game{id, reinterpret_cast<const char *>(gameName),
87+ reinterpret_cast<const char *>(gamePath)});
88+ }
89+ sqlite3_finalize(stmt);
90+ return games;
91+ }
92+};
new file mode 100644
@@ -0,0 +1,92 @@
1+#pragma once
2+
3+#include <sqlite3.h>
4+#include <string>
5+
6+#include <game.hpp>
7+
8+class Database
9+{
10+private:
11+ sqlite3 *database;
12+
13+ std::string database_initialization_command =
14+ "CREATE TABLE games("
15+ "GAME_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
16+ "GAME_NAME TEXT NOT NULL, "
17+ "GAME_PATH TEXT NOT NULL);";
18+ std::string select_all_games_command = "SELECT * FROM games;";
19+
20+ auto initializeDatabase() -> void {
21+ executeSqlCommand(database_initialization_command);
22+ //printMessage("Database Initialized");
23+ }
24+
25+public:
26+
27+ Database(std::filesystem::path databasePath) {
28+ loadDatabase(databasePath);
29+ }
30+
31+ ~Database() {
32+ sqlite3_close(database);
33+ }
34+
35+ auto executeSqlCommand(std::string command) -> void {
36+ int exit = 0;
37+ char *messageError;
38+ exit = sqlite3_exec(database, command.c_str(), nullptr, nullptr, &messageError);
39+
40+ if (exit != SQLITE_OK) {
41+ //printMessage("Error with command: " + command + " " + messageError);
42+ sqlite3_free(messageError);
43+ throw std::exception();
44+ }
45+ }
46+
47+
48+
49+ auto loadDatabase(std::filesystem::path databasePath) -> void {
50+ bool newCreation = not std::filesystem::exists(databasePath.string());
51+
52+ int exit = 0;
53+ exit = sqlite3_open(databasePath.c_str(), &database);
54+
55+ if (exit) {
56+ std::cerr << "Error opening database" << sqlite3_errmsg(database)
57+ << std::endl;
58+ throw std::exception();
59+ }
60+
61+ //printMessage("Opened database successfully!");
62+
63+ if (newCreation) {
64+ initializeDatabase();
65+ }
66+ }
67+
68+ auto getGames() -> std::vector<Game> {
69+ sqlite3_stmt *stmt;
70+ int exit = 0;
71+ exit = sqlite3_prepare_v2(database, select_all_games_command.c_str(), -1, &stmt, nullptr);
72+
73+ if (exit) {
74+ std::cerr << "Error retrieving data" << sqlite3_errmsg(database)
75+ << std::endl;
76+ sqlite3_close(database);
77+ return {};
78+ }
79+
80+ std::vector<Game> games;
81+ while (sqlite3_step(stmt) == SQLITE_ROW) {
82+ int id = sqlite3_column_int(stmt, 0);
83+ const unsigned char *gameName = sqlite3_column_text(stmt, 1);
84+ const unsigned char *gamePath = sqlite3_column_text(stmt, 2);
85+
86+ games.emplace_back(Game{id, reinterpret_cast<const char *>(gameName),
87+ reinterpret_cast<const char *>(gamePath)});
88+ }
89+ sqlite3_finalize(stmt);
90+ return games;
91+ }
92+};
modified app/include/game.hpp +3 -3
@@ -13,7 +13,7 @@ public:
1313 : id{id}, name{name}, path{path} {}
1414 ~Game() {}
1515
16- int getId() { return id; }
17- std::string getName() { return name; }
18- std::string getPath() { return path; }
16+ auto getId() -> int { return id; }
17+ auto getName() -> std::string { return name; }
18+ auto getPath() -> std::string { return path; }
1919 };
@@ -13,7 +13,7 @@ public:
13 : id{id}, name{name}, path{path} {}13 : id{id}, name{name}, path{path} {}
14 ~Game() {}14 ~Game() {}
15 15
16- int getId() { return id; }16+ auto getId() -> int { return id; }
17- std::string getName() { return name; }17+ auto getName() -> std::string { return name; }
18- std::string getPath() { return path; }18+ auto getPath() -> std::string { return path; }
19 };19 };
modified app/src/main.cpp +27 -82
@@ -17,57 +17,34 @@
1717 #include <limits.h>
1818
1919 #include <game.hpp>
20+#include <database.hpp>
2021
2122 using namespace ftxui;
2223
2324 std::vector<Game> games;
2425
25-std::string database_initialization_command =
26- "CREATE TABLE games("
27- "GAME_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
28- "GAME_NAME TEXT NOT NULL, "
29- "GAME_PATH TEXT NOT NULL);";
30-
31-std::string select_all_games_command = "SELECT * FROM games;";
32-
3326 bool debugRun = false;
3427
35-void printMessage(std::string message) {
28+auto printMessage(std::string message) -> void {
3629 if (debugRun) {
3730 std::cout << message << std::endl;
3831 }
3932 }
4033
41-void execute_sql_command(sqlite3 *database, std::string command) {
42- int exit = 0;
43- char *messageError;
44- exit = sqlite3_exec(database, command.c_str(), nullptr, nullptr, &messageError);
45-
46- if (exit != SQLITE_OK) {
47- printMessage("Error with command: " + command + " " + messageError);
48- sqlite3_free(messageError);
49- }
50-}
51-
52-void addGame(sqlite3 *database, std::string name, std::string path) {
34+auto addGame(Database& database, std::string name, std::string path) -> void {
5335 std::string command =
5436 "INSERT INTO games (GAME_NAME, GAME_PATH) VALUES (";
5537 command += "'" + name + "', \"" + path + "\");";
56- execute_sql_command(database, command);
38+ database.executeSqlCommand(command);
5739 }
5840
59-void removeGame(sqlite3 *database, std::string name) {
41+auto removeGame(Database& database, std::string name) -> void{
6042 std::string command = "DELETE FROM games WHERE GAME_NAME=";
6143 command += "'" + name + "';";
62- execute_sql_command(database, command);
63-}
64-
65-void initialize_database(sqlite3 *database) {
66- execute_sql_command(database, database_initialization_command);
67- printMessage("Database Initialized");
44+ database.executeSqlCommand(command);
6845 }
6946
70-void runGame(sqlite3 *database, std::string gameName) {
47+auto runGame(std::string gameName) -> void {
7148 std::string pathToRun = "";
7249 for (auto &game : games) {
7350 if (gameName == game.getName()) {
@@ -77,7 +54,7 @@ void runGame(sqlite3 *database, std::string gameName) {
7754 system(pathToRun.c_str());
7855 }
7956
80-void handleCommand(int argc, char const *argv[], sqlite3 *database) {
57+auto handleCommand(int argc, char const *argv[], Database& database) -> void{
8158 std::string command{};
8259 switch (argc) {
8360 case 2:
@@ -95,7 +72,7 @@ void handleCommand(int argc, char const *argv[], sqlite3 *database) {
9572 removeGame(database, gameName);
9673 } else if (command == "play") {
9774 std::string gameName{argv[2]};
98- runGame(database, gameName);
75+ runGame(gameName);
9976 }
10077 case 4:
10178 command = argv[1];
@@ -120,7 +97,7 @@ void handleCommand(int argc, char const *argv[], sqlite3 *database) {
12097 }
12198 }
12299
123-auto Style() -> ButtonOption {
100+auto style() -> ButtonOption {
124101 auto option = ButtonOption::Border();
125102 option.transform = [](const EntryState &s) {
126103 auto element = text(s.label);
@@ -132,7 +109,7 @@ auto Style() -> ButtonOption {
132109 return option;
133110 }
134111
135-auto runConsoleApp(sqlite3* database) -> void {
112+auto runConsoleApp() -> void {
136113 system("clear");
137114
138115 std::vector<std::string> localGames = {};
@@ -144,12 +121,12 @@ auto runConsoleApp(sqlite3* database) -> void {
144121 auto gamesContainer{Container::Vertical({})};
145122 for (auto &game : games) {
146123 gamesContainer->Add(Button(
147- game.getName(), [&] { runGame(database, game.getName()); }, Style()));
124+ game.getName(), [&] { runGame(game.getName()); }, style()));
148125 }
149126
150127 auto menu_screen = ScreenInteractive::TerminalOutput();
151128
152- auto quitButton = Button("Exit", menu_screen.ExitLoopClosure(), Style());
129+ auto quitButton = Button("Exit", menu_screen.ExitLoopClosure(), style());
153130 gamesContainer->Add(quitButton);
154131
155132 int menuOptionSelected{0};
@@ -170,60 +147,28 @@ auto runConsoleApp(sqlite3* database) -> void {
170147
171148 }
172149
173-std::string getExecutablePath() {
150+auto getExecutablePath() -> std::filesystem::path {
174151 char result[PATH_MAX];
175152 ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
176- return std::string(result, (count > 0) ? count : 0);
153+ return std::filesystem::path(std::string(result, (count > 0) ? count : 0));
177154 }
178155
179156 auto main(int argc, char const *argv[]) -> int {
180- std::filesystem::path appPath{ getExecutablePath() };
181- auto databasePath{ std::filesystem::path(appPath.parent_path().string() + "/data.db")};
182- bool newCreation = not std::filesystem::exists(databasePath.string());
183- char *messageError;
184- sqlite3 *database;
185- sqlite3_stmt *stmt;
186- int exit = 0;
187- exit = sqlite3_open(databasePath.c_str(), &database);
188-
189- if (exit) {
190- std::cerr << "Error opening database" << sqlite3_errmsg(database)
191- << std::endl;
192- return -1;
193- }
194-
195- printMessage("Opened database successfully!");
157+ try {
158+ auto databasePath{ std::filesystem::path(getExecutablePath().parent_path().string() + "/data.db")};
159+ Database database{databasePath};
160+ games = database.getGames();
196161
197- if (newCreation) {
198- initialize_database(database);
199- }
200-
201- exit = sqlite3_prepare_v2(database, select_all_games_command.c_str(), -1, &stmt, nullptr);
202-
203- if (exit) {
204- std::cerr << "Error retrieving data" << sqlite3_errmsg(database)
205- << std::endl;
206- sqlite3_close(database);
207- return -1;
208- }
209-
210- while (sqlite3_step(stmt) == SQLITE_ROW) {
211- int id = sqlite3_column_int(stmt, 0);
212- const unsigned char *gameName = sqlite3_column_text(stmt, 1);
213- const unsigned char *gamePath = sqlite3_column_text(stmt, 2);
214-
215- games.emplace_back(Game{id, reinterpret_cast<const char *>(gameName),
216- reinterpret_cast<const char *>(gamePath)});
217- }
218- sqlite3_finalize(stmt);
219-
220- if (argc > 1) {
221- handleCommand(argc, argv, database);
162+ if (argc > 1) {
163+ handleCommand(argc, argv, database);
164+ }
165+ else {
166+ runConsoleApp();
167+ }
222168 }
223- else {
224- runConsoleApp(database);
169+ catch(...) {
170+ return EXIT_FAILURE;
225171 }
226172
227- sqlite3_close(database);
228173 return EXIT_SUCCESS;
229174 }
\ No newline at end of file
@@ -17,57 +17,34 @@
17 #include <limits.h>17 #include <limits.h>
18 18
19 #include <game.hpp>19 #include <game.hpp>
20+#include <database.hpp>
20 21
21 using namespace ftxui;22 using namespace ftxui;
22 23
23 std::vector<Game> games;24 std::vector<Game> games;
24 25
25-std::string database_initialization_command =
26- "CREATE TABLE games("
27- "GAME_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
28- "GAME_NAME TEXT NOT NULL, "
29- "GAME_PATH TEXT NOT NULL);";
30-
31-std::string select_all_games_command = "SELECT * FROM games;";
32-
33 bool debugRun = false;26 bool debugRun = false;
34 27
35-void printMessage(std::string message) {28+auto printMessage(std::string message) -> void {
36 if (debugRun) {29 if (debugRun) {
37 std::cout << message << std::endl;30 std::cout << message << std::endl;
38 }31 }
39 }32 }
40 33
41-void execute_sql_command(sqlite3 *database, std::string command) {34+auto addGame(Database& database, std::string name, std::string path) -> void {
42- int exit = 0;
43- char *messageError;
44- exit = sqlite3_exec(database, command.c_str(), nullptr, nullptr, &messageError);
45-
46- if (exit != SQLITE_OK) {
47- printMessage("Error with command: " + command + " " + messageError);
48- sqlite3_free(messageError);
49- }
50-}
51-
52-void addGame(sqlite3 *database, std::string name, std::string path) {
53 std::string command =35 std::string command =
54 "INSERT INTO games (GAME_NAME, GAME_PATH) VALUES (";36 "INSERT INTO games (GAME_NAME, GAME_PATH) VALUES (";
55 command += "'" + name + "', \"" + path + "\");";37 command += "'" + name + "', \"" + path + "\");";
56- execute_sql_command(database, command);38+ database.executeSqlCommand(command);
57 }39 }
58 40
59-void removeGame(sqlite3 *database, std::string name) {41+auto removeGame(Database& database, std::string name) -> void{
60 std::string command = "DELETE FROM games WHERE GAME_NAME=";42 std::string command = "DELETE FROM games WHERE GAME_NAME=";
61 command += "'" + name + "';";43 command += "'" + name + "';";
62- execute_sql_command(database, command);44+ database.executeSqlCommand(command);
63-}
64-
65-void initialize_database(sqlite3 *database) {
66- execute_sql_command(database, database_initialization_command);
67- printMessage("Database Initialized");
68 }45 }
69 46
70-void runGame(sqlite3 *database, std::string gameName) {47+auto runGame(std::string gameName) -> void {
71 std::string pathToRun = "";48 std::string pathToRun = "";
72 for (auto &game : games) {49 for (auto &game : games) {
73 if (gameName == game.getName()) {50 if (gameName == game.getName()) {
@@ -77,7 +54,7 @@ void runGame(sqlite3 *database, std::string gameName) {
77 system(pathToRun.c_str());54 system(pathToRun.c_str());
78 }55 }
79 56
80-void handleCommand(int argc, char const *argv[], sqlite3 *database) {57+auto handleCommand(int argc, char const *argv[], Database& database) -> void{
81 std::string command{};58 std::string command{};
82 switch (argc) {59 switch (argc) {
83 case 2:60 case 2:
@@ -95,7 +72,7 @@ void handleCommand(int argc, char const *argv[], sqlite3 *database) {
95 removeGame(database, gameName);72 removeGame(database, gameName);
96 } else if (command == "play") {73 } else if (command == "play") {
97 std::string gameName{argv[2]};74 std::string gameName{argv[2]};
98- runGame(database, gameName);75+ runGame(gameName);
99 }76 }
100 case 4:77 case 4:
101 command = argv[1];78 command = argv[1];
@@ -120,7 +97,7 @@ void handleCommand(int argc, char const *argv[], sqlite3 *database) {
120 }97 }
121 }98 }
122 99
123-auto Style() -> ButtonOption {100+auto style() -> ButtonOption {
124 auto option = ButtonOption::Border();101 auto option = ButtonOption::Border();
125 option.transform = [](const EntryState &s) {102 option.transform = [](const EntryState &s) {
126 auto element = text(s.label);103 auto element = text(s.label);
@@ -132,7 +109,7 @@ auto Style() -> ButtonOption {
132 return option;109 return option;
133 }110 }
134 111
135-auto runConsoleApp(sqlite3* database) -> void {112+auto runConsoleApp() -> void {
136 system("clear");113 system("clear");
137 114
138 std::vector<std::string> localGames = {};115 std::vector<std::string> localGames = {};
@@ -144,12 +121,12 @@ auto runConsoleApp(sqlite3* database) -> void {
144 auto gamesContainer{Container::Vertical({})};121 auto gamesContainer{Container::Vertical({})};
145 for (auto &game : games) {122 for (auto &game : games) {
146 gamesContainer->Add(Button(123 gamesContainer->Add(Button(
147- game.getName(), [&] { runGame(database, game.getName()); }, Style()));124+ game.getName(), [&] { runGame(game.getName()); }, style()));
148 }125 }
149 126
150 auto menu_screen = ScreenInteractive::TerminalOutput();127 auto menu_screen = ScreenInteractive::TerminalOutput();
151 128
152- auto quitButton = Button("Exit", menu_screen.ExitLoopClosure(), Style());129+ auto quitButton = Button("Exit", menu_screen.ExitLoopClosure(), style());
153 gamesContainer->Add(quitButton);130 gamesContainer->Add(quitButton);
154 131
155 int menuOptionSelected{0};132 int menuOptionSelected{0};
@@ -170,60 +147,28 @@ auto runConsoleApp(sqlite3* database) -> void {
170 147
171 }148 }
172 149
173-std::string getExecutablePath() {150+auto getExecutablePath() -> std::filesystem::path {
174 char result[PATH_MAX];151 char result[PATH_MAX];
175 ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);152 ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
176- return std::string(result, (count > 0) ? count : 0);153+ return std::filesystem::path(std::string(result, (count > 0) ? count : 0));
177 }154 }
178 155
179 auto main(int argc, char const *argv[]) -> int {156 auto main(int argc, char const *argv[]) -> int {
180- std::filesystem::path appPath{ getExecutablePath() };157+ try {
181- auto databasePath{ std::filesystem::path(appPath.parent_path().string() + "/data.db")};158+ auto databasePath{ std::filesystem::path(getExecutablePath().parent_path().string() + "/data.db")};
182- bool newCreation = not std::filesystem::exists(databasePath.string());159+ Database database{databasePath};
183- char *messageError;160+ games = database.getGames();
184- sqlite3 *database;
185- sqlite3_stmt *stmt;
186- int exit = 0;
187- exit = sqlite3_open(databasePath.c_str(), &database);
188-
189- if (exit) {
190- std::cerr << "Error opening database" << sqlite3_errmsg(database)
191- << std::endl;
192- return -1;
193- }
194-
195- printMessage("Opened database successfully!");
196 161
197- if (newCreation) {162+ if (argc > 1) {
198- initialize_database(database);163+ handleCommand(argc, argv, database);
199- }164+ }
200-165+ else {
201- exit = sqlite3_prepare_v2(database, select_all_games_command.c_str(), -1, &stmt, nullptr);166+ runConsoleApp();
202-167+ }
203- if (exit) {
204- std::cerr << "Error retrieving data" << sqlite3_errmsg(database)
205- << std::endl;
206- sqlite3_close(database);
207- return -1;
208- }
209-
210- while (sqlite3_step(stmt) == SQLITE_ROW) {
211- int id = sqlite3_column_int(stmt, 0);
212- const unsigned char *gameName = sqlite3_column_text(stmt, 1);
213- const unsigned char *gamePath = sqlite3_column_text(stmt, 2);
214-
215- games.emplace_back(Game{id, reinterpret_cast<const char *>(gameName),
216- reinterpret_cast<const char *>(gamePath)});
217- }
218- sqlite3_finalize(stmt);
219-
220- if (argc > 1) {
221- handleCommand(argc, argv, database);
222 }168 }
223- else {169+ catch(...) {
224- runConsoleApp(database);170+ return EXIT_FAILURE;
225 }171 }
226 172
227- sqlite3_close(database);
228 return EXIT_SUCCESS;173 return EXIT_SUCCESS;
229 }174 }
\ No newline at end of file\ No newline at end of file