mirror of
https://github.com/typesense/typesense.git
synced 2025-05-22 06:40:30 +08:00
Merge remote-tracking branch 'up/v0.26-facets' into v0.26-facets
This commit is contained in:
commit
6a573b4541
@ -623,31 +623,70 @@ bool CollectionManager::parse_sort_by_str(std::string sort_by_str, std::vector<s
|
||||
char prev_non_space_char = 'a';
|
||||
|
||||
for(size_t i=0; i < sort_by_str.size(); i++) {
|
||||
if (sort_field_expr.empty() && sort_by_str[i] == '$') {
|
||||
// Sort by reference field
|
||||
auto open_paren_pos = sort_by_str.find('(', i);
|
||||
if (open_paren_pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
sort_field_expr = sort_by_str.substr(i, open_paren_pos - i + 1);
|
||||
|
||||
i = open_paren_pos;
|
||||
int paren_count = 1;
|
||||
while (++i < sort_by_str.size() && paren_count > 0) {
|
||||
if (sort_by_str[i] == '(') {
|
||||
paren_count++;
|
||||
} else if (sort_by_str[i] == ')') {
|
||||
paren_count--;
|
||||
if (sort_field_expr.empty()) {
|
||||
if (sort_by_str[i] == '$') {
|
||||
// Sort by reference field
|
||||
auto open_paren_pos = sort_by_str.find('(', i);
|
||||
if (open_paren_pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
sort_field_expr += sort_by_str[i];
|
||||
}
|
||||
if (paren_count != 0) {
|
||||
return false;
|
||||
}
|
||||
sort_field_expr = sort_by_str.substr(i, open_paren_pos - i + 1);
|
||||
|
||||
sort_fields.emplace_back(sort_field_expr, "");
|
||||
sort_field_expr = "";
|
||||
continue;
|
||||
i = open_paren_pos;
|
||||
int paren_count = 1;
|
||||
while (++i < sort_by_str.size() && paren_count > 0) {
|
||||
if (sort_by_str[i] == '(') {
|
||||
paren_count++;
|
||||
} else if (sort_by_str[i] == ')') {
|
||||
paren_count--;
|
||||
}
|
||||
sort_field_expr += sort_by_str[i];
|
||||
}
|
||||
if (paren_count != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sort_fields.emplace_back(sort_field_expr, "");
|
||||
sort_field_expr = "";
|
||||
continue;
|
||||
} else if (sort_by_str.substr(i, 5) == sort_field_const::eval) {
|
||||
// Optional filtering
|
||||
auto open_paren_pos = sort_by_str.find('(', i);
|
||||
if (open_paren_pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
sort_field_expr = sort_field_const::eval + "(";
|
||||
|
||||
i = open_paren_pos;
|
||||
int paren_count = 1;
|
||||
while (++i < sort_by_str.size() && paren_count > 0) {
|
||||
if (sort_by_str[i] == '(') {
|
||||
paren_count++;
|
||||
} else if (sort_by_str[i] == ')') {
|
||||
paren_count--;
|
||||
}
|
||||
sort_field_expr += sort_by_str[i];
|
||||
}
|
||||
if (paren_count != 0 || i >= sort_by_str.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (sort_by_str[i] != ':' && ++i < sort_by_str.size());
|
||||
if (i >= sort_by_str.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string order_str;
|
||||
while (++i < sort_by_str.size() && sort_by_str[i] != ',') {
|
||||
order_str += sort_by_str[i];
|
||||
}
|
||||
StringUtils::trim(order_str);
|
||||
StringUtils::toupper(order_str);
|
||||
|
||||
sort_fields.emplace_back(sort_field_expr, order_str);
|
||||
sort_field_expr = "";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(i == sort_by_str.size()-1 || (sort_by_str[i] == ',' && !isdigit(prev_non_space_char))) {
|
||||
|
@ -1902,9 +1902,9 @@ bool get_stopwords(const std::shared_ptr<http_req>& req, const std::shared_ptr<h
|
||||
|
||||
for(const auto& stopwords_kv: stopwords) {
|
||||
nlohmann::json stopword;
|
||||
stopword["name"] = stopwords_kv.first;
|
||||
stopword["id"] = stopwords_kv.first;
|
||||
for(const auto& val : stopwords_kv.second) {
|
||||
stopword["value"].push_back(val);
|
||||
stopword["stopwords"].push_back(val);
|
||||
}
|
||||
res_json["stopwords"].push_back(stopword);
|
||||
}
|
||||
@ -1914,7 +1914,7 @@ bool get_stopwords(const std::shared_ptr<http_req>& req, const std::shared_ptr<h
|
||||
}
|
||||
|
||||
bool get_stopword(const std::shared_ptr<http_req>& req, const std::shared_ptr<http_res>& res) {
|
||||
const std::string & stopword_name = req->params["stopword_name"];
|
||||
const std::string & stopword_name = req->params["name"];
|
||||
StopwordsManager& stopwordManager = StopwordsManager::get_instance();
|
||||
|
||||
spp::sparse_hash_set<std::string> stopwords;
|
||||
@ -1980,9 +1980,9 @@ bool del_stopword(const std::shared_ptr<http_req>& req, const std::shared_ptr<ht
|
||||
}
|
||||
|
||||
nlohmann::json res_json;
|
||||
res_json["name"] = stopword_name;
|
||||
res_json["id"] = stopword_name;
|
||||
for(const auto& stopword : stopwords) {
|
||||
res_json["value"].push_back(stopword);
|
||||
res_json["stopwords"].push_back(stopword);
|
||||
}
|
||||
|
||||
res->set_200(res_json.dump());
|
||||
|
@ -28,6 +28,7 @@ Option<bool> StopwordsManager::upsert_stopword(const std::string& stopword_name,
|
||||
|
||||
const char* STOPWORD_VALUES = "stopwords";
|
||||
const char* STOPWORD_LOCALE = "locale";
|
||||
std::string locale = "";
|
||||
|
||||
if(stopwords_json.count(STOPWORD_VALUES) == 0){
|
||||
return Option<bool>(400, (std::string("Parameter `") + STOPWORD_VALUES + "` is required"));
|
||||
@ -37,12 +38,11 @@ Option<bool> StopwordsManager::upsert_stopword(const std::string& stopword_name,
|
||||
return Option<bool>(400, (std::string("Parameter `") + STOPWORD_VALUES + "` is required as string array value"));
|
||||
}
|
||||
|
||||
if(stopwords_json.count(STOPWORD_LOCALE) == 0) {
|
||||
return Option<bool>(400, (std::string("Parameter `") + STOPWORD_LOCALE + "` is required"));
|
||||
}
|
||||
|
||||
if(!stopwords_json[STOPWORD_LOCALE].is_string()) {
|
||||
return Option<bool>(400, (std::string("Parameter `") + STOPWORD_LOCALE + "` is required as string value"));
|
||||
if(stopwords_json.count(STOPWORD_LOCALE) != 0) {
|
||||
if (!stopwords_json[STOPWORD_LOCALE].is_string()) {
|
||||
return Option<bool>(400, (std::string("Parameter `") + STOPWORD_LOCALE + "` is required as string value"));
|
||||
}
|
||||
locale = stopwords_json[STOPWORD_LOCALE];
|
||||
}
|
||||
|
||||
if(write_to_store) {
|
||||
@ -55,7 +55,6 @@ Option<bool> StopwordsManager::upsert_stopword(const std::string& stopword_name,
|
||||
std::vector<std::string> tokens;
|
||||
spp::sparse_hash_set<std::string> stopwords_set;
|
||||
const auto& stopwords = stopwords_json[STOPWORD_VALUES];
|
||||
const auto& locale = stopwords_json[STOPWORD_LOCALE];
|
||||
|
||||
for (const auto &stopword: stopwords.items()) {
|
||||
const auto& val = stopword.value().get<std::string>();
|
||||
|
@ -2135,6 +2135,22 @@ TEST_F(CollectionSortingTest, OptionalFilteringViaSortingSearch) {
|
||||
results = coll1->search("title", {"title"}, "", {}, sort_fields, {2}, 10, 1, FREQUENCY, {true}, 10).get();
|
||||
ASSERT_EQ(5, results["hits"].size());
|
||||
|
||||
std::map<std::string, std::string> req_params = {
|
||||
{"collection", "coll1"},
|
||||
{"q", "title"},
|
||||
{"query_by", "title"},
|
||||
{"sort_by", "_eval(brand:[nike, adidas] && points:0):desc, points:DESC"}
|
||||
};
|
||||
nlohmann::json embedded_params;
|
||||
std::string json_res;
|
||||
auto now_ts = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
|
||||
auto search_op = collectionManager.do_search(req_params, embedded_params, json_res, now_ts);
|
||||
ASSERT_TRUE(search_op.ok());
|
||||
results = nlohmann::json::parse(json_res);
|
||||
ASSERT_EQ(5, results["hits"].size());
|
||||
|
||||
expected_ids = {"0", "4", "3", "2", "1"};
|
||||
for(size_t i = 0; i < expected_ids.size(); i++) {
|
||||
ASSERT_EQ(expected_ids[i], results["hits"][i]["document"]["id"].get<std::string>());
|
||||
|
@ -328,20 +328,8 @@ TEST_F(StopwordsManagerTest, StopwordsValidation) {
|
||||
std::shared_ptr<http_req> req = std::make_shared<http_req>();
|
||||
std::shared_ptr<http_res> res = std::make_shared<http_res>(nullptr);
|
||||
|
||||
auto stopword_value = R"(
|
||||
{"stopwords": ["america", "europe"]}
|
||||
)"_json;
|
||||
|
||||
req->params["collection"] = "coll1";
|
||||
req->params["name"] = "continents";
|
||||
req->body = stopword_value.dump();
|
||||
|
||||
auto result = put_upsert_stopword(req, res);
|
||||
ASSERT_EQ(400, res->status_code);
|
||||
ASSERT_EQ("{\"message\": \"Parameter `locale` is required\"}", res->body);
|
||||
|
||||
//with a typo
|
||||
stopword_value = R"(
|
||||
auto stopword_value = R"(
|
||||
{"stopword": ["america", "europe"], "locale": "en"}
|
||||
)"_json;
|
||||
|
||||
@ -349,7 +337,7 @@ TEST_F(StopwordsManagerTest, StopwordsValidation) {
|
||||
req->params["name"] = "continents";
|
||||
req->body = stopword_value.dump();
|
||||
|
||||
result = put_upsert_stopword(req, res);
|
||||
auto result = put_upsert_stopword(req, res);
|
||||
ASSERT_EQ(400, res->status_code);
|
||||
ASSERT_STREQ("{\"message\": \"Parameter `stopwords` is required\"}", res->body.c_str());
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user