From 861ea2c8090c11a800a2572fc6132594129ee8cb Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sat, 12 Dec 2015 20:20:57 +0000 Subject: [PATCH] Implement deleting sets from the db. --- include/helpers/infix_iterator.hpp | 48 ++++++++++++++++++++ src/delete/CMakeLists.txt | 1 + src/delete/main.cpp | 43 ++++++++++++++++-- src/delete/postgre_delete.cpp | 73 ++++++++++++++++++++++++++++++ src/delete/postgre_delete.hpp | 38 ++++++++++++++++ 5 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 include/helpers/infix_iterator.hpp create mode 100644 src/delete/postgre_delete.cpp create mode 100644 src/delete/postgre_delete.hpp diff --git a/include/helpers/infix_iterator.hpp b/include/helpers/infix_iterator.hpp new file mode 100644 index 0000000..ca65e34 --- /dev/null +++ b/include/helpers/infix_iterator.hpp @@ -0,0 +1,48 @@ +// see http://stackoverflow.com/questions/3496982/printing-lists-with-commas-c/3497021#3497021 +// infix_iterator.h +// +// Lifted from Jerry Coffin's 's prefix_ostream_iterator +#if !defined(INFIX_ITERATOR_H_) +#define INFIX_ITERATOR_H_ +#include +#include +template > +class infix_ostream_iterator : + public std::iterator +{ + std::basic_ostream *os; + charT const* delimiter; + bool first_elem; +public: + typedef charT char_type; + typedef traits traits_type; + typedef std::basic_ostream ostream_type; + infix_ostream_iterator(ostream_type& s) + : os(&s),delimiter(0), first_elem(true) + {} + infix_ostream_iterator(ostream_type& s, charT const *d) + : os(&s),delimiter(d), first_elem(true) + {} + infix_ostream_iterator& operator=(T const &item) + { + // Here's the only real change from ostream_iterator: + // Normally, the '*os << item;' would come before the 'if'. + if (!first_elem && delimiter != 0) + *os << delimiter; + *os << item; + first_elem = false; + return *this; + } + infix_ostream_iterator &operator*() { + return *this; + } + infix_ostream_iterator &operator++() { + return *this; + } + infix_ostream_iterator &operator++(int) { + return *this; + } +}; +#endif diff --git a/src/delete/CMakeLists.txt b/src/delete/CMakeLists.txt index affee67..7a59ab5 100644 --- a/src/delete/CMakeLists.txt +++ b/src/delete/CMakeLists.txt @@ -3,6 +3,7 @@ project(${bare_name}-delete CXX C) add_executable(${PROJECT_NAME} main.cpp commandline.cpp + postgre_delete.cpp ) target_include_directories(${PROJECT_NAME} diff --git a/src/delete/main.cpp b/src/delete/main.cpp index e62e94a..60412d0 100644 --- a/src/delete/main.cpp +++ b/src/delete/main.cpp @@ -16,10 +16,32 @@ */ #include "commandline.hpp" +#include "dindexer-common/settings.hpp" +#include "dindexerConfig.h" +#include "postgre_delete.hpp" #include +#include +#include #include #include +namespace { + bool confirm_delete (const din::IDDescMap& parMap) { + for (const auto& itm : parMap) { + std::cout << "ID " << itm.first << '\t' << itm.second << '\n'; + } + std::cout << "Confirm deleting these sets? (Y/n)" << std::endl; + std::string answer; + std::cin >> std::noskipws >> answer >> std::skipws; + + return (answer.empty() or "y" == answer or "Y" == answer); + } + + bool always_delete (const din::IDDescMap&) { + return true; + } +} //unnamed namespace + int main (int parArgc, char* parArgv[]) { using boost::program_options::variables_map; @@ -38,12 +60,23 @@ int main (int parArgc, char* parArgv[]) { return 2; } - auto ids = vm["groupid"].as>(); - std::cout << "Would delete " << ids.size() << " ids: "; - for (auto n : ids) { - std::cout << n << ", "; + dinlib::Settings settings; + { + const bool loaded = dinlib::load_settings(CONFIG_FILE_PATH, settings); + if (not loaded) { + std::cerr << "Can't load settings from " << CONFIG_FILE_PATH << ", quitting\n"; + return 1; + } } - std::cout << std::endl; + + if (not vm.count("groupid")) { + std::cerr << "No IDs specified\n"; + return 2; + } + + const auto ids = vm["groupid"].as>(); + auto confirm_func = (vm.count("confirm") ? &always_delete : &confirm_delete); + din::delete_group_from_db(settings.db, ids, confirm_func); return 0; } diff --git a/src/delete/postgre_delete.cpp b/src/delete/postgre_delete.cpp new file mode 100644 index 0000000..b940e74 --- /dev/null +++ b/src/delete/postgre_delete.cpp @@ -0,0 +1,73 @@ +/* Copyright 2015, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "dindexer". If not, see . + */ + +#include "postgre_delete.hpp" +#include "pq/connection.hpp" +#include "dindexer-common/settings.hpp" +#include "helpers/infix_iterator.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace din { + namespace { + IDDescMap fetch_existing_ids (pq::Connection& parConn, const std::vector& parIDs) { + IDDescMap retmap; + if (parIDs.empty()) { + return std::move(retmap); + } + + std::ostringstream oss; + oss << "SELECT \"id\",\"desc\" FROM \"sets\" WHERE \"id\"="; + boost::copy(parIDs, infix_ostream_iterator(oss, " OR \"id\"=")); + oss << ';'; + + auto resultset = parConn.query(oss.str()); + for (const auto& record : resultset) { + retmap[std::stoul(record["id"])] = record["desc"]; + } + return std::move(retmap); + } + } //unnamed namespace + + void delete_group_from_db (const dinlib::SettingsDB& parDB, const std::vector& parIDs, ConfirmDeleCallback parConf) { + pq::Connection conn(std::string(parDB.username), std::string(parDB.password), std::string(parDB.dbname), std::string(parDB.address), parDB.port); + conn.connect(); + const auto dele_ids = fetch_existing_ids(conn, parIDs); + if (dele_ids.empty()) { + return; + } + if (not parConf(dele_ids)) { + return; + } + + std::vector ids; + ids.reserve(dele_ids.size()); + std::ostringstream oss; + oss << "BEGIN;\nDELETE FROM \"files\" WHERE \"group_id\"="; + boost::copy(dele_ids | boost::adaptors::map_keys, infix_ostream_iterator(oss, " OR \"group_id\"=")); + oss << ";\nDELETE FROM \"sets\" WHERE \"id\"="; + boost::copy(dele_ids | boost::adaptors::map_keys, infix_ostream_iterator(oss, " OR \"id\"=")); + oss << ";\nCOMMIT;"; + + conn.query_void(oss.str()); + } +} //namespace din diff --git a/src/delete/postgre_delete.hpp b/src/delete/postgre_delete.hpp new file mode 100644 index 0000000..308d06e --- /dev/null +++ b/src/delete/postgre_delete.hpp @@ -0,0 +1,38 @@ +/* Copyright 2015, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "dindexer". If not, see . + */ + +#ifndef idB070B86E0E4047B1AF4144DEF2759F3C +#define idB070B86E0E4047B1AF4144DEF2759F3C + +#include +#include +#include +#include +#include + +namespace dinlib { + struct SettingsDB; +} //namespace dinlib + +namespace din { + using IDDescMap = std::map; + using ConfirmDeleCallback = std::function; + + void delete_group_from_db ( const dinlib::SettingsDB& parDB, const std::vector& parIDs, ConfirmDeleCallback parConf ); +} //namespace din + +#endif