Skip to content

Commit b2e42c8

Browse files
jedelbotgoyne
andauthored
Support assigning nested collections via templated API (#7478)
Co-authored-by: Thomas Goyne <[email protected]>
1 parent 6728a18 commit b2e42c8

File tree

11 files changed

+581
-193
lines changed

11 files changed

+581
-193
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292

9393
### Enhancements
9494
* Introduce sync 'progress_estimate' parameter (value from 0.0 to 1.0) for existing sync 'ProgressNotifierCallback' api to report sync progress on current batch of upload/download until completion ([#7450](https://github.com/realm/realm-core/issues/7450))
95+
* Support assigning nested collections via templated API (PR [#7478](https://github.com/realm/realm-core/pull/7478))
9596

9697
### Fixed
9798
* Fix an assertion failure "m_lock_info && m_lock_info->m_file.get_path() == m_filename" that appears to be related to opening a Realm while the file is in the process of being closed on another thread ([Swift #8507](https://github.com/realm/realm-swift/issues/8507)).

src/realm/collection.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,6 @@ UpdateStatus CollectionBase::do_init_from_parent(BPlusTreeBase* tree, ref_type r
243243
tree->init_from_ref(ref);
244244
}
245245
else {
246-
if (tree->init_from_parent()) {
247-
// All is well
248-
return UpdateStatus::Updated;
249-
}
250246
if (!allow_create) {
251247
tree->detach();
252248
return UpdateStatus::Detached;

src/realm/list.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ class Lst final : public CollectionBaseImpl<LstBase> {
260260
m_tree->set_parent(const_cast<ArrayParent*>(parent), 0);
261261
}
262262
Base::update_content_version();
263-
return do_init_from_parent(m_tree.get(), 0, allow_create);
263+
return do_init_from_parent(m_tree.get(), Base::get_collection_ref(), allow_create);
264264
}
265265

266266
template <class Func>

src/realm/object-store/dictionary.hpp

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ class Dictionary : public object_store::Collection {
142142
Obj get_object(StringData key) const;
143143
};
144144

145-
146145
template <typename Fn>
147146
auto Dictionary::dispatch(Fn&& fn) const
148147
{
@@ -178,62 +177,7 @@ inline Obj Dictionary::get<Obj>(StringData key) const
178177
return get_object(key);
179178
}
180179

181-
template <typename T, typename Context>
182-
void Dictionary::insert(Context& ctx, StringData key, T&& value, CreatePolicy policy)
183-
{
184-
if (ctx.is_null(value)) {
185-
this->insert(key, Mixed());
186-
return;
187-
}
188-
if (m_is_embedded) {
189-
validate_embedded(ctx, value, policy);
190-
auto obj_key = dict().create_and_insert_linked_object(key).get_key();
191-
ctx.template unbox<Obj>(value, policy, obj_key);
192-
return;
193-
}
194-
dispatch([&](auto t) {
195-
this->insert(key, ctx.template unbox<std::decay_t<decltype(*t)>>(value, policy));
196-
});
197-
}
198-
199-
template <typename Context>
200-
auto Dictionary::get(Context& ctx, StringData key) const
201-
{
202-
return dispatch([&](auto t) {
203-
return ctx.box(this->get<std::decay_t<decltype(*t)>>(key));
204-
});
205-
}
206-
207-
template <typename T, typename Context>
208-
void Dictionary::assign(Context& ctx, T&& values, CreatePolicy policy)
209-
{
210-
if (ctx.is_same_dictionary(*this, values))
211-
return;
212-
213-
if (ctx.is_null(values)) {
214-
remove_all();
215-
return;
216-
}
217-
218-
if (!policy.diff)
219-
remove_all();
220-
221-
ctx.enumerate_dictionary(values, [&](StringData key, auto&& value) {
222-
if (policy.diff) {
223-
util::Optional<Mixed> old_value = dict().try_get(key);
224-
auto new_value = ctx.template unbox<Mixed>(value);
225-
if (!old_value || *old_value != new_value) {
226-
dict().insert(key, new_value);
227-
}
228-
}
229-
else {
230-
this->insert(ctx, key, value, policy);
231-
}
232-
});
233-
}
234-
235180
} // namespace object_store
236181
} // namespace realm
237182

238-
239183
#endif /* REALM_OS_DICTIONARY_HPP */

src/realm/object-store/impl/object_accessor_impl.hpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ namespace realm {
3131
using AnyDict = std::map<std::string, std::any>;
3232
using AnyVector = std::vector<std::any>;
3333

34+
struct UnmanagedObject {
35+
std::string object_type;
36+
std::any properties;
37+
};
38+
3439
// An object accessor context which can be used to create and access objects
3540
// using std::any as the type-erased value type. In addition, this serves as
3641
// the reference implementation of an accessor context that must be implemented
@@ -370,7 +375,7 @@ inline util::Optional<UUID> CppContext::unbox(std::any& v, CreatePolicy, ObjKey)
370375
}
371376

372377
template <>
373-
inline Mixed CppContext::unbox(std::any& v, CreatePolicy, ObjKey) const
378+
inline Mixed CppContext::unbox(std::any& v, CreatePolicy policy, ObjKey) const
374379
{
375380
if (v.has_value()) {
376381
const std::type_info& this_type{v.type()};
@@ -408,6 +413,23 @@ inline Mixed CppContext::unbox(std::any& v, CreatePolicy, ObjKey) const
408413
else if (this_type == typeid(UUID)) {
409414
return Mixed(util::any_cast<UUID>(v));
410415
}
416+
else if (this_type == typeid(AnyDict)) {
417+
return Mixed(0, CollectionType::Dictionary);
418+
}
419+
else if (this_type == typeid(AnyVector)) {
420+
return Mixed(0, CollectionType::List);
421+
}
422+
else if (this_type == typeid(UnmanagedObject)) {
423+
UnmanagedObject unmanaged_obj = util::any_cast<UnmanagedObject>(v);
424+
auto os = realm->schema().find(unmanaged_obj.object_type);
425+
CppContext child_ctx(realm, &*os);
426+
auto obj = child_ctx.unbox<Obj>(unmanaged_obj.properties, policy, ObjKey());
427+
return Mixed(obj);
428+
}
429+
else if (this_type == typeid(Obj)) {
430+
Obj obj = util::any_cast<Obj>(v);
431+
return Mixed(obj);
432+
}
411433
}
412434
return Mixed{};
413435
}

src/realm/object-store/list.hpp

Lines changed: 0 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,6 @@ class List : public object_store::Collection {
127127
template <typename T>
128128
auto& as() const;
129129

130-
template <typename T, typename Context>
131-
void set_if_different(Context&, size_t row_ndx, T&& value, CreatePolicy);
132-
133130
friend struct std::hash<List>;
134131
};
135132

@@ -164,120 +161,6 @@ auto List::dispatch(Fn&& fn) const
164161
return switch_on_type(get_type(), std::forward<Fn>(fn));
165162
}
166163

167-
template <typename Context>
168-
auto List::get(Context& ctx, size_t row_ndx) const
169-
{
170-
return dispatch([&](auto t) {
171-
return ctx.box(this->get<std::decay_t<decltype(*t)>>(row_ndx));
172-
});
173-
}
174-
175-
template <typename T, typename Context>
176-
size_t List::find(Context& ctx, T&& value) const
177-
{
178-
return dispatch([&](auto t) {
179-
return this->find(ctx.template unbox<std::decay_t<decltype(*t)>>(value, CreatePolicy::Skip));
180-
});
181-
}
182-
183-
template <typename T, typename Context>
184-
void List::add(Context& ctx, T&& value, CreatePolicy policy)
185-
{
186-
if (m_is_embedded) {
187-
validate_embedded(ctx, value, policy);
188-
auto key = as<Obj>().create_and_insert_linked_object(size()).get_key();
189-
ctx.template unbox<Obj>(value, policy, key);
190-
return;
191-
}
192-
dispatch([&](auto t) {
193-
this->add(ctx.template unbox<std::decay_t<decltype(*t)>>(value, policy));
194-
});
195-
}
196-
197-
template <typename T, typename Context>
198-
void List::insert(Context& ctx, size_t list_ndx, T&& value, CreatePolicy policy)
199-
{
200-
if (m_is_embedded) {
201-
validate_embedded(ctx, value, policy);
202-
auto key = as<Obj>().create_and_insert_linked_object(list_ndx).get_key();
203-
ctx.template unbox<Obj>(value, policy, key);
204-
return;
205-
}
206-
dispatch([&](auto t) {
207-
this->insert(list_ndx, ctx.template unbox<std::decay_t<decltype(*t)>>(value, policy));
208-
});
209-
}
210-
211-
template <typename T, typename Context>
212-
void List::set(Context& ctx, size_t list_ndx, T&& value, CreatePolicy policy)
213-
{
214-
if (m_is_embedded) {
215-
validate_embedded(ctx, value, policy);
216-
217-
auto& list = as<Obj>();
218-
auto key = policy.diff ? list.get(list_ndx) : list.create_and_set_linked_object(list_ndx).get_key();
219-
ctx.template unbox<Obj>(value, policy, key);
220-
return;
221-
}
222-
dispatch([&](auto t) {
223-
this->set(list_ndx, ctx.template unbox<std::decay_t<decltype(*t)>>(value, policy));
224-
});
225-
}
226-
227-
template <typename T, typename Context>
228-
void List::set_if_different(Context& ctx, size_t row_ndx, T&& value, CreatePolicy policy)
229-
{
230-
if (m_is_embedded) {
231-
validate_embedded(ctx, value, policy);
232-
auto key = policy.diff ? this->get<Obj>(row_ndx) : as<Obj>().create_and_set_linked_object(row_ndx);
233-
ctx.template unbox<Obj>(value, policy, key.get_key());
234-
return;
235-
}
236-
dispatch([&](auto t) {
237-
using U = std::decay_t<decltype(*t)>;
238-
if constexpr (std::is_same_v<U, Obj>) {
239-
auto old_value = this->get<U>(row_ndx);
240-
auto new_value = ctx.template unbox<U>(value, policy, old_value.get_key());
241-
if (new_value.get_key() != old_value.get_key())
242-
this->set(row_ndx, new_value);
243-
}
244-
else {
245-
auto old_value = this->get<U>(row_ndx);
246-
auto new_value = ctx.template unbox<U>(value, policy);
247-
if (old_value != new_value)
248-
this->set(row_ndx, new_value);
249-
}
250-
});
251-
}
252-
253-
template <typename T, typename Context>
254-
void List::assign(Context& ctx, T&& values, CreatePolicy policy)
255-
{
256-
if (ctx.is_same_list(*this, values))
257-
return;
258-
259-
if (ctx.is_null(values)) {
260-
remove_all();
261-
return;
262-
}
263-
264-
if (!policy.diff)
265-
remove_all();
266-
267-
size_t sz = size();
268-
size_t index = 0;
269-
ctx.enumerate_collection(values, [&](auto&& element) {
270-
if (index >= sz)
271-
this->add(ctx, element, policy);
272-
else if (policy.diff)
273-
this->set_if_different(ctx, index, element, policy);
274-
else
275-
this->set(ctx, index, element, policy);
276-
index++;
277-
});
278-
while (index < sz)
279-
remove(--sz);
280-
}
281164
} // namespace realm
282165

283166
namespace std {

0 commit comments

Comments
 (0)