From 7ca2b28548502891b3c87989188dd75e27ff037c Mon Sep 17 00:00:00 2001 From: ZhuangYumin Date: Thu, 14 Dec 2023 03:01:37 +0000 Subject: [PATCH] upd: first version of booksystem --- backend/include/database.h | 1 + backend/include/drivearray.hpp | 12 ++++ backend/include/lexer.h | 2 +- backend/src/database.cpp | 108 ++++++++++++++++++++++++++++++++- backend/src/engine.cpp | 106 +++++++++++++++++++++++++++++++- backend/src/lexer.cpp | 10 ++- 6 files changed, 230 insertions(+), 9 deletions(-) diff --git a/backend/include/database.h b/backend/include/database.h index 64c5d7e..3a836ac 100644 --- a/backend/include/database.h +++ b/backend/include/database.h @@ -28,6 +28,7 @@ class BookDataBase { public: void Open(std::string file_name); bool HaveISBN(const std::string &ISBN); + bool HaveISBN(const std::string &ISBN,BookItemClass &ret); void CreateEmptyBook(const std::string &ISBN); void QueryBook(const std::string &ISBN, const std::string &name, const std::string &author, const std::string &keyword, diff --git a/backend/include/drivearray.hpp b/backend/include/drivearray.hpp index ff085ef..519f74b 100644 --- a/backend/include/drivearray.hpp +++ b/backend/include/drivearray.hpp @@ -226,6 +226,18 @@ class DriveArray { first_vacant_data_index; first_vacant_data_index = index; } + + void FetchAll(std::vector &vec) noexcept { + vec.clear(); + for (int i = 1; i <= total_block_number; ++i) { + BlockType *blk_ptr = OrderBlock(i); + for (int j = 0; j < kDataPerBlock; ++j) { + if (blk_ptr->data[j].next_vacant_data_index == -1) { + vec.push_back(blk_ptr->data[j].val); + } + } + } + } }; #endif // PROTECTOR_DRIVEARRAY_HPP \ No newline at end of file diff --git a/backend/include/lexer.h b/backend/include/lexer.h index b14d7f8..1be389a 100644 --- a/backend/include/lexer.h +++ b/backend/include/lexer.h @@ -27,5 +27,5 @@ bool CommandModifyLexer(const std::string &command, std::string &ISBN, bool CommandImportLexer(const std::string &command, int &quantity, double &total_cost); bool CommandShowfinanceLexer(const std::string &command,int &count); -bool KeyWordSpliter(const std::string &keyword, std::vector &words); +bool KeyWordSpliter(const std::string &keyword, std::vector &words,bool allow_empty=false); #endif // PROTECTOR_LEXER_H \ No newline at end of file diff --git a/backend/src/database.cpp b/backend/src/database.cpp index a2cf7cb..b42ddb0 100644 --- a/backend/src/database.cpp +++ b/backend/src/database.cpp @@ -1,6 +1,7 @@ #include "database.h" #include "bs-utility.h" +#include "lexer.h" void UserDataBase::Open(std::string file_name) { full_user_data.OpenFile(file_name + ".full"); user_name2index.OpenFile(file_name + ".n2i"); @@ -76,6 +77,14 @@ bool BookDataBase::HaveISBN(const std::string &ISBN) { auto ret = ISBN2index.Find(ISBN); return ret.size() == 1; } +bool BookDataBase::HaveISBN(const std::string &ISBN, BookItemClass &ans) { + auto ret = ISBN2index.Find(ISBN); + if (ret.size() == 1) { + full_book_data.read(ans, ret[0]); + return true; + } + return false; +} void BookDataBase::CreateEmptyBook(const std::string &ISBN) { BookItemClass tmp; @@ -117,8 +126,15 @@ void BookDataBase::ModifyInfo(const std::string &ISBN, strcpy(tmp.author, author.c_str()); } if (keyword != "") { - keyword2index.Delete(tmp.keyword, ret[0]); - keyword2index.Insert(keyword, ret[0]); + std::vector keyword_vec; + KeyWordSpliter(tmp.keyword, keyword_vec, true); + for (auto &i : keyword_vec) { + keyword2index.Delete(i, ret[0]); + } + KeyWordSpliter(keyword, keyword_vec); + for (auto &i : keyword_vec) { + keyword2index.Insert(i, ret[0]); + } strcpy(tmp.keyword, keyword.c_str()); } if (price >= 0) tmp.price = price; @@ -131,5 +147,91 @@ void BookDataBase::QueryBook(const std::string &ISBN, const std::string &name, const std::string &keyword, std::vector &ret) { ret.clear(); - if (ISBN == "" && name == "" && author == "" && keyword == "") return; + std::vector cache; + std::vector valid; + if (ISBN == "" && name == "" && author == "" && keyword == "") { + full_book_data.FetchAll(ret); + /* sort by ISBN */ + sort(ret.begin(), ret.end(), + [](const BookItemClass &a, const BookItemClass &b) { + return strcmp(a.ISBN, b.ISBN) < 0; + }); + return; + } + bool first_ristrict = true; + if (ISBN != "") { + first_ristrict = false; + auto tmp = ISBN2index.Find(ISBN); + if (tmp.size() == 1) { + BookItemClass tmp_book; + full_book_data.read(tmp_book, tmp[0]); + cache.push_back(tmp_book); + valid.push_back(1); + } + if (tmp.size() > 1) throw FatalError("ISBN not unique", 7); + } + if (name != "") { + if (first_ristrict) { + first_ristrict = false; + auto tmp = name2index.Find(name); + for (auto &i : tmp) { + BookItemClass tmp_book; + full_book_data.read(tmp_book, i); + cache.push_back(tmp_book); + valid.push_back(1); + } + } else { + for (int i = 0; i < cache.size(); i++) { + if (!valid[i]) continue; + if (strcmp(cache[i].name, name.c_str()) != 0) { + valid[i] = 0; + } + } + } + } + if (author != "") { + if (first_ristrict) { + first_ristrict = false; + auto tmp = author2index.Find(author); + for (auto &i : tmp) { + BookItemClass tmp_book; + full_book_data.read(tmp_book, i); + cache.push_back(tmp_book); + valid.push_back(1); + } + } else { + for (int i = 0; i < cache.size(); i++) { + if (!valid[i]) continue; + if (strcmp(cache[i].author, author.c_str()) != 0) { + valid[i] = 0; + } + } + } + } + if (keyword != "") { + if (first_ristrict) { + first_ristrict = false; + auto tmp = keyword2index.Find(keyword); + for (auto &j : tmp) { + BookItemClass tmp_book; + full_book_data.read(tmp_book, j); + cache.push_back(tmp_book); + valid.push_back(1); + } + } else { + for (int i = 0; i < cache.size(); i++) { + if (!valid[i]) continue; + if (strcmp(cache[i].keyword, keyword.c_str()) != 0) { + valid[i] = 0; + } + } + } + } + for (int i = 0; i < cache.size(); i++) { + if (valid[i]) ret.push_back(cache[i]); + } + sort(ret.begin(), ret.end(), + [](const BookItemClass &a, const BookItemClass &b) { + return strcmp(a.ISBN, b.ISBN) < 0; + }); } \ No newline at end of file diff --git a/backend/src/engine.cpp b/backend/src/engine.cpp index 63d4756..22250b6 100644 --- a/backend/src/engine.cpp +++ b/backend/src/engine.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "bs-utility.h" @@ -135,6 +136,9 @@ std::vector BookStoreEngineClass::ExecuteLogout( const std::string &cmd, std::stack> &login_stack) { if (login_stack.empty()) return std::vector({"Invalid"}); + if (user_data_base.GetPrevilege(login_stack.top().first) < 1) { + return std::vector({"Invalid"}); + } login_count[login_stack.top().first]--; login_stack.pop(); return std::vector(); @@ -159,7 +163,7 @@ std::vector BookStoreEngineClass::ExecutePasswd( if (!CommandPasswdLexer(cmd, user_id, current_password, new_password)) return std::vector({"Invalid"}); // debugPrint("sucessfully lexed passwd"); - if (user_data_base.GetPrevilege(user_id) == -1) + if (user_data_base.GetPrevilege(user_id) < 1) return std::vector({"Invalid"}); // debugPrint("begin checing authority"); if (login_stack.size() > 0 && @@ -215,30 +219,126 @@ std::vector BookStoreEngineClass::ExecuteDelete( std::vector BookStoreEngineClass::ExecuteShow( const std::string &cmd, std::stack> &login_stack) { - return std::vector(); + if (login_stack.empty() || + user_data_base.GetPrevilege(login_stack.top().first) < 1) + return std::vector({"Invalid"}); + std::string ISBN, name, author, keyword; + if (!CommandShowLexer(cmd, ISBN, name, author, keyword)) + return std::vector({"Invalid"}); + std::vector ret; + book_data_base.QueryBook(ISBN, name, author, keyword, ret); + if (ret.empty()) return std::vector({""}); + /* output format + * [ISBN]\t[BookName]\t[Author]\t[Keyword]\t[Price]\t[库存数量]\n */ + std::vector ans; + for (auto &i : ret) { + std::string tmp = i.ISBN; + tmp += '\t'; + tmp += i.name; + tmp += '\t'; + tmp += i.author; + tmp += '\t'; + tmp += i.keyword; + tmp += '\t'; + tmp += std::to_string(i.price); + tmp += '\t'; + tmp += std::to_string(i.quantity_remain); + ans.push_back(tmp); + } + return ans; } std::vector BookStoreEngineClass::ExecuteBuy( const std::string &cmd, std::stack> &login_stack) { - return std::vector(); + std::string ISBN; + int quantity; + if (!CommandBuyLexer(cmd, ISBN, quantity)) + return std::vector({"Invalid"}); + if (login_stack.empty() || + user_data_base.GetPrevilege(login_stack.top().first) < 1) + return std::vector({"Invalid"}); + BookItemClass tmp; + if (!book_data_base.HaveISBN(ISBN, tmp)) + return std::vector({"Invalid"}); + if (quantity <= 0) return std::vector({"Invalid"}); + if (quantity > tmp.quantity_remain) + return std::vector({"Invalid"}); + book_data_base.ModifyInfo(ISBN, "", "", "", "", -1, + tmp.quantity_remain - quantity); + /*浮点数输出购买图书所需的总金额,小数点后有且仅有两位小数*/ + std::vector ans; + unsigned long long cost_tmp = tmp.price * quantity * 100 + 0.5; + ans.push_back(std::to_string(cost_tmp / 100) + '.' + + std::to_string(cost_tmp % 100 / 10) + + std::to_string(cost_tmp % 10)); + return ans; } std::vector BookStoreEngineClass::ExecuteSelect( const std::string &cmd, std::stack> &login_stack) { + std::string ISBN; + if (!CommandSelectLexer(cmd, ISBN)) + return std::vector({"Invalid"}); + if (login_stack.empty() || + user_data_base.GetPrevilege(login_stack.top().first) < 3) + return std::vector({"Invalid"}); + if (!book_data_base.HaveISBN(ISBN)) book_data_base.CreateEmptyBook(ISBN); + std::pair tmp; + tmp = login_stack.top(); + login_stack.pop(); + tmp.second = ISBN; + login_stack.push(tmp); return std::vector(); } std::vector BookStoreEngineClass::ExecuteMOdify( const std::string &cmd, std::stack> &login_stack) { + std::string new_ISBN, name, author, keyword; + double price; + if (!CommandModifyLexer(cmd, new_ISBN, name, author, keyword, price)) + return std::vector({"Invalid"}); + if (login_stack.empty() || + user_data_base.GetPrevilege(login_stack.top().first) < 3) + return std::vector({"Invalid"}); + if (login_stack.top().second == "" || login_stack.top().second == new_ISBN) + return std::vector({"Invalid"}); + if (keyword != "") { + std::vector key_list; + if (!KeyWordSpliter(keyword, key_list, false)) + return std::vector({"Invalid"}); + std::unordered_set key_set; + for (auto &i : key_list) { + if (key_set.find(i) != key_set.end()) + return std::vector({"Invalid"}); + key_set.insert(i); + } + } + book_data_base.ModifyInfo(login_stack.top().second, new_ISBN, name, author, + keyword, price, -1); return std::vector(); } std::vector BookStoreEngineClass::ExecuteImport( const std::string &cmd, std::stack> &login_stack) { + int quantity; + double total_cost; + if (!CommandImportLexer(cmd, quantity, total_cost)) + return std::vector({"Invalid"}); + if (login_stack.empty() || + user_data_base.GetPrevilege(login_stack.top().first) < 3) + return std::vector({"Invalid"}); + if (login_stack.top().second == "") + return std::vector({"Invalid"}); + if (quantity <= 0) return std::vector({"Invalid"}); + if (total_cost <= 0) return std::vector({"Invalid"}); + BookItemClass tmp; + book_data_base.HaveISBN(login_stack.top().second, tmp); + book_data_base.ModifyInfo(login_stack.top().second, "", "", "", "", -1, + tmp.quantity_remain + quantity); return std::vector(); } diff --git a/backend/src/lexer.cpp b/backend/src/lexer.cpp index 7de7cf1..7935f9d 100644 --- a/backend/src/lexer.cpp +++ b/backend/src/lexer.cpp @@ -346,7 +346,7 @@ bool CommandModifyLexer(const std::string &command, std::string &ISBN, name = ""; author = ""; keyword = ""; - price = 0; + price = -1; while (ss >> token) { if (token[1] == 'I') { ISBN = token.substr(6); @@ -431,7 +431,13 @@ bool CommandShowfinanceLexer(const std::string &command, int &count) { return false; } -bool KeyWordSpliter(const std::string &keyword, std::vector &words) { +bool KeyWordSpliter(const std::string &keyword, std::vector &words, + bool allow_empty) { + words.clear(); + if (keyword == "") { + if (!allow_empty) return false; + return true; + } int current_beg = 0; for (int i = 0; i < keyword.length(); i++) { if (keyword[i] == '|') {