• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 1829

13 Nov 2023 04:39AM UTC coverage: 91.666% (+0.001%) from 91.665%
1829

push

Evergreen

web-flow
Merge pull request #7119 from realm/tg/client-reset-flx-notifications

Deliver appropriate subscription state change notifications in DiscardLocal client resets

92104 of 168886 branches covered (0.0%)

512 of 522 new or added lines in 12 files covered. (98.08%)

95 existing lines in 18 files now uncovered.

231065 of 252072 relevant lines covered (91.67%)

6642642.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.04
/src/realm/object_converter.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2022 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include <realm/object_converter.hpp>
20

21
#include <realm/dictionary.hpp>
22
#include <realm/list.hpp>
23
#include <realm/set.hpp>
24

25
#include <realm/util/flat_map.hpp>
26

27
namespace realm::converters {
28

29
// Takes two lists, src and dst, and makes dst equal src. src is unchanged.
30
void InterRealmValueConverter::copy_list(const Obj& src_obj, Obj& dst_obj, bool* update_out)
31
{
16,236✔
32
    // The two arrays are compared by finding the longest common prefix and
8,118✔
33
    // suffix.  The middle section differs between them and is made equal by
8,118✔
34
    // updating the middle section of dst.
8,118✔
35
    //
8,118✔
36
    // Example:
8,118✔
37
    // src = abcdefghi
8,118✔
38
    // dst = abcxyhi
8,118✔
39
    // The common prefix is abc. The common suffix is hi. xy is replaced by defg.
8,118✔
40
    LstBasePtr src = src_obj.get_listbase_ptr(m_src_col);
16,236✔
41
    LstBasePtr dst = dst_obj.get_listbase_ptr(m_dst_col);
16,236✔
42

8,118✔
43
    bool updated = false;
16,236✔
44
    size_t len_src = src->size();
16,236✔
45
    size_t len_dst = dst->size();
16,236✔
46
    size_t len_min = std::min(len_src, len_dst);
16,236✔
47

8,118✔
48
    size_t ndx = 0;
16,236✔
49
    size_t suffix_len = 0;
16,236✔
50

8,118✔
51
    while (ndx < len_min && cmp_src_to_dst(src->get_any(ndx), dst->get_any(ndx), nullptr, update_out) == 0) {
29,070✔
52
        ndx++;
12,834✔
53
    }
12,834✔
54

8,118✔
55
    size_t suffix_len_max = len_min - ndx;
16,236✔
56

8,118✔
57
    while (suffix_len < suffix_len_max &&
16,818✔
58
           cmp_src_to_dst(src->get_any(len_src - 1 - suffix_len), dst->get_any(len_dst - 1 - suffix_len), nullptr,
9,339✔
59
                          update_out) == 0) {
1,221✔
60
        suffix_len++;
582✔
61
    }
582✔
62

8,118✔
63
    len_min -= (ndx + suffix_len);
16,236✔
64

8,118✔
65
    for (size_t i = 0; i < len_min; i++) {
18,840✔
66
        InterRealmValueConverter::ConversionResult converted_src;
2,604✔
67
        if (cmp_src_to_dst(src->get_any(ndx), dst->get_any(ndx), &converted_src, update_out)) {
2,604✔
68
            if (converted_src.requires_new_embedded_object) {
2,316✔
69
                auto lnklist = dynamic_cast<LnkLst*>(dst.get());
×
70
                REALM_ASSERT(lnklist); // this is the only type of list that supports embedded objects
×
71
                Obj embedded = lnklist->create_and_set_linked_object(ndx);
×
72
                track_new_embedded(converted_src.src_embedded_to_check, embedded);
×
73
            }
×
74
            else {
2,316✔
75
                dst->set_any(ndx, converted_src.converted_value);
2,316✔
76
            }
2,316✔
77
            updated = true;
2,316✔
78
        }
2,316✔
79
        ndx++;
2,604✔
80
    }
2,604✔
81

8,118✔
82
    // New elements must be inserted in dst.
8,118✔
83
    while (len_dst < len_src) {
19,716✔
84
        InterRealmValueConverter::ConversionResult converted_src;
3,480✔
85
        cmp_src_to_dst(src->get_any(ndx), Mixed{}, &converted_src, update_out);
3,480✔
86
        if (converted_src.requires_new_embedded_object) {
3,480✔
87
            auto lnklist = dynamic_cast<LnkLst*>(dst.get());
432✔
88
            REALM_ASSERT(lnklist); // this is the only type of list that supports embedded objects
432✔
89
            Obj embedded = lnklist->create_and_insert_linked_object(ndx);
432✔
90
            track_new_embedded(converted_src.src_embedded_to_check, embedded);
432✔
91
        }
432✔
92
        else {
3,048✔
93
            dst->insert_any(ndx, converted_src.converted_value);
3,048✔
94
        }
3,048✔
95
        len_dst++;
3,480✔
96
        ndx++;
3,480✔
97
        updated = true;
3,480✔
98
    }
3,480✔
99
    // Excess elements must be removed from ll_dst.
8,118✔
100
    if (len_dst > len_src) {
16,236✔
101
        dst->remove(len_src - suffix_len, len_dst - suffix_len);
972✔
102
        updated = true;
972✔
103
    }
972✔
104

8,118✔
105
    REALM_ASSERT(dst->size() == len_src);
16,236✔
106
    if (updated && update_out) {
16,236✔
107
        *update_out = updated;
1,650✔
108
    }
1,650✔
109
}
16,236✔
110

111
void InterRealmValueConverter::copy_set(const Obj& src_obj, Obj& dst_obj, bool* update_out)
112
{
10,902✔
113
    SetBasePtr src = src_obj.get_setbase_ptr(m_src_col);
10,902✔
114
    SetBasePtr dst = dst_obj.get_setbase_ptr(m_dst_col);
10,902✔
115

5,451✔
116
    std::vector<size_t> sorted_src, sorted_dst, to_insert, to_delete;
10,902✔
117
    constexpr bool ascending = true;
10,902✔
118
    // the implementation could be storing elements in sorted order, but
5,451✔
119
    // we don't assume that here.
5,451✔
120
    src->sort(sorted_src, ascending);
10,902✔
121
    dst->sort(sorted_dst, ascending);
10,902✔
122

5,451✔
123
    size_t dst_ndx = 0;
10,902✔
124
    size_t src_ndx = 0;
10,902✔
125
    while (src_ndx < sorted_src.size()) {
19,692✔
126
        if (dst_ndx == sorted_dst.size()) {
10,170✔
127
            // if we have reached the end of the dst items, all remaining
690✔
128
            // src items should be added
690✔
129
            while (src_ndx < sorted_src.size()) {
3,816✔
130
                to_insert.push_back(sorted_src[src_ndx++]);
2,436✔
131
            }
2,436✔
132
            break;
1,380✔
133
        }
1,380✔
134
        size_t ndx_in_src = sorted_src[src_ndx];
8,790✔
135
        Mixed src_val = src->get_any(ndx_in_src);
8,790✔
136
        while (dst_ndx < sorted_dst.size()) {
9,540✔
137
            size_t ndx_in_dst = sorted_dst[dst_ndx];
9,114✔
138

4,557✔
139
            int cmp = cmp_src_to_dst(src_val, dst->get_any(ndx_in_dst), nullptr, update_out);
9,114✔
140
            if (cmp == 0) {
9,114✔
141
                // equal: advance both src and dst
3,852✔
142
                ++dst_ndx;
7,704✔
143
                ++src_ndx;
7,704✔
144
                break;
7,704✔
145
            }
7,704✔
146
            else if (cmp < 0) {
1,410✔
147
                // src < dst: insert src, advance src only
330✔
148
                to_insert.push_back(ndx_in_src);
660✔
149
                ++src_ndx;
660✔
150
                break;
660✔
151
            }
660✔
152
            else {
750✔
153
                // src > dst: delete dst, advance only dst
375✔
154
                to_delete.push_back(ndx_in_dst);
750✔
155
                ++dst_ndx;
750✔
156
                continue;
750✔
157
            }
750✔
158
        }
9,114✔
159
    }
8,790✔
160
    while (dst_ndx < sorted_dst.size()) {
12,132✔
161
        to_delete.push_back(sorted_dst[dst_ndx++]);
1,230✔
162
    }
1,230✔
163

5,451✔
164
    std::sort(to_delete.begin(), to_delete.end());
10,902✔
165
    for (auto it = to_delete.rbegin(); it != to_delete.rend(); ++it) {
12,882✔
166
        dst->erase_any(dst->get_any(*it));
1,980✔
167
    }
1,980✔
168
    for (auto ndx : to_insert) {
6,999✔
169
        InterRealmValueConverter::ConversionResult converted_src;
3,096✔
170
        cmp_src_to_dst(src->get_any(ndx), Mixed{}, &converted_src, update_out);
3,096✔
171
        // we do not support a set of embedded objects
1,548✔
172
        REALM_ASSERT(!converted_src.requires_new_embedded_object);
3,096✔
173
        dst->insert_any(converted_src.converted_value);
3,096✔
174
    }
3,096✔
175

5,451✔
176
    if (update_out && (to_delete.size() || to_insert.size())) {
10,902✔
177
        *update_out = true;
1,782✔
178
    }
1,782✔
179
}
10,902✔
180

181
void InterRealmValueConverter::copy_dictionary(const Obj& src_obj, Obj& dst_obj, bool* update_out)
182
{
11,364✔
183
    Dictionary src = src_obj.get_dictionary(m_src_col);
11,364✔
184
    Dictionary dst = dst_obj.get_dictionary(m_dst_col);
11,364✔
185

5,682✔
186
    std::vector<size_t> to_insert, to_delete;
11,364✔
187

5,682✔
188
    size_t dst_ndx = 0;
11,364✔
189
    size_t src_ndx = 0;
11,364✔
190
    while (src_ndx < src.size()) {
22,746✔
191
        if (dst_ndx == dst.size()) {
12,504✔
192
            // if we have reached the end of the dst items, all remaining
561✔
193
            // src items should be added
561✔
194
            while (src_ndx < src.size()) {
2,988✔
195
                to_insert.push_back(src_ndx++);
1,866✔
196
            }
1,866✔
197
            break;
1,122✔
198
        }
1,122✔
199

5,691✔
200
        auto src_val = src.get_pair(src_ndx);
11,382✔
201
        while (dst_ndx < dst.size()) {
11,574✔
202
            auto dst_val = dst.get_pair(dst_ndx);
11,562✔
203
            int cmp = src_val.first.compare(dst_val.first);
11,562✔
204
            if (cmp == 0) {
11,562✔
205
                // Check if the values differ
5,280✔
206
                if (cmp_src_to_dst(src_val.second, dst_val.second, nullptr, update_out)) {
10,560✔
207
                    // values are different - modify destination, advance both
687✔
208
                    to_insert.push_back(src_ndx);
1,374✔
209
                }
1,374✔
210
                // keys and values equal: advance both src and dst
5,280✔
211
                ++dst_ndx;
10,560✔
212
                ++src_ndx;
10,560✔
213
                break;
10,560✔
214
            }
10,560✔
215
            else if (cmp < 0) {
1,002✔
216
                // src < dst: insert src, advance src only
405✔
217
                to_insert.push_back(src_ndx++);
810✔
218
                break;
810✔
219
            }
810✔
220
            else {
192✔
221
                // src > dst: delete dst, advance only dst
96✔
222
                to_delete.push_back(dst_ndx++);
192✔
223
                continue;
192✔
224
            }
192✔
225
        }
11,562✔
226
    }
11,382✔
227
    // at this point, we've gone through all src items but still have dst items
5,682✔
228
    // oustanding; these should all be deleted because they are not in src
5,682✔
229
    while (dst_ndx < dst.size()) {
11,772✔
230
        to_delete.push_back(dst_ndx++);
408✔
231
    }
408✔
232

5,682✔
233
    for (auto it = to_delete.rbegin(); it != to_delete.rend(); ++it) {
11,964✔
234
        dst.erase(dst.begin() + *it);
600✔
235
    }
600✔
236
    for (auto ndx : to_insert) {
7,707✔
237
        auto pair = src.get_pair(ndx);
4,050✔
238
        InterRealmValueConverter::ConversionResult converted_val;
4,050✔
239
        cmp_src_to_dst(pair.second, Mixed{}, &converted_val, update_out);
4,050✔
240
        if (converted_val.requires_new_embedded_object) {
4,050✔
241
            Obj new_embedded = dst.create_and_insert_linked_object(pair.first);
120✔
242
            track_new_embedded(converted_val.src_embedded_to_check, new_embedded);
120✔
243
        }
120✔
244
        else {
3,930✔
245
            dst.insert(pair.first, converted_val.converted_value);
3,930✔
246
        }
3,930✔
247
    }
4,050✔
248
    if (update_out && (to_delete.size() || to_insert.size())) {
11,364✔
249
        *update_out = true;
1,500✔
250
    }
1,500✔
251
}
11,364✔
252

253
void InterRealmValueConverter::copy_value(const Obj& src_obj, Obj& dst_obj, bool* update_out)
254
{
152,124✔
255
    if (m_src_col.is_list()) {
152,124✔
256
        copy_list(src_obj, dst_obj, update_out);
16,236✔
257
    }
16,236✔
258
    else if (m_src_col.is_dictionary()) {
135,888✔
259
        copy_dictionary(src_obj, dst_obj, update_out);
11,364✔
260
    }
11,364✔
261
    else if (m_src_col.is_set()) {
124,524✔
262
        copy_set(src_obj, dst_obj, update_out);
10,902✔
263
    }
10,902✔
264
    else {
113,622✔
265
        REALM_ASSERT(!m_src_col.is_collection());
113,622✔
266
        InterRealmValueConverter::ConversionResult converted_src;
113,622✔
267
        if (cmp_src_to_dst(src_obj.get_any(m_src_col), dst_obj.get_any(m_dst_col), &converted_src, update_out)) {
113,622✔
268
            if (converted_src.requires_new_embedded_object) {
70,344✔
269
                Obj new_embedded = dst_obj.create_and_set_linked_object(m_dst_col);
498✔
270
                track_new_embedded(converted_src.src_embedded_to_check, new_embedded);
498✔
271
            }
498✔
272
            else {
69,846✔
273
                dst_obj.set_any(m_dst_col, converted_src.converted_value);
69,846✔
274
            }
69,846✔
275
        }
70,344✔
276
    }
113,622✔
277
}
152,124✔
278

279

280
// If an embedded object is encountered, add it to a list of embedded objects to process.
281
// This relies on the property that embedded objects only have one incoming link
282
// otherwise there could be an infinite loop while discovering embedded objects.
283
void EmbeddedObjectConverter::track(const Obj& e_src, const Obj& e_dst)
284
{
67,158✔
285
    embedded_pending.push_back({e_src, e_dst});
67,158✔
286
}
67,158✔
287

288
void EmbeddedObjectConverter::process_pending()
289
{
29,574✔
290
    util::FlatMap<TableKey, InterRealmObjectConverter> converters;
29,574✔
291

14,787✔
292
    while (!embedded_pending.empty()) {
96,732✔
293
        EmbeddedToCheck pending = embedded_pending.back();
67,158✔
294
        embedded_pending.pop_back();
67,158✔
295

33,579✔
296
        TableRef dst_table = pending.embedded_in_dst.get_table();
67,158✔
297
        TableKey dst_table_key = dst_table->get_key();
67,158✔
298
        auto it = converters.find(dst_table_key);
67,158✔
299
        if (it == converters.end()) {
67,158✔
300
            TableRef src_table = pending.embedded_in_src.get_table();
1,074✔
301
            it = converters.insert({dst_table_key, InterRealmObjectConverter{src_table, dst_table, this}}).first;
1,074✔
302
        }
1,074✔
303
        InterRealmObjectConverter& converter = it->second;
67,158✔
304
        converter.copy(pending.embedded_in_src, pending.embedded_in_dst, nullptr);
67,158✔
305
    }
67,158✔
306
}
29,574✔
307

308
InterRealmValueConverter::InterRealmValueConverter(ConstTableRef src_table, ColKey src_col, ConstTableRef dst_table,
309
                                                   ColKey dst_col, EmbeddedObjectConverter* ec)
310
    : m_src_table(src_table)
311
    , m_dst_table(dst_table)
312
    , m_src_col(src_col)
313
    , m_dst_col(dst_col)
314
    , m_embedded_converter(ec)
315
    , m_is_embedded_link(false)
316
    , m_primitive_types_only(!(src_col.get_type() == col_type_TypedLink || src_col.get_type() == col_type_Link ||
317
                               src_col.get_type() == col_type_LinkList || src_col.get_type() == col_type_Mixed))
318
{
56,610✔
319
    if (!m_primitive_types_only) {
56,610✔
320
        REALM_ASSERT(src_table);
8,286✔
321
        m_opposite_of_src = src_table->get_opposite_table(src_col);
8,286✔
322
        m_opposite_of_dst = dst_table->get_opposite_table(dst_col);
8,286✔
323
        REALM_ASSERT(bool(m_opposite_of_src) == bool(m_opposite_of_dst));
8,286✔
324
        if (m_opposite_of_src) {
8,286✔
325
            m_is_embedded_link = m_opposite_of_src->is_embedded();
4,968✔
326
        }
4,968✔
327
    }
8,286✔
328
}
56,610✔
329

330
void InterRealmValueConverter::track_new_embedded(const Obj& src, const Obj& dst)
331
{
6,840✔
332
    m_embedded_converter->track(src, dst);
6,840✔
333
}
6,840✔
334

335
// convert `src` to the destination Realm and compare that value with `dst`
336
// If `converted_src_out` is provided, it will be set to the converted src value
337
int InterRealmValueConverter::cmp_src_to_dst(Mixed src, Mixed dst, ConversionResult* converted_src_out,
338
                                             bool* did_update_out)
339
{
162,912✔
340
    int cmp = 0;
162,912✔
341
    Mixed converted_src;
162,912✔
342
    if (m_primitive_types_only || !src.is_type(type_Link, type_TypedLink)) {
162,912✔
343
        converted_src = src;
149,484✔
344
        cmp = src.compare(dst);
149,484✔
345
    }
149,484✔
346
    else if (m_opposite_of_src) {
13,428✔
347
        ObjKey src_link_key = src.get<ObjKey>();
10,320✔
348
        if (m_is_embedded_link) {
10,320✔
349
            Obj src_embedded = m_opposite_of_src->get_object(src_link_key);
6,858✔
350
            REALM_ASSERT_DEBUG(src_embedded.is_valid());
6,858✔
351
            if (dst.is_type(type_Link, type_TypedLink)) {
6,858✔
352
                cmp = 0; // no need to set this link, there is already an embedded object here
5,790✔
353
                Obj dst_embedded = m_opposite_of_dst->get_object(dst.get<ObjKey>());
5,790✔
354
                REALM_ASSERT_DEBUG(dst_embedded.is_valid());
5,790✔
355
                converted_src = dst_embedded.get_key();
5,790✔
356
                track_new_embedded(src_embedded, dst_embedded);
5,790✔
357
            }
5,790✔
358
            else {
1,068✔
359
                cmp = src.compare(dst);
1,068✔
360
                if (converted_src_out) {
1,068✔
361
                    converted_src_out->requires_new_embedded_object = true;
1,050✔
362
                    converted_src_out->src_embedded_to_check = src_embedded;
1,050✔
363
                }
1,050✔
364
            }
1,068✔
365
        }
6,858✔
366
        else {
3,462✔
367
            Obj dst_link;
3,462✔
368
            if (m_opposite_of_dst == m_opposite_of_src) {
3,462✔
369
                // if this is the same Realm, we can use the ObjKey
96✔
370
                dst_link = m_opposite_of_dst->get_object(src_link_key);
192✔
371
            }
192✔
372
            else {
3,270✔
373
                // in different Realms we create a new object
1,635✔
374
                if (m_opposite_of_src->get_primary_key_column()) {
3,270✔
375
                    Mixed src_link_pk = m_opposite_of_src->get_primary_key(src_link_key);
3,270✔
376
                    dst_link = m_opposite_of_dst->create_object_with_primary_key(src_link_pk, did_update_out);
3,270✔
377
                }
3,270✔
378
                else {
×
379
                    dst_link = m_opposite_of_dst->create_object();
×
380
                }
×
381
            }
3,270✔
382
            converted_src = dst_link.get_key();
3,462✔
383
            if (dst.is_type(type_TypedLink)) {
3,462✔
384
                cmp = converted_src.compare(dst.get<ObjKey>());
2,724✔
385
            }
2,724✔
386
            else {
738✔
387
                cmp = converted_src.compare(dst);
738✔
388
            }
738✔
389
        }
3,462✔
390
    }
10,320✔
391
    else {
3,108✔
392
        ObjLink src_link = src.get<ObjLink>();
3,108✔
393
        if (src_link.is_unresolved()) {
3,108✔
394
            converted_src = Mixed{}; // no need to transfer over unresolved links
×
395
            cmp = converted_src.compare(dst);
×
396
        }
×
397
        else {
3,108✔
398
            TableRef src_link_table = m_src_table->get_parent_group()->get_table(src_link.get_table_key());
3,108✔
399
            REALM_ASSERT_EX(src_link_table, src_link.get_table_key());
3,108✔
400
            TableRef dst_link_table = m_dst_table->get_parent_group()->get_table(src_link_table->get_name());
3,108✔
401
            REALM_ASSERT_EX(dst_link_table, src_link_table->get_name());
3,108✔
402
            // embedded tables should always be covered by the m_opposite_of_src case above.
1,554✔
403
            REALM_ASSERT_EX(!src_link_table->is_embedded(), src_link_table->get_name());
3,108✔
404
            // regular table, convert by pk
1,554✔
405
            if (src_link_table->get_primary_key_column()) {
3,108✔
406
                Mixed src_pk = src_link_table->get_primary_key(src_link.get_obj_key());
3,108✔
407
                Obj dst_link = dst_link_table->create_object_with_primary_key(src_pk, did_update_out);
3,108✔
408
                converted_src = ObjLink{dst_link_table->get_key(), dst_link.get_key()};
3,108✔
409
            }
3,108✔
UNCOV
410
            else if (src_link_table == dst_link_table) {
×
411
                // no pk, but this is the same Realm, so convert by ObjKey
412
                Obj dst_link = dst_link_table->get_object(src_link.get_obj_key());
×
413
                converted_src = ObjLink{dst_link_table->get_key(), dst_link.get_key()};
×
414
            }
×
UNCOV
415
            else {
×
416
                // no pk, and different Realm, create an object
UNCOV
417
                Obj dst_link = dst_link_table->create_object();
×
UNCOV
418
                converted_src = ObjLink{dst_link_table->get_key(), dst_link.get_key()};
×
UNCOV
419
            }
×
420
            cmp = converted_src.compare(dst);
3,108✔
421
        }
3,108✔
422
    }
3,108✔
423
    if (converted_src_out) {
162,912✔
424
        converted_src_out->converted_value = converted_src;
126,852✔
425
    }
126,852✔
426
    if (did_update_out && cmp) {
162,912✔
427
        *did_update_out = true;
15,012✔
428
    }
15,012✔
429
    return cmp;
162,912✔
430
}
162,912✔
431

432
InterRealmObjectConverter::InterRealmObjectConverter(ConstTableRef table_src, TableRef table_dst,
433
                                                     EmbeddedObjectConverter* embedded_tracker)
434
    : m_embedded_tracker(embedded_tracker)
435
{
23,994✔
436
    m_columns_cache.reserve(table_src->get_column_count());
23,994✔
437
    ColKey pk_col = table_src->get_primary_key_column();
23,994✔
438
    for (ColKey col_key_src : table_src->get_column_keys()) {
78,246✔
439
        if (col_key_src == pk_col)
78,246✔
440
            continue;
22,920✔
441
        StringData col_name = table_src->get_column_name(col_key_src);
55,326✔
442
        ColKey col_key_dst = table_dst->get_column_key(col_name);
55,326✔
443
        REALM_ASSERT(col_key_dst);
55,326✔
444
        m_columns_cache.emplace_back(table_src, col_key_src, table_dst, col_key_dst, m_embedded_tracker);
55,326✔
445
    }
55,326✔
446
}
23,994✔
447

448
void InterRealmObjectConverter::copy(const Obj& src, Obj& dst, bool* update_out)
449
{
99,654✔
450
    for (auto& column : m_columns_cache) {
150,840✔
451
        column.copy_value(src, dst, update_out);
150,840✔
452
    }
150,840✔
453
}
99,654✔
454

455
} // namespace realm::converters
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc