DBapp logic
This commit is contained in:
parent
873929cd83
commit
5f29d179d7
CT1/database
|
@ -0,0 +1,221 @@
|
|||
#include <sqlite3.h>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
#define RESET "\033[0m"
|
||||
#define RED "❌ \033[31m"
|
||||
#define GREEN "✅ \033[32m"
|
||||
#define BOLDWHITE "\033[1m\033[37m"
|
||||
|
||||
constexpr const char* DB_FILE = "users.db";
|
||||
constexpr const char* MENU_MSG = "=== Database Management System ===\n1. Connect to database\n2. Execute custom SQL query\n3. Execute prepared SQL query\n4. Setup demo database\n5. Exit\n";
|
||||
constexpr const char* MENU_PREP_MSG = "=== Prepared Statement Menu: Select statement type ===\n1. SELECT\n2. INSERT\n3. EXIT\n";
|
||||
constexpr const char* MENU_PREP_COL_MSG = "=== Prepared Statement Menu: Select filter culumn ===\n1. Connect to database\n2. Execute custom SQL query\n3. Execute prepared SQL query\n4. Setup demo database\n5. Exit\n";
|
||||
constexpr const char* MENU_PREP_TYPE_MSG = "=== Prepared Statement Menu: Select filter type ===\n1. Connect to database\n2. Execute custom SQL query\n3. Execute prepared SQL query\n4. Setup demo database\n5. Exit\n";
|
||||
|
||||
constexpr const char* DEMO_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS users (ID INTEGER PRIMARY KEY AUTOINCREMENT, FirstName varchar(255) NOT NULL, LastName varchar(255) NOT NULL, Age int);";
|
||||
constexpr const char* DEMO_INSERT1 = "INSERT INTO users (FirstName, LastName, Age) VALUES ('Tedd', 'Chadwick', 23)";
|
||||
constexpr const char* DEMO_INSERT2 = "INSERT INTO users (FirstName, LastName, Age) VALUES ('Kathe', 'Claris', 31)";
|
||||
constexpr const char* DEMO_INSERT3 = "INSERT INTO users (FirstName, LastName, Age) VALUES ('Meryl', 'Chadwick', NULL)";
|
||||
constexpr const char* DEMO_SELECT1 = "SELECT * FROM users;";
|
||||
constexpr const char* DEMO_SELECT2 = "SELECT * FROM users WHERE LastName is 'Chadwick';";
|
||||
|
||||
class DatabaseException : public std::exception {
|
||||
public:
|
||||
explicit DatabaseException() = default;
|
||||
DatabaseException(const char *errMsg) : errMsg(errMsg) {}
|
||||
const char* what() const noexcept override {
|
||||
return "Internal exception!";
|
||||
}
|
||||
private:
|
||||
const char *errMsg;
|
||||
};
|
||||
class InvalidArgument : public DatabaseException {
|
||||
const char* what() const noexcept override {
|
||||
return "Invalid argument!";
|
||||
}
|
||||
};
|
||||
class SQLiteException : public DatabaseException {
|
||||
public:
|
||||
SQLiteException(char *errMsg) : DatabaseException(), errMsg(errMsg) {}
|
||||
const char* what() const noexcept override {
|
||||
return errMsg;
|
||||
}
|
||||
~SQLiteException() {
|
||||
sqlite3_free((void*)(errMsg));
|
||||
}
|
||||
private:
|
||||
char *errMsg;
|
||||
};
|
||||
|
||||
enum class MenuState {
|
||||
MENU,
|
||||
CONNECT = 1,
|
||||
QUERY_CUSTOM = 2,
|
||||
QUERY_PREPARED = 3,
|
||||
SETUP_DEMO = 4,
|
||||
EXIT = 5,
|
||||
};
|
||||
|
||||
enum class StatementMenuState {
|
||||
MENU,
|
||||
SELECT = 1,
|
||||
INSERT = 2,
|
||||
EXIT = 3,
|
||||
};
|
||||
|
||||
enum class ColumnMenuState {
|
||||
MENU,
|
||||
FIRST_NAME = 1,
|
||||
SECOND_NAME = 2,
|
||||
AGE = 3,
|
||||
EXIT = 4,
|
||||
};
|
||||
|
||||
enum class FilterMenuState {
|
||||
MENU,
|
||||
IS = 1,
|
||||
IS_NOT = 2,
|
||||
LESS = 3,
|
||||
GREATER = 4,
|
||||
EXIT = 5,
|
||||
};
|
||||
|
||||
std::istream& operator>>(std::istream& is, MenuState& state) {
|
||||
int a;
|
||||
if (!(is >> a)) {
|
||||
is.clear();
|
||||
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
throw InvalidArgument();
|
||||
}
|
||||
|
||||
state = static_cast<MenuState>(a);
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
bool dbConnect(sqlite3** db, std::ostream& os) {
|
||||
int rc;
|
||||
|
||||
os << "Connecting to SQLite...";
|
||||
if (*db) {
|
||||
constexpr const char* errMsg = "Already connected!";
|
||||
throw DatabaseException(errMsg);
|
||||
}
|
||||
|
||||
rc = sqlite3_open(DB_FILE, db);
|
||||
if (rc != SQLITE_OK) {
|
||||
constexpr const char* errMsg = "Connecting failed!";
|
||||
throw DatabaseException(errMsg);
|
||||
}
|
||||
|
||||
os << GREEN << "Connected\n" << RESET;
|
||||
return true;
|
||||
}
|
||||
|
||||
int printQuery(void *os_vp, int argc, char **argv, char **colName) {
|
||||
std::ostream& os = *static_cast<std::ostream*>(os_vp); // oh god...
|
||||
for (int i = 0; i < argc; i++) {
|
||||
os << colName[i] << " = " << (argv[i] ? argv[i] : "NULL") << '\n';
|
||||
}
|
||||
os << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sendQuery(sqlite3* db, std::ostream& os, const char* q, int (*callback)(void *, int, char **, char **)) {
|
||||
int rc;
|
||||
char* errMsg;
|
||||
void* os_p = &os; // oh god...
|
||||
|
||||
os << "Sending query: '" << q << "'...";
|
||||
rc = sqlite3_exec(db, q, callback, os_p, &errMsg);
|
||||
if (rc != SQLITE_OK) {
|
||||
throw SQLiteException(errMsg);
|
||||
}
|
||||
os << GREEN << "Successful\n" << RESET;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setupDemo(sqlite3** db, std::ostream& os) {
|
||||
dbConnect(db, os);
|
||||
|
||||
os << "Creating table 'users':\n";
|
||||
sendQuery(*db, os, DEMO_CREATE_TABLE, nullptr);
|
||||
|
||||
os << "Adding records:\n";
|
||||
sendQuery(*db, os, DEMO_INSERT1, nullptr);
|
||||
sendQuery(*db, os, DEMO_INSERT2, nullptr);
|
||||
sendQuery(*db, os, DEMO_INSERT3, nullptr);
|
||||
|
||||
os << "Testing queries:\n";
|
||||
sendQuery(*db, os, DEMO_SELECT1, printQuery);
|
||||
sendQuery(*db, os, DEMO_SELECT2, printQuery);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool preparedStatementMenu(sqlite3* db, std::ostream& os, std::istream& is) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool executePrepared(sqlite3* db, std::ostream& os) {
|
||||
|
||||
}
|
||||
|
||||
int main(int ragc, char* argv[]) {
|
||||
std::ostream& os = std::cout;
|
||||
std::istream& is = std::cin;
|
||||
|
||||
MenuState state = MenuState::MENU;
|
||||
|
||||
sqlite3* db = nullptr;
|
||||
std::string userInput;
|
||||
|
||||
for (;;) {
|
||||
userInput.clear();
|
||||
try {
|
||||
os << BOLDWHITE << MENU_MSG << RESET;
|
||||
is >> state;
|
||||
is.clear();
|
||||
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
|
||||
switch (state) {
|
||||
case MenuState::CONNECT :
|
||||
dbConnect(&db, os);
|
||||
break;
|
||||
|
||||
case MenuState::QUERY_CUSTOM :
|
||||
os << "> ";
|
||||
std::getline(is, userInput);
|
||||
if(is.bad()) throw DatabaseException("Input error!");
|
||||
sendQuery(db, os, userInput.c_str(), printQuery);
|
||||
break;
|
||||
|
||||
case MenuState::QUERY_PREPARED :
|
||||
os << "Account number: ";
|
||||
os << GREEN << "Balance: " << "$" << "\n" << RESET;
|
||||
break;
|
||||
|
||||
case MenuState::SETUP_DEMO :
|
||||
setupDemo(&db, os);
|
||||
break;
|
||||
|
||||
case MenuState::EXIT :
|
||||
os << "Exiting...\n";
|
||||
sqlite3_close(db);
|
||||
return EXIT_SUCCESS;
|
||||
break;
|
||||
|
||||
case MenuState::MENU :
|
||||
default:
|
||||
throw InvalidArgument();
|
||||
}
|
||||
} catch (DatabaseException& e) {
|
||||
os << RED << e.what() << RESET;
|
||||
// return EXIT_FAILURE;
|
||||
}
|
||||
state = MenuState::MENU;
|
||||
os << "\n\n";
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue