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

realm / realm-core / 2085

01 Mar 2024 12:26PM UTC coverage: 90.926% (-0.001%) from 90.927%
2085

push

Evergreen

jedelbo
Avoid doing unneeded logger work in Replication

Most of the replication log statements do some work including memory
allocations which are then thrown away if the log level it too high, so always
check the log level first. A few places don't actually benefit from this, but
it's easier to consistently check the log level every time.

93986 of 173116 branches covered (54.29%)

63 of 100 new or added lines in 2 files covered. (63.0%)

114 existing lines in 17 files now uncovered.

238379 of 262169 relevant lines covered (90.93%)

6007877.32 hits per line

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

87.7
/src/realm/query_expression.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 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/query_expression.hpp>
20
#include <realm/group.hpp>
21
#include <realm/dictionary.hpp>
22

23
namespace realm {
24

25
void LinkMap::set_base_table(ConstTableRef table)
26
{
862,728✔
27
    if (table == get_base_table())
862,728✔
28
        return;
43,428✔
29

409,641✔
30
    m_tables.clear();
819,300✔
31
    m_tables.push_back(table);
819,300✔
32
    m_link_types.clear();
819,300✔
33
    m_only_unary_links = true;
819,300✔
34

409,641✔
35
    for (size_t i = 0; i < m_link_column_keys.size(); i++) {
856,512✔
36
        ColKey link_column_key = m_link_column_keys[i];
37,212✔
37
        // Link column can be either LinkList or single Link
18,606✔
38
        ColumnType type = link_column_key.get_type();
37,212✔
39
        REALM_ASSERT(Table::is_link_type(type) || type == col_type_BackLink);
37,212✔
40
        if (type == col_type_BackLink || (type == col_type_Link && link_column_key.is_collection())) {
37,212✔
41
            m_only_unary_links = false;
12,474✔
42
        }
12,474✔
43

18,606✔
44
        m_link_types.push_back(type);
37,212✔
45
        REALM_ASSERT(table->valid_column(link_column_key));
37,212✔
46
        table = table.unchecked_ptr()->get_opposite_table(link_column_key);
37,212✔
47
        m_tables.push_back(table);
37,212✔
48
    }
37,212✔
49
}
819,300✔
50

51
void LinkMap::collect_dependencies(std::vector<TableKey>& tables) const
52
{
3,246✔
53
    for (auto& t : m_tables) {
5,460✔
54
        TableKey k = t->get_key();
5,460✔
55
        if (find(tables.begin(), tables.end(), k) == tables.end()) {
5,460✔
56
            tables.push_back(k);
1,998✔
57
        }
1,998✔
58
    }
5,460✔
59
}
3,246✔
60

61
std::string LinkMap::description(util::serializer::SerialisationState& state) const
62
{
8,406✔
63
    std::string s;
8,406✔
64
    for (size_t i = 0; i < m_link_column_keys.size(); ++i) {
19,368✔
65
        if (i < m_tables.size() && m_tables[i]) {
10,962✔
66
            s += m_link_column_keys[i].get_description(m_tables[i], state);
10,962✔
67
            if (i != m_link_column_keys.size() - 1) {
10,962✔
68
                s += util::serializer::value_separator;
2,556✔
69
            }
2,556✔
70
        }
10,962✔
71
    }
10,962✔
72
    return s;
8,406✔
73
}
8,406✔
74

75
bool LinkMap::map_links(size_t column, ObjKey key, LinkMapFunction lm) const
76
{
508,815✔
77
    if (!key || key.is_unresolved())
508,815✔
78
        return true;
7,446✔
79
    if (column == m_link_column_keys.size()) {
501,369✔
80
        return lm(key);
464,754✔
81
    }
464,754✔
82

18,312✔
83
    ColumnType type = m_link_types[column];
36,615✔
84
    ColKey column_key = m_link_column_keys[column];
36,615✔
85
    const Obj obj = m_tables[column]->get_object(key);
36,615✔
86
    if (column_key.is_collection()) {
36,615✔
87
        auto& pe = m_link_column_keys[column].get_index();
2,484✔
88
        if (pe.is_all()) {
2,484✔
89
            auto coll = obj.get_linkcollection_ptr(column_key);
2,412✔
90
            size_t sz = coll->size();
2,412✔
91
            for (size_t t = 0; t < sz; t++) {
6,252✔
92
                if (!map_links(column + 1, coll->get_key(t), lm))
3,840✔
93
                    return false;
×
94
            }
3,840✔
95
        }
2,412✔
96
        else if (pe.is_key()) {
72✔
97
            REALM_ASSERT(column_key.is_dictionary());
36✔
98
            auto dict = obj.get_dictionary(column_key);
36✔
99
            if (auto x = dict.try_get(pe.get_key())) {
36✔
100
                if (!map_links(column + 1, x->get<ObjKey>(), lm))
36✔
101
                    return false;
×
102
            }
36✔
103
        }
36✔
104
        else if (pe.is_ndx()) {
36✔
105
            REALM_ASSERT(column_key.is_list());
36✔
106
            auto list = obj.get_linklist(column_key);
36✔
107
            if (auto sz = list.size()) {
36✔
108
                auto ndx = pe.get_ndx();
12✔
109
                if (ndx == realm::npos) {
12✔
110
                    ndx = sz - 1;
12✔
111
                }
12✔
112
                if (ndx < sz) {
12✔
113
                    if (!map_links(column + 1, list.get(ndx), lm))
12✔
114
                        return false;
×
115
                }
34,131✔
116
            }
12✔
117
        }
36✔
118
    }
34,131✔
119
    else if (type == col_type_Link) {
34,131✔
120
        return map_links(column + 1, obj.get<ObjKey>(column_key), lm);
33,486✔
121
    }
33,486✔
122
    else if (type == col_type_BackLink) {
654✔
123
        auto backlinks = obj.get_all_backlinks(column_key);
654✔
124
        for (auto k : backlinks) {
651✔
125
            if (!map_links(column + 1, k, lm))
648✔
126
                return false;
×
127
        }
648✔
128
    }
654✔
129
    else {
4,294,967,294✔
130
        REALM_TERMINATE("Invalid column type in LinkMap::map_links()");
131
    }
4,294,967,294✔
132
    return true;
19,875✔
133
}
36,615✔
134

135
void LinkMap::map_links(size_t column, size_t row, LinkMapFunction lm) const
136
{
366,285✔
137
    ColumnType type = m_link_types[column];
366,285✔
138
    ColKey column_key = m_link_column_keys[column];
366,285✔
139
    if (column_key.is_collection()) {
366,285✔
140
        if (column_key.is_dictionary()) {
198,264✔
141
            auto& leaf = mpark::get<ArrayInteger>(m_leaf);
1,518✔
142
            if (leaf.get(row)) {
1,518✔
143
                auto& pe = m_link_column_keys[column].get_index();
924✔
144
                Allocator& alloc = get_base_table()->get_alloc();
924✔
145
                Array top(alloc);
924✔
146
                top.set_parent(const_cast<ArrayInteger*>(&leaf), row);
924✔
147
                top.init_from_parent();
924✔
148
                BPlusTree<Mixed> values(alloc);
924✔
149
                values.set_parent(&top, 1);
924✔
150
                values.init_from_parent();
924✔
151
                size_t start = 0;
924✔
152
                size_t end = values.size();
924✔
153
                if (pe.is_key()) {
924✔
154
                    BPlusTree<StringData> keys(alloc);
186✔
155
                    keys.set_parent(&top, 0);
186✔
156
                    keys.init_from_parent();
186✔
157
                    start = keys.find_first(StringData(pe.get_key()));
186✔
158
                    if (start == realm::not_found) {
186✔
159
                        return;
×
160
                    }
×
161
                    end = start + 1;
186✔
162
                }
186✔
163
                // Iterate through values and insert all link values
462✔
164
                for (; start < end; start++) {
2,580✔
165
                    Mixed m = values.get(start);
1,656✔
166
                    if (m.is_type(type_TypedLink)) {
1,656✔
167
                        auto link = m.get_link();
1,638✔
168
                        REALM_ASSERT(link.get_table_key() == this->m_tables[column + 1]->get_key());
1,638✔
169
                        if (!map_links(column + 1, link.get_obj_key(), lm))
1,638✔
170
                            break;
×
171
                    }
1,638✔
172
                }
1,656✔
173
            }
924✔
174
        }
1,518✔
175
        else {
196,746✔
176
            ref_type ref;
196,746✔
177
            if (auto list = mpark::get_if<ArrayList>(&m_leaf)) {
196,746✔
178
                ref = list->get(row);
195,840✔
179
            }
195,840✔
180
            else {
906✔
181
                ref = mpark::get<ArrayKey>(m_leaf).get_as_ref(row);
906✔
182
            }
906✔
183

98,373✔
184
            if (ref) {
196,746✔
185
                BPlusTree<ObjKey> links(get_base_table()->get_alloc());
139,824✔
186
                links.init_from_ref(ref);
139,824✔
187
                size_t sz = links.size();
139,824✔
188
                size_t start = 0;
139,824✔
189
                size_t end = sz;
139,824✔
190
                auto& pe = m_link_column_keys[column].get_index();
139,824✔
191
                if (pe.is_ndx()) {
139,824✔
192
                    start = pe.get_ndx();
288✔
193
                    if (start == realm::npos) {
288✔
194
                        start = sz - 1;
72✔
195
                    }
72✔
196
                    else if (start < sz) {
216✔
197
                        end = start + 1;
216✔
198
                    }
216✔
199
                }
288✔
200
                for (size_t t = start; t < end; t++) {
416,928✔
201
                    if (!map_links(column + 1, links.get(t), lm))
277,410✔
202
                        break;
306✔
203
                }
277,410✔
204
            }
139,824✔
205
        }
196,746✔
206
    }
198,264✔
207
    else if (type == col_type_Link) {
168,021✔
208
        map_links(column + 1, mpark::get<ArrayKey>(m_leaf).get(row), lm);
163,653✔
209
    }
163,653✔
210
    else if (type == col_type_BackLink) {
4,368✔
211
        auto& back_links = mpark::get<ArrayBacklink>(m_leaf);
4,368✔
212
        size_t sz = back_links.get_backlink_count(row);
4,368✔
213
        for (size_t t = 0; t < sz; t++) {
32,412✔
214
            ObjKey k = back_links.get_backlink(row, t);
28,122✔
215
            if (!map_links(column + 1, k, lm))
28,122✔
216
                break;
78✔
217
        }
28,122✔
218
    }
4,368✔
UNCOV
219
    else {
×
220
        REALM_TERMINATE("Invalid column type in LinkMap::map_links()");
UNCOV
221
    }
×
222
}
366,285✔
223

224
std::vector<ObjKey> LinkMap::get_origin_objkeys(ObjKey key, size_t column) const
225
{
20,364✔
226
    if (column == m_link_types.size()) {
20,364✔
227
        return {key};
16,170✔
228
    }
16,170✔
229
    std::vector<ObjKey> keys = get_origin_objkeys(key, column + 1);
4,194✔
230
    std::vector<ObjKey> ret;
4,194✔
231
    auto origin_col = m_link_column_keys[column];
4,194✔
232
    auto origin = m_tables[column];
4,194✔
233
    auto link_type = m_link_types[column];
4,194✔
234
    if (link_type == col_type_BackLink) {
4,194✔
235
        auto link_table = origin->get_opposite_table(origin_col);
660✔
236
        ColKey link_col_key = origin->get_opposite_column(origin_col);
660✔
237

330✔
238
        for (auto k : keys) {
660✔
239
            const Obj o = link_table.unchecked_ptr()->get_object(k);
660✔
240
            if (link_col_key.is_collection()) {
660✔
241
                auto coll = o.get_linkcollection_ptr(link_col_key);
48✔
242
                auto sz = coll->size();
48✔
243
                for (size_t i = 0; i < sz; i++) {
144✔
244
                    if (ObjKey x = coll->get_key(i))
96✔
245
                        ret.push_back(x);
84✔
246
                }
96✔
247
            }
48✔
248
            else if (link_col_key.get_type() == col_type_Link) {
612✔
249
                ret.push_back(o.get<ObjKey>(link_col_key));
612✔
250
            }
612✔
251
        }
660✔
252
    }
660✔
253
    else {
3,534✔
254
        auto target = m_tables[column + 1];
3,534✔
255
        for (auto k : keys) {
3,648✔
256
            const Obj o = target->get_object(k);
3,648✔
257
            auto cnt = o.get_backlink_count(*origin, origin_col);
3,648✔
258
            for (size_t i = 0; i < cnt; i++) {
7,998✔
259
                ret.push_back(o.get_backlink(*origin, origin_col, i));
4,350✔
260
            }
4,350✔
261
        }
3,648✔
262
    }
3,534✔
263
    return ret;
4,194✔
264
}
4,194✔
265

266
ColumnDictionaryKeys Columns<Dictionary>::keys()
267
{
12✔
268
    return ColumnDictionaryKeys(*this);
12✔
269
}
12✔
270

271
void Columns<Dictionary>::init_path(const PathElement* begin, const PathElement* end)
272
{
882✔
273
    m_path.clear();
882✔
274
    m_path_only_unary_keys = true;
882✔
275
    while (begin != end) {
1,818✔
276
        if (begin->is_all()) {
936✔
277
            m_path_only_unary_keys = false;
54✔
278
        }
54✔
279
        m_path.emplace_back(std::move(*begin));
936✔
280
        ++begin;
936✔
281
    }
936✔
282
    std::move(begin, end, std::back_inserter(m_path));
882✔
283
    if (m_path.empty()) {
882✔
284
        m_path_only_unary_keys = false;
×
285
        m_path.push_back(PathElement::AllTag());
×
286
    }
×
287
}
882✔
288

289
void ColumnDictionaryKeys::set_cluster(const Cluster* cluster)
290
{
78✔
291
    if (m_link_map.has_links()) {
78✔
292
        m_link_map.set_cluster(cluster);
6✔
293
    }
6✔
294
    else {
72✔
295
        m_leaf.emplace(m_link_map.get_base_table()->get_alloc());
72✔
296
        cluster->init_leaf(m_column_key, &*m_leaf);
72✔
297
    }
72✔
298
}
78✔
299

300

301
void ColumnDictionaryKeys::evaluate(size_t index, ValueBase& destination)
302
{
6,666✔
303
    if (m_link_map.has_links()) {
6,666✔
304
        REALM_ASSERT(!m_leaf);
60✔
305
        std::vector<ObjKey> links = m_link_map.get_links(index);
60✔
306
        auto sz = links.size();
60✔
307

30✔
308
        // Here we don't really know how many values to expect
30✔
309
        std::vector<Mixed> values;
60✔
310
        for (size_t t = 0; t < sz; t++) {
120✔
311
            const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
60✔
312
            auto dict = obj.get_dictionary(m_column_key);
60✔
313
            // Insert all values
30✔
314
            dict.for_all_keys<StringData>([&values](const Mixed& value) {
150✔
315
                values.emplace_back(value);
150✔
316
            });
150✔
317
        }
60✔
318

30✔
319
        // Copy values over
30✔
320
        destination.init(true, values.size());
60✔
321
        destination.set(values.begin(), values.end());
60✔
322
    }
60✔
323
    else {
6,606✔
324
        // Not a link column
3,303✔
325
        Allocator& alloc = get_base_table()->get_alloc();
6,606✔
326

3,303✔
327
        REALM_ASSERT(m_leaf);
6,606✔
328
        if (m_leaf->get(index)) {
6,606✔
329
            Array top(alloc);
6,606✔
330
            top.set_parent(&*m_leaf, index);
6,606✔
331
            top.init_from_parent();
6,606✔
332
            BPlusTree<StringData> keys(alloc);
6,606✔
333
            keys.set_parent(&top, 0);
6,606✔
334
            keys.init_from_parent();
6,606✔
335

3,303✔
336
            destination.init(true, keys.size());
6,606✔
337
            size_t n = 0;
6,606✔
338
            // Iterate through BPlusTree and insert all keys
3,303✔
339
            keys.for_all([&](StringData str) {
13,086✔
340
                destination.set(n, str);
13,086✔
341
                n++;
13,086✔
342
            });
13,086✔
343
        }
6,606✔
344
    }
6,606✔
345
}
6,666✔
346

347
class DictionarySize : public Columns<Dictionary> {
348
public:
349
    DictionarySize(const Columns<Dictionary>& other)
350
        : Columns<Dictionary>(other)
351
    {
12✔
352
    }
12✔
353
    void evaluate(size_t index, ValueBase& destination) override
354
    {
1,200✔
355
        Allocator& alloc = this->m_link_map.get_target_table()->get_alloc();
1,200✔
356
        Value<int64_t> list_refs;
1,200✔
357
        this->get_lists(index, list_refs, 1);
1,200✔
358
        destination.init(list_refs.m_from_list, list_refs.size());
1,200✔
359
        for (size_t i = 0; i < list_refs.size(); i++) {
2,400✔
360
            ref_type ref = to_ref(list_refs[i].get_int());
1,200✔
361
            size_t s = _impl::get_collection_size_from_ref(ref, alloc);
1,200✔
362
            destination.set(i, int64_t(s));
1,200✔
363
        }
1,200✔
364
    }
1,200✔
365

366
    std::unique_ptr<Subexpr> clone() const override
367
    {
24✔
368
        return std::unique_ptr<Subexpr>(new DictionarySize(*this));
24✔
369
    }
24✔
370
};
371

372
SizeOperator<int64_t> Columns<Dictionary>::size()
373
{
12✔
374
    std::unique_ptr<Subexpr> ptr(new DictionarySize(*this));
12✔
375
    return SizeOperator<int64_t>(std::move(ptr));
12✔
376
}
12✔
377

378
void Columns<Dictionary>::evaluate(size_t index, ValueBase& destination)
379
{
21,942✔
380
    Collection::QueryCtrlBlock ctrl(m_path, *m_link_map.get_target_table(), !m_path_only_unary_keys);
21,942✔
381

10,971✔
382
    if (links_exist()) {
21,942✔
383
        REALM_ASSERT(!m_leaf);
2,040✔
384
        std::vector<ObjKey> links = m_link_map.get_links(index);
2,040✔
385
        auto sz = links.size();
2,040✔
386
        if (!m_link_map.only_unary_links())
2,040✔
387
            ctrl.from_list = true;
540✔
388

1,020✔
389
        for (size_t t = 0; t < sz; t++) {
8,940✔
390
            const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
6,900✔
391
            auto val = obj.get_any(m_column_key);
6,900✔
392
            if (!val.is_null()) {
6,900✔
393
                Collection::get_any(ctrl, val, 0);
6,900✔
394
            }
6,900✔
395
        }
6,900✔
396
    }
2,040✔
397
    else {
19,902✔
398
        // Not a link column
9,951✔
399
        REALM_ASSERT(m_leaf);
19,902✔
400
        if (ref_type ref = to_ref(m_leaf->get(index))) {
19,902✔
401
            Collection::get_any(ctrl, {ref, CollectionType::Dictionary}, 0);
19,902✔
402
        }
19,902✔
403
    }
19,902✔
404

10,971✔
405
    // Copy values over
10,971✔
406
    auto sz = ctrl.matches.size();
21,942✔
407
    destination.init(ctrl.from_list || sz == 0, sz);
21,942✔
408
    destination.set(ctrl.matches.begin(), ctrl.matches.end());
21,942✔
409
}
21,942✔
410

411

412
void Columns<Link>::evaluate(size_t index, ValueBase& destination)
413
{
2,070✔
414
    // Destination must be of Key type. It only makes sense to
1,035✔
415
    // compare keys with keys
1,035✔
416
    std::vector<ObjKey> links = m_link_map.get_links(index);
2,070✔
417

1,035✔
418
    if (m_link_map.only_unary_links()) {
2,070✔
419
        ObjKey key;
1,242✔
420
        if (!links.empty()) {
1,242✔
421
            key = links[0];
1,038✔
422
        }
1,038✔
423
        destination.init(false, 1);
1,242✔
424
        destination.set(0, key);
1,242✔
425
    }
1,242✔
426
    else {
828✔
427
        destination.init(true, links.size());
828✔
428
        destination.set(links.begin(), links.end());
828✔
429
    }
828✔
430
}
2,070✔
431

432
void ColumnListBase::set_cluster(const Cluster* cluster)
433
{
43,158✔
434
    if (m_link_map.has_links()) {
43,158✔
435
        m_link_map.set_cluster(cluster);
9,600✔
436
    }
9,600✔
437
    else {
33,558✔
438
        m_leaf.emplace(m_link_map.get_base_table()->get_alloc());
33,558✔
439
        cluster->init_leaf(m_column_key, &*m_leaf);
33,558✔
440
    }
33,558✔
441
}
43,158✔
442

443
void ColumnListBase::get_lists(size_t index, Value<int64_t>& destination, size_t nb_elements)
444
{
2,109,201✔
445
    if (m_link_map.has_links()) {
2,109,201✔
446
        std::vector<ObjKey> links = m_link_map.get_links(index);
64,863✔
447
        auto sz = links.size();
64,863✔
448

32,433✔
449
        if (m_link_map.only_unary_links()) {
64,863✔
450
            int64_t val = 0;
64,059✔
451
            if (sz == 1) {
64,059✔
452
                const Obj obj = m_link_map.get_target_table()->get_object(links[0]);
63,909✔
453
                val = obj._get<int64_t>(m_column_key.get_index());
63,909✔
454
            }
63,909✔
455
            destination.init(false, 1);
64,059✔
456
            destination.set(0, val);
64,059✔
457
        }
64,059✔
458
        else {
804✔
459
            destination.init(true, sz);
804✔
460
            for (size_t t = 0; t < sz; t++) {
3,738✔
461
                const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
2,934✔
462
                int64_t val = obj._get<int64_t>(m_column_key.get_index());
2,934✔
463
                destination.set(t, val);
2,934✔
464
            }
2,934✔
465
        }
804✔
466
    }
64,863✔
467
    else {
2,044,338✔
468
        size_t rows = std::min(m_leaf->size() - index, nb_elements);
2,044,338✔
469

1,022,226✔
470
        destination.init(false, rows);
2,044,338✔
471

1,022,226✔
472
        for (size_t t = 0; t < rows; t++) {
4,088,163✔
473
            destination.set(t, m_leaf->get(index + t));
2,043,825✔
474
        }
2,043,825✔
475
    }
2,044,338✔
476
}
2,109,201✔
477

478
void LinkCount::evaluate(size_t index, ValueBase& destination)
479
{
23,028✔
480
    if (m_column_key) {
23,028✔
481
        REALM_ASSERT(m_link_map.has_links());
198✔
482
        std::vector<ObjKey> links = m_link_map.get_links(index);
198✔
483
        auto sz = links.size();
198✔
484

99✔
485
        if (sz == 0) {
198✔
486
            destination.init(true, 0);
36✔
487
        }
36✔
488
        else {
162✔
489
            destination.init(true, sz);
162✔
490
            Allocator& alloc = m_link_map.get_target_table()->get_alloc();
162✔
491
            for (size_t i = 0; i < sz; i++) {
330✔
492
                const Obj obj = m_link_map.get_target_table()->get_object(links[i]);
168✔
493
                auto val = obj._get<int64_t>(m_column_key.get_index());
168✔
494
                size_t s;
168✔
495
                if (m_column_key.get_type() == col_type_Link && !m_column_key.is_collection()) {
168✔
496
                    // It is a single link column
9✔
497
                    s = (val == 0) ? 0 : 1;
18✔
498
                }
18✔
499
                else if (val & 1) {
150✔
500
                    // It is a backlink column with just one value
27✔
501
                    s = 1;
54✔
502
                }
54✔
503
                else {
96✔
504
                    // This is some kind of collection or backlink column
48✔
505
                    s = _impl::get_collection_size_from_ref(to_ref(val), alloc);
96✔
506
                }
96✔
507
                destination.set(i, int64_t(s));
168✔
508
            }
168✔
509
        }
162✔
510
    }
198✔
511
    else {
22,830✔
512
        destination = Value<int64_t>(m_link_map.count_links(index));
22,830✔
513
    }
22,830✔
514
}
23,028✔
515

516
std::string LinkCount::description(util::serializer::SerialisationState& state) const
517
{
240✔
518
    return state.describe_columns(m_link_map, m_column_key) + util::serializer::value_separator + "@count";
240✔
519
}
240✔
520

521
Query Subexpr2<StringData>::equal(StringData sd, bool case_sensitive)
522
{
798✔
523
    return string_compare<StringData, Equal, EqualIns>(*this, sd, case_sensitive);
798✔
524
}
798✔
525

526
Query Subexpr2<StringData>::equal(const Subexpr2<StringData>& col, bool case_sensitive)
527
{
276✔
528
    return string_compare<Equal, EqualIns>(*this, col, case_sensitive);
276✔
529
}
276✔
530

531
Query Subexpr2<StringData>::not_equal(StringData sd, bool case_sensitive)
532
{
762✔
533
    return string_compare<StringData, NotEqual, NotEqualIns>(*this, sd, case_sensitive);
762✔
534
}
762✔
535

536
Query Subexpr2<StringData>::not_equal(const Subexpr2<StringData>& col, bool case_sensitive)
537
{
276✔
538
    return string_compare<NotEqual, NotEqualIns>(*this, col, case_sensitive);
276✔
539
}
276✔
540

541
Query Subexpr2<StringData>::begins_with(StringData sd, bool case_sensitive)
542
{
1,464✔
543
    return string_compare<StringData, BeginsWith, BeginsWithIns>(*this, sd, case_sensitive);
1,464✔
544
}
1,464✔
545

546
Query Subexpr2<StringData>::begins_with(const Subexpr2<StringData>& col, bool case_sensitive)
547
{
576✔
548
    return string_compare<BeginsWith, BeginsWithIns>(*this, col, case_sensitive);
576✔
549
}
576✔
550

551
Query Subexpr2<StringData>::ends_with(StringData sd, bool case_sensitive)
552
{
1,434✔
553
    return string_compare<StringData, EndsWith, EndsWithIns>(*this, sd, case_sensitive);
1,434✔
554
}
1,434✔
555

556
Query Subexpr2<StringData>::ends_with(const Subexpr2<StringData>& col, bool case_sensitive)
557
{
564✔
558
    return string_compare<EndsWith, EndsWithIns>(*this, col, case_sensitive);
564✔
559
}
564✔
560

561
Query Subexpr2<StringData>::contains(StringData sd, bool case_sensitive)
562
{
1,470✔
563
    return string_compare<StringData, Contains, ContainsIns>(*this, sd, case_sensitive);
1,470✔
564
}
1,470✔
565

566
Query Subexpr2<StringData>::contains(const Subexpr2<StringData>& col, bool case_sensitive)
567
{
570✔
568
    return string_compare<Contains, ContainsIns>(*this, col, case_sensitive);
570✔
569
}
570✔
570

571
Query Subexpr2<StringData>::like(StringData sd, bool case_sensitive)
572
{
1,440✔
573
    return string_compare<StringData, Like, LikeIns>(*this, sd, case_sensitive);
1,440✔
574
}
1,440✔
575

576
Query Subexpr2<StringData>::like(const Subexpr2<StringData>& col, bool case_sensitive)
577
{
558✔
578
    return string_compare<Like, LikeIns>(*this, col, case_sensitive);
558✔
579
}
558✔
580

581
Query Columns<StringData>::fulltext(StringData text) const
582
{
12✔
583
    const LinkMap& link_map = get_link_map();
12✔
584
    return link_map.get_base_table()->where().fulltext(column_key(), text, link_map);
12✔
585
}
12✔
586

587

588
// BinaryData
589

590
Query Subexpr2<BinaryData>::equal(BinaryData sd, bool case_sensitive)
591
{
×
592
    return binary_compare<BinaryData, Equal, EqualIns>(*this, sd, case_sensitive);
×
593
}
×
594

595
Query Subexpr2<BinaryData>::equal(const Subexpr2<BinaryData>& col, bool case_sensitive)
596
{
×
597
    return binary_compare<Equal, EqualIns>(*this, col, case_sensitive);
×
598
}
×
599

600
Query Subexpr2<BinaryData>::not_equal(BinaryData sd, bool case_sensitive)
601
{
×
602
    return binary_compare<BinaryData, NotEqual, NotEqualIns>(*this, sd, case_sensitive);
×
603
}
×
604

605
Query Subexpr2<BinaryData>::not_equal(const Subexpr2<BinaryData>& col, bool case_sensitive)
606
{
×
607
    return binary_compare<NotEqual, NotEqualIns>(*this, col, case_sensitive);
×
608
}
×
609

610
Query Subexpr2<BinaryData>::begins_with(BinaryData sd, bool case_sensitive)
611
{
×
612
    return binary_compare<BinaryData, BeginsWith, BeginsWithIns>(*this, sd, case_sensitive);
×
613
}
×
614

615
Query Subexpr2<BinaryData>::begins_with(const Subexpr2<BinaryData>& col, bool case_sensitive)
616
{
×
617
    return binary_compare<BeginsWith, BeginsWithIns>(*this, col, case_sensitive);
×
618
}
×
619

620
Query Subexpr2<BinaryData>::ends_with(BinaryData sd, bool case_sensitive)
621
{
×
622
    return binary_compare<BinaryData, EndsWith, EndsWithIns>(*this, sd, case_sensitive);
×
623
}
×
624

625
Query Subexpr2<BinaryData>::ends_with(const Subexpr2<BinaryData>& col, bool case_sensitive)
626
{
×
627
    return binary_compare<EndsWith, EndsWithIns>(*this, col, case_sensitive);
×
628
}
×
629

630
Query Subexpr2<BinaryData>::contains(BinaryData sd, bool case_sensitive)
631
{
×
632
    return binary_compare<BinaryData, Contains, ContainsIns>(*this, sd, case_sensitive);
×
633
}
×
634

635
Query Subexpr2<BinaryData>::contains(const Subexpr2<BinaryData>& col, bool case_sensitive)
636
{
×
637
    return binary_compare<Contains, ContainsIns>(*this, col, case_sensitive);
×
638
}
×
639

640
Query Subexpr2<BinaryData>::like(BinaryData sd, bool case_sensitive)
641
{
×
642
    return binary_compare<BinaryData, Like, LikeIns>(*this, sd, case_sensitive);
×
643
}
×
644

645
Query Subexpr2<BinaryData>::like(const Subexpr2<BinaryData>& col, bool case_sensitive)
646
{
×
647
    return binary_compare<Like, LikeIns>(*this, col, case_sensitive);
×
648
}
×
649

650
// Mixed
651

652
Query Subexpr2<Mixed>::equal(Mixed sd, bool case_sensitive)
653
{
6✔
654
    return mixed_compare<Mixed, Equal, EqualIns>(*this, sd, case_sensitive);
6✔
655
}
6✔
656

657
Query Subexpr2<Mixed>::equal(const Subexpr2<Mixed>& col, bool case_sensitive)
658
{
×
659
    return mixed_compare<Equal, EqualIns>(*this, col, case_sensitive);
×
660
}
×
661

662
Query Subexpr2<Mixed>::not_equal(Mixed sd, bool case_sensitive)
663
{
×
664
    return mixed_compare<Mixed, NotEqual, NotEqualIns>(*this, sd, case_sensitive);
×
665
}
×
666

667
Query Subexpr2<Mixed>::not_equal(const Subexpr2<Mixed>& col, bool case_sensitive)
668
{
×
669
    return mixed_compare<NotEqual, NotEqualIns>(*this, col, case_sensitive);
×
670
}
×
671

672
Query Subexpr2<Mixed>::begins_with(Mixed sd, bool case_sensitive)
673
{
12✔
674
    return mixed_compare<Mixed, BeginsWith, BeginsWithIns>(*this, sd, case_sensitive);
12✔
675
}
12✔
676

677
Query Subexpr2<Mixed>::begins_with(const Subexpr2<Mixed>& col, bool case_sensitive)
678
{
×
679
    return mixed_compare<BeginsWith, BeginsWithIns>(*this, col, case_sensitive);
×
680
}
×
681

682
Query Subexpr2<Mixed>::ends_with(Mixed sd, bool case_sensitive)
683
{
12✔
684
    return mixed_compare<Mixed, EndsWith, EndsWithIns>(*this, sd, case_sensitive);
12✔
685
}
12✔
686

687
Query Subexpr2<Mixed>::ends_with(const Subexpr2<Mixed>& col, bool case_sensitive)
688
{
×
689
    return mixed_compare<EndsWith, EndsWithIns>(*this, col, case_sensitive);
×
690
}
×
691

692
Query Subexpr2<Mixed>::contains(Mixed sd, bool case_sensitive)
693
{
24✔
694
    return mixed_compare<Mixed, Contains, ContainsIns>(*this, sd, case_sensitive);
24✔
695
}
24✔
696

697
Query Subexpr2<Mixed>::contains(const Subexpr2<Mixed>& col, bool case_sensitive)
698
{
×
699
    return mixed_compare<Contains, ContainsIns>(*this, col, case_sensitive);
×
700
}
×
701

702
Query Subexpr2<Mixed>::like(Mixed sd, bool case_sensitive)
703
{
12✔
704
    return mixed_compare<Mixed, Like, LikeIns>(*this, sd, case_sensitive);
12✔
705
}
12✔
706

707
Query Subexpr2<Mixed>::like(const Subexpr2<Mixed>& col, bool case_sensitive)
708
{
×
709
    return mixed_compare<Like, LikeIns>(*this, col, case_sensitive);
×
710
}
×
711

712
} // 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