• 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

96.04
/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
{
850,677✔
27
    if (table == get_base_table())
850,677✔
28
        return;
39,459✔
29

404,199✔
30
    m_tables.clear();
811,218✔
31
    m_tables.push_back(table);
811,218✔
32
    m_link_types.clear();
811,218✔
33
    m_only_unary_links = true;
811,218✔
34

404,199✔
35
    for (size_t i = 0; i < m_link_column_keys.size(); i++) {
845,796✔
36
        ColKey link_column_key = m_link_column_keys[i];
34,578✔
37
        // Link column can be either LinkList or single Link
16,077✔
38
        ColumnType type = link_column_key.get_type();
34,578✔
39
        REALM_ASSERT(Table::is_link_type(type) || type == col_type_BackLink);
34,578✔
40
        if (type == col_type_LinkList || type == col_type_BackLink ||
34,578✔
41
            (type == col_type_Link && link_column_key.is_collection())) {
28,734✔
42
            m_only_unary_links = false;
12,228✔
43
        }
12,228✔
44

16,077✔
45
        m_link_types.push_back(type);
34,578✔
46
        REALM_ASSERT(table->valid_column(link_column_key));
34,578✔
47
        table = table.unchecked_ptr()->get_opposite_table(link_column_key);
34,578✔
48
        m_tables.push_back(table);
34,578✔
49
    }
34,578✔
50
}
811,218✔
51

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

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

76
bool LinkMap::map_links(size_t column, ObjKey key, LinkMapFunction lm) const
77
{
498,909✔
78
    if (!key || key.is_unresolved())
498,909✔
79
        return true;
7,416✔
80
    if (column == m_link_column_keys.size()) {
491,493✔
81
        return lm(key);
456,813✔
82
    }
456,813✔
83

16,365✔
84
    ColumnType type = m_link_types[column];
34,680✔
85
    ColKey column_key = m_link_column_keys[column];
34,680✔
86
    const Obj obj = m_tables[column]->get_object(key);
34,680✔
87
    if (column_key.is_collection()) {
34,680✔
88
        auto coll = obj.get_linkcollection_ptr(column_key);
2,448✔
89
        size_t sz = coll->size();
2,448✔
90
        for (size_t t = 0; t < sz; t++) {
4,332✔
91
            if (!map_links(column + 1, coll->get_key(t), lm))
3,126✔
92
                return false;
3,126✔
93
        }
3,840✔
94
    }
1,206✔
95
    else if (type == col_type_Link) {
17,079✔
96
        return map_links(column + 1, obj.get<ObjKey>(column_key), lm);
16,032✔
97
    }
14,862✔
98
    else if (type == col_type_BackLink) {
351✔
99
        auto backlinks = obj.get_all_backlinks(column_key);
345✔
100
        for (auto k : backlinks) {
345✔
101
            if (!map_links(column + 1, k, lm))
342✔
NEW
102
                return false;
×
103
        }
342✔
104
    }
345✔
105
    else {
24✔
106
        REALM_TERMINATE("Invalid column type in LinkMap::map_links()");
24✔
107
    }
24✔
108
    return true;
16,383✔
109
}
16,371✔
110

6✔
111
void LinkMap::map_links(size_t column, size_t row, LinkMapFunction lm) const
6✔
112
{
177,888✔
113
    ColumnType type = m_link_types[column];
177,888✔
114
    ColKey column_key = m_link_column_keys[column];
177,888✔
115
    if (type == col_type_Link && !column_key.is_set()) {
177,882✔
116
        if (column_key.is_dictionary()) {
95,001✔
117
            auto& leaf = mpark::get<ArrayInteger>(m_leaf);
474✔
118
            if (leaf.get(row)) {
486✔
119
                Allocator& alloc = get_base_table()->get_alloc();
17,424✔
120
                Array top(alloc);
17,424✔
121
                top.set_parent(const_cast<ArrayInteger*>(&leaf), row);
17,097✔
122
                top.init_from_parent();
17,097✔
123
                BPlusTree<Mixed> values(alloc);
678✔
124
                values.set_parent(&top, 1);
678✔
125
                values.init_from_parent();
675✔
126

675✔
127
                // Iterate through values and insert all link values
351✔
128
                values.for_all([&](Mixed m) {
1,017✔
129
                    if (m.is_type(type_TypedLink)) {
1,020✔
130
                        auto link = m.get_link();
684✔
131
                        REALM_ASSERT(link.get_table_key() == this->m_tables[column + 1]->get_key());
684✔
132
                        if (!map_links(column + 1, link.get_obj_key(), lm))
684✔
133
                            return false;
1,569✔
134
                    }
19,008✔
135
                    return true;
693✔
136
                });
693✔
137
            }
182,964✔
138
        }
183,081✔
139
        else {
260,073✔
140
            REALM_ASSERT(!column_key.is_collection());
260,073✔
141
            map_links(column + 1, mpark::get<ArrayKey>(m_leaf).get(row), lm);
176,448✔
142
        }
78,219✔
143
    }
78,687✔
144
    else if (type == col_type_LinkList || (type == col_type_Link && column_key.is_set())) {
100,416✔
145
        ref_type ref;
98,253✔
146
        if (auto list = mpark::get_if<ArrayList>(&m_leaf)) {
98,253✔
147
            ref = list->get(row);
97,800✔
148
        }
97,800✔
149
        else {
915✔
150
            ref = mpark::get<ArrayKey>(m_leaf).get_as_ref(row);
915✔
151
        }
915✔
152

98,253✔
153
        if (ref) {
98,253✔
154
            BPlusTree<ObjKey> links(get_base_table()->get_alloc());
69,924✔
155
            links.init_from_ref(ref);
69,555✔
156
            size_t sz = links.size();
69,555✔
157
            for (size_t t = 0; t < sz; t++) {
205,857✔
158
                if (!map_links(column + 1, links.get(t), lm))
136,548✔
159
                    break;
246✔
160
            }
136,455✔
161
        }
69,462✔
162
    }
97,884✔
163
    else if (type == col_type_BackLink) {
2,277✔
164
        auto& back_links = mpark::get<ArrayBacklink>(m_leaf);
2,184✔
165
        size_t sz = back_links.get_backlink_count(row);
3,474✔
166
        for (size_t t = 0; t < sz; t++) {
17,034✔
167
            ObjKey k = back_links.get_backlink(row, t);
14,889✔
168
            if (!map_links(column + 1, k, lm))
14,880✔
169
                break;
858✔
170
        }
14,880✔
171
    }
2,184✔
172
    else {
2,147,484,466✔
173
        REALM_ASSERT(false);
2,147,484,475✔
174
    }
2,147,484,109✔
175
}
178,641✔
176

98,229✔
177
std::vector<ObjKey> LinkMap::get_origin_ndxs(ObjKey key, size_t column) const
98,229✔
178
{
107,910✔
179
    if (column == m_link_types.size()) {
107,457✔
180
        return {key};
105,372✔
181
    }
8,049✔
182
    std::vector<ObjKey> keys = get_origin_ndxs(key, column + 1);
2,538✔
183
    std::vector<ObjKey> ret;
2,538✔
184
    auto origin_col = m_link_column_keys[column];
2,085✔
185
    auto origin = m_tables[column];
100,314✔
186
    auto link_type = m_link_types[column];
71,853✔
187
    if (link_type == col_type_BackLink) {
71,853✔
188
        auto link_table = origin->get_opposite_table(origin_col);
70,098✔
189
        ColKey link_col_key = origin->get_opposite_column(origin_col);
70,098✔
190

70,098✔
191
        for (auto k : keys) {
70,098✔
192
            const Obj o = link_table.unchecked_ptr()->get_object(k);
70,098✔
193
            if (link_col_key.is_collection()) {
474✔
194
                auto coll = o.get_linkcollection_ptr(link_col_key);
168✔
195
                auto sz = coll->size();
60✔
196
                for (size_t i = 0; i < sz; i++) {
108✔
197
                    if (ObjKey x = coll->get_key(i))
156✔
198
                        ret.push_back(x);
150✔
199
                }
156✔
200
            }
168✔
201
            else if (link_col_key.get_type() == col_type_Link) {
207,810✔
202
                ret.push_back(o.get<ObjKey>(link_col_key));
138,195✔
203
            }
459✔
204
        }
138,219✔
205
    }
70,098✔
206
    else {
99,984✔
207
        auto target = m_tables[column + 1];
100,743✔
208
        for (auto k : keys) {
85,437✔
209
            const Obj o = target->get_object(k);
83,253✔
210
            auto cnt = o.get_backlink_count(*origin, origin_col);
83,253✔
211
            for (size_t i = 0; i < cnt; i++) {
6,153✔
212
                ret.push_back(o.get_backlink(*origin, origin_col, i));
4,341✔
213
            }
4,341✔
214
        }
18,018✔
215
    }
15,816✔
216
    return ret;
16,146✔
217
}
2,124✔
218

14,061✔
219
ColumnDictionaryKey Columns<Dictionary>::key(const Mixed& key_value)
2,184✔
220
{
381✔
221
    if (m_key_type != type_Mixed && key_value.get_type() != m_key_type) {
381✔
UNCOV
222
        throw InvalidArgument(ErrorCodes::TypeMismatch, util::format("Key not a %1", m_key_type));
×
223
    }
182,613✔
224

381✔
225
    return ColumnDictionaryKey(key_value, *this);
381✔
226
}
10,032✔
227

9,651✔
228
ColumnDictionaryKeys Columns<Dictionary>::keys()
7,581✔
229
{
7,587✔
230
    return ColumnDictionaryKeys(*this);
2,076✔
231
}
2,076✔
232

2,070✔
233
void ColumnDictionaryKey::init_key(Mixed key_value)
2,070✔
234
{
2,916✔
235
    REALM_ASSERT(!key_value.is_null());
2,916✔
236

1,176✔
237
    m_key = key_value;
1,176✔
238
    m_key.use_buffer(m_buffer);
846✔
239
}
1,176✔
240

330✔
241
void ColumnDictionaryKeys::set_cluster(const Cluster* cluster)
330✔
242
{
63✔
243
    if (m_link_map.has_links()) {
63✔
244
        m_link_map.set_cluster(cluster);
75✔
245
    }
51✔
246
    else {
78✔
247
        m_leaf.emplace(m_link_map.get_base_table()->get_alloc());
84✔
248
        cluster->init_leaf(m_column_key, &*m_leaf);
60✔
249
    }
342✔
250
}
345✔
251

306✔
252

330✔
253
void ColumnDictionaryKeys::evaluate(size_t index, ValueBase& destination)
330✔
254
{
5,073✔
255
    if (m_link_map.has_links()) {
5,073✔
256
        REALM_ASSERT(!m_leaf);
1,827✔
257
        std::vector<ObjKey> links = m_link_map.get_links(index);
1,827✔
258
        auto sz = links.size();
1,827✔
259

3,975✔
260
        // Here we don't really know how many values to expect
2,178✔
261
        std::vector<Mixed> values;
2,178✔
262
        for (size_t t = 0; t < sz; t++) {
1,857✔
263
            const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
1,770✔
264
            auto dict = obj.get_dictionary(m_column_key);
2,100✔
265
            // Insert all values
2,100✔
266
            dict.for_all_keys<StringData>([&values](const Mixed& value) {
75✔
267
                values.emplace_back(value);
75✔
268
            });
81✔
269
        }
36✔
270

36✔
271
        // Copy values over
30✔
272
        destination.init(true, values.size());
30✔
273
        destination.set(values.begin(), values.end());
471✔
274
    }
471✔
275
    else {
3,744✔
276
        // Not a link column
4,212✔
277
        Allocator& alloc = get_base_table()->get_alloc();
3,771✔
278

3,330✔
279
        REALM_ASSERT(m_leaf);
3,330✔
280
        if (m_leaf->get(index)) {
3,771✔
281
            Array top(alloc);
3,771✔
282
            top.set_parent(&*m_leaf, index);
3,771✔
283
            top.init_from_parent();
3,744✔
284
            BPlusTree<StringData> keys(alloc);
3,744✔
285
            keys.set_parent(&top, 0);
3,303✔
286
            keys.init_from_parent();
3,303✔
287

3,303✔
288
            destination.init(true, keys.size());
3,744✔
289
            size_t n = 0;
3,303✔
290
            // Iterate through BPlusTree and insert all keys
3,303✔
291
            keys.for_all([&](StringData str) {
6,546✔
292
                destination.set(n, str);
6,546✔
293
                n++;
6,510✔
294
            });
6,510✔
295
        }
3,339✔
296
    }
3,339✔
297
}
3,369✔
298

36✔
299
void ColumnDictionaryKey::evaluate(size_t index, ValueBase& destination)
39✔
300
{
5,088✔
301
    if (links_exist()) {
5,088✔
302
        REALM_ASSERT(!m_leaf);
270✔
303
        std::vector<ObjKey> links = m_link_map.get_links(index);
3,603✔
304
        auto sz = links.size();
3,603✔
305

300✔
306
        destination.init_for_links(m_link_map.only_unary_links(), sz);
300✔
307
        for (size_t t = 0; t < sz; t++) {
2,190✔
308
            const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
1,890✔
309
            auto dict = obj.get_dictionary(m_column_key);
1,890✔
310
            Mixed val;
1,920✔
311
            if (auto opt_val = dict.try_get(m_key)) {
1,950✔
312
                val = *opt_val;
1,602✔
313
                if (m_prop_list.size()) {
1,602✔
314
                    if (val.is_type(type_TypedLink)) {
315
                        auto obj = get_base_table()->get_parent_group()->get_object(val.get<ObjLink>());
75✔
316
                        val = obj.get_any(m_prop_list.begin(), m_prop_list.end());
75✔
317
                    }
75✔
318
                    else {
30✔
319
                        val = {};
320
                    }
321
                }
30✔
322
            }
1,602✔
323
            destination.set(t, val);
1,920✔
324
        }
5,193✔
325
    }
270✔
326
    else {
8,121✔
327
        // Not a link column
4,818✔
328
        Allocator& alloc = get_base_table()->get_alloc();
8,121✔
329

8,121✔
330
        REALM_ASSERT(m_leaf);
8,121✔
331
        if (m_leaf->get(index)) {
8,121✔
332
            Array top(alloc);
8,121✔
333
            top.set_parent(&*m_leaf, index);
8,121✔
334
            top.init_from_parent();
8,121✔
335
            BPlusTree<StringData> keys(alloc);
8,121✔
336
            keys.set_parent(&top, 0);
4,818✔
337
            keys.init_from_parent();
8,121✔
338

8,121✔
339
            Mixed val;
4,818✔
340
            size_t ndx = keys.find_first(m_key.get_string());
11,361✔
341
            if (ndx != realm::npos) {
11,361✔
342
                BPlusTree<Mixed> values(alloc);
9,918✔
343
                values.set_parent(&top, 1);
9,918✔
344
                values.init_from_parent();
6,678✔
345
                val = values.get(ndx);
6,678✔
346
                if (m_prop_list.size()) {
6,708✔
347
                    if (val.is_type(type_TypedLink)) {
18✔
348
                        auto obj = get_base_table()->get_parent_group()->get_object(val.get<ObjLink>());
18✔
349
                        val = obj.get_any(m_prop_list.begin(), m_prop_list.end());
18✔
350
                    }
18✔
351
                    else {
352
                        val = {};
6✔
353
                    }
6✔
354
                }
18✔
355
            }
3,975✔
356
            destination.set(0, val);
5,418✔
357
        }
5,418✔
358
    }
5,418✔
359
}
5,688✔
360

1,200✔
361
class DictionarySize : public Columns<Dictionary> {
600✔
362
public:
600✔
363
    DictionarySize(const Columns<Dictionary>& other)
600✔
364
        : Columns<Dictionary>(other)
600✔
365
    {
606✔
366
    }
6✔
367
    void evaluate(size_t index, ValueBase& destination) override
368
    {
612✔
369
        Allocator& alloc = this->m_link_map.get_target_table()->get_alloc();
612✔
370
        Value<int64_t> list_refs;
612✔
371
        this->get_lists(index, list_refs, 1);
600✔
372
        destination.init(list_refs.m_from_list, list_refs.size());
600✔
373
        for (size_t i = 0; i < list_refs.size(); i++) {
1,200✔
374
            ref_type ref = to_ref(list_refs[i].get_int());
606✔
375
            size_t s = _impl::get_collection_size_from_ref(ref, alloc);
606✔
376
            destination.set(i, int64_t(s));
606✔
377
        }
606✔
378
    }
600✔
379

380
    std::unique_ptr<Subexpr> clone() const override
10,371✔
381
    {
10,383✔
382
        return std::unique_ptr<Subexpr>(new DictionarySize(*this));
12✔
383
    }
10,383✔
384
};
420✔
385

420✔
386
SizeOperator<int64_t> Columns<Dictionary>::size()
420✔
387
{
426✔
388
    std::unique_ptr<Subexpr> ptr(new DictionarySize(*this));
276✔
389
    return SizeOperator<int64_t>(std::move(ptr));
6✔
390
}
3,276✔
391

2,850✔
392
void Columns<Dictionary>::evaluate(size_t index, ValueBase& destination)
2,850✔
393
{
6,243✔
394
    if (links_exist()) {
6,243✔
395
        REALM_ASSERT(!m_leaf);
2,940✔
396
        std::vector<ObjKey> links = m_link_map.get_links(index);
2,940✔
397
        auto sz = links.size();
510✔
398

10,041✔
399
        // Here we don't really know how many values to expect
90✔
400
        std::vector<Mixed> values;
10,041✔
401
        for (size_t t = 0; t < sz; t++) {
10,941✔
402
            const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
10,851✔
403
            auto dict = obj.get_dictionary(m_column_key);
10,851✔
404
            // Insert all values
10,851✔
405
            dict.for_all_values([&values](const Mixed& value) {
1,776✔
406
                values.emplace_back(value);
1,776✔
407
            });
12,147✔
408
        }
11,271✔
409

10,461✔
410
        // Copy values over
10,461✔
411
        destination.init(true, values.size());
90✔
412
        destination.set(values.begin(), values.end());
90✔
413
    }
90✔
414
    else {
4,611✔
415
        // Not a link column
3,303✔
416
        Allocator& alloc = get_base_table()->get_alloc();
3,303✔
417

4,611✔
418
        REALM_ASSERT(m_leaf);
3,303✔
419
        if (m_leaf->get(index)) {
4,611✔
420
            Array top(alloc);
4,197✔
421
            top.set_parent(&*m_leaf, index);
4,197✔
422
            top.init_from_parent();
4,092✔
423
            BPlusTree<Mixed> values(alloc);
4,092✔
424
            values.set_parent(&top, 1);
4,197✔
425
            values.init_from_parent();
4,197✔
426

4,197✔
427
            destination.init(true, values.size());
3,717✔
428
            size_t n = 0;
3,717✔
429
            // Iterate through BPlusTreee and insert all values
3,717✔
430
            values.for_all([&](Mixed val) {
6,927✔
431
                destination.set(n, val);
7,821✔
432
                n++;
6,513✔
433
            });
6,513✔
434
        }
23,883✔
435
    }
23,883✔
436
}
8,190✔
437

4,797✔
438

15,783✔
439
void Columns<Link>::evaluate(size_t index, ValueBase& destination)
15,783✔
440
{
17,091✔
441
    // Destination must be of Key type. It only makes sense to
17,091✔
442
    // compare keys with keys
21,888✔
443
    std::vector<ObjKey> links = m_link_map.get_links(index);
1,308✔
444

1,308✔
445
    if (m_link_map.only_unary_links()) {
1,015,089✔
446
        ObjKey key;
1,014,675✔
447
        if (!links.empty()) {
33,330✔
448
            key = links[0];
33,225✔
449
        }
789✔
450
        destination.init(false, 1);
33,330✔
451
        destination.set(0, key);
32,928✔
452
    }
32,928✔
453
    else {
32,373✔
454
        destination.init(true, links.size());
32,373✔
455
        destination.set(links.begin(), links.end());
32,373✔
456
    }
32,448✔
457
}
33,342✔
458

32,034✔
459
void ColumnListBase::set_cluster(const Cluster* cluster)
402✔
460
{
19,752✔
461
    if (m_link_map.has_links()) {
21,219✔
462
        m_link_map.set_cluster(cluster);
5,478✔
463
    }
5,478✔
464
    else {
16,806✔
465
        m_leaf.emplace(m_link_map.get_base_table()->get_alloc());
16,806✔
466
        cluster->init_leaf(m_column_key, &*m_leaf);
15,741✔
467
    }
47,775✔
468
}
1,000,695✔
469

981,345✔
470
void ColumnListBase::get_lists(size_t index, Value<int64_t>& destination, size_t nb_elements)
471
{
1,988,883✔
472
    if (m_link_map.has_links()) {
1,007,538✔
473
        std::vector<ObjKey> links = m_link_map.get_links(index);
1,991,166✔
474
        auto sz = links.size();
1,009,821✔
475

1,009,821✔
476
        if (m_link_map.only_unary_links()) {
1,009,845✔
477
            int64_t val = 0;
1,041,975✔
478
            if (sz == 1) {
28,194✔
479
                const Obj obj = m_link_map.get_target_table()->get_object(links[0]);
28,119✔
480
                val = obj._get<int64_t>(m_column_key.get_index());
39,633✔
481
            }
39,633✔
482
            destination.init(false, 1);
28,293✔
483
            destination.set(0, val);
28,293✔
484
        }
28,293✔
485
        else {
306✔
486
            destination.init(true, sz);
405✔
487
            for (size_t t = 0; t < sz; t++) {
1,755✔
488
                const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
1,449✔
489
                int64_t val = obj._get<int64_t>(m_column_key.get_index());
1,512✔
490
                destination.set(t, val);
1,512✔
491
            }
1,512✔
492
        }
471✔
493
    }
28,584✔
494
    else {
979,122✔
495
        size_t rows = std::min(m_leaf->size() - index, nb_elements);
979,122✔
496

979,122✔
497
        destination.init(false, rows);
979,038✔
498

979,047✔
499
        for (size_t t = 0; t < rows; t++) {
1,957,137✔
500
            destination.set(t, m_leaf->get(index + t));
978,165✔
501
        }
978,090✔
502
    }
979,065✔
503
}
1,007,565✔
504

48✔
505
void LinkCount::evaluate(size_t index, ValueBase& destination)
506
{
11,466✔
507
    if (m_column_key) {
11,466✔
508
        REALM_ASSERT(m_link_map.has_links());
183✔
509
        std::vector<ObjKey> links = m_link_map.get_links(index);
183✔
510
        auto sz = links.size();
180✔
511

198✔
512
        if (sz == 0) {
11,514✔
513
            destination.init(true, 0);
11,433✔
514
        }
11,433✔
515
        else {
11,595✔
516
            destination.init(true, sz);
81✔
517
            Allocator& alloc = m_link_map.get_target_table()->get_alloc();
81✔
518
            for (size_t i = 0; i < sz; i++) {
285✔
519
                const Obj obj = m_link_map.get_target_table()->get_object(links[i]);
204✔
520
                auto val = obj._get<int64_t>(m_column_key.get_index());
204✔
521
                size_t s;
84✔
522
                if (m_column_key.get_type() == col_type_Link && !m_column_key.is_collection()) {
84✔
523
                    // It is a single link column
408✔
524
                    s = (val == 0) ? 0 : 1;
408✔
525
                }
408✔
526
                else if (val & 1) {
75✔
527
                    // It is a backlink column with just one value
27✔
528
                    s = 1;
165✔
529
                }
165✔
530
                else {
186✔
531
                    // This is some kind of collection or backlink column
48✔
532
                    s = _impl::get_collection_size_from_ref(to_ref(val), alloc);
48✔
533
                }
429✔
534
                destination.set(i, int64_t(s));
465✔
535
            }
465✔
536
        }
81✔
537
    }
99✔
538
    else {
11,457✔
539
        destination = Value<int64_t>(m_link_map.count_links(index));
11,457✔
540
    }
11,457✔
541
}
11,418✔
542

543
std::string LinkCount::description(util::serializer::SerialisationState& state) const
732✔
544
{
846✔
545
    return state.describe_columns(m_link_map, m_column_key) + util::serializer::value_separator + "@count";
846✔
546
}
114✔
547

548
Query Subexpr2<StringData>::equal(StringData sd, bool case_sensitive)
288✔
549
{
687✔
550
    return string_compare<StringData, Equal, EqualIns>(*this, sd, case_sensitive);
687✔
551
}
399✔
552

553
Query Subexpr2<StringData>::equal(const Subexpr2<StringData>& col, bool case_sensitive)
717✔
554
{
855✔
555
    return string_compare<Equal, EqualIns>(*this, col, case_sensitive);
855✔
556
}
138✔
557

558
Query Subexpr2<StringData>::not_equal(StringData sd, bool case_sensitive)
282✔
559
{
663✔
560
    return string_compare<StringData, NotEqual, NotEqualIns>(*this, sd, case_sensitive);
663✔
561
}
381✔
562

563
Query Subexpr2<StringData>::not_equal(const Subexpr2<StringData>& col, bool case_sensitive)
735✔
564
{
873✔
565
    return string_compare<NotEqual, NotEqualIns>(*this, col, case_sensitive);
873✔
566
}
138✔
567

568
Query Subexpr2<StringData>::begins_with(StringData sd, bool case_sensitive)
285✔
569
{
1,017✔
570
    return string_compare<StringData, BeginsWith, BeginsWithIns>(*this, sd, case_sensitive);
1,017✔
571
}
732✔
572

573
Query Subexpr2<StringData>::begins_with(const Subexpr2<StringData>& col, bool case_sensitive)
720✔
574
{
1,008✔
575
    return string_compare<BeginsWith, BeginsWithIns>(*this, col, case_sensitive);
1,008✔
576
}
288✔
577

578
Query Subexpr2<StringData>::ends_with(StringData sd, bool case_sensitive)
279✔
579
{
996✔
580
    return string_compare<StringData, EndsWith, EndsWithIns>(*this, sd, case_sensitive);
996✔
581
}
717✔
582

583
Query Subexpr2<StringData>::ends_with(const Subexpr2<StringData>& col, bool case_sensitive)
6✔
584
{
288✔
585
    return string_compare<EndsWith, EndsWithIns>(*this, col, case_sensitive);
288✔
586
}
288✔
587

588
Query Subexpr2<StringData>::contains(StringData sd, bool case_sensitive)
589
{
735✔
590
    return string_compare<StringData, Contains, ContainsIns>(*this, sd, case_sensitive);
735✔
591
}
735✔
592

593
Query Subexpr2<StringData>::contains(const Subexpr2<StringData>& col, bool case_sensitive)
594
{
285✔
595
    return string_compare<Contains, ContainsIns>(*this, col, case_sensitive);
285✔
596
}
285✔
597

598
Query Subexpr2<StringData>::like(StringData sd, bool case_sensitive)
599
{
720✔
600
    return string_compare<StringData, Like, LikeIns>(*this, sd, case_sensitive);
720✔
601
}
720✔
602

603
Query Subexpr2<StringData>::like(const Subexpr2<StringData>& col, bool case_sensitive)
604
{
279✔
605
    return string_compare<Like, LikeIns>(*this, col, case_sensitive);
279✔
606
}
279✔
607

608
Query Columns<StringData>::fulltext(StringData text) const
609
{
6✔
610
    const LinkMap& link_map = get_link_map();
6✔
611
    return link_map.get_base_table()->where().fulltext(column_key(), text, link_map);
6✔
612
}
6✔
613

614

615
// BinaryData
616

617
Query Subexpr2<BinaryData>::equal(BinaryData sd, bool case_sensitive)
618
{
×
619
    return binary_compare<BinaryData, Equal, EqualIns>(*this, sd, case_sensitive);
×
620
}
621

622
Query Subexpr2<BinaryData>::equal(const Subexpr2<BinaryData>& col, bool case_sensitive)
623
{
×
624
    return binary_compare<Equal, EqualIns>(*this, col, case_sensitive);
×
625
}
626

627
Query Subexpr2<BinaryData>::not_equal(BinaryData sd, bool case_sensitive)
628
{
×
629
    return binary_compare<BinaryData, NotEqual, NotEqualIns>(*this, sd, case_sensitive);
×
630
}
631

632
Query Subexpr2<BinaryData>::not_equal(const Subexpr2<BinaryData>& col, bool case_sensitive)
633
{
×
634
    return binary_compare<NotEqual, NotEqualIns>(*this, col, case_sensitive);
×
635
}
636

637
Query Subexpr2<BinaryData>::begins_with(BinaryData sd, bool case_sensitive)
638
{
×
639
    return binary_compare<BinaryData, BeginsWith, BeginsWithIns>(*this, sd, case_sensitive);
×
640
}
641

642
Query Subexpr2<BinaryData>::begins_with(const Subexpr2<BinaryData>& col, bool case_sensitive)
643
{
×
644
    return binary_compare<BeginsWith, BeginsWithIns>(*this, col, case_sensitive);
×
645
}
646

647
Query Subexpr2<BinaryData>::ends_with(BinaryData sd, bool case_sensitive)
648
{
×
649
    return binary_compare<BinaryData, EndsWith, EndsWithIns>(*this, sd, case_sensitive);
×
650
}
651

652
Query Subexpr2<BinaryData>::ends_with(const Subexpr2<BinaryData>& col, bool case_sensitive)
653
{
654
    return binary_compare<EndsWith, EndsWithIns>(*this, col, case_sensitive);
3✔
655
}
3✔
656

3✔
657
Query Subexpr2<BinaryData>::contains(BinaryData sd, bool case_sensitive)
658
{
659
    return binary_compare<BinaryData, Contains, ContainsIns>(*this, sd, case_sensitive);
×
660
}
×
661

662
Query Subexpr2<BinaryData>::contains(const Subexpr2<BinaryData>& col, bool case_sensitive)
663
{
664
    return binary_compare<Contains, ContainsIns>(*this, col, case_sensitive);
×
665
}
×
666

667
Query Subexpr2<BinaryData>::like(BinaryData sd, bool case_sensitive)
668
{
669
    return binary_compare<BinaryData, Like, LikeIns>(*this, sd, case_sensitive);
×
670
}
×
671

672
Query Subexpr2<BinaryData>::like(const Subexpr2<BinaryData>& col, bool case_sensitive)
673
{
674
    return binary_compare<Like, LikeIns>(*this, col, case_sensitive);
6✔
675
}
6✔
676

6✔
677
// Mixed
678

679
Query Subexpr2<Mixed>::equal(Mixed sd, bool case_sensitive)
680
{
3✔
681
    return mixed_compare<Mixed, Equal, EqualIns>(*this, sd, case_sensitive);
3✔
682
}
3✔
683

684
Query Subexpr2<Mixed>::equal(const Subexpr2<Mixed>& col, bool case_sensitive)
6✔
685
{
6✔
686
    return mixed_compare<Equal, EqualIns>(*this, col, case_sensitive);
6✔
687
}
688

689
Query Subexpr2<Mixed>::not_equal(Mixed sd, bool case_sensitive)
690
{
×
691
    return mixed_compare<Mixed, NotEqual, NotEqualIns>(*this, sd, case_sensitive);
×
692
}
693

694
Query Subexpr2<Mixed>::not_equal(const Subexpr2<Mixed>& col, bool case_sensitive)
12✔
695
{
12✔
696
    return mixed_compare<NotEqual, NotEqualIns>(*this, col, case_sensitive);
12✔
697
}
698

699
Query Subexpr2<Mixed>::begins_with(Mixed sd, bool case_sensitive)
700
{
6✔
701
    return mixed_compare<Mixed, BeginsWith, BeginsWithIns>(*this, sd, case_sensitive);
6✔
702
}
6✔
703

704
Query Subexpr2<Mixed>::begins_with(const Subexpr2<Mixed>& col, bool case_sensitive)
6✔
705
{
6✔
706
    return mixed_compare<BeginsWith, BeginsWithIns>(*this, col, case_sensitive);
6✔
707
}
708

709
Query Subexpr2<Mixed>::ends_with(Mixed sd, bool case_sensitive)
710
{
6✔
711
    return mixed_compare<Mixed, EndsWith, EndsWithIns>(*this, sd, case_sensitive);
6✔
712
}
6✔
713

714
Query Subexpr2<Mixed>::ends_with(const Subexpr2<Mixed>& col, bool case_sensitive)
715
{
716
    return mixed_compare<EndsWith, EndsWithIns>(*this, col, case_sensitive);
717
}
718

719
Query Subexpr2<Mixed>::contains(Mixed sd, bool case_sensitive)
720
{
6✔
721
    return mixed_compare<Mixed, Contains, ContainsIns>(*this, sd, case_sensitive);
6✔
722
}
6✔
723

724
Query Subexpr2<Mixed>::contains(const Subexpr2<Mixed>& col, bool case_sensitive)
725
{
726
    return mixed_compare<Contains, ContainsIns>(*this, col, case_sensitive);
727
}
728

729
Query Subexpr2<Mixed>::like(Mixed sd, bool case_sensitive)
730
{
6✔
731
    return mixed_compare<Mixed, Like, LikeIns>(*this, sd, case_sensitive);
6✔
732
}
6✔
733

734
Query Subexpr2<Mixed>::like(const Subexpr2<Mixed>& col, bool case_sensitive)
735
{
736
    return mixed_compare<Like, LikeIns>(*this, col, case_sensitive);
737
}
738

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