diff --git a/src/navigate/CMakeLists.txt b/src/navigate/CMakeLists.txt index 44cfe5f..5069141 100644 --- a/src/navigate/CMakeLists.txt +++ b/src/navigate/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(${PROJECT_NAME} commandline.cpp commandprocessor.cpp genericpath.cpp + dbsource.cpp ) target_include_directories(${PROJECT_NAME} diff --git a/src/navigate/dbsource.cpp b/src/navigate/dbsource.cpp new file mode 100644 index 0000000..2a5bce3 --- /dev/null +++ b/src/navigate/dbsource.cpp @@ -0,0 +1,96 @@ +/* Copyright 2016, 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 "dbsource.hpp" +#include "dindexer-common/settings.hpp" +#include "pq/connection.hpp" +#include "helpers/infix_iterator.hpp" +#include +#include +#include +#include +#include + +namespace din { + struct DBSource::LocalData { + explicit LocalData ( const dinlib::SettingsDB& parDBSettings ) : + conn( + std::string(parDBSettings.username), + std::string(parDBSettings.password), + std::string(parDBSettings.dbname), + std::string(parDBSettings.address), + parDBSettings.port + ) + { + } + + pq::Connection conn; + }; + + DBSource::DBSource (const dinlib::SettingsDB& parDBSettings) : + m_local_data(new LocalData(parDBSettings)) + { + assert(not m_local_data->conn.is_connected()); + } + + DBSource::~DBSource() noexcept { + } + + void DBSource::disconnect() { + if (m_local_data->conn.is_connected()) { + m_local_data->conn.disconnect(); + } + } + + pq::Connection& DBSource::get_conn() { + if (not m_local_data->conn.is_connected()) { + m_local_data->conn.connect(); + } + return m_local_data->conn; + } + + std::vector DBSource::sets() { + using boost::lexical_cast; + + auto& conn = get_conn(); + const std::string query = "SELECT \"id\" FROM \"sets\";"; + auto res = conn.query(query); + std::vector retval; + + retval.reserve(res.size()); + for (const auto& row : res) { + retval.push_back(lexical_cast(row[0])); + } + return std::move(retval); + } + + void DBSource::query_push_results (const std::vector& parCols, boost::string_ref parTable, const std::vector& parIDs, std::function parCallback) { + std::ostringstream oss; + oss << "SELECT \""; + boost::copy(parCols, infix_ostream_iterator(oss, "\", \"")); + oss << '"'; + oss << " FROM \"" << parTable << "\" WHERE \"id\" = ANY($1) ORDER BY \"desc\" ASC LIMIT 500;"; + + auto& conn = get_conn(); + auto result = conn.query(oss.str(), parIDs); + for (auto row : result) { + for (auto val : row) { + parCallback(std::move(val)); + } + } + } +} //namespace din diff --git a/src/navigate/dbsource.hpp b/src/navigate/dbsource.hpp new file mode 100644 index 0000000..d139fc8 --- /dev/null +++ b/src/navigate/dbsource.hpp @@ -0,0 +1,105 @@ +/* Copyright 2016, 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 id63F35BA8B3C94A129291D963ABE66018 +#define id63F35BA8B3C94A129291D963ABE66018 + +#include "dindexer-machinery/recorddata.hpp" +#include "flatinsertin2dlist.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dinlib { + struct SettingsDB; +} //namespace dinlib + +namespace pq { + class Connection; +} //namespace pq + +namespace din { + enum SetDetails { + SetDetail_Desc = 0x01, + SetDetail_Type = 0x02, + SetDetail_CreeationDate = 0x04, + SetDetail_AppName = 0x08, + SetDetail_ID = 0x10 + }; + + class DBSource { + public: + explicit DBSource ( const dinlib::SettingsDB& parDBSettings ); + ~DBSource ( void ) noexcept; + + void disconnect ( void ); + std::vector sets ( void ); + + template + std::vector> set_details ( const std::vector& parIDs ); + //TODO: replace return value with vector of maxsizedarray + //auto set_details ( const std::vector& parIDs ) -> std::array; + + private: + struct LocalData; + + pq::Connection& get_conn ( void ); + void query_push_results ( const std::vector& parCols, boost::string_ref parTable, const std::vector& parIDs, std::function parCallback ); + + std::unique_ptr m_local_data; + }; + + template + std::vector> DBSource::set_details (const std::vector& parIDs) { + //auto DBSource::set_details (const std::vector& parIDs) -> std::array { + typedef std::vector> ReturnType; + typedef std::map DetailsMap; + typedef const std::string&(DetailsMap::*AtFunc)(const SetDetails&) const; + typedef void(din::FlatInsertIn2DList::*FlatPushBackFunc)(const std::string&); + + const std::array details { D... }; + const DetailsMap details_dic { + {SetDetail_Desc, "desc"}, + {SetDetail_Type, "type"}, + {SetDetail_CreeationDate, "creation"}, + {SetDetail_AppName, "app_name"}, + {SetDetail_ID, "id"} + }; + + std::vector columns; + columns.reserve(sizeof...(D)); + AtFunc at_func = &DetailsMap::at; + //std::generate(details.begin(), details.end(), columns.begin(), std::bind(at_func, &details_dic, std::placeholders::_1)); + for (auto detail : details) { + columns.push_back(details_dic.at(detail)); + } + + ReturnType list; + FlatInsertIn2DList flat_list(&list, sizeof...(D)); + FlatPushBackFunc pback_func = &FlatInsertIn2DList::push_back; + this->query_push_results(columns, "sets", parIDs, std::bind(pback_func, &flat_list, std::placeholders::_1)); + return std::move(list); + } +} //namespace din + +#endif diff --git a/src/navigate/flatinsertin2dlist.hpp b/src/navigate/flatinsertin2dlist.hpp new file mode 100644 index 0000000..ce07726 --- /dev/null +++ b/src/navigate/flatinsertin2dlist.hpp @@ -0,0 +1,51 @@ +/* Copyright 2016, 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 idAA901DA47E234E37B325B3192EF50423 +#define idAA901DA47E234E37B325B3192EF50423 + +#include +#include +#include +#include +#include + +namespace din { + template + class FlatInsertIn2DList { + public: + typedef OuterList list_type; + typedef InnerVal value_type; + typedef InnerList inner_list_type; + + FlatInsertIn2DList ( list_type* parList, std::size_t parInnerCount, std::size_t parOuterCount=0 ); + void push_back ( value_type&& parValue ); + void push_back ( const value_type& parValue ); + std::size_t size ( void ) const; + + private: + void expand_array ( void ); + + list_type* const m_list; + const std::size_t m_inner_count; + const std::size_t m_outer_count; + }; +} //namespace din + +#include "flatinsertin2dlist.inl" + +#endif diff --git a/src/navigate/flatinsertin2dlist.inl b/src/navigate/flatinsertin2dlist.inl new file mode 100644 index 0000000..186c81e --- /dev/null +++ b/src/navigate/flatinsertin2dlist.inl @@ -0,0 +1,73 @@ +/* Copyright 2016, 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 . + */ + +namespace din { + template + FlatInsertIn2DList::FlatInsertIn2DList (list_type* parList, std::size_t parInnerCount, std::size_t parOuterCount) : + m_list(parList), + m_inner_count(parInnerCount), + m_outer_count(parOuterCount) + { + assert(m_list); + if (m_outer_count) { + m_list->reserve(m_outer_count); + } + } + + template + void FlatInsertIn2DList::push_back (value_type&& parValue) { + expand_array(); + const auto curr_outer_index = m_list->size() - 1; + (*m_list)[curr_outer_index].push_back(std::move(parValue)); + } + + template + void FlatInsertIn2DList::push_back (const value_type& parValue) { + expand_array(); + const auto curr_outer_index = m_list->size() - 1; + (*m_list)[curr_outer_index].push_back(parValue); + } + + template + void FlatInsertIn2DList::expand_array() { + auto& list = *m_list; + const auto inner_size = (list.empty() ? m_inner_count : list[list.size() - 1].size()); + if (inner_size == m_inner_count) { + if (not m_outer_count or m_outer_count < list.size()) { + list.push_back(inner_list_type()); + list[list.size() - 1].reserve(m_inner_count); + } + else { + throw std::runtime_error("Outer list is full"); + } + } + + assert(not m_outer_count or list.size() <= m_outer_count); + assert(list.size() > 0); + assert(list[list.size() - 1].size() <= m_inner_count); + } + + template + std::size_t FlatInsertIn2DList::size() const { + if (m_list->empty()) { + return 0; + } + else { + return (m_list->size() - 1) * m_inner_count + m_list[m_list->size() - 1].size(); + } + } +} //namespace din diff --git a/src/navigate/main.cpp b/src/navigate/main.cpp index a7eb2e8..2430e74 100644 --- a/src/navigate/main.cpp +++ b/src/navigate/main.cpp @@ -17,19 +17,24 @@ #include "commandline.hpp" #include "commandprocessor.hpp" +#include "dindexer-common/settings.hpp" #include "genericpath.hpp" +#include "dbsource.hpp" +#include "dindexerConfig.h" +#include "helpers/infix_iterator.hpp" #include #include #include #include #include +#include namespace { - void do_navigation ( void ); + void do_navigation ( din::DBSource& parDB ); bool on_exit ( void ); void on_pwd ( const din::GenericPath& parDirMan ); - void on_ls ( const din::GenericPath& parDirMan ); + void on_ls ( const din::GenericPath& parDirMan, din::DBSource& parDB ); } //unnamed namespace int main (int parArgc, char* parArgv[]) { @@ -46,7 +51,18 @@ int main (int parArgc, char* parArgv[]) { return 2; } - do_navigation(); + 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; + } + } + + din::DBSource db_source(settings.db); + + do_navigation(db_source); return 0; } @@ -59,8 +75,15 @@ namespace { std::cout << parDirMan.to_string() << '\n'; } - void on_ls (const din::GenericPath& parDirMan) { + void on_ls (const din::GenericPath& parDirMan, din::DBSource& parDB) { + using namespace din; + auto sets_ids = parDB.sets(); + auto sets_info = parDB.set_details(sets_ids); + for (const auto& row : sets_info) { + boost::copy(row, infix_ostream_iterator(std::cout, "\t")); + std::cout << "\n"; + } } void do_navigation (din::DBSource& parDB) { @@ -74,7 +97,7 @@ namespace { proc.add_command("cd", std::function(std::bind(&din::GenericPath::push_piece, &dir_man, std::placeholders::_1)), 1); proc.add_command("disconnect", std::function(std::bind(&din::DBSource::disconnect, &parDB)), 0); proc.add_command("pwd", std::function(std::bind(&on_pwd, std::ref(dir_man))), 0); - proc.add_command("ls", std::function(std::bind(&on_ls, std::ref(dir_man))), 0); + proc.add_command("ls", std::function(std::bind(&on_ls, std::ref(dir_man), std::ref(parDB))), 0); do { do { std::getline(inp, curr_line);