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

realm / realm-core / 2123

12 Mar 2024 11:18PM UTC coverage: 91.833% (+0.05%) from 91.787%
2123

push

Evergreen

web-flow
RCORE-1928 Use baasaas for baas integration tests in CI (#7423)

94732 of 174812 branches covered (54.19%)

201 of 288 new or added lines in 4 files covered. (69.79%)

62 existing lines in 11 files now uncovered.

242847 of 264443 relevant lines covered (91.83%)

5989046.65 hits per line

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

94.18
/src/realm/table_view.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/table_view.hpp>
20
#include <realm/column_integer.hpp>
21
#include <realm/index_string.hpp>
22
#include <realm/transaction.hpp>
23

24
#include <unordered_set>
25

26
using namespace realm;
27

28
TableView::TableView(TableView& src, Transaction* tr, PayloadPolicy policy_mode)
29
    : m_source_column_key(src.m_source_column_key)
30
{
63,498✔
31
    bool was_in_sync = src.is_in_sync();
63,498✔
32
    if (src.m_query)
63,498✔
33
        m_query = Query(*src.m_query, tr, policy_mode);
62,892✔
34
    m_table = tr->import_copy_of(src.m_table);
63,498✔
35

31,656✔
36
    if (policy_mode == PayloadPolicy::Stay)
63,498✔
37
        was_in_sync = false;
96✔
38

31,656✔
39
    VersionID src_version =
63,498✔
40
        dynamic_cast<Transaction*>(src.m_table->get_parent_group())->get_version_of_current_transaction();
63,498✔
41
    if (src_version != tr->get_version_of_current_transaction())
63,498✔
42
        was_in_sync = false;
18✔
43

31,656✔
44
    m_table = tr->import_copy_of(src.m_table);
63,498✔
45
    m_collection_source = tr->import_copy_of(src.m_collection_source);
63,498✔
46
    if (src.m_source_column_key) {
63,498✔
47
        m_linked_obj = tr->import_copy_of(src.m_linked_obj);
606✔
48
    }
606✔
49

31,656✔
50
    if (was_in_sync)
63,498✔
51
        get_dependencies(m_last_seen_versions);
63,378✔
52

31,656✔
53
    // don't use methods which throw after this point...or m_table_view_key_values will leak
31,656✔
54
    if (policy_mode == PayloadPolicy::Copy && src.m_key_values.is_attached()) {
63,498✔
55
        m_key_values = src.m_key_values;
702✔
56
    }
702✔
57
    else if (policy_mode == PayloadPolicy::Move && src.m_key_values.is_attached())
62,796✔
58
        // Requires that 'src' is a writable object
31,257✔
59
        m_key_values = std::move(src.m_key_values);
62,700✔
60
    else {
96✔
61
        m_key_values.create();
96✔
62
    }
96✔
63
    if (policy_mode == PayloadPolicy::Move) {
63,498✔
64
        src.m_last_seen_versions.clear();
62,700✔
65
    }
62,700✔
66
    m_descriptor_ordering = src.m_descriptor_ordering;
63,498✔
67
    m_limit = src.m_limit;
63,498✔
68
}
63,498✔
69

70
// Aggregates ----------------------------------------------------
71

72
template <typename T, Action AggregateOpType>
73
struct Aggregator {
74
};
75

76
template <typename T>
77
struct Aggregator<T, act_Sum> {
78
    using AggType = typename aggregate_operations::Sum<typename util::RemoveOptional<T>::type>;
79
};
80

81
template <typename T>
82
struct Aggregator<T, act_Average> {
83
    using AggType = typename aggregate_operations::Average<typename util::RemoveOptional<T>::type>;
84
};
85

86
template <typename T>
87
struct Aggregator<T, act_Min> {
88
    using AggType = typename aggregate_operations::Minimum<typename util::RemoveOptional<T>::type>;
89
};
90

91
template <typename T>
92
struct Aggregator<T, act_Max> {
93
    using AggType = typename aggregate_operations::Maximum<typename util::RemoveOptional<T>::type>;
94
};
95

96
template <Action action, typename T>
97
Mixed TableView::aggregate(ColKey column_key, size_t* result_count, ObjKey* return_key) const
98
{
4,230✔
99
    static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Average);
4,230✔
100
    REALM_ASSERT(m_table->valid_column(column_key));
4,230!
101

2,115✔
102
    size_t non_nulls = 0;
4,230✔
103
    typename Aggregator<T, action>::AggType agg;
4,230✔
104
    ObjKey last_accumulated_key = null_key;
4,230✔
105
    for (size_t tv_index = 0; tv_index < m_key_values.size(); ++tv_index) {
58,308!
106
        ObjKey key(get_key(tv_index));
54,078✔
107

27,474✔
108
        // skip detached references:
27,474✔
109
        if (key == realm::null_key)
54,078!
110
            continue;
×
111

27,474✔
112
        const Obj obj = m_table->try_get_object(key);
54,078✔
113
        // aggregation must be robust in the face of stale keys:
27,474✔
114
        if (!obj.is_valid())
54,078!
115
            continue;
24✔
116

27,462✔
117
        if (obj.is_null(column_key))
54,054!
118
            continue;
8,958✔
119

22,638✔
120
        auto v = obj.get<T>(column_key);
45,096✔
121
        if (agg.accumulate(v)) {
45,096!
122
            ++non_nulls;
30,744✔
123
            if constexpr (action == act_Min || action == act_Max) {
30,744✔
124
                last_accumulated_key = key;
15,096✔
125
            }
15,096✔
126
        }
30,744✔
127
    }
45,096✔
128

2,115✔
129
    if (result_count)
4,230!
130
        *result_count = non_nulls;
696✔
131

2,115✔
132
    if constexpr (action == act_Max || action == act_Min) {
4,230✔
133
        if (return_key) {
2,532!
134
            *return_key = last_accumulated_key;
2,040✔
135
        }
2,040✔
136
    }
2,532✔
137
    else {
1,698✔
138
        static_cast<void>(last_accumulated_key);
1,698✔
139
        static_cast<void>(return_key);
1,698✔
140
    }
1,698✔
141

2,115✔
142
    if (!agg.is_null()) {
4,230!
143
        return agg.result();
3,330✔
144
    }
3,330✔
145
    if (action == act_Sum) {
900✔
146
        if (std::is_same_v<T, Mixed>) {
×
147
            return Decimal128{0};
×
148
        }
×
149
        return T{};
×
150
    }
×
151
    return Mixed();
900✔
152
}
900✔
153

154
template <typename T>
155
size_t TableView::aggregate_count(ColKey column_key, T count_target) const
156
{
48✔
157
    REALM_ASSERT(m_table->valid_column(column_key));
48!
158

24✔
159
    if ((m_key_values.size()) == 0) {
48!
160
        return {};
×
161
    }
×
162

24✔
163
    size_t cnt = 0;
48✔
164
    for (size_t tv_index = 0; tv_index < m_key_values.size(); ++tv_index) {
240!
165
        ObjKey key(get_key(tv_index));
192✔
166

96✔
167
        // skip detached references:
96✔
168
        if (key == realm::null_key)
192!
169
            continue;
×
170

96✔
171
        const Obj obj = m_table->try_get_object(key);
192✔
172
        if (!obj.is_valid())
192!
173
            continue;
×
174

96✔
175
        auto v = obj.get<T>(column_key);
192✔
176
        if (v == count_target) {
192!
177
            cnt++;
102✔
178
        }
102✔
179
    }
192✔
180

24✔
181
    return cnt;
48✔
182
}
48✔
183

184
// Count
185
size_t TableView::count_int(ColKey column_key, int64_t target) const
186
{
12✔
187
    if (m_table->is_nullable(column_key))
12✔
188
        return aggregate_count<util::Optional<int64_t>>(column_key, target);
×
189
    else
12✔
190
        return aggregate_count<int64_t>(column_key, target);
12✔
191
}
12✔
192
size_t TableView::count_float(ColKey column_key, float target) const
193
{
12✔
194
    return aggregate_count<float>(column_key, target);
12✔
195
}
12✔
196
size_t TableView::count_double(ColKey column_key, double target) const
197
{
12✔
198
    return aggregate_count<double>(column_key, target);
12✔
199
}
12✔
200
size_t TableView::count_timestamp(ColKey column_key, Timestamp target) const
201
{
12✔
202
    return aggregate_count<Timestamp>(column_key, target);
12✔
203
}
12✔
204
size_t TableView::count_decimal(ColKey column_key, Decimal128 target) const
205
{
×
206
    return aggregate_count<Decimal128>(column_key, target);
×
207
}
×
208
size_t TableView::count_mixed(ColKey column_key, Mixed target) const
209
{
×
210
    return aggregate_count<Mixed>(column_key, target);
×
211
}
×
212

213
template <Action action>
214
std::optional<Mixed> TableView::aggregate(ColKey column_key, size_t* count, ObjKey* return_key) const
215
{
4,422✔
216
    static_assert(action == act_Sum || action == act_Max || action == act_Min || action == act_Average);
4,422✔
217
    m_table->check_column(column_key);
4,422✔
218
    if (column_key.is_collection()) {
4,422✔
219
        return std::nullopt;
48✔
220
    }
48✔
221

2,187✔
222
    switch (column_key.get_type()) {
4,374✔
223
        case col_type_Int:
1,596✔
224
            if (m_table->is_nullable(column_key))
1,596✔
225
                return aggregate<action, util::Optional<int64_t>>(column_key, count, return_key);
1,470✔
226
            return aggregate<action, int64_t>(column_key, count, return_key);
126✔
227
        case col_type_Float:
1,506✔
228
            return aggregate<action, float>(column_key, count, return_key);
1,506✔
229
        case col_type_Double:
342✔
230
            return aggregate<action, double>(column_key, count, return_key);
342✔
231
        case col_type_Timestamp:
99✔
232
            if constexpr (action == act_Min || action == act_Max) {
858✔
233
                return aggregate<action, Timestamp>(column_key, count, return_key);
786✔
234
            }
786✔
235
            break;
×
236
        case col_type_Decimal:
✔
237
            return aggregate<action, Decimal128>(column_key, count, return_key);
×
238
        case col_type_Mixed:
✔
239
            return aggregate<action, Mixed>(column_key, count, return_key);
×
240
        default:
✔
241
            break;
×
242
    }
72✔
243
    return util::none;
72✔
244
}
72✔
245

246
util::Optional<Mixed> TableView::min(ColKey column_key, ObjKey* return_key) const
247
{
1,290✔
248
    return aggregate<act_Min>(column_key, nullptr, return_key);
1,290✔
249
}
1,290✔
250

251
util::Optional<Mixed> TableView::max(ColKey column_key, ObjKey* return_key) const
252
{
1,302✔
253
    return aggregate<act_Max>(column_key, nullptr, return_key);
1,302✔
254
}
1,302✔
255

256
util::Optional<Mixed> TableView::sum(ColKey column_key) const
257
{
900✔
258
    return aggregate<act_Sum>(column_key, nullptr, nullptr);
900✔
259
}
900✔
260

261
util::Optional<Mixed> TableView::avg(ColKey column_key, size_t* value_count) const
262
{
930✔
263
    return aggregate<act_Average>(column_key, value_count, nullptr);
930✔
264
}
930✔
265

266
void TableView::to_json(std::ostream& out, JSONOutputMode mode) const
267
{
36✔
268
    // Represent table as list of objects
18✔
269
    out << "[";
36✔
270

18✔
271
    const size_t row_count = size();
36✔
272
    bool first = true;
36✔
273
    for (size_t r = 0; r < row_count; ++r) {
468✔
274
        if (ObjKey key = get_key(r)) {
432✔
275
            if (first) {
432✔
276
                first = false;
36✔
277
            }
36✔
278
            else {
396✔
279
                out << ",";
396✔
280
            }
396✔
281
            m_table->get_object(key).to_json(out, mode);
432✔
282
        }
432✔
283
    }
432✔
284

18✔
285
    out << "]";
36✔
286
}
36✔
287

288
bool TableView::depends_on_deleted_object() const
289
{
42✔
290
    if (m_collection_source) {
42✔
291
        return !m_collection_source->get_owning_obj().is_valid();
12✔
292
    }
12✔
293

15✔
294
    if (m_source_column_key && !m_linked_obj.is_valid()) {
30✔
295
        return true;
12✔
296
    }
12✔
297
    else if (m_query && m_query->m_source_table_view) {
18✔
298
        return m_query->m_source_table_view->depends_on_deleted_object();
6✔
299
    }
6✔
300
    return false;
12✔
301
}
12✔
302

303
void TableView::get_dependencies(TableVersions& ret) const
304
{
1,903,620✔
305
    auto table = m_table ? m_table.unchecked_ptr() : nullptr;
2,148,459,910✔
306
    if (m_source_column_key && m_linked_obj) {
1,903,620✔
307
        // m_source_column_key is set when this TableView was created by Table::get_backlink_view().
1,056✔
308
        if (auto linked_table = m_linked_obj.get_table()) {
2,112✔
309
            ret.emplace_back(linked_table->get_key(), linked_table->get_content_version());
2,112✔
310
        }
2,112✔
311
    }
2,112✔
312
    else if (m_query) {
1,921,191✔
313
        m_query->get_outside_versions(ret);
1,910,541✔
314
    }
1,910,541✔
315
    else {
2,147,494,297✔
316
        // This TableView was created by Table::get_distinct_view() or get_sorted_view() on collections
2,147,483,647✔
317
        ret.emplace_back(table->get_key(), table->get_content_version());
2,147,494,297✔
318
    }
2,147,494,297✔
319

919,788✔
320
    // Finally add dependencies from sort/distinct
919,788✔
321
    if (table) {
1,957,734✔
322
        m_descriptor_ordering.get_versions(table->get_parent_group(), ret);
1,952,910✔
323
    }
1,952,910✔
324
}
1,903,620✔
325

326
bool TableView::is_in_sync() const
327
{
282,942✔
328
    return m_table && !has_changed();
282,948✔
329
}
282,942✔
330

331
void TableView::sync_if_needed() const
332
{
165,636✔
333
    if (!is_in_sync()) {
165,636✔
334
        // FIXME: Is this a reasonable handling of constness?
28,431✔
335
        const_cast<TableView*>(this)->do_sync();
56,955✔
336
    }
56,955✔
337
}
165,636✔
338

339
void TableView::update_query(const Query& q)
340
{
12✔
341
    REALM_ASSERT(m_query);
12✔
342
    REALM_ASSERT(m_query->m_table);
12✔
343
    REALM_ASSERT(m_query->m_table == q.m_table);
12✔
344

6✔
345
    m_query = q;
12✔
346
    do_sync();
12✔
347
}
12✔
348

349
void TableView::clear()
350
{
5,706✔
351
    m_table.check();
5,706✔
352

2,853✔
353
    // If distinct is applied then removing an object may leave us out of sync
2,853✔
354
    // if there's another object with the same value in the distinct column
2,853✔
355
    // as the removed object
2,853✔
356
    bool sync_to_keep =
5,706✔
357
        m_last_seen_versions == get_dependency_versions() && !m_descriptor_ordering.will_apply_distinct();
5,706✔
358

2,853✔
359
    // Remove all invalid keys
2,853✔
360
    auto it = std::remove_if(m_key_values.begin(), m_key_values.end(), [this](const ObjKey& key) {
2,511,612✔
361
        return !m_table->is_valid(key);
2,511,612✔
362
    });
2,511,612✔
363
    m_key_values.erase(it, m_key_values.end());
5,706✔
364

2,853✔
365
    _impl::TableFriend::batch_erase_objects(*get_parent(), m_key_values); // Throws
5,706✔
366

2,853✔
367
    // It is important to not accidentally bring us in sync, if we were
2,853✔
368
    // not in sync to start with:
2,853✔
369
    if (sync_to_keep)
5,706✔
370
        m_last_seen_versions = get_dependency_versions();
5,688✔
371
}
5,706✔
372

373
void TableView::distinct(ColKey column)
374
{
144✔
375
    distinct(DistinctDescriptor({{column}}));
144✔
376
}
144✔
377

378
/// Remove rows that are duplicated with respect to the column set passed as argument.
379
/// Will keep original sorting order so that you can both have a distinct and sorted view.
380
void TableView::distinct(DistinctDescriptor columns)
381
{
432✔
382
    m_descriptor_ordering.append_distinct(std::move(columns));
432✔
383
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
432✔
384

216✔
385
    do_sync();
432✔
386
}
432✔
387

388
void TableView::limit(LimitDescriptor lim)
389
{
12✔
390
    m_descriptor_ordering.append_limit(std::move(lim));
12✔
391
    do_sync();
12✔
392
}
12✔
393

394
void TableView::filter(FilterDescriptor filter)
395
{
12✔
396
    m_descriptor_ordering.append_filter(std::move(filter));
12✔
397
    do_sync();
12✔
398
}
12✔
399

400
void TableView::apply_descriptor_ordering(const DescriptorOrdering& new_ordering)
401
{
45,189✔
402
    m_descriptor_ordering = new_ordering;
45,189✔
403
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
45,189✔
404

22,731✔
405
    do_sync();
45,189✔
406
}
45,189✔
407

408
std::string TableView::get_descriptor_ordering_description() const
409
{
18✔
410
    return m_descriptor_ordering.get_description(m_table);
18✔
411
}
18✔
412

413
// Sort according to one column
414
void TableView::sort(ColKey column, bool ascending)
415
{
438✔
416
    sort(SortDescriptor({{column}}, {ascending}));
438✔
417
}
438✔
418

419
// Sort according to multiple columns, user specified order on each column
420
void TableView::sort(SortDescriptor order)
421
{
1,008✔
422
    m_descriptor_ordering.append_sort(std::move(order), SortDescriptor::MergeMode::prepend);
1,008✔
423
    m_descriptor_ordering.collect_dependencies(m_table.unchecked_ptr());
1,008✔
424

504✔
425
    apply_descriptors(m_descriptor_ordering);
1,008✔
426
}
1,008✔
427

428

429
void TableView::do_sync()
430
{
1,501,686✔
431
    util::CriticalSection cs(m_race_detector);
1,501,686✔
432
    // This TableView can be "born" from 4 different sources:
708,636✔
433
    // - LinkView
708,636✔
434
    // - Query::find_all()
708,636✔
435
    // - Table::get_distinct_view()
708,636✔
436
    // - Table::get_backlink_view()
708,636✔
437
    // Here we sync with the respective source.
708,636✔
438
    m_last_seen_versions.clear();
1,501,686✔
439

708,636✔
440
    if (m_collection_source) {
1,501,686✔
441
        m_key_values.clear();
102✔
442
        auto sz = m_collection_source->size();
102✔
443
        for (size_t i = 0; i < sz; i++) {
330✔
444
            m_key_values.add(m_collection_source->get_key(i));
228✔
445
        }
228✔
446
    }
102✔
447
    else if (m_source_column_key) {
1,501,584✔
448
        m_key_values.clear();
756✔
449
        if (m_table && m_linked_obj.is_valid()) {
756✔
450
            if (m_table->valid_column(m_source_column_key)) { // return empty result, if column has been removed
744✔
451
                ColKey backlink_col = m_table->get_opposite_column(m_source_column_key);
738✔
452
                REALM_ASSERT(backlink_col);
738✔
453
                auto backlinks = m_linked_obj.get_all_backlinks(backlink_col);
738✔
454
                for (auto k : backlinks) {
723✔
455
                    m_key_values.add(k);
708✔
456
                }
708✔
457
            }
738✔
458
        }
744✔
459
    }
756✔
460
    // FIXME: Unimplemented for link to a column
708,207✔
461
    else {
1,500,828✔
462
        REALM_ASSERT(m_query);
1,500,828✔
463
        m_query->m_table.check();
1,500,828✔
464

708,207✔
465
        // valid query, so clear earlier results and reexecute it.
708,207✔
466
        if (m_key_values.is_attached())
1,500,828✔
467
            m_key_values.clear();
1,519,755✔
468
        else
4,294,967,294✔
469
            m_key_values.create();
4,294,967,294✔
470

708,207✔
471
        if (m_query->m_view)
1,500,828✔
472
            m_query->m_view->sync_if_needed();
1,101✔
473
        size_t limit = m_limit;
1,500,828✔
474
        if (!m_descriptor_ordering.is_empty()) {
1,500,828✔
475
            auto type = m_descriptor_ordering[0]->get_type();
36,975✔
476
            if (type == DescriptorType::Limit) {
36,975✔
477
                size_t l = static_cast<const LimitDescriptor*>(m_descriptor_ordering[0])->get_limit();
138✔
478
                if (l < limit)
138✔
479
                    limit = l;
138✔
480
            }
138✔
481
        }
36,975✔
482
        QueryStateFindAll<std::vector<ObjKey>> st(m_key_values, limit);
1,500,828✔
483
        m_query->do_find_all(st);
1,500,828✔
484
    }
1,500,828✔
485

708,636✔
486
    apply_descriptors(m_descriptor_ordering);
1,501,686✔
487

708,636✔
488
    get_dependencies(m_last_seen_versions);
1,501,686✔
489
}
1,501,686✔
490

491
void TableView::apply_descriptors(const DescriptorOrdering& ordering)
492
{
1,585,593✔
493
    if (ordering.is_empty())
1,585,593✔
494
        return;
1,603,146✔
495
    size_t sz = size();
2,147,504,872✔
496
    if (sz == 0)
2,147,504,872✔
497
        return;
18,699✔
498

2,147,483,647✔
499
    // Gather the current rows into a container we can use std algorithms on
2,147,483,647✔
500
    size_t detached_ref_count = 0;
2,147,495,689✔
501
    BaseDescriptor::IndexPairs index_pairs;
2,147,495,689✔
502
    bool using_indexpairs = false;
2,147,495,689✔
503

2,147,483,647✔
504
    auto apply_indexpairs = [&] {
2,147,493,217✔
505
        m_key_values.clear();
19,143✔
506
        for (auto& pair : index_pairs) {
183,480✔
507
            m_key_values.add(pair.key_for_object);
183,480✔
508
        }
183,480✔
509
        for (size_t t = 0; t < detached_ref_count; ++t)
19,143✔
510
            m_key_values.add(null_key);
×
511
        using_indexpairs = false;
19,143✔
512
    };
19,143✔
513

2,147,483,647✔
514
    auto use_indexpairs = [&] {
2,147,493,229✔
515
        index_pairs.reserve(sz);
19,167✔
516
        index_pairs.clear();
19,167✔
517
        // always put any detached refs at the end of the sort
9,585✔
518
        // FIXME: reconsider if this is the right thing to do
9,585✔
519
        // FIXME: consider specialized implementations in derived classes
9,585✔
520
        // (handling detached refs is not required in linkviews)
9,585✔
521
        for (size_t t = 0; t < sz; t++) {
264,969✔
522
            ObjKey key = get_key(t);
245,802✔
523
            if (m_table->is_valid(key)) {
245,802✔
524
                index_pairs.emplace_back(key, t);
245,802✔
525
            }
245,802✔
UNCOV
526
            else
×
UNCOV
527
                ++detached_ref_count;
×
528
        }
245,802✔
529
        using_indexpairs = true;
19,167✔
530
    };
19,167✔
531

2,147,483,647✔
532
    const int num_descriptors = int(ordering.size());
2,147,495,689✔
533
    for (int desc_ndx = 0; desc_ndx < num_descriptors; ++desc_ndx) {
2,147,506,900✔
534
        const BaseDescriptor* base_descr = ordering[desc_ndx];
22,434✔
535
        const BaseDescriptor* next = ((desc_ndx + 1) < num_descriptors) ? ordering[desc_ndx + 1] : nullptr;
20,853✔
536

11,223✔
537
        // Some descriptors, like Sort and Distinct, needs us to gather the current rows
11,223✔
538
        // into a container we can use std algorithms on
11,223✔
539
        if (base_descr->need_indexpair()) {
22,434✔
540
            if (!using_indexpairs) {
19,773✔
541
                use_indexpairs();
19,167✔
542
            }
19,167✔
543

9,888✔
544
            BaseDescriptor::Sorter predicate = base_descr->sorter(*m_table, index_pairs);
19,773✔
545

9,888✔
546
            // Sorting can be specified by multiple columns, so that if two entries in the first column are
9,888✔
547
            // identical, then the rows are ordered according to the second column, and so forth. For the
9,888✔
548
            // first column, we cache all the payload of fields of the view in a std::vector<Mixed>
9,888✔
549
            predicate.cache_first_column(index_pairs);
19,773✔
550

9,888✔
551
            base_descr->execute(index_pairs, predicate, next);
19,773✔
552
        }
19,773✔
553
        else {
2,661✔
554
            if (using_indexpairs) {
2,661✔
555
                apply_indexpairs();
2,433✔
556
            }
2,433✔
557
            base_descr->execute(*m_table, m_key_values, next);
2,661✔
558
            sz = size();
2,661✔
559
        }
2,661✔
560
    }
22,434✔
561
    // Apply the results
2,147,483,647✔
562
    if (using_indexpairs) {
2,147,495,689✔
563
        apply_indexpairs();
16,710✔
564
    }
16,710✔
565
}
2,147,495,689✔
566

567
bool TableView::is_in_table_order() const
568
{
3,342✔
569
    if (!m_table) {
3,342✔
570
        return false;
6✔
571
    }
6✔
572
    else if (m_collection_source) {
3,336✔
573
        return false;
6✔
574
    }
6✔
575
    else if (m_source_column_key) {
3,330✔
576
        return false;
6✔
577
    }
6✔
578
    else if (!m_query) {
3,324✔
579
        return false;
66✔
580
    }
66✔
581
    else {
3,258✔
582
        m_query->m_table.check();
3,258✔
583
        return m_query->produces_results_in_table_order() && !m_descriptor_ordering.will_apply_sort();
3,258✔
584
    }
3,258✔
585
}
3,342✔
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