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

realm / realm-core / github_pull_request_281750

30 Oct 2023 03:37PM UTC coverage: 90.528% (-1.0%) from 91.571%
github_pull_request_281750

Pull #6073

Evergreen

jedelbo
Log free space and history sizes when opening file
Pull Request #6073: Merge next-major

95488 of 175952 branches covered (0.0%)

8973 of 12277 new or added lines in 149 files covered. (73.09%)

622 existing lines in 51 files now uncovered.

233503 of 257934 relevant lines covered (90.53%)

6533720.56 hits per line

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

93.32
/src/realm/object-store/c_api/query.cpp
1
#include "realm/sort_descriptor.hpp"
2
#include "realm/util/scope_exit.hpp"
3
#include <realm/object-store/c_api/types.hpp>
4
#include <realm/object-store/c_api/util.hpp>
5

6
#include <realm/object-store/keypath_helpers.hpp>
7
#include <realm/parser/query_parser.hpp>
8
#include <realm/parser/keypath_mapping.hpp>
9

10
namespace realm::c_api {
11

12
namespace {
13
struct QueryArgumentsAdapter : query_parser::Arguments {
14
    const realm_query_arg_t* m_args = nullptr;
15

16
    QueryArgumentsAdapter(size_t num_args, const realm_query_arg_t* args) noexcept
17
        : Arguments(num_args)
18
        , m_args(args)
19
    {
186✔
20
    }
186✔
21

22
    bool bool_for_argument(size_t i) final
23
    {
2✔
24
        verify_ndx(i);
2✔
25
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_BOOL);
2✔
26
        return m_args[i].arg[0].boolean;
2✔
27
    }
2✔
28

29
    long long long_for_argument(size_t i) final
30
    {
8✔
31
        verify_ndx(i);
8✔
32
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_INT);
8✔
33
        return m_args[i].arg[0].integer;
8✔
34
    }
8✔
35

36
    float float_for_argument(size_t i) final
37
    {
2✔
38
        verify_ndx(i);
2✔
39
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_FLOAT);
2✔
40
        return m_args[i].arg[0].fnum;
2✔
41
    }
2✔
42

43
    double double_for_argument(size_t i) final
44
    {
2✔
45
        verify_ndx(i);
2✔
46
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_DOUBLE);
2✔
47
        return m_args[i].arg[0].dnum;
2✔
48
    }
2✔
49

50
    StringData string_for_argument(size_t i) final
51
    {
100✔
52
        verify_ndx(i);
100✔
53
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_STRING);
100✔
54
        return from_capi(m_args[i].arg[0].string);
100✔
55
    }
100✔
56

57
    BinaryData binary_for_argument(size_t i) final
58
    {
2✔
59
        verify_ndx(i);
2✔
60
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_BINARY);
2✔
61
        return from_capi(m_args[i].arg[0].binary);
2✔
62
    }
2✔
63

64
    Timestamp timestamp_for_argument(size_t i) final
65
    {
2✔
66
        verify_ndx(i);
2✔
67
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_TIMESTAMP);
2✔
68
        return from_capi(m_args[i].arg[0].timestamp);
2✔
69
    }
2✔
70

71
    ObjKey object_index_for_argument(size_t i) final
72
    {
4✔
73
        verify_ndx(i);
4✔
74
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_LINK);
4✔
75
        // FIXME: Somehow check the target table type?
2✔
76
        return from_capi(m_args[i].arg[0].link).get_obj_key();
4✔
77
    }
4✔
78

79
    ObjectId objectid_for_argument(size_t i) final
80
    {
2✔
81
        verify_ndx(i);
2✔
82
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_OBJECT_ID);
2✔
83
        return from_capi(m_args[i].arg[0].object_id);
2✔
84
    }
2✔
85

86
    Decimal128 decimal128_for_argument(size_t i) final
87
    {
6✔
88
        verify_ndx(i);
6✔
89
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_DECIMAL128);
6✔
90
        return from_capi(m_args[i].arg[0].decimal128);
6✔
91
    }
6✔
92

93
    UUID uuid_for_argument(size_t i) final
94
    {
2✔
95
        verify_ndx(i);
2✔
96
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_UUID);
2✔
97
        return from_capi(m_args[i].arg[0].uuid);
2✔
98
    }
2✔
99

100
    ObjLink objlink_for_argument(size_t i) final
101
    {
×
102
        verify_ndx(i);
×
103
        REALM_ASSERT(m_args[i].arg[0].type == RLM_TYPE_LINK);
×
104
        return from_capi(m_args[i].arg[0].link);
×
105
    }
×
106

107
#if REALM_ENABLE_GEOSPATIAL
108
    Geospatial geospatial_for_argument(size_t i) final
109
    {
×
110
        verify_ndx(i);
×
111
        // FIXME: implement this
112
        throw LogicError{
×
113
            ErrorCodes::RuntimeError,
×
114
            util::format("geospatial in the C-API is not yet implemented (for argument %1)", i)}; // LCOV_EXCL_LINE
×
115
    }
×
116
#endif
117

118
    bool is_argument_null(size_t i) final
119
    {
142✔
120
        verify_ndx(i);
142✔
121
        return !m_args[i].is_list && m_args[i].arg[0].type == RLM_TYPE_NULL;
142✔
122
    }
142✔
123

124
    bool is_argument_list(size_t i) final
125
    {
144✔
126
        verify_ndx(i);
144✔
127
        return m_args[i].is_list;
144✔
128
    }
144✔
129

130
    std::vector<Mixed> list_for_argument(size_t ndx) final
131
    {
8✔
132
        verify_ndx(ndx);
8✔
133
        REALM_ASSERT(m_args[ndx].is_list);
8✔
134
        std::vector<Mixed> list;
8✔
135
        list.reserve(m_args[ndx].nb_args);
8✔
136
        for (size_t i = 0; i < m_args[ndx].nb_args; ++i) {
20✔
137
            list.push_back(from_capi(m_args[ndx].arg[i]));
12✔
138
        }
12✔
139
        return list;
8✔
140
    }
8✔
141
    DataType type_for_argument(size_t i) override
142
    {
132✔
143
        verify_ndx(i);
132✔
144
        switch (m_args[i].arg[0].type) {
132✔
145
            case RLM_TYPE_NULL:                                                  // LCOV_EXCL_LINE
✔
146
                REALM_TERMINATE("Query parser did not call is_argument_null()"); // LCOV_EXCL_LINE
×
147
            case RLM_TYPE_INT:
8✔
148
                return type_Int;
8✔
149
            case RLM_TYPE_STRING:
100✔
150
                return type_String;
100✔
151
            case RLM_TYPE_BOOL:
2✔
152
                return type_Bool;
2✔
153
            case RLM_TYPE_FLOAT:
2✔
154
                return type_Float;
2✔
155
            case RLM_TYPE_DOUBLE:
2✔
156
                return type_Double;
2✔
157
            case RLM_TYPE_BINARY:
2✔
158
                return type_Binary;
2✔
159
            case RLM_TYPE_TIMESTAMP:
2✔
160
                return type_Timestamp;
2✔
161
            case RLM_TYPE_LINK:
4✔
162
                return type_Link;
4✔
163
            case RLM_TYPE_OBJECT_ID:
2✔
164
                return type_ObjectId;
2✔
165
            case RLM_TYPE_DECIMAL128:
6✔
166
                return type_Decimal;
6✔
167
            case RLM_TYPE_UUID:
2✔
168
                return type_UUID;
2✔
NEW
169
            case RLM_TYPE_LIST:
✔
NEW
170
                return type_List;
×
NEW
171
            case RLM_TYPE_SET:
✔
NEW
172
                return type_Set;
×
NEW
173
            case RLM_TYPE_DICTIONARY:
✔
NEW
174
                return type_Dictionary;
×
175
        }
×
176
        throw LogicError{ErrorCodes::TypeMismatch, "Unsupported type"}; // LCOV_EXCL_LINE
×
177
        return type_Int;
×
178
    }
×
179
};
180
} // namespace
181

182
static Query parse_and_apply_query(const std::shared_ptr<Realm>& realm, ConstTableRef table, const char* query_string,
183
                                   size_t num_args, const realm_query_arg_t* args)
184
{
186✔
185
    query_parser::KeyPathMapping mapping;
186✔
186
    realm::populate_keypath_mapping(mapping, *realm);
186✔
187
    QueryArgumentsAdapter arguments{num_args, args};
186✔
188
    Query query = table->query(query_string, arguments, mapping);
186✔
189
    return query;
186✔
190
}
186✔
191

192
RLM_API realm_query_t* realm_query_parse(const realm_t* realm, realm_class_key_t target_table_key,
193
                                         const char* query_string, size_t num_args, const realm_query_arg_t* args)
194
{
156✔
195
    return wrap_err([&]() {
156✔
196
        auto table = (*realm)->read_group().get_table(TableKey(target_table_key));
156✔
197
        Query query = parse_and_apply_query(*realm, table, query_string, num_args, args);
156✔
198
        auto ordering = query.get_ordering();
156✔
199
        return new realm_query_t{std::move(query), std::move(ordering), *realm};
156✔
200
    });
156✔
201
}
156✔
202

203
RLM_API const char* realm_query_get_description(realm_query_t* query)
204
{
2✔
205
    return wrap_err([&]() {
2✔
206
        return query->get_description();
2✔
207
    });
2✔
208
}
2✔
209

210
RLM_API realm_query_t* realm_query_append_query(const realm_query_t* existing_query, const char* query_string,
211
                                                size_t num_args, const realm_query_arg_t* args)
212
{
14✔
213
    return wrap_err([&]() {
14✔
214
        auto realm = existing_query->weak_realm.lock();
14✔
215
        auto table = existing_query->query.get_table();
14✔
216
        auto query = parse_and_apply_query(realm, table, query_string, num_args, args);
14✔
217
        auto combined = Query(existing_query->query).and_query(query);
14✔
218
        auto ordering_copy = util::make_bind<DescriptorOrdering>();
14✔
219
        *ordering_copy = existing_query->get_ordering();
14✔
220
        if (auto ordering = query.get_ordering())
14✔
221
            ordering_copy->append(*ordering);
10✔
222
        return new realm_query_t{std::move(combined), std::move(ordering_copy), realm};
14✔
223
    });
14✔
224
}
14✔
225

226
RLM_API realm_query_t* realm_query_parse_for_list(const realm_list_t* list, const char* query_string, size_t num_args,
227
                                                  const realm_query_arg_t* args)
228
{
4✔
229
    return wrap_err([&]() {
4✔
230
        auto existing_query = list->get_query();
4✔
231
        auto realm = list->get_realm();
4✔
232
        auto table = list->get_table();
4✔
233
        auto query = parse_and_apply_query(realm, table, query_string, num_args, args);
4✔
234
        auto combined = existing_query.and_query(query);
4✔
235
        auto ordering_copy = util::make_bind<DescriptorOrdering>();
4✔
236
        if (auto ordering = query.get_ordering())
4✔
237
            ordering_copy->append(*ordering);
×
238
        return new realm_query_t{std::move(combined), std::move(ordering_copy), realm};
4✔
239
    });
4✔
240
}
4✔
241

242
RLM_API realm_query_t* realm_query_parse_for_set(const realm_set_t* set, const char* query_string, size_t num_args,
243
                                                 const realm_query_arg_t* args)
244
{
2✔
245
    return wrap_err([&]() {
2✔
246
        auto existing_query = set->get_query();
2✔
247
        auto realm = set->get_realm();
2✔
248
        auto table = set->get_table();
2✔
249
        auto query = parse_and_apply_query(realm, table, query_string, num_args, args);
2✔
250
        auto combined = existing_query.and_query(query);
2✔
251
        auto ordering_copy = util::make_bind<DescriptorOrdering>();
2✔
252
        if (auto ordering = query.get_ordering())
2✔
253
            ordering_copy->append(*ordering);
×
254
        return new realm_query_t{std::move(combined), std::move(ordering_copy), realm};
2✔
255
    });
2✔
256
}
2✔
257

258
RLM_API realm_query_t* realm_query_parse_for_results(const realm_results_t* results, const char* query_string,
259
                                                     size_t num_args, const realm_query_arg_t* args)
260
{
12✔
261
    return wrap_err([&]() {
12✔
262
        auto existing_query = results->get_query();
12✔
263
        auto realm = results->get_realm();
12✔
264
        auto table = results->get_table();
12✔
265
        auto query = parse_and_apply_query(realm, table, query_string, num_args, args);
12✔
266
        auto combined = existing_query.and_query(query);
12✔
267
        auto ordering_copy = util::make_bind<DescriptorOrdering>();
12✔
268
        if (auto ordering = query.get_ordering())
12✔
269
            ordering_copy->append(*ordering);
×
270
        return new realm_query_t{std::move(combined), std::move(ordering_copy), realm};
12✔
271
    });
12✔
272
}
12✔
273

274
RLM_API bool realm_query_count(const realm_query_t* query, size_t* out_count)
275
{
28✔
276
    return wrap_err([&]() {
28✔
277
        *out_count = Query(query->query).count(query->get_ordering());
28✔
278
        return true;
28✔
279
    });
28✔
280
}
28✔
281

282
RLM_API bool realm_query_find_first(realm_query_t* query, realm_value_t* out_value, bool* out_found)
283
{
8✔
284
    return wrap_err([&]() {
8✔
285
        const auto& realm_query_ordering = query->get_ordering();
8✔
286
        if (realm_query_ordering.size() > 0) {
8✔
287
            auto orderding = util::make_bind<DescriptorOrdering>();
6✔
288
            orderding->append(realm_query_ordering);
6✔
289
            query->query.set_ordering(orderding);
6✔
290
        }
6✔
291
        auto key = query->query.find();
8✔
292
        if (out_found)
8✔
293
            *out_found = bool(key);
8✔
294
        if (key && out_value) {
8✔
295
            ObjLink link{query->query.get_table()->get_key(), key};
8✔
296
            out_value->type = RLM_TYPE_LINK;
8✔
297
            out_value->link = to_capi(link);
8✔
298
        }
8✔
299
        return true;
8✔
300
    });
8✔
301
}
8✔
302

303
RLM_API realm_results_t* realm_query_find_all(realm_query_t* query)
304
{
104✔
305
    return wrap_err([&]() {
104✔
306
        auto shared_realm = query->weak_realm.lock();
104✔
307
        REALM_ASSERT_RELEASE(shared_realm);
104✔
308
        return new realm_results{Results{shared_realm, query->query, query->get_ordering()}};
104✔
309
    });
104✔
310
}
104✔
311

312
RLM_API realm_results_t* realm_list_to_results(realm_list_t* list)
313
{
6✔
314
    return wrap_err([&]() {
6✔
315
        return new realm_results_t{list->as_results()};
6✔
316
    });
6✔
317
}
6✔
318

319
RLM_API realm_results_t* realm_set_to_results(realm_set_t* set)
320
{
×
321
    return wrap_err([&]() {
×
322
        return new realm_results_t{set->as_results()};
×
323
    });
×
324
}
×
325

326
RLM_API realm_results_t* realm_dictionary_to_results(realm_dictionary_t* dictionary)
327
{
2✔
328
    return wrap_err([&]() {
2✔
329
        return new realm_results_t{dictionary->as_results()};
2✔
330
    });
2✔
331
}
2✔
332

333
RLM_API realm_results_t* realm_get_backlinks(realm_object_t* object, realm_class_key_t source_table_key,
334
                                             realm_property_key_t property_key)
335
{
8✔
336
    return wrap_err([&]() {
8✔
337
        object->verify_attached();
8✔
338
        auto realm = object->realm();
8✔
339
        return new realm_results_t{
8✔
340
            Results{realm, object->get_obj(), TableKey{source_table_key}, ColKey{property_key}}};
8✔
341
    });
8✔
342
}
8✔
343

344
RLM_API bool realm_results_is_valid(const realm_results_t* results, bool* is_valid)
345
{
8✔
346
    return wrap_err([&]() {
8✔
347
        if (is_valid)
8✔
348
            *is_valid = results->is_valid();
8✔
349
        return true;
8✔
350
    });
8✔
351
}
8✔
352

353
RLM_API bool realm_results_count(realm_results_t* results, size_t* out_count)
354
{
60✔
355
    return wrap_err([&]() {
60✔
356
        auto count = results->size();
60✔
357
        if (out_count) {
60✔
358
            *out_count = count;
58✔
359
        }
58✔
360
        return true;
60✔
361
    });
60✔
362
}
60✔
363

364
RLM_API realm_results_t* realm_results_filter(realm_results_t* results, realm_query_t* query)
365
{
4✔
366
    return wrap_err([&]() {
4✔
367
        return new realm_results{results->filter(std::move(query->query))};
4✔
368
    });
4✔
369
}
4✔
370

371
namespace {
372
realm_results_t* realm_results_ordering(realm_results_t* results, const char* op, const char* ordering)
373
{
4✔
374
    return wrap_err([&]() -> realm_results_t* {
4✔
375
        std::string str = "TRUEPREDICATE " + std::string(op) + "(" + std::string(ordering) + ")";
4✔
376
        auto q = results->get_table()->query(str);
4✔
377
        auto ordering{q.get_ordering()};
4✔
378
        return new realm_results{results->apply_ordering(std::move(*ordering))};
4✔
379
        return nullptr;
2✔
380
    });
4✔
381
}
4✔
382
} // namespace
383

384
RLM_API realm_results_t* realm_results_sort(realm_results_t* results, const char* sort_string)
385
{
2✔
386
    return realm_results_ordering(results, "SORT", sort_string);
2✔
387
}
2✔
388

389
RLM_API realm_results_t* realm_results_distinct(realm_results_t* results, const char* distinct_string)
390
{
2✔
391
    return realm_results_ordering(results, "DISTINCT", distinct_string);
2✔
392
}
2✔
393

394
RLM_API realm_results_t* realm_results_limit(realm_results_t* results, size_t max_count)
395
{
2✔
396
    return wrap_err([&]() {
2✔
397
        return new realm_results{results->limit(max_count)};
2✔
398
    });
2✔
399
}
2✔
400

401

402
RLM_API bool realm_results_get(realm_results_t* results, size_t index, realm_value_t* out_value)
403
{
18✔
404
    return wrap_err([&]() {
18✔
405
        auto mixed = results->get_any(index);
18✔
406
        if (out_value) {
18✔
407
            *out_value = to_capi(mixed);
14✔
408
        }
14✔
409
        return true;
18✔
410
    });
18✔
411
}
18✔
412

413
RLM_API realm_list_t* realm_results_get_list(realm_results_t* results, size_t index)
414
{
4✔
415
    return wrap_err([&]() {
4✔
416
        realm_list_t* out = nullptr;
4✔
417
        auto result_list = results->get_list(index);
4✔
418
        if (result_list.is_valid())
4✔
419
            out = new realm_list_t{result_list};
4✔
420
        return out;
4✔
421
    });
4✔
422
}
4✔
423

424
RLM_API realm_set_t* realm_results_get_set(realm_results_t* results, size_t index)
425
{
4✔
426
    return wrap_err([&]() {
4✔
427
        realm_set_t* out = nullptr;
4✔
428
        auto result_set = results->get_set(index);
4✔
429
        if (result_set.is_valid())
4✔
430
            out = new realm_set_t{result_set};
4✔
431
        return out;
4✔
432
    });
4✔
433
}
4✔
434

435
RLM_API realm_dictionary_t* realm_results_get_dictionary(realm_results_t* results, size_t index)
436
{
4✔
437
    return wrap_err([&]() {
4✔
438
        realm_dictionary_t* out = nullptr;
4✔
439
        auto result_dictionary = results->get_dictionary(index);
4✔
440
        if (result_dictionary.is_valid())
4✔
441
            out = new realm_dictionary_t{result_dictionary};
4✔
442
        return out;
4✔
443
    });
4✔
444
}
4✔
445

446
RLM_API bool realm_results_find(realm_results_t* results, realm_value_t* value, size_t* out_index, bool* out_found)
447
{
12✔
448
    if (out_index)
12✔
449
        *out_index = realm::not_found;
12✔
450
    if (out_found)
12✔
451
        *out_found = false;
12✔
452

6✔
453
    return wrap_err([&]() {
12✔
454
        auto val = from_capi(*value);
12✔
455
        if (out_index) {
12✔
456
            *out_index = results->index_of(val);
12✔
457
            if (out_found && *out_index != realm::not_found) {
12✔
458
                *out_found = true;
8✔
459
            }
8✔
460
        }
12✔
461
        return true;
12✔
462
    });
12✔
463
}
12✔
464

465
RLM_API realm_object_t* realm_results_get_object(realm_results_t* results, size_t index)
466
{
14✔
467
    return wrap_err([&]() {
14✔
468
        auto shared_realm = results->get_realm();
14✔
469
        auto obj = results->get<Obj>(index);
14✔
470
        return new realm_object_t{Object{shared_realm, std::move(obj)}};
14✔
471
    });
14✔
472
}
14✔
473

474
RLM_API realm_query_t* realm_results_get_query(realm_results_t* results)
475
{
2✔
476
    return wrap_err([&]() {
2✔
477
        auto query = results->get_query();
2✔
478
        auto shared_realm = results->get_realm();
2✔
479
        auto ordering = query.get_ordering();
2✔
480
        return new realm_query_t{std::move(query), std::move(ordering), shared_realm};
2✔
481
    });
2✔
482
}
2✔
483

484
RLM_API bool realm_results_find_object(realm_results_t* results, realm_object_t* value, size_t* out_index,
485
                                       bool* out_found)
486
{
4✔
487
    if (out_index)
4✔
488
        *out_index = realm::not_found;
4✔
489
    if (out_found)
4✔
490
        *out_found = false;
4✔
491

2✔
492
    return wrap_err([&]() {
4✔
493
        if (out_index) {
4✔
494
            *out_index = results->index_of(value->get_obj());
4✔
495
            if (out_found && *out_index != realm::not_found)
4✔
496
                *out_found = true;
2✔
497
        }
4✔
498
        return true;
4✔
499
    });
4✔
500
}
4✔
501

502
RLM_API bool realm_results_delete_all(realm_results_t* results)
503
{
10✔
504
    return wrap_err([&]() {
10✔
505
        // Note: This method is very confusingly named. It actually does erase
5✔
506
        // all the objects.
5✔
507
        results->clear();
10✔
508
        return true;
10✔
509
    });
10✔
510
}
10✔
511

512
RLM_API realm_results_t* realm_results_snapshot(const realm_results_t* results)
513
{
2✔
514
    return wrap_err([&]() {
2✔
515
        return new realm_results{results->snapshot()};
2✔
516
    });
2✔
517
}
2✔
518

519
RLM_API bool realm_results_min(realm_results_t* results, realm_property_key_t col, realm_value_t* out_value,
520
                               bool* out_found)
521
{
6✔
522
    return wrap_err([&]() {
6✔
523
        if (auto x = results->min(ColKey(col))) {
6✔
524
            if (out_found) {
2✔
525
                *out_found = true;
2✔
526
            }
2✔
527
            if (out_value) {
2✔
528
                *out_value = to_capi(*x);
2✔
529
            }
2✔
530
        }
2✔
531
        else {
4✔
532
            if (out_found) {
4✔
533
                *out_found = false;
2✔
534
            }
2✔
535
            if (out_value) {
4✔
536
                out_value->type = RLM_TYPE_NULL;
2✔
537
            }
2✔
538
        }
4✔
539
        return true;
6✔
540
    });
6✔
541
}
6✔
542

543
RLM_API bool realm_results_max(realm_results_t* results, realm_property_key_t col, realm_value_t* out_value,
544
                               bool* out_found)
545
{
6✔
546
    return wrap_err([&]() {
6✔
547
        if (auto x = results->max(ColKey(col))) {
6✔
548
            if (out_found) {
2✔
549
                *out_found = true;
2✔
550
            }
2✔
551
            if (out_value) {
2✔
552
                *out_value = to_capi(*x);
2✔
553
            }
2✔
554
        }
2✔
555
        else {
4✔
556
            if (out_found) {
4✔
557
                *out_found = false;
2✔
558
            }
2✔
559
            if (out_value) {
4✔
560
                out_value->type = RLM_TYPE_NULL;
2✔
561
            }
2✔
562
        }
4✔
563
        return true;
6✔
564
    });
6✔
565
}
6✔
566

567
RLM_API bool realm_results_sum(realm_results_t* results, realm_property_key_t col, realm_value_t* out_value,
568
                               bool* out_found)
569
{
6✔
570
    return wrap_err([&]() {
6✔
571
        if (out_found) {
6✔
572
            *out_found = results->size() != 0;
4✔
573
        }
4✔
574

3✔
575
        if (auto x = results->sum(ColKey(col))) {
6✔
576
            if (out_value)
4✔
577
                *out_value = to_capi(*x);
4✔
578
        }
4✔
579
        else {
2✔
580
            // Note: This can only be hit when the `m_table` and `m_collection`
1✔
581
            // pointers in `Results` are NULL.
1✔
582
            //
1✔
583
            // FIXME: It is unclear when that happens.
1✔
584

1✔
585
            // LCOV_EXCL_START
1✔
586
            if (out_value) {
2✔
587
                out_value->type = RLM_TYPE_NULL;
×
588
            }
×
589
            // LCOV_EXCL_STOP
1✔
590
        }
2✔
591
        return true;
6✔
592
    });
6✔
593
}
6✔
594

595
RLM_API bool realm_results_average(realm_results_t* results, realm_property_key_t col, realm_value_t* out_value,
596
                                   bool* out_found)
597
{
6✔
598
    return wrap_err([&]() {
6✔
599
        if (auto x = results->average(ColKey(col))) {
6✔
600
            if (out_found) {
2✔
601
                *out_found = true;
2✔
602
            }
2✔
603
            if (out_value) {
2✔
604
                *out_value = to_capi(*x);
2✔
605
            }
2✔
606
        }
2✔
607
        else {
4✔
608
            if (out_found) {
4✔
609
                *out_found = false;
2✔
610
            }
2✔
611
            if (out_value) {
4✔
612
                out_value->type = RLM_TYPE_NULL;
2✔
613
            }
2✔
614
        }
4✔
615
        return true;
6✔
616
    });
6✔
617
}
6✔
618

619
RLM_API realm_results_t* realm_results_from_thread_safe_reference(const realm_t* realm,
620
                                                                  realm_thread_safe_reference_t* tsr)
621
{
4✔
622
    return wrap_err([&]() {
4✔
623
        auto rtsr = dynamic_cast<realm_results::thread_safe_reference*>(tsr);
4✔
624
        if (!rtsr) {
4✔
625
            throw LogicError{ErrorCodes::IllegalOperation, "Thread safe reference type mismatch"};
2✔
626
        }
2✔
627

1✔
628
        auto results = rtsr->resolve<Results>(*realm);
2✔
629
        return new realm_results_t{std::move(results)};
2✔
630
    });
2✔
631
}
4✔
632

633
RLM_API realm_results_t* realm_results_resolve_in(realm_results_t* from_results, const realm_t* target_realm)
634
{
6✔
635
    return wrap_err([&]() {
6✔
636
        const auto& realm = *target_realm;
6✔
637
        auto resolved_results = from_results->freeze(realm);
6✔
638
        return new realm_results_t{std::move(resolved_results)};
6✔
639
    });
6✔
640
}
6✔
641

642
} // namespace realm::c_api
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

© 2025 Coveralls, Inc