Fix bug in importing a reference doc having an id field.

This commit is contained in:
Harpreet Sangar 2023-08-29 17:09:29 +05:30
parent 6a573b4541
commit 8229ba5435
3 changed files with 80 additions and 62 deletions

View File

@ -361,6 +361,8 @@ public:
std::string get_default_sorting_field();
Option<bool> add_reference_helper_fields(nlohmann::json& document);
Option<doc_seq_id_t> to_doc(const std::string& json_str, nlohmann::json& document,
const index_operation_t& operation,
const DIRTY_VALUES dirty_values,

View File

@ -74,6 +74,73 @@ uint32_t Collection::get_next_seq_id() {
return next_seq_id++;
}
Option<bool> Collection::add_reference_helper_fields(nlohmann::json& document) {
// Add reference helper fields in the document.
for (auto const& pair: reference_fields) {
auto field_name = pair.first;
auto optional = get_schema().at(field_name).optional;
if (!optional && document.count(field_name) != 1) {
return Option<bool>(400, "Missing the required reference field `" + field_name
+ "` in the document.");
} else if (document.count(field_name) != 1) {
continue;
}
auto reference_pair = pair.second;
auto reference_collection_name = reference_pair.collection;
auto reference_field_name = reference_pair.field;
auto& cm = CollectionManager::get_instance();
auto ref_collection = cm.get_collection(reference_collection_name);
if (ref_collection == nullptr) {
return Option<bool>(400, "Referenced collection `" + reference_collection_name
+ "` not found.");
}
if (reference_field_name == "id") {
auto value = document[field_name].get<std::string>();
auto ref_doc_id_op = ref_collection->doc_id_to_seq_id(value);
if (!ref_doc_id_op.ok()) {
return Option<bool>(400, "Referenced document having `id: " + value +
"` not found in the collection `" +
reference_collection_name + "`." );
}
document[field_name + REFERENCE_HELPER_FIELD_SUFFIX] = ref_doc_id_op.get();
continue;
}
if (ref_collection->get_schema().count(reference_field_name) == 0) {
return Option<bool>(400, "Referenced field `" + reference_field_name +
"` not found in the collection `" + reference_collection_name + "`.");
}
if (!ref_collection->get_schema().at(reference_field_name).index) {
return Option<bool>(400, "Referenced field `" + reference_field_name +
"` in the collection `" + reference_collection_name + "` must be indexed.");
}
// Get the doc id of the referenced document.
auto value = document[field_name].get<std::string>();
filter_result_t filter_result;
ref_collection->get_filter_ids(reference_field_name + ":=" + value, filter_result);
if (filter_result.count != 1) {
auto match = " `" + reference_field_name + ": " + value + "` ";
// Constraints similar to foreign key apply here. The reference match must be unique and not null.
return Option<bool>(400, filter_result.count < 1 ?
"Referenced document having" + match + "not found in the collection `"
+ reference_collection_name + "`." :
"Multiple documents having" + match + "found in the collection `" +
reference_collection_name + "`.");
}
document[field_name + REFERENCE_HELPER_FIELD_SUFFIX] = filter_result.docs[0];
}
return Option<bool>(true);
}
Option<doc_seq_id_t> Collection::to_doc(const std::string & json_str, nlohmann::json& document,
const index_operation_t& operation,
const DIRTY_VALUES dirty_values,
@ -110,68 +177,9 @@ Option<doc_seq_id_t> Collection::to_doc(const std::string & json_str, nlohmann::
uint32_t seq_id = get_next_seq_id();
document["id"] = std::to_string(seq_id);
// Add reference helper fields in the document.
for (auto const& pair: reference_fields) {
auto field_name = pair.first;
auto optional = get_schema().at(field_name).optional;
if (!optional && document.count(field_name) != 1) {
return Option<doc_seq_id_t>(400, "Missing the required reference field `" + field_name
+ "` in the document.");
} else if (document.count(field_name) != 1) {
continue;
}
auto reference_pair = pair.second;
auto reference_collection_name = reference_pair.collection;
auto reference_field_name = reference_pair.field;
auto& cm = CollectionManager::get_instance();
auto ref_collection = cm.get_collection(reference_collection_name);
if (ref_collection == nullptr) {
return Option<doc_seq_id_t>(400, "Referenced collection `" + reference_collection_name
+ "` not found.");
}
if (reference_field_name == "id") {
auto value = document[field_name].get<std::string>();
auto ref_doc_id_op = ref_collection->doc_id_to_seq_id(value);
if (!ref_doc_id_op.ok()) {
return Option<doc_seq_id_t>(400, "Referenced document having `id: " + value +
"` not found in the collection `" +
reference_collection_name + "`." );
}
document[field_name + REFERENCE_HELPER_FIELD_SUFFIX] = ref_doc_id_op.get();
continue;
}
if (ref_collection->get_schema().count(reference_field_name) == 0) {
return Option<doc_seq_id_t>(400, "Referenced field `" + reference_field_name +
"` not found in the collection `" + reference_collection_name + "`.");
}
if (!ref_collection->get_schema().at(reference_field_name).index) {
return Option<doc_seq_id_t>(400, "Referenced field `" + reference_field_name +
"` in the collection `" + reference_collection_name + "` must be indexed.");
}
// Get the doc id of the referenced document.
auto value = document[field_name].get<std::string>();
filter_result_t filter_result;
ref_collection->get_filter_ids(reference_field_name + ":=" + value, filter_result);
if (filter_result.count != 1) {
auto match = " `" + reference_field_name + ": " + value + "` ";
// Constraints similar to foreign key apply here. The reference match must be unique and not null.
return Option<doc_seq_id_t>(400, filter_result.count < 1 ?
"Referenced document having" + match + "not found in the collection `"
+ reference_collection_name + "`." :
"Multiple documents having" + match + "found in the collection `" +
reference_collection_name + "`.");
}
document[field_name + REFERENCE_HELPER_FIELD_SUFFIX] = filter_result.docs[0];
auto add_reference_helper_fields_op = add_reference_helper_fields(document);
if (!add_reference_helper_fields_op.ok()) {
return Option<doc_seq_id_t>(add_reference_helper_fields_op.code(), add_reference_helper_fields_op.error());
}
return Option<doc_seq_id_t>(doc_seq_id_t{seq_id, true});
@ -210,6 +218,11 @@ Option<doc_seq_id_t> Collection::to_doc(const std::string & json_str, nlohmann::
// for UPSERT, EMPLACE or CREATE, if a document with given ID is not found, we will treat it as a new doc
uint32_t seq_id = get_next_seq_id();
auto add_reference_helper_fields_op = add_reference_helper_fields(document);
if (!add_reference_helper_fields_op.ok()) {
return Option<doc_seq_id_t>(add_reference_helper_fields_op.code(), add_reference_helper_fields_op.error());
}
return Option<doc_seq_id_t>(doc_seq_id_t{seq_id, true});
}
}

View File

@ -298,6 +298,7 @@ TEST_F(CollectionJoinTest, IndexDocumentHavingReferenceField) {
R"({
"name": "id_ref",
"fields": [
{"name": "id", "type": "string"},
{"name": "reference", "type": "string", "reference": "Products.id"}
]
})"_json;
@ -306,6 +307,7 @@ TEST_F(CollectionJoinTest, IndexDocumentHavingReferenceField) {
auto id_ref_collection = collection_create_op.get();
auto id_ref_json = R"({
"id": "0",
"reference": "foo"
})"_json;
add_doc_op = id_ref_collection->add(id_ref_json.dump());
@ -313,6 +315,7 @@ TEST_F(CollectionJoinTest, IndexDocumentHavingReferenceField) {
ASSERT_EQ("Referenced document having `id: foo` not found in the collection `Products`.", add_doc_op.error());
id_ref_json = R"({
"id": "0",
"reference": "1"
})"_json;
add_doc_op = id_ref_collection->add(id_ref_json.dump());