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

realm / realm-core / github_pull_request_275914

25 Sep 2023 03:10PM UTC coverage: 92.915% (+1.7%) from 91.215%
github_pull_request_275914

Pull #6073

Evergreen

jedelbo
Merge tag 'v13.21.0' into next-major

"Feature/Bugfix release"
Pull Request #6073: Merge next-major

96928 of 177706 branches covered (0.0%)

8324 of 8714 new or added lines in 122 files covered. (95.52%)

181 existing lines in 28 files now uncovered.

247505 of 266379 relevant lines covered (92.91%)

7164945.17 hits per line

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

82.24
/src/realm/collection_parent.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2023 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/collection_parent.hpp>
20
#include "realm/list.hpp"
21
#include "realm/set.hpp"
22
#include "realm/dictionary.hpp"
23
#include "realm/util/overload.hpp"
24

25
#include <random>
26
#include <mutex>
27

28
namespace realm {
29

30
std::ostream& operator<<(std::ostream& ostr, const PathElement& elem)
31
{
53,958✔
32
    if (elem.is_ndx()) {
53,958✔
33
        size_t ndx = elem.get_ndx();
12,114✔
34
        if (ndx == 0) {
12,114✔
35
            ostr << "FIRST";
5,439✔
36
        }
5,439✔
37
        else if (ndx == size_t(-1)) {
6,675✔
38
            ostr << "LAST";
165✔
39
        }
165✔
40
        else {
6,510✔
41
            ostr << elem.get_ndx();
6,510✔
42
        }
6,510✔
43
    }
12,114✔
44
    else if (elem.is_col_key()) {
41,844✔
NEW
45
        ostr << elem.get_col_key();
×
NEW
46
    }
×
47
    else if (elem.is_key()) {
41,844✔
48
        ostr << "'" << elem.get_key() << "'";
41,787✔
49
    }
41,787✔
50
    else if (elem.is_all()) {
57✔
51
        ostr << '*';
57✔
52
    }
57✔
53

54
    return ostr;
53,958✔
55
}
53,958✔
56

57
std::ostream& operator<<(std::ostream& ostr, const Path& path)
58
{
33,897✔
59
    for (auto& elem : path) {
53,430✔
60
        ostr << '[' << elem << ']';
53,430✔
61
    }
53,430✔
62
    return ostr;
33,897✔
63
}
33,897✔
64

65
/***************************** CollectionParent ******************************/
66

67
CollectionParent::~CollectionParent() {}
104,315,760✔
68

69
void CollectionParent::check_level() const
70
{
339✔
71
    if (m_level + 1 > s_max_level) {
339✔
72
        throw LogicError(ErrorCodes::LimitExceeded, "Max nesting level reached");
3✔
73
    }
3✔
74
}
339✔
75
void CollectionParent::set_backlink(ColKey col_key, ObjLink new_link) const
76
{
3,384,894✔
77
    if (new_link && new_link.get_obj_key()) {
3,384,894✔
78
        auto t = get_table();
3,364,692✔
79
        auto target_table = t->get_parent_group()->get_table(new_link.get_table_key());
3,364,692✔
80
        ColKey backlink_col_key;
3,364,692✔
81
        auto type = col_key.get_type();
3,364,692✔
82
        if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
3,364,692✔
83
            // This may modify the target table
84
            backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
15,075✔
85
            // it is possible that this was a link to the same table and that adding a backlink column has
86
            // caused the need to update this object as well.
87
            update_if_needed();
15,075✔
88
        }
15,075✔
89
        else {
3,349,617✔
90
            backlink_col_key = t->get_opposite_column(col_key);
3,349,617✔
91
        }
3,349,617✔
92
        auto obj_key = new_link.get_obj_key();
3,364,692✔
93
        auto target_obj = obj_key.is_unresolved() ? target_table->try_get_tombstone(obj_key)
4,941✔
94
                                                  : target_table->try_get_object(obj_key);
3,359,751✔
95
        if (!target_obj) {
3,364,692✔
96
            throw InvalidArgument(ErrorCodes::KeyNotFound, "Target object not found");
6✔
97
        }
6✔
98
        target_obj.add_backlink(backlink_col_key, get_object().get_key());
3,364,686✔
99
    }
3,364,686✔
100
}
3,384,894✔
101

102
bool CollectionParent::replace_backlink(ColKey col_key, ObjLink old_link, ObjLink new_link, CascadeState& state) const
103
{
168,744✔
104
    bool recurse = remove_backlink(col_key, old_link, state);
168,744✔
105
    set_backlink(col_key, new_link);
168,744✔
106

107
    return recurse;
168,744✔
108
}
168,744✔
109

110
bool CollectionParent::remove_backlink(ColKey col_key, ObjLink old_link, CascadeState& state) const
111
{
178,041✔
112
    if (old_link && old_link.get_obj_key()) {
178,041✔
113
        auto t = get_table();
66,660✔
114
        REALM_ASSERT(t->valid_column(col_key));
66,660✔
115
        ObjKey old_key = old_link.get_obj_key();
66,660✔
116
        auto target_obj = t->get_parent_group()->get_object(old_link);
66,660✔
117
        TableRef target_table = target_obj.get_table();
66,660✔
118
        ColKey backlink_col_key;
66,660✔
119
        auto type = col_key.get_type();
66,660✔
120
        if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
66,663✔
121
            backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
5,685✔
122
        }
5,685✔
123
        else {
60,975✔
124
            backlink_col_key = t->get_opposite_column(col_key);
60,975✔
125
        }
60,975✔
126

127
        bool strong_links = target_table->is_embedded();
66,660✔
128
        bool is_unres = old_key.is_unresolved();
66,660✔
129

130
        bool last_removed = target_obj.remove_one_backlink(backlink_col_key, get_object().get_key()); // Throws
66,660✔
131
        if (is_unres) {
66,660✔
132
            if (last_removed) {
4,626✔
133
                // Check is there are more backlinks
134
                if (!target_obj.has_backlinks(false)) {
4,611✔
135
                    // Tombstones can be erased right away - there is no cascading effect
136
                    target_table->m_tombstones->erase(old_key, state);
4,605✔
137
                }
4,605✔
138
            }
4,611✔
139
        }
4,626✔
140
        else {
62,034✔
141
            return state.enqueue_for_cascade(target_obj, strong_links, last_removed);
62,034✔
142
        }
62,034✔
143
    }
116,007✔
144

145
    return false;
116,007✔
146
}
116,007✔
147

148
LstBasePtr CollectionParent::get_listbase_ptr(ColKey col_key) const
149
{
170,037✔
150
    auto table = get_table();
170,037✔
151
    auto attr = table->get_column_attr(col_key);
170,037✔
152
    REALM_ASSERT(attr.test(col_attr_List) || attr.test(col_attr_Nullable));
170,037✔
153
    bool nullable = attr.test(col_attr_Nullable);
170,037✔
154

155
    switch (table->get_column_type(col_key)) {
170,037✔
156
        case type_Int: {
21,675✔
157
            if (nullable)
21,675✔
158
                return std::make_unique<Lst<util::Optional<Int>>>(col_key);
1,065✔
159
            else
20,610✔
160
                return std::make_unique<Lst<Int>>(col_key);
20,610✔
NEW
161
        }
×
162
        case type_Bool: {
1,680✔
163
            if (nullable)
1,680✔
164
                return std::make_unique<Lst<util::Optional<Bool>>>(col_key);
852✔
165
            else
828✔
166
                return std::make_unique<Lst<Bool>>(col_key);
828✔
NEW
167
        }
×
168
        case type_Float: {
1,692✔
169
            if (nullable)
1,692✔
170
                return std::make_unique<Lst<util::Optional<Float>>>(col_key);
867✔
171
            else
825✔
172
                return std::make_unique<Lst<Float>>(col_key);
825✔
NEW
173
        }
×
174
        case type_Double: {
1,725✔
175
            if (nullable)
1,725✔
176
                return std::make_unique<Lst<util::Optional<Double>>>(col_key);
867✔
177
            else
858✔
178
                return std::make_unique<Lst<Double>>(col_key);
858✔
NEW
179
        }
×
180
        case type_String: {
116,703✔
181
            return std::make_unique<Lst<String>>(col_key);
116,703✔
NEW
182
        }
×
183
        case type_Binary: {
1,677✔
184
            return std::make_unique<Lst<Binary>>(col_key);
1,677✔
NEW
185
        }
×
186
        case type_Timestamp: {
1,689✔
187
            return std::make_unique<Lst<Timestamp>>(col_key);
1,689✔
NEW
188
        }
×
189
        case type_Decimal: {
1,683✔
190
            return std::make_unique<Lst<Decimal128>>(col_key);
1,683✔
NEW
191
        }
×
192
        case type_ObjectId: {
1,713✔
193
            if (nullable)
1,713✔
194
                return std::make_unique<Lst<util::Optional<ObjectId>>>(col_key);
876✔
195
            else
837✔
196
                return std::make_unique<Lst<ObjectId>>(col_key);
837✔
NEW
197
        }
×
198
        case type_UUID: {
1,701✔
199
            if (nullable)
1,701✔
200
                return std::make_unique<Lst<util::Optional<UUID>>>(col_key);
870✔
201
            else
831✔
202
                return std::make_unique<Lst<UUID>>(col_key);
831✔
NEW
203
        }
×
NEW
204
        case type_TypedLink: {
✔
NEW
205
            return std::make_unique<Lst<ObjLink>>(col_key);
×
NEW
206
        }
×
207
        case type_Mixed: {
2,301✔
208
            return std::make_unique<Lst<Mixed>>(col_key, get_level() + 1);
2,301✔
NEW
209
        }
×
210
        case type_LinkList:
15,798✔
211
            return std::make_unique<LnkLst>(col_key);
15,798✔
NEW
212
        case type_Link:
✔
NEW
213
            break;
×
NEW
214
    }
×
NEW
215
    REALM_TERMINATE("Unsupported column type");
×
NEW
216
}
×
217

218
SetBasePtr CollectionParent::get_setbase_ptr(ColKey col_key) const
219
{
58,641✔
220
    auto table = get_table();
58,641✔
221
    auto attr = table->get_column_attr(col_key);
58,641✔
222
    REALM_ASSERT(attr.test(col_attr_Set));
58,641✔
223
    bool nullable = attr.test(col_attr_Nullable);
58,641✔
224

225
    switch (table->get_column_type(col_key)) {
58,641✔
226
        case type_Int: {
4,059✔
227
            if (nullable)
4,059✔
228
                return std::make_unique<Set<util::Optional<Int>>>(col_key);
1,917✔
229
            else
2,142✔
230
                return std::make_unique<Set<Int>>(col_key);
2,142✔
NEW
231
        }
×
232
        case type_Bool: {
2,952✔
233
            if (nullable)
2,952✔
234
                return std::make_unique<Set<util::Optional<Bool>>>(col_key);
1,554✔
235
            else
1,398✔
236
                return std::make_unique<Set<Bool>>(col_key);
1,398✔
NEW
237
        }
×
238
        case type_Float: {
3,336✔
239
            if (nullable)
3,336✔
240
                return std::make_unique<Set<util::Optional<Float>>>(col_key);
1,746✔
241
            else
1,590✔
242
                return std::make_unique<Set<Float>>(col_key);
1,590✔
NEW
243
        }
×
244
        case type_Double: {
3,336✔
245
            if (nullable)
3,336✔
246
                return std::make_unique<Set<util::Optional<Double>>>(col_key);
1,746✔
247
            else
1,590✔
248
                return std::make_unique<Set<Double>>(col_key);
1,590✔
NEW
249
        }
×
250
        case type_String: {
3,336✔
251
            return std::make_unique<Set<String>>(col_key);
3,336✔
NEW
252
        }
×
253
        case type_Binary: {
3,264✔
254
            return std::make_unique<Set<Binary>>(col_key);
3,264✔
NEW
255
        }
×
256
        case type_Timestamp: {
3,300✔
257
            return std::make_unique<Set<Timestamp>>(col_key);
3,300✔
NEW
258
        }
×
259
        case type_Decimal: {
3,099✔
260
            return std::make_unique<Set<Decimal128>>(col_key);
3,099✔
NEW
261
        }
×
262
        case type_ObjectId: {
7,386✔
263
            if (nullable)
7,386✔
264
                return std::make_unique<Set<util::Optional<ObjectId>>>(col_key);
5,988✔
265
            else
1,398✔
266
                return std::make_unique<Set<ObjectId>>(col_key);
1,398✔
NEW
267
        }
×
268
        case type_UUID: {
2,952✔
269
            if (nullable)
2,952✔
270
                return std::make_unique<Set<util::Optional<UUID>>>(col_key);
1,554✔
271
            else
1,398✔
272
                return std::make_unique<Set<UUID>>(col_key);
1,398✔
NEW
273
        }
×
NEW
274
        case type_TypedLink: {
✔
NEW
275
            return std::make_unique<Set<ObjLink>>(col_key);
×
NEW
276
        }
×
277
        case type_Mixed: {
5,079✔
278
            return std::make_unique<Set<Mixed>>(col_key);
5,079✔
NEW
279
        }
×
280
        case type_Link: {
16,542✔
281
            return std::make_unique<LnkSet>(col_key);
16,542✔
NEW
282
        }
×
NEW
283
        case type_LinkList:
✔
NEW
284
            break;
×
NEW
285
    }
×
NEW
286
    REALM_TERMINATE("Unsupported column type.");
×
NEW
287
}
×
288

289
CollectionBasePtr CollectionParent::get_collection_ptr(ColKey col_key) const
290
{
64,056✔
291
    if (col_key.is_list()) {
64,056✔
292
        return get_listbase_ptr(col_key);
11,970✔
293
    }
11,970✔
294
    else if (col_key.is_set()) {
52,086✔
295
        return get_setbase_ptr(col_key);
37,260✔
296
    }
37,260✔
297
    else if (col_key.is_dictionary()) {
14,826✔
298
        return std::make_unique<Dictionary>(col_key, get_level() + 1);
14,826✔
299
    }
14,826✔
NEW
300
    return {};
×
NEW
301
}
×
302

303

304
int64_t CollectionParent::generate_key(size_t sz)
305
{
474✔
306
    static std::mt19937 gen32;
474✔
307
    static std::mutex mutex;
474✔
308

309
    int64_t key;
474✔
310
    const std::lock_guard<std::mutex> lock(mutex);
474✔
311
    do {
474✔
312
        if (sz < 0x10) {
474✔
313
            key = int8_t(gen32());
333✔
314
        }
333✔
315
        else if (sz < 0x1000) {
141✔
316
            key = int16_t(gen32());
141✔
317
        }
141✔
NEW
318
        else {
×
NEW
319
            key = int32_t(gen32());
×
NEW
320
        }
×
321
    } while (key == 0);
474✔
322

323
    return key;
474✔
324
}
474✔
325

326

327
} // namespace realm
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