Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
}