Skip to content

Commit

Permalink
Add contains_key to managed maps (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
leemaguire authored Jul 16, 2024
1 parent 9044238 commit 359569d
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ NEXT-RELEASE Release notes (YYYY-MM-DD)
* Add ability to use `managed<std::map<std::string, T>>` in type safe queries when comparing a value for a key. e.g.
`realm.object<MyObject>().where([](auto& o) { return o.my_map["foo_key"] == "some value"; })`
Supported operators are `==`, `!=`, `>`, `<`, `>=`, `<=` and `contains(const std::string&)`.
* Add `managed<std::map<std::string, T>>::contains_key` for conveniently checking if a managed map
contains a given key. Use this method in the Type Safe Query API instead of `managed<std::map<std::string, T>>::find`.

### Compatibility
* Fileformat: Generates files with format v24. Reads and automatically upgrade from fileformat v10.
Expand Down
1 change: 1 addition & 0 deletions include/cpprealm/internal/bridge/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ namespace realm::internal::bridge {
query& dictionary_has_value_for_key_greater_than_equals(col_key column_key, const std::string& key, const mixed& value);
query& dictionary_has_value_for_key_less_than_equals(col_key column_key, const std::string& key, const mixed& value);
query& dictionary_contains_string_for_key(col_key column_key, const std::string& key, const std::string& value);
query& dictionary_contains_key(col_key column_key, const std::string& key);
subexpr dictionary_link_subexpr(col_key column_key, col_key link_column_key, const std::string& key);

// Expressions
Expand Down
12 changes: 12 additions & 0 deletions include/cpprealm/managed_dictionary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,9 @@ namespace realm {
}

iterator find(const std::string& key) {
if (m_rbool_query) {
throw std::runtime_error("`find` is not available in Type Safe Queries, use `contains_key` instead.");
}
// Dictionary's `find` searches for the index of the value and not the key.
auto d = m_obj->get_dictionary(m_key);
auto i = d.find_any_key(key);
Expand Down Expand Up @@ -627,6 +630,15 @@ namespace realm {
m_obj->get_dictionary(m_key).erase(key);
}

/// Convenience method to be primarily used in type safe queries.
rbool contains_key(const std::string& key) {
if (m_rbool_query) {
return m_rbool_query->dictionary_has_key(m_key, key);
} else {
return m_obj->get_dictionary(m_key).find_any_key(key) != size_t(-1);
}
}

notification_token observe(std::function<void(realm::dictionary_collection_change)>&& fn)
{
auto o = internal::bridge::object(*m_realm, *m_obj);
Expand Down
5 changes: 5 additions & 0 deletions include/cpprealm/rbool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ namespace realm {
return *this;
}

rbool& dictionary_has_key(internal::bridge::col_key column_key, const std::string& key) {
q = internal::bridge::query(q.get_table()).dictionary_contains_key(column_key, key);
return *this;
}

~rbool() {
if (is_for_queries)
q.~query();
Expand Down
9 changes: 9 additions & 0 deletions src/cpprealm/internal/bridge/query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,15 @@ namespace realm::internal::bridge {
return *this;
}

query& query::dictionary_contains_key(col_key column_key, const std::string& key) {
#ifdef CPPREALM_HAVE_GENERATED_BRIDGE_TYPES
*reinterpret_cast<Query *>(&m_query) = reinterpret_cast<Query *>(&m_query)->get_table()->column<CoreDictionary>(column_key.operator ColKey()).keys().contains(key);
#else
m_query = std::make_shared<Query>(m_query->get_table()->column<CoreDictionary>(column_key.operator ColKey()).keys().contains(key));
#endif
return *this;
}

subexpr query::dictionary_link_subexpr(col_key column_key, col_key link_column_key, const std::string& key) {
#ifdef CPPREALM_HAVE_GENERATED_BRIDGE_TYPES
auto table = reinterpret_cast<Query *>(&m_query)->get_table()->column<CoreDictionary>(column_key.operator ColKey()).key(key).get_target_table();
Expand Down
16 changes: 16 additions & 0 deletions tests/db/map_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,22 @@ TEST_CASE("map", "[map]") {
CHECK(as_values == std::map<std::string, std::string>({{"a", std::string("baz")}, {"b", std::string("foo")}}));
}

SECTION("contains_key") {
auto obj = AllTypesObject();
obj.map_str_col = {
{"a", std::string("baz")},
{"b", std::string("foo")}
};

auto realm = db(std::move(config));
auto managed_obj = realm.write([&realm, &obj] {
return realm.add(std::move(obj));
});

CHECK(managed_obj.map_str_col.contains_key("a"));
CHECK_FALSE(managed_obj.map_str_col.contains_key("c"));
}

SECTION("object lifetime") {
managed<AllTypesObjectLink> ptr;
{
Expand Down
6 changes: 6 additions & 0 deletions tests/db/query_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,12 @@ namespace realm {

// Test non existent key
CHECK(do_query([](realm::managed<AllTypesObject>& o) -> rbool { return o.map_int_col["NA"] == 1; }) == 0);

// Check key exists in dictionary
CHECK(do_query([](realm::managed<AllTypesObject>& o) -> rbool { return o.map_int_col.contains_key("one"); }) == 3);
CHECK(do_query([](realm::managed<AllTypesObject>& o) -> rbool { return o.map_int_col.contains_key("three"); }) == 0);
CHECK(do_query([](realm::managed<AllTypesObject>& o) -> rbool { return o.map_int_col.contains_key("one"); }) != 0);
CHECK(do_query([](realm::managed<AllTypesObject>& o) -> rbool { return o.map_int_col.contains_key("three"); }) != 3);
}
}
}

0 comments on commit 359569d

Please sign in to comment.