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

realm / realm-core / nicola.cabiddu_1042

27 Sep 2023 06:04PM UTC coverage: 91.085% (-1.8%) from 92.915%
nicola.cabiddu_1042

Pull #6766

Evergreen

nicola-cab
Fix logic for dictionaries
Pull Request #6766: Client Reset for collections in mixed / nested collections

97276 of 178892 branches covered (0.0%)

1994 of 2029 new or added lines in 7 files covered. (98.28%)

4556 existing lines in 112 files now uncovered.

237059 of 260260 relevant lines covered (91.09%)

6321099.55 hits per line

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

88.12
/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
{
854,733✔
27
    if (table == get_base_table())
854,733✔
28
        return;
40,701✔
29

407,019✔
30
    m_tables.clear();
814,032✔
31
    m_tables.push_back(table);
814,032✔
32
    m_link_types.clear();
814,032✔
33
    m_only_unary_links = true;
814,032✔
34

407,019✔
35
    for (size_t i = 0; i < m_link_column_keys.size(); i++) {
851,034✔
36
        ColKey link_column_key = m_link_column_keys[i];
37,002✔
37
        // Link column can be either LinkList or single Link
18,501✔
38
        ColumnType type = link_column_key.get_type();
37,002✔
39
        REALM_ASSERT(Table::is_link_type(type) || type == col_type_BackLink);
37,002✔
40
        if (type == col_type_LinkList || type == col_type_BackLink ||
37,002✔
41
            (type == col_type_Link && link_column_key.is_collection())) {
31,158✔
42
            m_only_unary_links = false;
12,366✔
43
        }
12,366✔
44

18,501✔
45
        m_link_types.push_back(type);
37,002✔
46
        REALM_ASSERT(table->valid_column(link_column_key));
37,002✔
47
        table = table.unchecked_ptr()->get_opposite_table(link_column_key);
37,002✔
48
        m_tables.push_back(table);
37,002✔
49
    }
37,002✔
50
}
814,032✔
51

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

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

76
bool LinkMap::map_links(size_t column, ObjKey key, LinkMapFunction lm) const
77
{
506,313✔
78
    if (!key || key.is_unresolved())
506,313✔
79
        return true;
7,428✔
80
    if (column == m_link_column_keys.size()) {
498,885✔
81
        return lm(key);
462,222✔
82
    }
462,222✔
83

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

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

98,223✔
185
            if (ref) {
196,452✔
186
                BPlusTree<ObjKey> links(get_base_table()->get_alloc());
139,527✔
187
                links.init_from_ref(ref);
139,527✔
188
                size_t sz = links.size();
139,527✔
189
                size_t start = 0;
139,527✔
190
                size_t end = sz;
139,527✔
191
                auto& pe = m_link_column_keys[column].get_index();
139,527✔
192
                if (pe.is_ndx()) {
139,527✔
193
                    start = pe.get_ndx();
288✔
194
                    if (start == realm::npos) {
288✔
195
                        start = sz - 1;
72✔
196
                    }
72✔
197
                    else if (start < sz) {
216✔
198
                        end = start + 1;
216✔
199
                    }
216✔
200
                }
288✔
201
                for (size_t t = start; t < end; t++) {
414,942✔
202
                    if (!map_links(column + 1, links.get(t), lm))
275,721✔
203
                        break;
306✔
204
                }
275,721✔
205
            }
139,527✔
206
        }
196,452✔
207
    }
197,970✔
208
    else if (type == col_type_Link) {
167,241✔
209
        map_links(column + 1, mpark::get<ArrayKey>(m_leaf).get(row), lm);
162,882✔
210
    }
162,882✔
211
    else if (type == col_type_BackLink) {
4,368✔
212
        auto& back_links = mpark::get<ArrayBacklink>(m_leaf);
4,368✔
213
        size_t sz = back_links.get_backlink_count(row);
4,368✔
214
        for (size_t t = 0; t < sz; t++) {
32,412✔
215
            ObjKey k = back_links.get_backlink(row, t);
28,122✔
216
            if (!map_links(column + 1, k, lm))
28,122✔
217
                break;
78✔
218
        }
28,122✔
219
    }
4,368✔
220
    else {
2,147,483,647✔
221
        REALM_TERMINATE("Invalid column type in LinkMap::map_links()");
2,147,483,647✔
222
    }
2,147,483,647✔
223
}
365,211✔
224

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

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

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

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

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

301

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

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

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

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

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

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

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

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

379
void Columns<Dictionary>::evaluate(size_t index, ValueBase& destination)
380
{
20,742✔
381
    Collection::QueryCtrlBlock ctrl(m_path, *get_base_table(), !m_path_only_unary_keys);
20,742✔
382

10,371✔
383
    if (links_exist()) {
20,742✔
384
        REALM_ASSERT(!m_leaf);
840✔
385
        std::vector<ObjKey> links = m_link_map.get_links(index);
840✔
386
        auto sz = links.size();
840✔
387
        if (!m_link_map.only_unary_links())
840✔
388
            ctrl.from_list = true;
540✔
389

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

10,371✔
406
    // Copy values over
10,371✔
407
    auto sz = ctrl.matches.size();
20,742✔
408
    destination.init(ctrl.from_list || sz == 0, sz);
20,742✔
409
    destination.set(ctrl.matches.begin(), ctrl.matches.end());
20,742✔
410
}
20,742✔
411

412

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

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

433
void ColumnListBase::set_cluster(const Cluster* cluster)
434
{
41,157✔
435
    if (m_link_map.has_links()) {
41,157✔
436
        m_link_map.set_cluster(cluster);
9,594✔
437
    }
9,594✔
438
    else {
31,563✔
439
        m_leaf.emplace(m_link_map.get_base_table()->get_alloc());
31,563✔
440
        cluster->init_leaf(m_column_key, &*m_leaf);
31,563✔
441
    }
31,563✔
442
}
41,157✔
443

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

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

981,174✔
471
        destination.init(false, rows);
1,961,241✔
472

981,174✔
473
        for (size_t t = 0; t < rows; t++) {
3,919,653✔
474
            destination.set(t, m_leaf->get(index + t));
1,958,412✔
475
        }
1,958,412✔
476
    }
1,961,241✔
477
}
2,026,113✔
478

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

588

589
// BinaryData
590

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

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

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

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

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

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

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

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

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

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

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

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

651
// Mixed
652

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

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

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

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

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

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

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

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

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

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

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

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

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

© 2025 Coveralls, Inc