From c938101c70c25906c582d94db7d50f8db2447f9c Mon Sep 17 00:00:00 2001 From: Nikhil Tanwar <2002nikhiltanwar@gmail.com> Date: Sun, 23 Jul 2023 18:57:42 +0530 Subject: [PATCH 1/2] Allow multiple category support Created a generic function multipleQuery which takes: 1. string (representing a comma separated list) 2. param (the value to query on using Xapian). Category and language query will use this function. --- include/library.h | 6 ++++++ src/library.cpp | 25 +++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/include/library.h b/include/library.h index 3fefa140e..602cfb9fd 100644 --- a/include/library.h +++ b/include/library.h @@ -105,6 +105,12 @@ class Filter { Filter& acceptTags(const Tags& tags); Filter& rejectTags(const Tags& tags); + /** + * Set the filter to only accept books in the specified category. + * + * Multiple categories can be specified as a comma-separated list (in + * which case a book in any of those categories will match). + */ Filter& category(std::string category); /** diff --git a/src/library.cpp b/src/library.cpp index 4ce865b7f..6ee51602f 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -549,27 +549,32 @@ Xapian::Query nameQuery(const std::string& name) return Xapian::Query("XN" + normalizeText(name)); } -Xapian::Query categoryQuery(const std::string& category) -{ - return Xapian::Query("XC" + normalizeText(category)); -} - -Xapian::Query langQuery(const std::string& commaSeparatedLanguageList) +Xapian::Query multipleParamQuery(const std::string& commaSeparatedList, const std::string& prefix) { Xapian::Query q; bool firstIteration = true; - for ( const auto& lang : kiwix::split(commaSeparatedLanguageList, ",") ) { - const Xapian::Query singleLangQuery("L" + normalizeText(lang)); + for ( const auto& elem : kiwix::split(commaSeparatedList, ",") ) { + const Xapian::Query singleQuery(prefix + normalizeText(elem)); if ( firstIteration ) { - q = singleLangQuery; + q = singleQuery; firstIteration = false; } else { - q = Xapian::Query(Xapian::Query::OP_OR, q, singleLangQuery); + q = Xapian::Query(Xapian::Query::OP_OR, q, singleQuery); } } return q; } +Xapian::Query categoryQuery(const std::string& commaSeparatedCategoryList) +{ + return multipleParamQuery(commaSeparatedCategoryList, "XC"); +} + +Xapian::Query langQuery(const std::string& commaSeparatedLanguageList) +{ + return multipleParamQuery(commaSeparatedLanguageList, "L"); +} + Xapian::Query publisherQuery(const std::string& publisher) { Xapian::QueryParser queryParser; From d47c4fa72f94dd360be8cc2259cbf227fb4d9dff Mon Sep 17 00:00:00 2001 From: Nikhil Tanwar <2002nikhiltanwar@gmail.com> Date: Sun, 23 Jul 2023 19:54:07 +0530 Subject: [PATCH 2/2] Unit tests for OPDS filtering by category Added tests for multiple category filtering for zims Added new test: catalog_v2_entries_filtered_by_category for entry filtering by category. --- test/library_server.cpp | 83 ++++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/test/library_server.cpp b/test/library_server.cpp index 2274ccf4c..c9c34e367 100644 --- a/test/library_server.cpp +++ b/test/library_server.cpp @@ -301,20 +301,41 @@ TEST_F(LibraryServerTest, catalog_search_by_tag) TEST_F(LibraryServerTest, catalog_search_by_category) { - const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?category=jazz"); - EXPECT_EQ(r->status, 200); - EXPECT_EQ(maskVariableOPDSFeedData(r->body), - OPDS_FEED_TAG - " 12345678-90ab-cdef-1234-567890abcdef\n" - " Filtered zims (category=jazz)\n" - " YYYY-MM-DDThh:mm:ssZ\n" - " 1\n" - " 0\n" - " 1\n" - CATALOG_LINK_TAGS - CHARLES_RAY_CATALOG_ENTRY - "\n" - ); + + { + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?category=jazz"); + EXPECT_EQ(r->status, 200); + EXPECT_EQ(maskVariableOPDSFeedData(r->body), + OPDS_FEED_TAG + " 12345678-90ab-cdef-1234-567890abcdef\n" + " Filtered zims (category=jazz)\n" + " YYYY-MM-DDThh:mm:ssZ\n" + " 1\n" + " 0\n" + " 1\n" + CATALOG_LINK_TAGS + CHARLES_RAY_CATALOG_ENTRY + "\n" + ); + } + + { + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/search?category=jazz,wikipedia"); + EXPECT_EQ(r->status, 200); + EXPECT_EQ(maskVariableOPDSFeedData(r->body), + OPDS_FEED_TAG + " 12345678-90ab-cdef-1234-567890abcdef\n" + " Filtered zims (category=jazz%2Cwikipedia)\n" + " YYYY-MM-DDThh:mm:ssZ\n" + " 2\n" + " 0\n" + " 2\n" + CATALOG_LINK_TAGS + RAY_CHARLES_CATALOG_ENTRY + CHARLES_RAY_CATALOG_ENTRY + "\n" + ); + } } TEST_F(LibraryServerTest, catalog_search_by_language) @@ -793,6 +814,40 @@ TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_language) } } +TEST_F(LibraryServerTest, catalog_v2_entries_filtered_by_category) +{ + { + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?category=jazz"); + EXPECT_EQ(r->status, 200); + EXPECT_EQ(maskVariableOPDSFeedData(r->body), + CATALOG_V2_ENTRIES_PREAMBLE("?category=jazz") + " Filtered Entries (category=jazz)\n" + " YYYY-MM-DDThh:mm:ssZ\n" + " 1\n" + " 0\n" + " 1\n" + CHARLES_RAY_CATALOG_ENTRY + "\n" + ); + } + + { + const auto r = zfs1_->GET("/ROOT%23%3F/catalog/v2/entries?category=jazz,wikipedia"); + EXPECT_EQ(r->status, 200); + EXPECT_EQ(maskVariableOPDSFeedData(r->body), + CATALOG_V2_ENTRIES_PREAMBLE("?category=jazz%2Cwikipedia") + " Filtered Entries (category=jazz%2Cwikipedia)\n" + " YYYY-MM-DDThh:mm:ssZ\n" + " 2\n" + " 0\n" + " 2\n" + RAY_CHARLES_CATALOG_ENTRY + CHARLES_RAY_CATALOG_ENTRY + "\n" + ); + } +} + TEST_F(LibraryServerTest, catalog_v2_entries_multiple_filters) { {