diff --git a/CHANGELOG.md b/CHANGELOG.md index b3cc85fb864..a6ffabe571e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * (PR [#????](https://github.com/realm/realm-core/pull/????)) * Convert object_store::Collection types into Results (PR [#5845](https://github.com/realm/realm-core/pull/5845)) * Expose `realm_object_get_parent` in the C API (PR [#5851](https://github.com/realm/realm-core/pull/5851)) +* Expose `realm_list_find` in the C API (PR [#5848](https://github.com/realm/realm-core/pull/5848)) ### Fixed * ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?) diff --git a/src/realm.h b/src/realm.h index 86585fa37fe..2992c98b7c8 100644 --- a/src/realm.h +++ b/src/realm.h @@ -1703,6 +1703,15 @@ RLM_API bool realm_list_get_property(const realm_list_t*, realm_property_info_t* */ RLM_API bool realm_list_get(const realm_list_t*, size_t index, realm_value_t* out_value); +/** + * Find the value in the list passed as parameter. + * @param value to search in the list + * @param out_index the index in the list where the value has been found or realm::not_found. + * @param out_found boolean that indicates whether the value is found or not + * @return true if no exception occurred. + */ +RLM_API bool realm_list_find(const realm_list_t*, const realm_value_t* value, size_t* out_index, bool* out_found); + /** * Set the value at @a index. * diff --git a/src/realm/list.hpp b/src/realm/list.hpp index f571be402a1..70e4583587f 100644 --- a/src/realm/list.hpp +++ b/src/realm/list.hpp @@ -1047,6 +1047,12 @@ inline size_t LnkLst::find_any(Mixed value) const else if (value.get_type() == type_Link) { return find_first(value.get()); } + else if (value.get_type() == type_TypedLink) { + auto link = value.get_link(); + if (link.get_table_key() == get_target_table()->get_key()) { + return find_first(link.get_obj_key()); + } + } return realm::not_found; } diff --git a/src/realm/object-store/c_api/list.cpp b/src/realm/object-store/c_api/list.cpp index ca26a0d7c3b..49a8fcf27cf 100644 --- a/src/realm/object-store/c_api/list.cpp +++ b/src/realm/object-store/c_api/list.cpp @@ -51,6 +51,27 @@ RLM_API bool realm_list_get(const realm_list_t* list, size_t index, realm_value_ }); } +RLM_API bool realm_list_find(const realm_list_t* list, const realm_value_t* value, size_t* out_index, bool* out_found) +{ + if (out_index) + *out_index = realm::not_found; + if (out_found) + *out_found = false; + + return wrap_err([&] { + list->verify_attached(); + auto val = from_capi(*value); + check_value_assignable(*list, val); + auto index = list->find_any(val); + if (out_index) + *out_index = index; + if (out_found) + *out_found = index < list->size(); + return true; + }); +} + + RLM_API bool realm_list_insert(realm_list_t* list, size_t index, realm_value_t value) { return wrap_err([&]() { diff --git a/src/realm/set.hpp b/src/realm/set.hpp index c426f35378c..93e1cb1b787 100644 --- a/src/realm/set.hpp +++ b/src/realm/set.hpp @@ -1240,13 +1240,18 @@ inline size_t LnkSet::find_any(Mixed value) const { if (value.is_null()) return not_found; - if (value.get_type() != type_Link) - return not_found; - size_t found = find(value.get()); - if (found != not_found) { - found = real2virtual(found); + + const auto type = value.get_type(); + if (type == type_Link) { + return find(value.get()); + } + if (type == type_TypedLink) { + auto link = value.get_link(); + if (link.get_table_key() == get_target_table()->get_key()) { + return find(link.get_obj_key()); + } } - return found; + return not_found; } inline bool LnkSet::is_obj_valid(size_t) const noexcept diff --git a/test/object-store/c_api/c_api.cpp b/test/object-store/c_api/c_api.cpp index 36a472aa7fb..32776ef2a2e 100644 --- a/test/object-store/c_api/c_api.cpp +++ b/test/object-store/c_api/c_api.cpp @@ -2460,6 +2460,23 @@ TEST_CASE("C API", "[c_api]") { CHECK(rlm_stdstr(a2) == "a"); CHECK(rlm_stdstr(b2) == "b"); CHECK(c2.type == RLM_TYPE_NULL); + + size_t out_index = -1; + bool found; + CHECK(checked(realm_list_find(strings.get(), &a2, &out_index, &found))); + CHECK(out_index == 0); + CHECK(found); + CHECK(checked(realm_list_find(strings.get(), &b2, &out_index, &found))); + CHECK(out_index == 1); + CHECK(found); + CHECK(checked(realm_list_find(strings.get(), &c2, &out_index, &found))); + CHECK(out_index == 2); + CHECK(found); + + realm_value_t dummy = rlm_str_val("c"); + CHECK(checked(realm_list_find(strings.get(), &dummy, &out_index, &found))); + CHECK(!found); + CHECK(out_index == realm::not_found); }); } @@ -2558,49 +2575,77 @@ TEST_CASE("C API", "[c_api]") { CHECK(realm_list_insert(nullable_uuid_list.get(), 1, null)); }); - realm_value_t value; + auto find = ([&](auto* list, auto* value) { + std::size_t index = -1; + bool found = false; + CHECK(checked(realm_list_find(list, value, &index, &found))); + CHECK(index == 0); + CHECK(found); + return (index < list->size()) && found == true; + }); + realm_value_t value; CHECK(realm_list_get(int_list.get(), 0, &value)); CHECK(rlm_val_eq(value, integer)); CHECK(!realm_list_get_linked_object(int_list.get(), 0)); + CHECK(find(int_list.get(), &value)); CHECK(realm_list_get(bool_list.get(), 0, &value)); CHECK(rlm_val_eq(value, boolean)); + CHECK(find(bool_list.get(), &value)); CHECK(realm_list_get(string_list.get(), 0, &value)); CHECK(rlm_val_eq(value, string)); + CHECK(find(string_list.get(), &value)); CHECK(realm_list_get(binary_list.get(), 0, &value)); CHECK(rlm_val_eq(value, binary)); + CHECK(find(binary_list.get(), &value)); CHECK(realm_list_get(timestamp_list.get(), 0, &value)); CHECK(rlm_val_eq(value, timestamp)); + CHECK(find(timestamp_list.get(), &value)); CHECK(realm_list_get(float_list.get(), 0, &value)); CHECK(rlm_val_eq(value, fnum)); + CHECK(find(float_list.get(), &value)); CHECK(realm_list_get(double_list.get(), 0, &value)); CHECK(rlm_val_eq(value, dnum)); + CHECK(find(double_list.get(), &value)); CHECK(realm_list_get(decimal_list.get(), 0, &value)); CHECK(rlm_val_eq(value, decimal)); + CHECK(find(decimal_list.get(), &value)); CHECK(realm_list_get(object_id_list.get(), 0, &value)); CHECK(rlm_val_eq(value, object_id)); + CHECK(find(object_id_list.get(), &value)); CHECK(realm_list_get(uuid_list.get(), 0, &value)); CHECK(rlm_val_eq(value, uuid)); + CHECK(find(uuid_list.get(), &value)); CHECK(realm_list_get(nullable_int_list.get(), 0, &value)); CHECK(rlm_val_eq(value, integer)); + CHECK(find(nullable_int_list.get(), &value)); CHECK(realm_list_get(nullable_bool_list.get(), 0, &value)); CHECK(rlm_val_eq(value, boolean)); + CHECK(find(nullable_bool_list.get(), &value)); CHECK(realm_list_get(nullable_string_list.get(), 0, &value)); CHECK(rlm_val_eq(value, string)); + CHECK(find(nullable_string_list.get(), &value)); CHECK(realm_list_get(nullable_binary_list.get(), 0, &value)); CHECK(rlm_val_eq(value, binary)); + CHECK(find(nullable_binary_list.get(), &value)); CHECK(realm_list_get(nullable_timestamp_list.get(), 0, &value)); CHECK(rlm_val_eq(value, timestamp)); + CHECK(find(nullable_timestamp_list.get(), &value)); CHECK(realm_list_get(nullable_float_list.get(), 0, &value)); CHECK(rlm_val_eq(value, fnum)); + CHECK(find(nullable_float_list.get(), &value)); CHECK(realm_list_get(nullable_double_list.get(), 0, &value)); CHECK(rlm_val_eq(value, dnum)); + CHECK(find(nullable_double_list.get(), &value)); CHECK(realm_list_get(nullable_decimal_list.get(), 0, &value)); CHECK(rlm_val_eq(value, decimal)); + CHECK(find(nullable_decimal_list.get(), &value)); CHECK(realm_list_get(nullable_object_id_list.get(), 0, &value)); CHECK(rlm_val_eq(value, object_id)); + CHECK(find(nullable_object_id_list.get(), &value)); CHECK(realm_list_get(nullable_uuid_list.get(), 0, &value)); CHECK(rlm_val_eq(value, uuid)); + CHECK(find(nullable_uuid_list.get(), &value)); write([&]() { CHECK(realm_list_insert(nullable_int_list.get(), 0, null)); @@ -2651,6 +2696,20 @@ TEST_CASE("C API", "[c_api]") { size_t size; CHECK(checked(realm_list_size(bars.get(), &size))); CHECK(size == 2); + + bool found = true; + size_t index = -1; + CHECK(checked(realm_list_find(bars.get(), &bar_link_val, &index, &found))); + CHECK(index == 0); + CHECK(found); + + realm_list_clear(bars.get()); + CHECK(checked(realm_list_find(bars.get(), &bar_link_val, &index, &found))); + CHECK(index == realm::not_found); + CHECK(!found); + + CHECK(checked(realm_list_insert(bars.get(), 0, bar_link_val))); + CHECK(checked(realm_list_insert(bars.get(), 1, bar_link_val))); }); SECTION("get") { diff --git a/test/test_set.cpp b/test/test_set.cpp index a2d3c4c0f5b..93e0f48ae31 100644 --- a/test/test_set.cpp +++ b/test/test_set.cpp @@ -268,8 +268,9 @@ TEST(Set_Links) CHECK_EQUAL(set_mixeds.find(bar3.get_link()), realm::npos); bar1.remove(); + set_links.insert(bar4.get_key()); - CHECK_EQUAL(set_links.size(), 2); + CHECK_EQUAL(set_links.size(), 3); CHECK_EQUAL(set_typed_links.size(), 3); CHECK_EQUAL(set_mixeds.size(), 3); @@ -281,14 +282,16 @@ TEST(Set_Links) auto bar2_link = bar2.get_link(); bar2.invalidate(); - CHECK_EQUAL(set_links.size(), 2); - CHECK_EQUAL(lnkset_links->size(), 1); // Unresolved link was hidden from LnkSet + CHECK_EQUAL(set_links.size(), 3); + CHECK_EQUAL(lnkset_links->size(), 2); // Unresolved link was hidden from LnkSet CHECK_EQUAL(set_typed_links.size(), 3); CHECK_EQUAL(set_mixeds.size(), 3); CHECK_EQUAL(set_links.find(bar2_key), realm::npos); // The original bar2 key is no longer in the set CHECK_NOT_EQUAL(set_links.find(bar2.get_key()), realm::npos); // The unresolved bar2 key is in the set CHECK_EQUAL(lnkset_links->find_any(bar2.get_key()), realm::npos); // The unresolved bar2 key is hidden by LnkSet + CHECK_EQUAL(lnkset_links->find_any(bar3.get_key()), 0); + CHECK_EQUAL(lnkset_links->find_any(bar4.get_key()), 1); CHECK_EQUAL(set_typed_links.find(bar2_link), realm::npos); CHECK_EQUAL(set_mixeds.find(bar2_link), realm::npos);