mirror of
https://github.com/typesense/typesense.git
synced 2025-05-20 05:32:30 +08:00
Merge branch 'v0.24-nested' into v0.25
This commit is contained in:
commit
3e774e6f77
@ -261,8 +261,15 @@ Option<bool> CollectionManager::load(const size_t collection_batch_size, const s
|
||||
iter = store->scan(preset_prefix_key, &preset_upper_bound);
|
||||
while(iter->Valid() && iter->key().starts_with(preset_prefix_key)) {
|
||||
std::vector<std::string> parts;
|
||||
StringUtils::split(iter->key().ToString(), parts, preset_prefix_key);
|
||||
preset_configs[parts[0]] = iter->value().ToString();
|
||||
std::string preset_name = iter->key().ToString().substr(preset_prefix_key.size());
|
||||
nlohmann::json preset_obj = nlohmann::json::parse(iter->value().ToString(), nullptr, false);
|
||||
|
||||
if(!preset_obj.is_discarded() && preset_obj.is_object()) {
|
||||
preset_configs[preset_name] = preset_obj;
|
||||
} else {
|
||||
LOG(INFO) << "Invalid value for preset " << preset_name;
|
||||
}
|
||||
|
||||
iter->Next();
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,17 @@ void get_collections_for_auth(std::map<std::string, std::string>& req_params,
|
||||
coll_name = el["collection"].get<std::string>();
|
||||
} else if(req_params.count("collection") != 0) {
|
||||
coll_name = req_params["collection"];
|
||||
} else {
|
||||
// if preset exists, that should be the lowest priority
|
||||
if(el.count("preset") != 0) {
|
||||
nlohmann::json preset_obj;
|
||||
auto preset_op = CollectionManager::get_instance().
|
||||
get_preset(el["preset"].get<std::string>(), preset_obj);
|
||||
if(preset_op.ok() && preset_obj.count("collection") != 0 &&
|
||||
preset_obj["collection"].is_string()) {
|
||||
coll_name = preset_obj["collection"].get<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& access_key = (el.count("x-typesense-api-key") != 0 &&
|
||||
@ -523,6 +534,27 @@ bool post_multi_search(const std::shared_ptr<http_req>& req, const std::shared_p
|
||||
}
|
||||
}
|
||||
|
||||
if(search_params.count("preset") != 0) {
|
||||
nlohmann::json preset;
|
||||
auto preset_op = CollectionManager::get_instance().get_preset(search_params["preset"].get<std::string>(),
|
||||
preset);
|
||||
if(preset_op.ok()) {
|
||||
if(!search_params.is_object()) {
|
||||
res->set_400("Search preset is not an object.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const auto& search_item: preset.items()) {
|
||||
// overwrite = false since req params will contain embedded params and so has higher priority
|
||||
bool populated = AuthManager::add_item_to_params(req->params, search_item, false);
|
||||
if(!populated) {
|
||||
res->set_400("One or more search parameters are malformed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string results_json_str;
|
||||
Option<bool> search_op = CollectionManager::do_search(req->params, req->embedded_params_vec[i],
|
||||
results_json_str, req->conn_ts);
|
||||
|
@ -660,6 +660,32 @@ TEST_F(CollectionManagerTest, RestoreAutoSchemaDocsOnRestart) {
|
||||
collectionManager2.drop_collection("coll1");
|
||||
}
|
||||
|
||||
TEST_F(CollectionManagerTest, RestorePresetsOnRestart) {
|
||||
auto preset_value = R"(
|
||||
{"q":"*", "per_page": "12"}
|
||||
)"_json;
|
||||
|
||||
collectionManager.upsert_preset("single_preset", preset_value);
|
||||
|
||||
// create a new collection manager to ensure that it restores the records from the disk backed store
|
||||
CollectionManager& collectionManager2 = CollectionManager::get_instance();
|
||||
collectionManager2.init(store, 1.0, "auth_key", quit);
|
||||
auto load_op = collectionManager2.load(8, 1000);
|
||||
|
||||
if(!load_op.ok()) {
|
||||
LOG(ERROR) << load_op.error();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(load_op.ok());
|
||||
|
||||
nlohmann::json preset;
|
||||
collectionManager2.get_preset("single_preset", preset);
|
||||
ASSERT_EQ("*", preset["q"].get<std::string>());
|
||||
|
||||
collectionManager.drop_collection("coll1");
|
||||
collectionManager2.drop_collection("coll1");
|
||||
}
|
||||
|
||||
TEST_F(CollectionManagerTest, RestoreNestedDocsOnRestart) {
|
||||
nlohmann::json schema = R"({
|
||||
"name": "coll1",
|
||||
|
@ -2125,6 +2125,32 @@ TEST_F(CollectionNestedFieldsTest, ErrorWhenObjectTypeUsedWithoutEnablingNestedF
|
||||
"enable_nested_fields` to true.", op.error());
|
||||
}
|
||||
|
||||
TEST_F(CollectionNestedFieldsTest, FieldsWithDotsButNotNested) {
|
||||
nlohmann::json schema = R"({
|
||||
"name": "coll1",
|
||||
"enable_nested_fields": true,
|
||||
"fields": [
|
||||
{"name": "name.first", "type": "string"}
|
||||
]
|
||||
})"_json;
|
||||
|
||||
auto op = collectionManager.create_collection(schema);
|
||||
ASSERT_TRUE(op.ok());
|
||||
Collection* coll1 = op.get();
|
||||
|
||||
auto doc1 = R"({
|
||||
"name.first": "Alpha Beta Gamma"
|
||||
})"_json;
|
||||
|
||||
auto add_op = coll1->add(doc1.dump(), CREATE);
|
||||
ASSERT_TRUE(add_op.ok());
|
||||
|
||||
auto results = coll1->search("beta", {"name.first"}, "", {}, {}, {0}, 10, 1, FREQUENCY, {false}).get();
|
||||
ASSERT_EQ(1, results["found"].get<size_t>());
|
||||
ASSERT_EQ("Alpha <mark>Beta</mark> Gamma",
|
||||
results["hits"][0]["highlight"]["name.first"]["snippet"].get<std::string>());
|
||||
}
|
||||
|
||||
TEST_F(CollectionNestedFieldsTest, UpdateNestedDocument) {
|
||||
nlohmann::json schema = R"({
|
||||
"name": "coll1",
|
||||
|
@ -491,7 +491,7 @@ TEST_F(CoreAPIUtilsTest, MultiSearchWithPresetShouldUsePresetForAuth) {
|
||||
std::vector<collection_key_t> collections;
|
||||
std::vector<nlohmann::json> embedded_params_vec;
|
||||
|
||||
std::string other_body = R"(
|
||||
std::string search_body = R"(
|
||||
{"searches":[
|
||||
{"collection":"foo1","q":"apple", "query_by": "title"},
|
||||
{"collection":"bar1","q":"apple", "query_by": "title"}
|
||||
@ -500,7 +500,7 @@ TEST_F(CoreAPIUtilsTest, MultiSearchWithPresetShouldUsePresetForAuth) {
|
||||
|
||||
// without preset parameter, use collections from request body
|
||||
|
||||
get_collections_for_auth(req_params, other_body, rpath_multi_search, "", collections, embedded_params_vec);
|
||||
get_collections_for_auth(req_params, search_body, rpath_multi_search, "", collections, embedded_params_vec);
|
||||
|
||||
ASSERT_EQ(2, collections.size());
|
||||
ASSERT_EQ("foo1", collections[0].collection);
|
||||
@ -512,12 +512,98 @@ TEST_F(CoreAPIUtilsTest, MultiSearchWithPresetShouldUsePresetForAuth) {
|
||||
embedded_params_vec.clear();
|
||||
|
||||
req_params["preset"] = "apple";
|
||||
get_collections_for_auth(req_params, other_body, rpath_multi_search, "", collections, embedded_params_vec);
|
||||
get_collections_for_auth(req_params, search_body, rpath_multi_search, "", collections, embedded_params_vec);
|
||||
|
||||
ASSERT_EQ(2, collections.size());
|
||||
ASSERT_EQ("foo", collections[0].collection);
|
||||
ASSERT_EQ("bar", collections[1].collection);
|
||||
ASSERT_EQ(2, embedded_params_vec.size());
|
||||
|
||||
// try using multi_search preset within individual search param
|
||||
|
||||
preset_value = R"(
|
||||
{"collection":"preset_coll"}
|
||||
)"_json;
|
||||
|
||||
collectionManager.upsert_preset("single_preset", preset_value);
|
||||
|
||||
req_params.clear();
|
||||
collections.clear();
|
||||
embedded_params_vec.clear();
|
||||
|
||||
search_body = R"(
|
||||
{"searches":[
|
||||
{"collection":"foo1","q":"apple", "query_by": "title", "preset": "single_preset"},
|
||||
{"collection":"bar1","q":"apple", "query_by": "title", "preset": "single_preset"}
|
||||
]}
|
||||
)";
|
||||
|
||||
get_collections_for_auth(req_params, search_body, rpath_multi_search, "", collections, embedded_params_vec);
|
||||
|
||||
ASSERT_EQ(2, collections.size());
|
||||
ASSERT_EQ("foo1", collections[0].collection);
|
||||
ASSERT_EQ("bar1", collections[1].collection);
|
||||
ASSERT_EQ(2, embedded_params_vec.size());
|
||||
|
||||
// without collection in search array
|
||||
req_params.clear();
|
||||
collections.clear();
|
||||
embedded_params_vec.clear();
|
||||
|
||||
search_body = R"(
|
||||
{"searches":[
|
||||
{"q":"apple", "query_by": "title", "preset": "single_preset"},
|
||||
{"q":"apple", "query_by": "title", "preset": "single_preset"}
|
||||
]}
|
||||
)";
|
||||
|
||||
get_collections_for_auth(req_params, search_body, rpath_multi_search, "", collections, embedded_params_vec);
|
||||
|
||||
ASSERT_EQ(2, collections.size());
|
||||
ASSERT_EQ("preset_coll", collections[0].collection);
|
||||
ASSERT_EQ("preset_coll", collections[1].collection);
|
||||
ASSERT_EQ(2, embedded_params_vec.size());
|
||||
}
|
||||
|
||||
TEST_F(CoreAPIUtilsTest, PresetSingleSearch) {
|
||||
nlohmann::json schema = R"({
|
||||
"name": "coll1",
|
||||
"fields": [
|
||||
{"name": "name", "type": "string" },
|
||||
{"name": "points", "type": "int32" }
|
||||
]
|
||||
})"_json;
|
||||
|
||||
auto op = collectionManager.create_collection(schema);
|
||||
ASSERT_TRUE(op.ok());
|
||||
Collection* coll1 = op.get();
|
||||
|
||||
auto preset_value = R"(
|
||||
{"collection":"preset_coll", "per_page": "12"}
|
||||
)"_json;
|
||||
|
||||
collectionManager.upsert_preset("single_preset", preset_value);
|
||||
|
||||
std::shared_ptr<http_req> req = std::make_shared<http_req>();
|
||||
std::shared_ptr<http_res> res = std::make_shared<http_res>(nullptr);
|
||||
req->params["collection"] = "coll1";
|
||||
|
||||
auto search_body = R"(
|
||||
{"searches":[
|
||||
{"collection":"coll1","q":"apple", "query_by": "title", "preset": "single_preset"}
|
||||
]}
|
||||
)";
|
||||
|
||||
req->body = search_body;
|
||||
nlohmann::json embedded_params;
|
||||
req->embedded_params_vec.push_back(embedded_params);
|
||||
|
||||
post_multi_search(req, res);
|
||||
|
||||
ASSERT_EQ("12", req->params["per_page"]);
|
||||
ASSERT_EQ("coll1", req->params["collection"]);
|
||||
|
||||
collectionManager.drop_collection("coll1");
|
||||
}
|
||||
|
||||
TEST_F(CoreAPIUtilsTest, ExportWithFilter) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user