diff --git a/src/realm/object-store/collection.hpp b/src/realm/object-store/collection.hpp index e809ee2bab1..5c0765f7c1b 100644 --- a/src/realm/object-store/collection.hpp +++ b/src/realm/object-store/collection.hpp @@ -156,6 +156,13 @@ void Collection::validate_embedded(Context& ctx, T&& value, CreatePolicy policy) throw IllegalOperation(util::format("Cannot add an existing managed embedded object to a %1.", type_name())); } +// Dummy implementation to satisfy StringifyingContext +inline std::ostream& operator<<(std::ostream& out, const Collection&) +{ + return out; +} + + } // namespace object_store } // namespace realm diff --git a/src/realm/object-store/dictionary.hpp b/src/realm/object-store/dictionary.hpp index 6ead9d7f6bc..717501d6531 100644 --- a/src/realm/object-store/dictionary.hpp +++ b/src/realm/object-store/dictionary.hpp @@ -223,9 +223,21 @@ void Dictionary::insert(Context& ctx, StringData key, T&& value, CreatePolicy po template auto Dictionary::get(Context& ctx, StringData key) const { - return dispatch([&](auto t) { - return ctx.box(this->get>(key)); - }); + if (m_type == PropertyType::Mixed) { + Mixed value = dict().get(key); + if (value.is_type(type_Dictionary)) { + return ctx.box(get_dictionary(key)); + } + if (value.is_type(type_List)) { + return ctx.box(get_list(key)); + } + return ctx.box(value); + } + else { + return dispatch([&](auto t) { + return ctx.box(this->get>(key)); + }); + } } template diff --git a/src/realm/object-store/list.hpp b/src/realm/object-store/list.hpp index c7724c8d40f..821fc62bc4e 100644 --- a/src/realm/object-store/list.hpp +++ b/src/realm/object-store/list.hpp @@ -171,9 +171,21 @@ auto List::dispatch(Fn&& fn) const template auto List::get(Context& ctx, size_t row_ndx) const { - return dispatch([&](auto t) { - return ctx.box(this->get>(row_ndx)); - }); + if (m_type == PropertyType::Mixed) { + Mixed value = get(row_ndx); + if (value.is_type(type_Dictionary)) { + return ctx.box(get_dictionary(row_ndx)); + } + if (value.is_type(type_List)) { + return ctx.box(get_list(row_ndx)); + } + return ctx.box(value); + } + else { + return dispatch([&](auto t) { + return ctx.box(this->get>(row_ndx)); + }); + } } template diff --git a/src/realm/object-store/object_accessor.hpp b/src/realm/object-store/object_accessor.hpp index 2435e29f529..6f13ea55a6b 100644 --- a/src/realm/object-store/object_accessor.hpp +++ b/src/realm/object-store/object_accessor.hpp @@ -234,8 +234,16 @@ ValueType Object::get_property_value_impl(ContextType& ctx, const Property& prop case PropertyType::UUID: return is_nullable(property.type) ? ctx.box(m_obj.get>(column)) : ctx.box(m_obj.get(column)); - case PropertyType::Mixed: - return ctx.box(m_obj.get(column)); + case PropertyType::Mixed: { + Mixed value = m_obj.get(column); + if (value.is_type(type_Dictionary)) { + return ctx.box(object_store::Dictionary(m_realm, m_obj, column)); + } + if (value.is_type(type_List)) { + return ctx.box(List(m_realm, m_obj, column)); + } + return ctx.box(value); + } case PropertyType::Object: { auto linkObjectSchema = m_realm->schema().find(property.object_type); auto linked = const_cast(m_obj).get_linked_object(column); diff --git a/test/object-store/dictionary.cpp b/test/object-store/dictionary.cpp index ca096d4e140..58a146e88f8 100644 --- a/test/object-store/dictionary.cpp +++ b/test/object-store/dictionary.cpp @@ -1369,9 +1369,10 @@ TEST_CASE("nested collection set by Object::create", "[dictionary]") { auto obj = Object::create(ctx, r, *r->schema().find("DictionaryObject"), value); r->commit_transaction(); - object_store::Dictionary dict(obj, r->schema().find("DictionaryObject")->property_for_name("any")); - auto dict0 = dict.get_dictionary("0"); - auto list1 = dict.get_list("1"); + auto dict = util::any_cast(obj.get_property_value(ctx, "any")); + + auto dict0 = util::any_cast(dict.get(ctx, "0")); + auto list1 = util::any_cast(dict.get(ctx, "1")); auto dict2 = dict.get_dictionary("2"); CHECK(dict0.get_any("zero") == Mixed(0)); CHECK(list1.get_any(0) == Mixed("one")); @@ -1422,8 +1423,8 @@ TEST_CASE("nested collection set by Object::create", "[dictionary]") { r->begin_transaction(); Object::create(ctx, r, *r->schema().find("DictionaryObject"), value, CreatePolicy::UpdateModified); r->commit_transaction(); - List list(obj, r->schema().find("DictionaryObject")->property_for_name("any")); - dict0 = list.get_dictionary(0); + auto list = util::any_cast(obj.get_property_value(ctx, "any")); + dict0 = util::any_cast(list.get(ctx, 0)); CHECK(dict0.get_any("zero") == Mixed(0)); SECTION("modify dictionary only") { @@ -1443,7 +1444,7 @@ TEST_CASE("nested collection set by Object::create", "[dictionary]") { r->begin_transaction(); Object::create(ctx, r, *r->schema().find("DictionaryObject"), new_value, CreatePolicy::UpdateModified); r->commit_transaction(); - auto list0 = list.get_list(0); + auto list0 = util::any_cast(list.get(ctx, 0)); CHECK(list0.get_any(0) == Mixed("seven")); CHECK(list0.get_any(1) == Mixed(7)); } diff --git a/test/object-store/primitive_list.cpp b/test/object-store/primitive_list.cpp index 9bab1b1deea..a7d40e17142 100644 --- a/test/object-store/primitive_list.cpp +++ b/test/object-store/primitive_list.cpp @@ -803,29 +803,37 @@ TEMPLATE_TEST_CASE("primitive list", "[primitives]", cf::MixedVal, cf::Int, cf:: } } -#if REALM_ENABLE_SYNC && REALM_HAVE_SYNC_STABLE_IDS +#if REALM_ENABLE_SYNC SECTION("sync compatibility") { if (!util::EventLoop::has_implementation()) return; - SyncServer server; - SyncTestFile sync_config(server, "shared"); - sync_config.schema = config.schema; + TestSyncManager init_sync_manager({}, {false}); + auto& server = init_sync_manager.sync_server(); + SyncTestFile sync_config(init_sync_manager, "shared"); + sync_config.schema = Schema{ + {"object", + {{"value", PropertyType::Array | TestType::property_type}, + {"_id", PropertyType::Int, Property::IsPrimary{true}}}}, + }; sync_config.schema_version = 0; + server.start(); { auto r = Realm::get_shared_realm(sync_config); r->begin_transaction(); CppContext ctx(r); - auto obj = Object::create(ctx, r, *r->schema().find("object"), std::any(AnyDict{})); + auto obj = Object::create(ctx, r, *r->schema().find("object"), std::any(AnyDict{{"_id", INT64_C(5)}})); auto list = util::any_cast(obj.get_property_value(ctx, "value")); list.add(static_cast(values[0])); r->commit_transaction(); wait_for_upload(*r); + wait_for_download(*r); } + std::this_thread::sleep_for(std::chrono::milliseconds(5)); util::File::remove(sync_config.path); {