diff --git a/src/navigate/MaxSizedArray.hpp b/src/navigate/MaxSizedArray.hpp index e27be8f..9e64461 100644 --- a/src/navigate/MaxSizedArray.hpp +++ b/src/navigate/MaxSizedArray.hpp @@ -29,6 +29,8 @@ namespace din { const size_t MAXSZARR_MAX_STACK_ALLOC_SIZE = MAX_STACK_ALLOC_SIZE; + //TODO: add a template parameter to force stack allocation regardless of + //sizeof(T) * S template > class MaxSizedArray : private std::conditional< diff --git a/src/navigate/dbsource.cpp b/src/navigate/dbsource.cpp index 2a5bce3..c5900e2 100644 --- a/src/navigate/dbsource.cpp +++ b/src/navigate/dbsource.cpp @@ -26,6 +26,41 @@ #include namespace din { + namespace { + const uint32_t g_files_query_limit = 500; + + std::ostream& operator<< (std::ostream& parOut, const std::vector& parCols) { + parOut << '"'; + boost::copy(parCols, infix_ostream_iterator(parOut, "\", \"")); + parOut << '"'; + return parOut; + } + } //unnamed namespace + + const DBSource::SetDetailsMap DBSource::m_set_details_map { + {SetDetail_Desc, "desc"}, + {SetDetail_Type, "type"}, + {SetDetail_CreeationDate, "creation"}, + {SetDetail_AppName, "app_name"}, + {SetDetail_ID, "id"} + }; + const DBSource::FileDetailsMap DBSource::m_file_details_map { + {FileDetail_ID, "id"}, + {FileDetail_Path, "path"}, + {FileDetail_Level, "level"}, + {FileDetail_GroupID, "group_id"}, + {FileDetail_IsDir, "is_directory"}, + {FileDetail_IsSymLink, "is_symlink"}, + {FileDetail_Size, "size"}, + {FileDetail_Hash, "hash"}, + {FileDetail_IsHashValid, "is_hash_valid"}, + {FileDetail_ATime, "access_time"}, + {FileDetail_MTime, "modify_time"}, + {FileDetail_Unreadable, "unreadable"}, + {FileDetail_MimeType, "mimetype"}, + {FileDetail_Charset, "charset"} + }; + struct DBSource::LocalData { explicit LocalData ( const dinlib::SettingsDB& parDBSettings ) : conn( @@ -78,12 +113,13 @@ namespace din { return std::move(retval); } - void DBSource::query_push_results (const std::vector& parCols, boost::string_ref parTable, const std::vector& parIDs, std::function parCallback) { + void DBSource::query_no_conditions (const ColumnList& 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;"; + oss << "SELECT " << parCols << ' ' << + "FROM \"" << parTable << "\" " << + "WHERE \"id\"=ANY($1) " << + "ORDER BY \"desc\" ASC " << + "LIMIT " << g_files_query_limit << ';'; auto& conn = get_conn(); auto result = conn.query(oss.str(), parIDs); @@ -93,4 +129,28 @@ namespace din { } } } + + void DBSource::query_files_in_dir (const ColumnList& parCols, boost::string_ref parDir, uint16_t parLevel, uint32_t parGroupID, QueryCallback parCallback) { + std::ostringstream oss; + oss << "SELECT " << parCols << ' ' << + "FROM \"files\" WHERE " << + "\"level\"=$1 " << + "AND \"group_id\"=$2 " << + "AND str_begins_with(\"path\", COALESCE($3, '')) " << + "ORDER BY \"path\" ASC " << + "LIMIT " << g_files_query_limit << ';'; + + auto& conn = get_conn(); + auto result = conn.query( + oss.str(), + parLevel, + parGroupID, + parDir + ); + 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 index 31892f0..dfca8ca 100644 --- a/src/navigate/dbsource.hpp +++ b/src/navigate/dbsource.hpp @@ -48,6 +48,23 @@ namespace din { SetDetail_ID = 0x10 }; + enum FileDetails { + FileDetail_ID = 0x0001, + FileDetail_Path = 0x0002, + FileDetail_Level = 0x0004, + FileDetail_GroupID = 0x0008, + FileDetail_IsDir = 0x0010, + FileDetail_IsSymLink = 0x0020, + FileDetail_Size = 0x0040, + FileDetail_Hash = 0x0080, + FileDetail_IsHashValid = 0x0100, + FileDetail_ATime = 0x0200, + FileDetail_MTime = 0x0400, + FileDetail_Unreadable = 0x800, + FileDetail_MimeType = 0x1000, + FileDetail_Charset = 0x2000 + }; + class DBSource { public: explicit DBSource ( const dinlib::SettingsDB& parDBSettings ); @@ -58,47 +75,72 @@ namespace din { template auto set_details ( const std::vector& parIDs ) -> std::vector>; - //TODO: replace return value with vector of maxsizedarray - //auto set_details ( const std::vector& parIDs ) -> std::array; + + template + auto file_details ( uint32_t parSetID, uint16_t parLevel, boost::string_ref parDir ) -> std::vector>; private: struct LocalData; + typedef std::map SetDetailsMap; + typedef std::map FileDetailsMap; + typedef std::vector ColumnList; + typedef std::function QueryCallback; pq::Connection& get_conn ( void ); - void query_push_results ( const std::vector& parCols, boost::string_ref parTable, const std::vector& parIDs, std::function parCallback ); + void query_no_conditions ( const ColumnList& parCols, boost::string_ref parTable, const std::vector& parIDs, QueryCallback parCallback ); + void query_files_in_dir ( const ColumnList& parCols, boost::string_ref parDir, uint16_t parLevel, uint32_t parGroupID, QueryCallback parCallback ); + + static const SetDetailsMap m_set_details_map; + static const FileDetailsMap m_file_details_map; std::unique_ptr m_local_data; }; + namespace implem { + template + inline + std::vector make_columns_vec (const std::map& parDic) { + std::vector columns; + columns.reserve(sizeof...(Details)); + + const std::array details { Details... }; + //std::generate(details.begin(), details.end(), columns.begin(), std::bind(at_func, &details_dic, std::placeholders::_1)); + for (auto detail : details) { + columns.push_back(parDic.at(detail)); + } + return std::move(columns); + } + } //namespace implem + template auto DBSource::set_details (const std::vector& parIDs) -> std::vector> { - //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 const std::string&(SetDetailsMap::*AtFunc)(const SetDetails&) const; typedef void(din::FlatInsertIn2DList::*FlatPushBackFunc)(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)); - } + const auto columns = implem::make_columns_vec(m_set_details_map); + AtFunc at_func = &SetDetailsMap::at; 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)); + this->query_no_conditions(columns, "sets", parIDs, std::bind(pback_func, &flat_list, std::placeholders::_1)); + return std::move(list); + } + + template + auto DBSource::file_details (uint32_t parSetID, uint16_t parLevel, boost::string_ref parDir) -> std::vector> { + typedef std::vector> ReturnType; + typedef const std::string&(SetDetailsMap::*AtFunc)(const SetDetails&) const; + typedef void(din::FlatInsertIn2DList::*FlatPushBackFunc)(std::string&&); + + const auto columns = implem::make_columns_vec(m_file_details_map); + AtFunc at_func = &SetDetailsMap::at; + + ReturnType list; + FlatInsertIn2DList flat_list(&list, sizeof...(D)); + FlatPushBackFunc pback_func = &FlatInsertIn2DList::push_back; + this->query_files_in_dir(columns, parDir, parLevel, parSetID, std::bind(pback_func, &flat_list, std::placeholders::_1)); return std::move(list); } } //namespace din diff --git a/src/navigate/genericpath.cpp b/src/navigate/genericpath.cpp index 96fe904..f8040f3 100644 --- a/src/navigate/genericpath.cpp +++ b/src/navigate/genericpath.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace qi = boost::spirit::qi; @@ -103,4 +104,13 @@ namespace din { boost::copy(m_stack, infix_ostream_iterator(oss, "/")); return oss.str(); } + + uint16_t GenericPath::level() const { + return static_cast(m_stack.size()); + } + + const std::string& GenericPath::operator[] (std::size_t parIndex) const { + assert(parIndex < level()); + return m_stack[parIndex]; + } } //namespace din diff --git a/src/navigate/genericpath.hpp b/src/navigate/genericpath.hpp index 5409e6e..52e3d49 100644 --- a/src/navigate/genericpath.hpp +++ b/src/navigate/genericpath.hpp @@ -20,6 +20,7 @@ #include #include +#include namespace din { class GenericPath { @@ -28,6 +29,8 @@ namespace din { void push_piece ( const std::string& parPiece ); std::string to_string ( void ) const; + uint16_t level ( void ) const; + const std::string& operator[] ( std::size_t parIndex ) const; private: using StackType = std::vector; diff --git a/src/navigate/main.cpp b/src/navigate/main.cpp index 2430e74..aaadb90 100644 --- a/src/navigate/main.cpp +++ b/src/navigate/main.cpp @@ -28,10 +28,12 @@ #include #include #include +#include namespace { void do_navigation ( din::DBSource& parDB ); + template void print_db_result ( const V& parResult ); bool on_exit ( void ); void on_pwd ( const din::GenericPath& parDirMan ); void on_ls ( const din::GenericPath& parDirMan, din::DBSource& parDB ); @@ -67,6 +69,14 @@ int main (int parArgc, char* parArgv[]) { } namespace { + template + void print_db_result (const V& parResult) { + for (const auto& row : parResult) { + boost::copy(row, infix_ostream_iterator(std::cout, "\t")); + std::cout << "\n"; + } + } + bool on_exit() { return true; } @@ -78,11 +88,18 @@ namespace { 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"; + const auto curr_path = parDirMan.to_string(); + if ("/" == curr_path) { + auto sets_ids = parDB.sets(); + auto sets_info = parDB.set_details(sets_ids); + print_db_result(sets_info); + } + else { + const auto start_from = curr_path.find('/', 1); + auto path_prefix = boost::string_ref(curr_path).substr(start_from == curr_path.npos ? curr_path.size() : start_from + 1); + const auto set_id = boost::lexical_cast(parDirMan[0]); + auto files_info = parDB.file_details(set_id, parDirMan.level(), path_prefix); + print_db_result(files_info); } }