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

realm / realm-core / jorgen.edelbo_402

21 Aug 2024 11:10AM UTC coverage: 91.054% (-0.03%) from 91.085%
jorgen.edelbo_402

Pull #7803

Evergreen

jedelbo
Small fix to Table::typed_write

When writing the realm to a new file from a write transaction,
the Table may be COW so that the top ref is changed. So don't
use the ref that is present in the group when the operation starts.
Pull Request #7803: Feature/string compression

103494 of 181580 branches covered (57.0%)

1929 of 1999 new or added lines in 46 files covered. (96.5%)

695 existing lines in 51 files now uncovered.

220142 of 241772 relevant lines covered (91.05%)

7344461.76 hits per line

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

86.62
/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
{
866,544✔
27
    if (table == get_base_table())
866,544✔
28
        return;
43,506✔
29

30
    m_tables.clear();
823,038✔
31
    m_tables.push_back(table);
823,038✔
32
    m_link_types.clear();
823,038✔
33
    m_only_unary_links = true;
823,038✔
34

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

44
        m_link_types.push_back(type);
37,368✔
45
        REALM_ASSERT(table->valid_column(link_column_key));
37,368✔
46
        table = table.unchecked_ptr()->get_opposite_table(link_column_key);
37,368✔
47
        m_tables.push_back(table);
37,368✔
48
    }
37,368✔
49
}
823,038✔
50

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

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

75
bool LinkMap::map_links(size_t column, ObjKey key, LinkMapFunction lm) const
76
{
509,475✔
77
    if (!key || key.is_unresolved())
509,475✔
78
        return true;
7,446✔
79
    if (column == m_link_column_keys.size()) {
502,029✔
80
        return lm(key);
465,405✔
81
    }
465,405✔
82

83
    ColumnType type = m_link_types[column];
36,624✔
84
    ColKey column_key = m_link_column_keys[column];
36,624✔
85
    const Obj obj = m_tables[column]->get_object(key);
36,624✔
86
    if (column_key.is_collection()) {
36,624✔
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
                }
12✔
116
            }
12✔
117
        }
36✔
118
    }
2,484✔
119
    else if (type == col_type_Link) {
34,140✔
120
        return map_links(column + 1, obj.get<ObjKey>(column_key), lm);
33,492✔
121
    }
33,492✔
122
    else if (type == col_type_BackLink) {
654✔
123
        auto backlinks = obj.get_all_backlinks(column_key);
654✔
124
        for (auto k : backlinks) {
654✔
125
            if (!map_links(column + 1, k, lm))
648✔
126
                return false;
×
127
        }
648✔
128
    }
654✔
129
    else {
2,147,483,647✔
130
        REALM_TERMINATE("Invalid column type in LinkMap::map_links()");
131
    }
2,147,483,647✔
132
    return true;
3,132✔
133
}
36,624✔
134

135
void LinkMap::map_links(size_t column, size_t row, LinkMapFunction lm) const
136
{
366,858✔
137
    ColumnType type = m_link_types[column];
366,858✔
138
    ColKey column_key = m_link_column_keys[column];
366,858✔
139
    if (column_key.is_collection()) {
366,858✔
140
        if (column_key.is_dictionary()) {
198,324✔
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
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,806✔
176
            ref_type ref;
196,806✔
177
            if (auto list = mpark::get_if<ArrayList>(&m_leaf)) {
196,806✔
178
                ref = list->get(row);
195,900✔
179
            }
195,900✔
180
            else {
906✔
181
                ref = mpark::get<ArrayKey>(m_leaf).get_as_ref(row);
906✔
182
            }
906✔
183

184
            if (ref) {
196,806✔
185
                BPlusTree<ObjKey> links(get_base_table()->get_alloc());
139,884✔
186
                links.init_from_ref(ref);
139,884✔
187
                size_t sz = links.size();
139,884✔
188
                size_t start = 0;
139,884✔
189
                size_t end = sz;
139,884✔
190
                auto& pe = m_link_column_keys[column].get_index();
139,884✔
191
                if (pe.is_ndx()) {
139,884✔
192
                    start = pe.get_ndx();
294✔
193
                    if (start == realm::npos) {
294✔
194
                        start = sz - 1;
72✔
195
                    }
72✔
196
                    else if (start < sz) {
222✔
197
                        end = start + 1;
222✔
198
                    }
222✔
199
                }
294✔
200
                for (size_t t = start; t < end; t++) {
417,111✔
201
                    if (!map_links(column + 1, links.get(t), lm))
277,533✔
202
                        break;
306✔
203
                }
277,533✔
204
            }
139,884✔
205
        }
196,806✔
206
    }
198,324✔
207
    else if (type == col_type_Link) {
168,534✔
208
        map_links(column + 1, mpark::get<ArrayKey>(m_leaf).get(row), lm);
164,166✔
209
    }
164,166✔
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,858✔
223

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

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,525✔
254
        auto target = m_tables[column + 1];
3,525✔
255
        for (auto k : keys) {
3,639✔
256
            const Obj o = target->get_object(k);
3,639✔
257
            auto cnt = o.get_backlink_count(*origin, origin_col);
3,639✔
258
            for (size_t i = 0; i < cnt; i++) {
7,980✔
259
                ret.push_back(o.get_backlink(*origin, origin_col, i));
4,341✔
260
            }
4,341✔
261
        }
3,639✔
262
    }
3,525✔
263
    return ret;
4,185✔
264
}
20,322✔
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
{
918✔
273
    m_ctrl.path.clear();
918✔
274
    m_ctrl.path_only_unary_keys = true;
918✔
275
    while (begin != end) {
1,914✔
276
        if (begin->is_all()) {
996✔
277
            m_ctrl.path_only_unary_keys = false;
102✔
278
        }
102✔
279
        m_ctrl.path.emplace_back(std::move(*begin));
996✔
280
        ++begin;
996✔
281
    }
996✔
282
    std::move(begin, end, std::back_inserter(m_ctrl.path));
918✔
283
    if (m_ctrl.path.empty()) {
918✔
284
        m_ctrl.path_only_unary_keys = false;
×
285
        m_ctrl.path.push_back(PathElement::AllTag());
×
286
    }
×
287
}
918✔
288

289
void ColumnDictionaryKeys::set_cluster(const Cluster* cluster)
290
{
90✔
291
    if (m_link_map.has_links()) {
90✔
292
        m_link_map.set_cluster(cluster);
18✔
293
    }
18✔
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
}
90✔
299

300
void ColumnDictionaryKeys::evaluate(Subexpr::Index& index, ValueBase& destination)
301
{
6,684✔
302
    if (m_link_map.has_links()) {
6,684✔
303
        if (index.initialize()) {
78✔
304
            m_links.clear();
72✔
305
            REALM_ASSERT(!m_leaf);
72✔
306
            m_links = m_link_map.get_links(index);
72✔
307
            if (!index.set_size(m_links.size())) {
72✔
308
                destination.init(true, 0);
×
309
                return;
×
310
            }
×
311
        }
72✔
312
        const Obj obj = m_link_map.get_target_table()->get_object(m_links[index.get_and_incr_sub_index()]);
78✔
313
        auto dict = obj.get_dictionary(m_column_key);
78✔
314
        destination.init(true, dict.size());
78✔
315
        // Insert all values
316
        size_t n = 0;
78✔
317
        dict.for_all_keys<StringData>([&](const Mixed& value) {
204✔
318
            destination.set(n, value);
204✔
319
            n++;
204✔
320
        });
204✔
321
    }
78✔
322
    else {
6,606✔
323
        // Not a link column
324
        Allocator& alloc = get_base_table()->get_alloc();
6,606✔
325

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

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

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

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

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

377
void Columns<Dictionary>::evaluate(Subexpr::Index& index, ValueBase& destination)
378
{
24,348✔
379
    if (index.initialize()) {
24,348✔
380
        m_ctrl.matches.clear();
22,026✔
381
        if (links_exist()) {
22,026✔
382
            REALM_ASSERT(!m_leaf);
2,052✔
383
            std::vector<ObjKey> links = m_link_map.get_links(index);
2,052✔
384
            auto sz = links.size();
2,052✔
385
            if (!m_link_map.only_unary_links())
2,052✔
386
                m_ctrl.path_only_unary_keys = false;
552✔
387

388
            for (size_t t = 0; t < sz; t++) {
8,976✔
389
                const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
6,924✔
390
                auto val = obj.get_any(m_column_key);
6,924✔
391
                if (!val.is_null()) {
6,924✔
392
                    Collection::get_any(m_ctrl, val, 0);
6,924✔
393
                }
6,924✔
394
            }
6,924✔
395
        }
2,052✔
396
        else {
19,974✔
397
            // Not a link column
398
            REALM_ASSERT(m_leaf);
19,974✔
399
            if (ref_type ref = to_ref(m_leaf->get(index))) {
19,974✔
400
                Collection::get_any(m_ctrl, {ref, CollectionType::Dictionary}, 0);
19,974✔
401
            }
19,974✔
402
        }
19,974✔
403
        if (!index.set_size(m_ctrl.matches.size())) {
22,026✔
404
            destination.init(true, 0);
6✔
405
            return;
6✔
406
        }
6✔
407
    }
22,026✔
408
    // Copy values over
409
    auto& matches = m_ctrl.matches[index.get_and_incr_sub_index()];
24,342✔
410
    auto sz = matches.size();
24,342✔
411
    destination.init(!m_ctrl.path_only_unary_keys || sz == 0, sz);
24,342✔
412
    destination.set(matches.begin(), matches.end());
24,342✔
413
}
24,342✔
414

415

416
void Columns<Link>::evaluate(Subexpr::Index& index, ValueBase& destination)
417
{
2,070✔
418
    // Destination must be of Key type. It only makes sense to
419
    // compare keys with keys
420
    std::vector<ObjKey> links = m_link_map.get_links(index);
2,070✔
421

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

436
void ColumnListBase::set_cluster(const Cluster* cluster)
437
{
43,224✔
438
    if (m_link_map.has_links()) {
43,224✔
439
        m_link_map.set_cluster(cluster);
9,642✔
440
    }
9,642✔
441
    else {
33,582✔
442
        m_leaf.emplace(m_link_map.get_base_table()->get_alloc());
33,582✔
443
        cluster->init_leaf(m_column_key, &*m_leaf);
33,582✔
444
    }
33,582✔
445
}
43,224✔
446

447
void ColumnListBase::get_lists(size_t index, Value<int64_t>& destination)
448
{
2,109,210✔
449
    if (m_link_map.has_links()) {
2,109,210✔
450
        std::vector<ObjKey> links = m_link_map.get_links(index);
64,902✔
451
        auto sz = links.size();
64,902✔
452

453
        if (m_link_map.only_unary_links()) {
64,902✔
454
            int64_t val = 0;
64,068✔
455
            if (sz == 1) {
64,068✔
456
                const Obj obj = m_link_map.get_target_table()->get_object(links[0]);
63,918✔
457
                val = obj._get<int64_t>(m_column_key.get_index());
63,918✔
458
            }
63,918✔
459
            destination.init(false, 1);
64,068✔
460
            destination.set(0, val);
64,068✔
461
        }
64,068✔
462
        else {
834✔
463
            destination.init(true, sz);
834✔
464
            for (size_t t = 0; t < sz; t++) {
3,822✔
465
                const Obj obj = m_link_map.get_target_table()->get_object(links[t]);
2,988✔
466
                int64_t val = obj._get<int64_t>(m_column_key.get_index());
2,988✔
467
                destination.set(t, val);
2,988✔
468
            }
2,988✔
469
        }
834✔
470
    }
64,902✔
471
    else {
2,044,308✔
472
        destination.init(false, 1);
2,044,308✔
473
        destination.set(0, m_leaf->get(index));
2,044,308✔
474
    }
2,044,308✔
475
}
2,109,210✔
476

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

586

587
// BinaryData
588

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

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

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

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

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

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

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

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

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

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

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

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

649
// Mixed
650

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

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

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

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

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

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

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

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

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

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

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

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

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