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

realm / realm-core / github_pull_request_312964

19 Feb 2025 07:31PM UTC coverage: 90.814% (-0.3%) from 91.119%
github_pull_request_312964

Pull #8071

Evergreen

web-flow
Bump serialize-javascript and mocha

Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) to 6.0.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `serialize-javascript` from 6.0.0 to 6.0.2
- [Release notes](https://github.com/yahoo/serialize-javascript/releases)
- [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.0...v6.0.2)

Updates `mocha` from 10.2.0 to 10.8.2
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v10.2.0...v10.8.2)

---
updated-dependencies:
- dependency-name: serialize-javascript
  dependency-type: indirect
- dependency-name: mocha
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #8071: Bump serialize-javascript and mocha

96552 of 179126 branches covered (53.9%)

212672 of 234185 relevant lines covered (90.81%)

3115802.0 hits per line

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

93.67
/src/realm/sort_descriptor.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/sort_descriptor.hpp>
20
#include <realm/table.hpp>
21
#include <realm/table_view.hpp>
22
#include <realm/db.hpp>
23
#include <realm/util/assert.hpp>
24
#include <realm/list.hpp>
25
#include <realm/dictionary.hpp>
26

27
using namespace realm;
28

29
ConstTableRef ExtendedColumnKey::get_target_table(const Table* table) const
30
{
375✔
31
    return (m_colkey.get_type() == col_type_Link) ? table->get_link_target(m_colkey) : ConstTableRef{};
375✔
32
}
375✔
33

34
std::string ExtendedColumnKey::get_description(const Table* table) const
35
{
354✔
36
    std::string description = table->get_column_name(m_colkey);
354✔
37
    if (has_index()) {
354✔
38
        description += util::format("[%1]", util::serializer::print_value(m_index));
12✔
39
    }
12✔
40
    return description;
354✔
41
}
354✔
42

43
std::string ExtendedColumnKey::get_description(ConstTableRef table, util::serializer::SerialisationState& state) const
44
{
5,520✔
45
    std::string description = state.get_column_name(table, m_colkey);
5,520✔
46
    // m_index has the type col_key if it is not set
47
    if (has_index()) {
5,520✔
48
        description += util::format("[%1]", util::serializer::print_value(m_index));
45✔
49
    }
45✔
50
    return description;
5,520✔
51
}
5,520✔
52

53
bool ExtendedColumnKey::is_collection() const
54
{
7,836✔
55
    return m_colkey.is_collection() && !has_index();
7,836✔
56
}
7,836✔
57

58
ObjKey ExtendedColumnKey::get_link_target(const Obj& obj) const
59
{
1,581✔
60
    if (!has_index()) {
1,581✔
61
        return obj.get<ObjKey>(m_colkey);
1,563✔
62
    }
1,563✔
63
    else if (m_colkey.is_dictionary()) {
18✔
64
        const auto dictionary = obj.get_dictionary(m_colkey);
18✔
65
        auto val = dictionary.try_get(m_index.get_key());
18✔
66
        if (val && val->is_type(type_TypedLink)) {
18✔
67
            return val->get<ObjKey>();
18✔
68
        }
18✔
69
    }
18✔
70
    return {};
×
71
}
1,581✔
72

73
Mixed ExtendedColumnKey::get_value(const Obj& obj) const
74
{
433,338✔
75
    if (!has_index()) {
433,338✔
76
        return obj.get_any(m_colkey);
433,239✔
77
    }
433,239✔
78
    else if (m_colkey.is_dictionary()) {
99✔
79
        const auto dictionary = obj.get_dictionary(m_colkey);
99✔
80
        auto val = dictionary.try_get(m_index.get_key());
99✔
81
        if (val) {
99✔
82
            return *val;
99✔
83
        }
99✔
84
    }
99✔
85
    return {};
×
86
}
433,338✔
87

88
LinkPathPart::LinkPathPart(ColKey col_key, ConstTableRef source)
89
    : column_key(col_key)
×
90
    , from(source->get_key())
×
91
{
×
92
}
×
93

94

95
ColumnsDescriptor::ColumnsDescriptor(std::vector<std::vector<ExtendedColumnKey>> column_keys)
96
    : m_column_keys(std::move(column_keys))
8,913✔
97
{
8,913✔
98
}
8,913✔
99

100
std::unique_ptr<BaseDescriptor> DistinctDescriptor::clone() const
101
{
843✔
102
    return std::unique_ptr<DistinctDescriptor>(new DistinctDescriptor(*this));
843✔
103
}
843✔
104

105
void ColumnsDescriptor::collect_dependencies(const Table* table, std::vector<TableKey>& table_keys) const
106
{
14,550✔
107
    for (auto& columns : m_column_keys) {
14,874✔
108
        auto sz = columns.size();
14,874✔
109
        // If size is 0 or 1 there is no link chain and hence no additional tables to check
110
        if (sz > 1) {
14,874✔
111
            const Table* t = table;
279✔
112
            for (size_t i = 0; i < sz - 1; i++) {
603✔
113
                const auto& col = columns[i];
327✔
114
                ConstTableRef target_table = col.get_target_table(t);
327✔
115
                if (!target_table)
327✔
116
                    return;
3✔
117
                table_keys.push_back(target_table->get_key());
324✔
118
                t = target_table.unchecked_ptr();
324✔
119
            }
324✔
120
        }
279✔
121
    }
14,874✔
122
}
14,550✔
123

124
std::string DistinctDescriptor::get_description(ConstTableRef attached_table) const
125
{
105✔
126
    std::string description = "DISTINCT(";
105✔
127
    for (size_t i = 0; i < m_column_keys.size(); ++i) {
222✔
128
        const size_t chain_size = m_column_keys[i].size();
117✔
129
        ConstTableRef cur_link_table = attached_table;
117✔
130
        for (size_t j = 0; j < chain_size; ++j) {
252✔
131
            const auto& col_key = m_column_keys[i][j];
135✔
132
            description += col_key.get_description(cur_link_table.unchecked_ptr());
135✔
133
            if (j < chain_size - 1) {
135✔
134
                description += ".";
18✔
135
                cur_link_table = col_key.get_target_table(cur_link_table.unchecked_ptr());
18✔
136
            }
18✔
137
        }
135✔
138
        if (i < m_column_keys.size() - 1) {
117✔
139
            description += ", ";
12✔
140
        }
12✔
141
    }
117✔
142
    description += ")";
105✔
143
    return description;
105✔
144
}
105✔
145

146
std::string SortDescriptor::get_description(ConstTableRef attached_table) const
147
{
171✔
148
    std::string description = "SORT(";
171✔
149
    for (size_t i = 0; i < m_column_keys.size(); ++i) {
360✔
150
        const size_t chain_size = m_column_keys[i].size();
189✔
151
        ConstTableRef cur_link_table = attached_table;
189✔
152
        for (size_t j = 0; j < chain_size; ++j) {
408✔
153
            const auto& col_key = m_column_keys[i][j];
219✔
154
            description += col_key.get_description(cur_link_table.unchecked_ptr());
219✔
155
            if (j < chain_size - 1) {
219✔
156
                description += ".";
30✔
157
                cur_link_table = col_key.get_target_table(cur_link_table.unchecked_ptr());
30✔
158
            }
30✔
159
        }
219✔
160
        description += " ";
189✔
161
        if (i < m_ascending.size()) {
189✔
162
            if (m_ascending[i]) {
189✔
163
                description += "ASC";
144✔
164
            }
144✔
165
            else {
45✔
166
                description += "DESC";
45✔
167
            }
45✔
168
        }
189✔
169
        if (i < m_column_keys.size() - 1) {
189✔
170
            description += ", ";
18✔
171
        }
18✔
172
    }
189✔
173
    description += ")";
171✔
174
    return description;
171✔
175
}
171✔
176

177
SortDescriptor::SortDescriptor(std::vector<std::vector<ExtendedColumnKey>> column_keys, std::vector<bool> ascending)
178
    : ColumnsDescriptor(std::move(column_keys))
7,842✔
179
    , m_ascending(std::move(ascending))
7,842✔
180
{
7,842✔
181
    REALM_ASSERT_EX(m_ascending.empty() || m_ascending.size() == m_column_keys.size(), m_ascending.size(),
7,842✔
182
                    m_column_keys.size());
7,842✔
183
    if (m_ascending.empty())
7,842✔
184
        m_ascending.resize(m_column_keys.size(), true);
57✔
185
}
7,842✔
186

187
std::unique_ptr<BaseDescriptor> SortDescriptor::clone() const
188
{
28,281✔
189
    return std::unique_ptr<ColumnsDescriptor>(new SortDescriptor(*this));
28,281✔
190
}
28,281✔
191

192
void SortDescriptor::merge(SortDescriptor&& other, MergeMode mode)
193
{
51✔
194
    if (mode == MergeMode::replace) {
51✔
195
        m_column_keys = std::move(other.m_column_keys);
3✔
196
        m_ascending = std::move(other.m_ascending);
3✔
197
        return;
3✔
198
    }
3✔
199

200
    m_column_keys.insert(mode == MergeMode::prepend ? m_column_keys.begin() : m_column_keys.end(),
48✔
201
                         other.m_column_keys.begin(), other.m_column_keys.end());
48✔
202
    // Do not use a move iterator on a vector of bools!
203
    // It will form a reference to a temporary and return incorrect results.
204
    m_ascending.insert(mode == MergeMode::prepend ? m_ascending.begin() : m_ascending.end(),
48✔
205
                       other.m_ascending.begin(), other.m_ascending.end());
48✔
206
}
48✔
207

208
BaseDescriptor::Sorter::Sorter(std::vector<std::vector<ExtendedColumnKey>> const& column_lists,
209
                               std::vector<bool> const& ascending, Table const& root_table, const IndexPairs& indexes)
210
{
7,485✔
211
    REALM_ASSERT(!column_lists.empty());
7,485✔
212
    REALM_ASSERT_EX(column_lists.size() == ascending.size(), column_lists.size(), ascending.size());
7,485✔
213
    size_t translated_size = std::max_element(indexes.begin(), indexes.end())->index_in_view + 1;
7,485✔
214

215
    m_columns.reserve(column_lists.size());
7,485✔
216
    for (size_t i = 0; i < column_lists.size(); ++i) {
15,309✔
217
        auto& columns = column_lists[i];
7,836✔
218
        auto sz = columns.size();
7,836✔
219
        REALM_ASSERT_EX(!columns.empty(), i);
7,836✔
220

221
        if (columns.empty()) {
7,836✔
222
            throw InvalidArgument(ErrorCodes::InvalidSortDescriptor, "Missing property");
×
223
        }
×
224
        if (columns.empty() || columns.back().is_collection()) {
7,836✔
225
            throw InvalidArgument(ErrorCodes::InvalidSortDescriptor, "Cannot sort on a collection property");
3✔
226
        }
3✔
227

228
        if (sz == 1) { // no link chain
7,833✔
229
            m_columns.emplace_back(&root_table, columns[0], ascending[i]);
7,551✔
230
            continue;
7,551✔
231
        }
7,551✔
232

233
        std::vector<const Table*> tables = {&root_table};
282✔
234
        tables.resize(sz);
282✔
235
        for (size_t j = 0; j + 1 < sz; ++j) {
606✔
236
            ColKey col = columns[j];
333✔
237
            if (!tables[j]->valid_column(col)) {
333✔
238
                throw InvalidArgument(ErrorCodes::InvalidSortDescriptor, "Invalid property");
3✔
239
            }
3✔
240
            if (!(col.get_type() == col_type_Link && !col.is_list())) {
330✔
241
                // Only last column in link chain is allowed to be non-link
242
                throw InvalidArgument(ErrorCodes::InvalidSortDescriptor, "All but last property must be a link");
6✔
243
            }
6✔
244
            tables[j + 1] = tables[j]->get_link_target(col).unchecked_ptr();
324✔
245
        }
324✔
246

247
        m_columns.emplace_back(tables.back(), columns.back(), ascending[i]);
273✔
248

249
        auto& translated_keys = m_columns.back().translated_keys;
273✔
250
        translated_keys.resize(translated_size);
273✔
251

252
        for (const auto& index : indexes) {
1,323✔
253
            size_t index_in_view = index.index_in_view;
1,323✔
254
            ObjKey translated_key = index.key_for_object;
1,323✔
255
            for (size_t j = 0; j + 1 < sz; ++j) {
2,787✔
256
                const Obj obj = tables[j]->get_object(translated_key);
1,581✔
257
                // type was checked when creating the ColumnsDescriptor
258
                translated_key = columns[j].get_link_target(obj);
1,581✔
259
                if (!translated_key || translated_key.is_unresolved()) {
1,581✔
260
                    translated_key = null_key; // normalize unresolve to null
117✔
261
                    break;
117✔
262
                }
117✔
263
            }
1,581✔
264
            translated_keys[index_in_view] = translated_key;
1,323✔
265
        }
1,323✔
266
    }
273✔
267
    m_cache.resize(column_lists.size() - 1);
7,473✔
268
}
7,473✔
269

270
BaseDescriptor::Sorter DistinctDescriptor::sorter(Table const& table, const IndexPairs& indexes) const
271
{
618✔
272
    REALM_ASSERT(!m_column_keys.empty());
618✔
273
    std::vector<bool> ascending(m_column_keys.size(), true);
618✔
274
    return Sorter(m_column_keys, ascending, table, indexes);
618✔
275
}
618✔
276

277
void DistinctDescriptor::execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const
278
{
618✔
279
    using IP = ColumnsDescriptor::IndexPair;
618✔
280
    // Remove all rows which have a null link along the way to the distinct columns
281
    if (predicate.has_links()) {
618✔
282
        auto nulls = std::remove_if(v.begin(), v.end(), [&](const IP& index) {
513✔
283
            return predicate.any_is_null(index);
513✔
284
        });
513✔
285
        v.erase(nulls, v.end());
99✔
286
    }
99✔
287

288
    // Sort by the columns to distinct on
289
    std::sort(v.begin(), v.end(), std::ref(predicate));
618✔
290

291
    // Move duplicates to the back - "not less than" is "equal" since they're sorted
292
    auto duplicates = std::unique(v.begin(), v.end(), [&](const IP& a, const IP& b) {
2,859✔
293
        return !predicate(a, b, false);
2,859✔
294
    });
2,859✔
295
    // Erase the duplicates
296
    v.erase(duplicates, v.end());
618✔
297
    bool will_be_sorted_next = next && next->get_type() == DescriptorType::Sort;
618✔
298
    if (!will_be_sorted_next) {
618✔
299
        // Restore the original order, this is either the original
300
        // tableview order or the order of the previous sort
301
        std::sort(v.begin(), v.end(), [](const IP& a, const IP& b) {
2,271✔
302
            return a.index_in_view < b.index_in_view;
2,271✔
303
        });
2,271✔
304
    }
510✔
305
}
618✔
306

307
BaseDescriptor::Sorter SortDescriptor::sorter(Table const& table, const IndexPairs& indexes) const
308
{
6,867✔
309
    REALM_ASSERT(!m_column_keys.empty());
6,867✔
310
    return Sorter(m_column_keys, m_ascending, table, indexes);
6,867✔
311
}
6,867✔
312

313
void SortDescriptor::execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const
314
{
6,855✔
315
    size_t limit = size_t(-1);
6,855✔
316
    if (next && next->get_type() == DescriptorType::Limit) {
6,855✔
317
        limit = static_cast<const LimitDescriptor*>(next)->get_limit();
99✔
318
    }
99✔
319
    // Measurements shows that if limit is smaller than size / 16, then
320
    // it is quicker to make a sorted insert into a smaller vector
321
    if (limit < (v.size() >> 4)) {
6,855✔
322
        IndexPairs buffer;
3✔
323
        buffer.reserve(limit + 1);
3✔
324
        for (auto& elem : v) {
30,000✔
325
            auto it = std::lower_bound(buffer.begin(), buffer.end(), elem, std::ref(predicate));
30,000✔
326
            buffer.insert(it, elem);
30,000✔
327
            if (buffer.size() > limit) {
30,000✔
328
                buffer.pop_back();
29,700✔
329
            }
29,700✔
330
        }
30,000✔
331
        v.m_removed_by_limit += v.size() - limit;
3✔
332
        v.erase(v.begin() + limit, v.end());
3✔
333
        std::move(buffer.begin(), buffer.end(), v.begin());
3✔
334
    }
3✔
335
    else {
6,852✔
336
        std::sort(v.begin(), v.end(), std::ref(predicate));
6,852✔
337
    }
6,852✔
338

339
    // not doing this on the last step is an optimisation
340
    if (next) {
6,855✔
341
        const size_t v_size = v.size();
282✔
342
        // Distinct must choose the winning unique elements by sorted
343
        // order not by the previous tableview order, the lowest
344
        // "index_in_view" wins.
345
        for (size_t i = 0; i < v_size; ++i) {
2,013✔
346
            v[i].index_in_view = i;
1,731✔
347
        }
1,731✔
348
    }
282✔
349
}
6,855✔
350

351
std::string LimitDescriptor::get_description(ConstTableRef) const
352
{
123✔
353
    return "LIMIT(" + util::serializer::print_value(m_limit) + ")";
123✔
354
}
123✔
355

356
std::unique_ptr<BaseDescriptor> LimitDescriptor::clone() const
357
{
369✔
358
    return std::unique_ptr<BaseDescriptor>(new LimitDescriptor(*this));
369✔
359
}
369✔
360

361
void LimitDescriptor::execute(const Table&, KeyValues& key_values, const BaseDescriptor*) const
362
{
291✔
363
    if (key_values.size() > m_limit) {
291✔
364
        key_values.erase(key_values.begin() + m_limit, key_values.end());
171✔
365
    }
171✔
366
}
291✔
367

368
std::string FilterDescriptor::get_description(ConstTableRef) const
369
{
×
370
    throw SerializationError("Serialization of FilterDescriptor is not supported");
×
371
    return "";
×
372
}
×
373

374
std::unique_ptr<BaseDescriptor> FilterDescriptor::clone() const
375
{
69✔
376
    return std::unique_ptr<BaseDescriptor>(new FilterDescriptor(*this));
69✔
377
}
69✔
378

379
void FilterDescriptor::execute(const Table& table, KeyValues& key_values, const BaseDescriptor*) const
380
{
48✔
381
    KeyValues filtered;
48✔
382
    filtered.create();
48✔
383
    auto sz = key_values.size();
48✔
384
    for (size_t i = 0; i < sz; i++) {
78,111✔
385
        auto key = key_values.get(i);
78,063✔
386
        Obj obj = table.try_get_object(key);
78,063✔
387
        if (obj && m_predicate(obj)) {
78,063✔
388
            filtered.add(key);
819✔
389
        }
819✔
390
    }
78,063✔
391
    key_values = std::move(filtered);
48✔
392
}
48✔
393

394
// This function must conform to 'is less' predicate - that is:
395
// return true if i is strictly smaller than j
396
bool BaseDescriptor::Sorter::operator()(IndexPair i, IndexPair j, bool total_ordering) const
397
{
1,234,485✔
398
    // Sorting can be specified by multiple columns, so that if two entries in the first column are
399
    // identical, then the rows are ordered according to the second column, and so forth. For the
400
    // first column, all the payload of the View is cached in IndexPair::cached_value.
401
    for (size_t t = 0; t < m_columns.size(); t++) {
1,917,564✔
402
        ObjKey key_i = i.key_for_object;
1,745,814✔
403
        ObjKey key_j = j.key_for_object;
1,745,814✔
404

405
        if (!m_columns[t].translated_keys.empty()) {
1,745,814✔
406
            key_i = m_columns[t].translated_keys[i.index_in_view];
2,523✔
407
            key_j = m_columns[t].translated_keys[j.index_in_view];
2,523✔
408

409
            bool null_i = !key_i;
2,523✔
410
            bool null_j = !key_j;
2,523✔
411

412
            if (null_i && null_j) {
2,523✔
413
                continue;
78✔
414
            }
78✔
415
            if (null_i || null_j) {
2,445✔
416
                // Sort null links at the end if m_ascending[t], else at beginning.
417
                return m_columns[t].ascending != null_i;
102✔
418
            }
102✔
419
        }
2,445✔
420

421
        int c;
1,745,634✔
422

423
        if (t == 0) {
1,745,634✔
424
            c = i.cached_value.compare(j.cached_value);
1,234,332✔
425
        }
1,234,332✔
426
        else {
511,302✔
427
            if (m_cache[t - 1].empty()) {
511,302✔
428
                m_cache[t - 1].resize(256);
294✔
429
            }
294✔
430
            ObjCache& cache_i = m_cache[t - 1][key_i.value & 0xFF];
511,302✔
431
            ObjCache& cache_j = m_cache[t - 1][key_j.value & 0xFF];
511,302✔
432

433
            if (cache_i.key != key_i) {
511,302✔
434
                const auto& obj = m_columns[t].table->get_object(key_i);
157,776✔
435
                const auto& col_key = m_columns[t].col_key;
157,776✔
436

437
                cache_i.value = col_key.get_value(obj);
157,776✔
438
                cache_i.key = key_i;
157,776✔
439
            }
157,776✔
440
            Mixed val_i = cache_i.value;
511,302✔
441

442
            if (cache_j.key != key_j) {
511,302✔
443
                const auto& obj = m_columns[t].table->get_object(key_j);
154,926✔
444
                const auto& col_key = m_columns[t].col_key;
154,926✔
445

446
                cache_j.value = col_key.get_value(obj);
154,926✔
447
                cache_j.key = key_j;
154,926✔
448
            }
154,926✔
449

450
            c = val_i.compare(cache_j.value);
511,302✔
451
        }
511,302✔
452
        // if c is negative i comes before j
453
        if (c) {
1,745,634✔
454
            return m_columns[t].ascending ? c < 0 : c > 0;
1,062,633✔
455
        }
1,062,633✔
456
    }
1,745,634✔
457
    // make sort stable by using original index as final comparison
458
    return total_ordering ? i.index_in_view < j.index_in_view : 0;
171,750✔
459
}
1,234,485✔
460

461
void BaseDescriptor::Sorter::cache_first_column(IndexPairs& v)
462
{
7,473✔
463
    if (m_columns.empty())
7,473✔
464
        return;
×
465

466
    auto& col = m_columns[0];
7,473✔
467
    const auto& ck = col.col_key;
7,473✔
468
    for (size_t i = 0; i < v.size(); i++) {
128,199✔
469
        IndexPair& index = v[i];
120,726✔
470
        ObjKey key = index.key_for_object;
120,726✔
471

472
        if (!col.translated_keys.empty()) {
120,726✔
473
            key = col.translated_keys[v[i].index_in_view];
1,170✔
474
            if (!key) {
1,170✔
475
                index.cached_value = Mixed();
90✔
476
                continue;
90✔
477
            }
90✔
478
        }
1,170✔
479

480
        const auto obj = col.table->get_object(key);
120,636✔
481
        index.cached_value = ck.get_value(obj);
120,636✔
482
    }
120,636✔
483
}
7,473✔
484

485
DescriptorOrdering::DescriptorOrdering(const DescriptorOrdering& other)
486
    : AtomicRefCountBase()
23,070✔
487
{
23,070✔
488
    for (const auto& d : other.m_descriptors) {
23,070✔
489
        m_descriptors.emplace_back(d->clone());
5,793✔
490
    }
5,793✔
491
}
23,070✔
492

493
DescriptorOrdering& DescriptorOrdering::operator=(const DescriptorOrdering& rhs)
494
{
42,681✔
495
    if (&rhs != this) {
42,681✔
496
        m_descriptors.clear();
42,681✔
497
        for (const auto& d : rhs.m_descriptors) {
42,681✔
498
            m_descriptors.emplace_back(d->clone());
23,745✔
499
        }
23,745✔
500
    }
42,681✔
501
    return *this;
42,681✔
502
}
42,681✔
503

504
void DescriptorOrdering::append_sort(SortDescriptor sort, SortDescriptor::MergeMode mode)
505
{
28,554✔
506
    if (!sort.is_valid()) {
28,554✔
507
        return;
20,712✔
508
    }
20,712✔
509
    if (!m_descriptors.empty()) {
7,842✔
510
        if (SortDescriptor* previous_sort = dynamic_cast<SortDescriptor*>(m_descriptors.back().get())) {
435✔
511
            previous_sort->merge(std::move(sort), mode);
51✔
512
            return;
51✔
513
        }
51✔
514
    }
435✔
515
    m_descriptors.emplace_back(new SortDescriptor(std::move(sort)));
7,791✔
516
}
7,791✔
517

518
void DescriptorOrdering::append_distinct(DistinctDescriptor distinct)
519
{
1,104✔
520
    if (distinct.is_valid()) {
1,104✔
521
        m_descriptors.emplace_back(new DistinctDescriptor(std::move(distinct)));
1,071✔
522
    }
1,071✔
523
}
1,104✔
524

525
void DescriptorOrdering::append_limit(LimitDescriptor limit)
526
{
474✔
527
    if (limit.is_valid()) {
474✔
528
        m_descriptors.emplace_back(new LimitDescriptor(std::move(limit)));
471✔
529
    }
471✔
530
}
474✔
531

532
void DescriptorOrdering::append_filter(FilterDescriptor filter)
533
{
21✔
534
    if (filter.is_valid()) {
21✔
535
        m_descriptors.emplace_back(new FilterDescriptor(std::move(filter)));
21✔
536
    }
21✔
537
}
21✔
538

539
void DescriptorOrdering::append(const DescriptorOrdering& other)
540
{
24✔
541
    for (const auto& d : other.m_descriptors) {
24✔
542
        m_descriptors.emplace_back(d->clone());
24✔
543
    }
24✔
544
}
24✔
545

546
void DescriptorOrdering::append(DescriptorOrdering&& other)
547
{
261✔
548
    std::move(other.m_descriptors.begin(), other.m_descriptors.end(), std::back_inserter(m_descriptors));
261✔
549
    other.m_descriptors.clear();
261✔
550
}
261✔
551

552
DescriptorType DescriptorOrdering::get_type(size_t index) const
553
{
702✔
554
    REALM_ASSERT(index < m_descriptors.size());
702✔
555
    return m_descriptors[index]->get_type();
702✔
556
}
702✔
557

558
const BaseDescriptor* DescriptorOrdering::operator[](size_t ndx) const
559
{
19,323✔
560
    if (ndx >= m_descriptors.size()) {
19,323✔
561
        throw OutOfBounds("DescriptorOrdering[]", ndx, m_descriptors.size());
×
562
    }
×
563
    return m_descriptors[ndx].get();
19,323✔
564
}
19,323✔
565

566
bool DescriptorOrdering::will_apply_sort() const
567
{
5,868✔
568
    return std::any_of(m_descriptors.begin(), m_descriptors.end(), [](const std::unique_ptr<BaseDescriptor>& desc) {
5,868✔
569
        REALM_ASSERT(desc->is_valid());
3,612✔
570
        return desc->get_type() == DescriptorType::Sort;
3,612✔
571
    });
3,612✔
572
}
5,868✔
573

574
bool DescriptorOrdering::will_apply_distinct() const
575
{
20,742✔
576
    return std::any_of(m_descriptors.begin(), m_descriptors.end(), [](const std::unique_ptr<BaseDescriptor>& desc) {
20,742✔
577
        REALM_ASSERT(desc->is_valid());
14,466✔
578
        return desc->get_type() == DescriptorType::Distinct;
14,466✔
579
    });
14,466✔
580
}
20,742✔
581

582
bool DescriptorOrdering::will_apply_limit() const
583
{
63✔
584
    return std::any_of(m_descriptors.begin(), m_descriptors.end(), [](const std::unique_ptr<BaseDescriptor>& desc) {
93✔
585
        REALM_ASSERT(desc->is_valid());
93✔
586
        return desc->get_type() == DescriptorType::Limit;
93✔
587
    });
93✔
588
}
63✔
589

590
bool DescriptorOrdering::will_apply_filter() const
591
{
7,872✔
592
    return std::any_of(m_descriptors.begin(), m_descriptors.end(), [](const std::unique_ptr<BaseDescriptor>& desc) {
7,872✔
593
        REALM_ASSERT(desc->is_valid());
7,137✔
594
        return desc->get_type() == DescriptorType::Filter;
7,137✔
595
    });
7,137✔
596
}
7,872✔
597

598
realm::util::Optional<size_t> DescriptorOrdering::get_min_limit() const
599
{
7,899✔
600
    realm::util::Optional<size_t> min_limit;
7,899✔
601
    for (auto it = m_descriptors.begin(); it != m_descriptors.end(); it++) {
15,099✔
602
        if ((*it)->get_type() == DescriptorType::Limit) {
7,200✔
603
            const LimitDescriptor* limit = static_cast<const LimitDescriptor*>(it->get());
135✔
604
            REALM_ASSERT(limit);
135✔
605
            min_limit = bool(min_limit) ? std::min(*min_limit, limit->get_limit()) : limit->get_limit();
135✔
606
        }
135✔
607
    }
7,200✔
608
    return min_limit;
7,899✔
609
}
7,899✔
610

611
util::Optional<size_t> DescriptorOrdering::remove_all_limits()
612
{
×
613
    size_t min_limit = size_t(-1);
×
614
    for (auto it = m_descriptors.begin(); it != m_descriptors.end();) {
×
615
        if ((*it)->get_type() == DescriptorType::Limit) {
×
616
            const LimitDescriptor* limit = static_cast<const LimitDescriptor*>(it->get());
×
617
            if (limit->get_limit() < min_limit) {
×
618
                min_limit = limit->get_limit();
×
619
            }
×
620
            it = m_descriptors.erase(it);
×
621
        }
×
622
        else {
×
623
            ++it;
×
624
        }
×
625
    }
×
626
    return min_limit == size_t(-1) ? util::none : util::some<size_t>(min_limit);
×
627
}
×
628

629
bool DescriptorOrdering::will_limit_to_zero() const
630
{
42✔
631
    return std::any_of(m_descriptors.begin(), m_descriptors.end(), [](const std::unique_ptr<BaseDescriptor>& desc) {
96✔
632
        REALM_ASSERT(desc.get()->is_valid());
96✔
633
        return (desc->get_type() == DescriptorType::Limit &&
96✔
634
                static_cast<LimitDescriptor*>(desc.get())->get_limit() == 0);
96✔
635
    });
96✔
636
}
42✔
637

638
std::string DescriptorOrdering::get_description(ConstTableRef target_table) const
639
{
270✔
640
    std::string description = "";
270✔
641
    for (auto it = m_descriptors.begin(); it != m_descriptors.end(); ++it) {
669✔
642
        REALM_ASSERT_DEBUG(bool(*it));
399✔
643
        description += (*it)->get_description(target_table);
399✔
644
        if (it != m_descriptors.end() - 1) {
399✔
645
            description += " ";
171✔
646
        }
171✔
647
    }
399✔
648
    return description;
270✔
649
}
270✔
650

651
void DescriptorOrdering::collect_dependencies(const Table* table)
652
{
24,009✔
653
    m_dependencies.clear();
24,009✔
654
    for (auto& descr : m_descriptors) {
24,009✔
655
        descr->collect_dependencies(table, m_dependencies);
14,910✔
656
    }
14,910✔
657
}
24,009✔
658

659
void DescriptorOrdering::get_versions(const Group* group, TableVersions& versions) const
660
{
1,001,121✔
661
    for (auto table_key : m_dependencies) {
1,001,121✔
662
        REALM_ASSERT_DEBUG(group);
279✔
663
        versions.emplace_back(table_key, group->get_table(table_key)->get_content_version());
279✔
664
    }
279✔
665
}
1,001,121✔
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