From 939719dea2ac98020448d5627b87560ec17e2a23 Mon Sep 17 00:00:00 2001 From: heck Date: Wed, 14 Apr 2021 18:04:21 +0200 Subject: [PATCH] LIB-12: listmanager prototype done --- .clang-format | 3 +- test/test_sqlite3.cc | 294 ++++++++++++++++++++++++++++++------------- 2 files changed, 207 insertions(+), 90 deletions(-) diff --git a/.clang-format b/.clang-format index 04d7370..f2c30cb 100644 --- a/.clang-format +++ b/.clang-format @@ -38,4 +38,5 @@ SpaceAfterTemplateKeyword: false AccessModifierOffset: -4 AllowShortBlocksOnASingleLine: Always IndentPPDirectives: BeforeHash -Cpp11BracedListStyle: false \ No newline at end of file +Cpp11BracedListStyle: false +BreakStringLiterals: false \ No newline at end of file diff --git a/test/test_sqlite3.cc b/test/test_sqlite3.cc index 3b7ca5a..1c22de9 100644 --- a/test/test_sqlite3.cc +++ b/test/test_sqlite3.cc @@ -4,64 +4,96 @@ #include #include #include +#include +#include //TODO: add const - using namespace std; +using namespace pEp; -sqlite3 *db; -string db_path; +using ResultSet = vector>; +using RSRecord = map; -void print_exception(const exception &e, int level = 0) -{ - cerr << string(level, ' ') << "exception: " << e.what() << endl; - try { - rethrow_if_nested(e); - } catch (const exception &e) { - print_exception(e, level + 1); - } catch (...) { - } -} +namespace pEp { + namespace SQLite3 { + ::sqlite3 *db; + string db_path; -static int callback(void *NotUsed, int argc, char **argv, char **azColName) -{ - int i; - for (i = 0; i < argc; i++) { - printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); - } - printf("\n"); - return 0; -} + ResultSet resultset; -void execute_sql(const string &stmt) -{ - // pEpLog("execute_sql(\"" + stmt + "\")"); - char *zErrMsg = nullptr; - int rc = sqlite3_exec(db, stmt.c_str(), callback, 0, &zErrMsg); - if (rc != SQLITE_OK) { - runtime_error e{ string("execute_sql: " + string(sqlite3_errmsg(db)) + ":" + string(zErrMsg)) }; - sqlite3_free(zErrMsg); - throw(e); - } -} + void create_or_open_db() + { + pEpLog("called"); + int rc{::sqlite3_open(db_path.c_str(), &db)}; -void create_or_open_db() -{ - pEpLog("called"); - int rc = sqlite3_open(db_path.c_str(), &db); + if (rc) { + runtime_error e{string("Can't open database (" + db_path + "):" + ::sqlite3_errmsg(db))}; + throw (e); + } + } + + void close_db() + { + ::sqlite3_close(db); + } + + void delete_db() + { + pEpLog("called"); + remove(db_path.c_str()); + if (errno) { + cerr << "could not delete db (" + db_path + "): " << strerror(errno) << endl; + } + } + + ResultSet execute(const string& stmt) + { + // pEpLog("execute(\"" + stmt + "\")"); + resultset.clear(); + char *zErrMsg = nullptr; + int rc = ::sqlite3_exec(db, stmt.c_str(), [](void *NotUsed, int argc, char **argv, char **azColName) -> int { + RSRecord record; + for (int col = 0; col < argc; col++) { + const string key = string{azColName[col]}; + // TODO: NULL is not correct, could be a valid value + const string val = string{argv[col] ? argv[col] : "NULL"}; + record.insert({key, val}); + } + resultset.push_back(record); + return 0; + }, 0, &zErrMsg); + if (rc != SQLITE_OK) { + runtime_error e{string("execute: " + string(::sqlite3_errmsg(db)) + ":" + string(zErrMsg))}; + ::sqlite3_free(zErrMsg); + throw (e); + } + return resultset; + } - if (rc) { - runtime_error e{ string("Can't open database (" + db_path + "):" + sqlite3_errmsg(db)) }; - throw(e); + string resultset_to_string(ResultSet rs) + { + stringstream ss; + int i = 0; + for (const RSRecord& rec : rs) { + for (const auto& item : rec) { + ss << "RESULTSET[" << i << "][" << item.first << "] = " << item.second << "\"" << endl; + } + i++; + } + return ss.str(); + } } } -void delete_db() + +void print_exception(const exception& e, int level = 0) { - pEpLog("called"); - remove(db_path.c_str()); - if (errno) { - cerr << "could not delete db (" + db_path + "): " << strerror(errno) << endl; + cerr << string(level, ' ') << "exception: " << e.what() << endl; + try { + rethrow_if_nested(e); + } catch (const exception& e) { + print_exception(e, level + 1); + } catch (...) { } } @@ -71,7 +103,7 @@ void db_config() try { string sql; sql = "PRAGMA foreign_keys=ON"; - execute_sql(sql); + SQLite3::execute(sql); } catch (...) { runtime_error e("db_config() - failed with exception"); throw_with_nested(e); @@ -85,123 +117,207 @@ void create_tables() string sql; sql = "CREATE TABLE IF NOT EXISTS lists(" - "address TEXT NOT NULL," - "manager_id TEXT NOT NULL," + "address TEXT NOT NULL," + "moderator_address TEXT NOT NULL," "PRIMARY KEY(address));"; - execute_sql(sql); + SQLite3::execute(sql); sql = "CREATE TABLE IF NOT EXISTS member_of(" "address TEXT NOT NULL," "list_address TEXT NOT NULL," "PRIMARY KEY (address, list_address)," "FOREIGN KEY(list_address) REFERENCES lists(address) ON DELETE CASCADE);"; - execute_sql(sql); + SQLite3::execute(sql); } catch (...) { runtime_error e("create_tables() - failed with exception"); throw_with_nested(e); } } -void list_add(const string &addr_list, const string &addr_mgr) +void list_add(const string& addr_list, const string& addr_mgr) { - pEpLog("list_add(addr_list: \"" + addr_list + "\"\taddr_mgr: \"" + addr_mgr + "\")"); + pEpLog("list_add(addr_list: \"" + addr_list + "\", addr_mgr: \"" + addr_mgr + "\")"); try { - string sql = "INSERT INTO lists(address, manager_id)" - "VALUES ('" + - addr_list + "','" + addr_mgr + "');"; - execute_sql(sql); + string sql = "INSERT INTO lists(address, moderator_address) VALUES ('" + addr_list + "','" + + addr_mgr + "');"; + SQLite3::execute(sql); } catch (...) { runtime_error e( - "list_add(addr_list: \"" + addr_list + "\"\taddr_mgr: \"" + addr_mgr + - "\") - failed with exception"); + "list_add(addr_list: \"" + addr_list + "\"\taddr_mgr: \"" + addr_mgr + + "\") - failed with exception"); throw_with_nested(e); } } -void list_delete(const string &addr_list) +void list_delete(const string& addr_list) { pEpLog("list_delete(addr_list: \"" + addr_list + "\")"); try { string sql; - sql = "DELETE FROM lists WHERE lists.address = '" + addr_list + "'"; - execute_sql(sql); + sql = "DELETE FROM lists WHERE lists.address = '" + addr_list + "';"; + SQLite3::execute(sql); } catch (...) { runtime_error e("list_delete(addr_list: \"" + addr_list + "\") - failed with exception"); throw_with_nested(e); } } -void member_add(const string &addr_list, const string &addr_member) +void member_add(const string& addr_list, const string& addr_member) { pEpLog("member_add(addr_list: \"" + addr_list + "\", addr_member: \"" + addr_member + "\")"); try { - string sql = "INSERT INTO member_of(address, list_address)" - "VALUES ('" + - addr_member + - "'," - "'" + - addr_list + "');"; - execute_sql(sql); + string sql = "INSERT INTO member_of(address, list_address) VALUES ('" + addr_member + + "', '" + addr_list + "');"; + SQLite3::execute(sql); } catch (...) { runtime_error e( - "member_add(addr_list: \"" + addr_list + "\", addr_member: \"" + addr_member + - "\") - failed with exception"); + "member_add(addr_list: \"" + addr_list + "\", addr_member: \"" + addr_member + + "\") - failed with exception"); throw_with_nested(e); } } -void member_remove(const string &addr_list, const string &addr_member) +void member_remove(const string& addr_list, const string& addr_member) { pEpLog("member_remove(addr_list: \"" + addr_list + "\", addr_member: '\"" + addr_member + "\")"); try { string sql; - sql = "DELETE FROM member_of WHERE" - "(member_of.address = '" + - addr_member + "') AND (member_of.list_address = '" + addr_list + "');"; - execute_sql(sql); + sql = "DELETE FROM member_of WHERE (member_of.address = '" + addr_member + + "') AND (member_of.list_address = '" + addr_list + "');"; + SQLite3::execute(sql); } catch (...) { runtime_error e( - "member_remove(" + addr_list + ", " + addr_member + ") - failed with exception"); + "member_remove(" + addr_list + ", " + addr_member + ") - failed with exception"); throw_with_nested(e); } } +vector lists() +{ + pEpLog("called"); + vector ret; + ResultSet rs; + + try { + string sql; + sql = "SELECT address FROM lists"; + rs = SQLite3::execute(sql); + } catch (...) { + runtime_error e("lists() - failed with exception"); + throw_with_nested(e); + } + + for (const RSRecord& rec : rs) { + ret.push_back(rec.at("address")); + } + + return ret; +} + +// Exceptions: +// * ListNotFound +string moderator(string list_address) +{ + pEpLog("called"); + string ret; + ResultSet rs; + + try { + string sql; + sql = "SELECT moderator_address FROM lists " + "WHERE lists.address = '" + list_address + "';"; + rs = SQLite3::execute(sql); + } catch (...) { + runtime_error e("lists() - failed with exception"); + throw_with_nested(e); + } + + if (!rs.empty()) { + for (const RSRecord& rec : rs) { + ret = rec.at("moderator_address"); + } + } + + return ret; +} + +// Exceptions: +// * ListNotFound +vector members(string list_address) +{ + pEpLog("called"); + vector ret; + ResultSet rs; + + try { + string sql; + sql = "SELECT address FROM member_of " + "WHERE list_address = '" + list_address + "'"; + rs = SQLite3::execute(sql); + } catch (...) { + runtime_error e("lists() - failed with exception"); + throw_with_nested(e); + } + + if (!rs.empty()) { + for (const RSRecord& rec : rs) { + ret.push_back(rec.at("address")); + } + } + + return ret; +} + +template +string vector_to_string(vector v) +{ + stringstream ss; + for (const T& elem : v) { + ss << elem << endl; + } + return ss.str(); +} + int main(int argc, char *argv[]) { pEp::Adapter::pEpLog::set_enabled(true); - db_path = "test.db"; + SQLite3::db_path = "test.db"; string dummy_in; + + try { - delete_db(); - create_or_open_db(); - cin >> dummy_in; + SQLite3::db_path = "test.db"; + SQLite3::delete_db(); + SQLite3::create_or_open_db(); db_config(); create_tables(); list_add("grp1@peptest.org", "alice@peptest.org"); + cout << vector_to_string(lists()); list_add("grp2@peptest.org", "alice@peptest.org"); + cout << vector_to_string(lists()); + try { list_add("grp1@peptest.org", "bob@peptest.org"); assert(false); - } catch (const exception &e) { + } catch (const exception& e) { print_exception(e); } - cin >> dummy_in; member_add("grp1@peptest.org", "bob@peptest.org"); member_add("grp1@peptest.org", "carol@peptest.org"); member_add("grp1@peptest.org", "joe@peptest.org"); - cin >> dummy_in; + cout << vector_to_string(members("grp1@peptest.org")) << endl; + + cout << moderator("grp1@peptest.org") << endl; member_remove("grp1@peptest.org", "joe@peptest.org"); - cin >> dummy_in; list_delete("grp1@peptest.org"); - - cin >> dummy_in; - } catch (const exception &e) { + cout << vector_to_string(lists()); + } catch (const exception& e) { print_exception(e); } - sqlite3_close(db); + SQLite3::close_db(); } \ No newline at end of file