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,25 +549,30 @@ Xapian::Query nameQuery(const std::string& name) return Xapian::Query("XN" + normalizeText(name)); } -Xapian::Query categoryQuery(const std::string& category) +Xapian::Query multipleParamQuery(const std::string& commaSeparatedList, const std::string& prefix) { - return Xapian::Query("XC" + normalizeText(category)); + Xapian::Query q; + bool firstIteration = true; + for ( const auto& elem : kiwix::split(commaSeparatedList, ",") ) { + const Xapian::Query singleQuery(prefix + normalizeText(elem)); + if ( firstIteration ) { + q = singleQuery; + firstIteration = false; + } else { + 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) { - Xapian::Query q; - bool firstIteration = true; - for ( const auto& lang : kiwix::split(commaSeparatedLanguageList, ",") ) { - const Xapian::Query singleLangQuery("L" + normalizeText(lang)); - if ( firstIteration ) { - q = singleLangQuery; - firstIteration = false; - } else { - q = Xapian::Query(Xapian::Query::OP_OR, q, singleLangQuery); - } - } - return q; + return multipleParamQuery(commaSeparatedLanguageList, "L"); } Xapian::Query publisherQuery(const std::string& publisher) 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) { {