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

paulmthompson / WhiskerToolbox / 18008514883

25 Sep 2025 01:08PM UTC coverage: 68.869% (-0.05%) from 68.919%
18008514883

push

github

paulmthompson
dlc loader for csv files

92 of 102 new or added lines in 3 files covered. (90.2%)

680 existing lines in 10 files now uncovered.

41941 of 60900 relevant lines covered (68.87%)

1139.5 hits per line

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

57.89
/src/DataManager/utils/TableView/core/TableView.cpp
1
#include "TableView.h"
2

3
#include "utils/TableView/adapters/DataManagerExtension.h"
4
#include "utils/TableView/columns/IColumn.h"
5
#include "utils/TableView/interfaces/IAnalogSource.h"
6
#include "utils/TableView/interfaces/IEventSource.h"
7
#include "utils/TableView/interfaces/IIntervalSource.h"
8
#include "utils/TableView/interfaces/ILineSource.h"
9
#include "utils/TableView/interfaces/IPointSource.h"
10
#include "utils/TableView/interfaces/IRowSelector.h"
11

12

13
#include <algorithm>
14
#include <optional>
15
#include <set>
16
#include <stdexcept>
17
#include <variant>
18

19
namespace {
20

21
// Utility to create an overloaded set for std::visit
22
template<class... Ts> struct Overloaded : Ts... { using Ts::operator()...; };
23
template<class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
24

25
// Visitor over IRowSelector without exposing dynamic_casts at call sites
26
template<typename FInterval, typename FTimestamp, typename FIndex>
27
ExecutionPlan visitSelector(IRowSelector const & selector,
121✔
28
                            FInterval && onInterval,
29
                            FTimestamp && onTimestamp,
30
                            FIndex && onIndex) {
31
    if (auto s = dynamic_cast<IntervalSelector const *>(&selector)) {
121✔
32
        return onInterval(*s);
71✔
33
    }
34
    if (auto s = dynamic_cast<TimestampSelector const *>(&selector)) {
50✔
35
        return onTimestamp(*s);
50✔
36
    }
37
    if (auto s = dynamic_cast<IndexSelector const *>(&selector)) {
×
38
        return onIndex(*s);
×
39
    }
40
    throw std::runtime_error("Unknown IRowSelector concrete type");
×
41
}
42

43
// Analog source -> plan
44
ExecutionPlan makePlanFromAnalog(std::shared_ptr<IAnalogSource> const & /*analog*/,
48✔
45
                                 IRowSelector const & selector) {
46
    return visitSelector(
47
        selector,
48
        // Interval
49
        [&](IntervalSelector const & intervalSelector) {
48✔
50
            return ExecutionPlan(intervalSelector.getIntervals(), intervalSelector.getTimeFrame());
25✔
51
        },
52
        // Timestamp
53
        [&](TimestampSelector const & timestampSelector) {
48✔
54
            return ExecutionPlan(timestampSelector.getTimestamps(), timestampSelector.getTimeFrame());
23✔
55
        },
56
        // Index
57
        [&](IndexSelector const & indexSelector) {
48✔
UNCOV
58
            std::vector<TimeFrameIndex> timeFrameIndices;
×
UNCOV
59
            auto const & indices = indexSelector.getIndices();
×
UNCOV
60
            timeFrameIndices.reserve(indices.size());
×
UNCOV
61
            for (size_t index : indices) {
×
UNCOV
62
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
63
            }
UNCOV
64
            std::cout << "WARNING: IndexSelector is not supported for analog data" << std::endl;
×
UNCOV
65
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
UNCOV
66
        }
×
67
    );
96✔
68
}
69

70
// Interval source -> plan
71
ExecutionPlan makePlanFromInterval(std::shared_ptr<IIntervalSource> const & /*interval*/,
30✔
72
                                   IRowSelector const & selector) {
73
    return visitSelector(
74
        selector,
75
        [&](IntervalSelector const & intervalSelector) {
30✔
76
            return ExecutionPlan(intervalSelector.getIntervals(), intervalSelector.getTimeFrame());
22✔
77
        },
78
        [&](TimestampSelector const & timestampSelector) {
30✔
79
            return ExecutionPlan(timestampSelector.getTimestamps(), timestampSelector.getTimeFrame());
8✔
80
        },
81
        [&](IndexSelector const & indexSelector) {
30✔
UNCOV
82
            std::vector<TimeFrameIndex> timeFrameIndices;
×
UNCOV
83
            auto const & indices = indexSelector.getIndices();
×
UNCOV
84
            timeFrameIndices.reserve(indices.size());
×
UNCOV
85
            for (size_t index : indices) {
×
UNCOV
86
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
87
            }
88
            std::cout << "WARNING: IndexSelector is not supported for interval data" << std::endl;
×
UNCOV
89
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
UNCOV
90
        }
×
91
    );
60✔
92
}
93

94
// Event source -> plan
95
ExecutionPlan makePlanFromEvent(std::shared_ptr<IEventSource> const & /*event*/,
24✔
96
                                IRowSelector const & selector) {
97
    return visitSelector(
98
        selector,
99
        [&](IntervalSelector const & intervalSelector) {
24✔
100
            return ExecutionPlan(intervalSelector.getIntervals(), intervalSelector.getTimeFrame());
24✔
101
        },
102
        [&](TimestampSelector const & timestampSelector) {
24✔
UNCOV
103
            return ExecutionPlan(timestampSelector.getTimestamps(), timestampSelector.getTimeFrame());
×
104
        },
105
        [&](IndexSelector const & indexSelector) {
24✔
UNCOV
106
            std::vector<TimeFrameIndex> timeFrameIndices;
×
UNCOV
107
            auto const & indices = indexSelector.getIndices();
×
UNCOV
108
            timeFrameIndices.reserve(indices.size());
×
UNCOV
109
            for (size_t index : indices) {
×
UNCOV
110
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
111
            }
UNCOV
112
            std::cout << "WARNING: IndexSelector is not supported for event data" << std::endl;
×
UNCOV
113
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
UNCOV
114
        }
×
115
    );
48✔
116
}
117

118
// Line source -> plan (needs columns and dm for entity expansion decision + ids)
119
ExecutionPlan makePlanFromLine(std::shared_ptr<ILineSource> const & lineSource,
18✔
120
                               IRowSelector const & selector,
121
                               std::vector<std::shared_ptr<IColumn>> const & columns,
122
                               DataManagerExtension & dm) {
123
    return visitSelector(
124
        selector,
125
        // IntervalSelector: legacy (no expansion)
126
        [&](IntervalSelector const & intervalSelector) {
18✔
UNCOV
127
            return ExecutionPlan(intervalSelector.getIntervals(), intervalSelector.getTimeFrame());
×
128
        },
129
        // TimestampSelector: entity expansion
130
        [&](TimestampSelector const & timestampSelector) {
18✔
131
            auto const & timestamps = timestampSelector.getTimestamps();
18✔
132
            auto timeFrame = timestampSelector.getTimeFrame();
18✔
133

134
            ExecutionPlan plan(std::vector<TimeFrameIndex>{}, timeFrame);
18✔
135

136
            // Determine if table contains any non-line columns; if so include singleton rows
137
            bool anyNonLineColumn = false;
18✔
138
            for (auto const & col : columns) {
146✔
139
                try {
140
                    auto const & dep = col->getSourceDependency();
129✔
141
                    if (!dm.getLineSource(dep)) {
129✔
142
                        anyNonLineColumn = true;
1✔
143
                        break;
1✔
144
                    }
145
                } catch (...) {
129✔
UNCOV
146
                }
×
147
            }
148

149
            std::vector<RowId> rows;
18✔
150
            rows.reserve(timestamps.size());
18✔
151
            std::map<TimeFrameIndex, std::pair<size_t, size_t>> spans;
18✔
152

153
            size_t cursor = 0;
18✔
154
            for (auto const & t : timestamps) {
76✔
155
                auto const count = lineSource->getEntityCountAt(t);
58✔
156
                if (count == 0) {
58✔
157
                    if (anyNonLineColumn) {
8✔
158
                        spans.emplace(t, std::make_pair(cursor, static_cast<size_t>(1)));
3✔
159
                        rows.push_back(RowId{t, std::nullopt});
3✔
160
                        ++cursor;
3✔
161
                    }
162
                } else {
163
                    spans.emplace(t, std::make_pair(cursor, static_cast<size_t>(count)));
50✔
164
                    for (size_t i = 0; i < count; ++i) {
129✔
165
                        rows.push_back(RowId{t, static_cast<int>(i)});
79✔
166
                        ++cursor;
79✔
167
                    }
168
                }
169
            }
170

171
            plan.setRows(std::move(rows));
18✔
172
            plan.setTimeToRowSpan(std::move(spans));
18✔
173
            plan.setSourceId(DataSourceNameInterner::instance().intern(lineSource->getName()));
18✔
174
            plan.setSourceKind(ExecutionPlan::DataSourceKind::Line);
18✔
175
            return plan;
36✔
176
        },
18✔
177
        // IndexSelector: unsupported
178
        [&](IndexSelector const & indexSelector) {
18✔
UNCOV
179
            std::vector<TimeFrameIndex> timeFrameIndices;
×
180
            auto const & indices = indexSelector.getIndices();
×
UNCOV
181
            timeFrameIndices.reserve(indices.size());
×
UNCOV
182
            for (size_t index : indices) {
×
UNCOV
183
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
184
            }
UNCOV
185
            std::cout << "WARNING: IndexSelector is not supported for line data" << std::endl;
×
UNCOV
186
            auto plan = ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
UNCOV
187
            plan.setSourceId(DataSourceNameInterner::instance().intern(lineSource->getName()));
×
UNCOV
188
            plan.setSourceKind(ExecutionPlan::DataSourceKind::Line);
×
UNCOV
189
            return plan;
×
UNCOV
190
        }
×
191
    );
36✔
192
}
193

194
// Point source -> plan (treat similar to event/interval/timestamp)
UNCOV
195
ExecutionPlan makePlanFromPoint(std::shared_ptr<IPointSource> const & /*point*/,
×
196
                                IRowSelector const & selector) {
197
    return visitSelector(
198
        selector,
UNCOV
199
        [&](IntervalSelector const & intervalSelector) {
×
UNCOV
200
            return ExecutionPlan(intervalSelector.getIntervals(), intervalSelector.getTimeFrame());
×
201
        },
UNCOV
202
        [&](TimestampSelector const & timestampSelector) {
×
UNCOV
203
            return ExecutionPlan(timestampSelector.getTimestamps(), timestampSelector.getTimeFrame());
×
204
        },
UNCOV
205
        [&](IndexSelector const & indexSelector) {
×
UNCOV
206
            std::vector<TimeFrameIndex> timeFrameIndices;
×
UNCOV
207
            auto const & indices = indexSelector.getIndices();
×
UNCOV
208
            timeFrameIndices.reserve(indices.size());
×
UNCOV
209
            for (size_t index : indices) {
×
UNCOV
210
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
211
            }
UNCOV
212
            std::cout << "WARNING: IndexSelector is not supported for point data" << std::endl;
×
213
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
214
        }
×
UNCOV
215
    );
×
216
}
217

218
} // namespace
219

220
TableView::TableView(std::unique_ptr<IRowSelector> rowSelector,
112✔
221
                     std::shared_ptr<DataManagerExtension> dataManager)
112✔
222
    : m_rowSelector(std::move(rowSelector)),
112✔
223
      m_dataManager(std::move(dataManager)) {
112✔
224
    if (!m_rowSelector) {
112✔
UNCOV
225
        throw std::invalid_argument("IRowSelector cannot be null");
×
226
    }
227
    if (!m_dataManager) {
112✔
UNCOV
228
        throw std::invalid_argument("DataManagerExtension cannot be null");
×
229
    }
230
}
112✔
231

232
TableView::TableView(TableView && other) noexcept
47✔
233
    : m_rowSelector(std::move(other.m_rowSelector)),
47✔
234
      m_dataManager(std::move(other.m_dataManager)),
47✔
235
      m_columns(std::move(other.m_columns)),
47✔
236
      m_colNameToIndex(std::move(other.m_colNameToIndex)),
47✔
237
      m_planCache(std::move(other.m_planCache)),
47✔
238
      m_direct_entity_ids(std::move(other.m_direct_entity_ids)) {}
47✔
239

UNCOV
240
TableView & TableView::operator=(TableView && other) {
×
UNCOV
241
    if (this != &other) {
×
UNCOV
242
        m_rowSelector = std::move(other.m_rowSelector);
×
UNCOV
243
        m_dataManager = std::move(other.m_dataManager);
×
UNCOV
244
        m_columns = std::move(other.m_columns);
×
UNCOV
245
        m_colNameToIndex = std::move(other.m_colNameToIndex);
×
246
        m_planCache = std::move(other.m_planCache);
×
247
        m_direct_entity_ids = std::move(other.m_direct_entity_ids);
×
248
    }
249
    return *this;
×
250
}
251

252
size_t TableView::getRowCount() const {
322✔
253
    // Prefer expanded row count if any execution plan has entity-expanded rows cached
254
    for (auto const & entry : m_planCache) {
568✔
255
        if (!entry.second.getRows().empty()) {
265✔
256
            return entry.second.getRows().size();
19✔
257
        }
258
    }
259
    // If nothing cached yet, proactively attempt expansion using a line-source dependent column
260
    // Find a column whose source is an ILineSource
261
    for (auto const & column : m_columns) {
1,590✔
262
        try {
263
            auto const & dep = column->getSourceDependency();
1,301✔
264
            // Query line source without mutating the cache in a surprising way
265
            auto lineSource = m_dataManager->getLineSource(dep);
1,301✔
266
            if (lineSource) {
1,301✔
267
                // Trigger plan generation for this source to populate expansion rows
268
                auto & self = const_cast<TableView &>(*this);
14✔
269
                ExecutionPlan const & plan = self.getExecutionPlanFor(dep);
14✔
270
                if (!plan.getRows().empty()) {
14✔
271
                    return plan.getRows().size();
13✔
272
                }
273
                break; // only expand based on the first line source column
1✔
274
            }
275
        } catch (...) {
1,315✔
276
            // Ignore and continue
277
        }
×
278
    }
279
    return m_rowSelector->getRowCount();
290✔
280
}
281

282
size_t TableView::getColumnCount() const {
63✔
283
    return m_columns.size();
63✔
284
}
285

286
std::vector<std::string> TableView::getColumnNames() const {
64✔
287
    std::vector<std::string> names;
64✔
288
    names.reserve(m_columns.size());
64✔
289

290
    for (auto const & column: m_columns) {
338✔
291
        names.push_back(column->getName());
274✔
292
    }
293

294
    return names;
64✔
UNCOV
295
}
×
296

297
bool TableView::hasColumn(std::string const & name) const {
649✔
298
    return m_colNameToIndex.find(name) != m_colNameToIndex.end();
649✔
299
}
300

301
std::type_info const & TableView::getColumnType(std::string const & name) const {
160✔
302
    auto it = m_colNameToIndex.find(name);
160✔
303
    if (it == m_colNameToIndex.end()) {
160✔
304
        throw std::runtime_error("Column '" + name + "' not found in table");
×
305
    }
306
    
307
    return m_columns[it->second]->getType();
320✔
308
}
309

310
std::type_index TableView::getColumnTypeIndex(std::string const & name) const {
160✔
311
    return std::type_index(getColumnType(name));
160✔
312
}
313

314
ColumnDataVariant TableView::getColumnDataVariant(std::string const & name) {
118✔
315
    auto type_index = getColumnTypeIndex(name);
118✔
316
    
317
    // Dispatch from element type_index to vector type using template metaprogramming
318
    std::optional<ColumnDataVariant> result;
118✔
319
    
320
    for_each_type<SupportedColumnElementTypes>([&](auto, auto type_instance) {
1,180✔
321
        using ElementType = std::decay_t<decltype(type_instance)>;
322
        
323
        if (!result.has_value() && type_index == std::type_index(typeid(ElementType))) {
1,062✔
324
            // Found matching element type, get the vector data
325
            auto vectorData = getColumnValues<ElementType>(name);
118✔
326
            result = vectorData;  // This will construct the variant with the correct vector type
118✔
327
        }
118✔
328
    });
1,062✔
329

330
    if (!result.has_value()) {
118✔
UNCOV
331
        throw std::runtime_error("Unsupported column type: " + std::string(type_index.name()) + 
×
UNCOV
332
                                " for column: " + name);
×
333
    }
334
    
335
    return result.value();
236✔
336
}
118✔
337

338

339
void TableView::materializeAll() {
17✔
340
    std::set<std::string> materializing;
17✔
341

342
    for (auto const & column: m_columns) {
97✔
343
        if (!column->isMaterialized()) {
80✔
344
            materializeColumn(column->getName(), materializing);
80✔
345
        }
346
    }
347
}
34✔
348

UNCOV
349
void TableView::clearCache() {
×
350
    // Clear column caches
UNCOV
351
    for (auto & column: m_columns) {
×
UNCOV
352
        column->clearCache();
×
353
    }
354

355
    // Clear execution plan cache
UNCOV
356
    m_planCache.clear();
×
UNCOV
357
}
×
358

359
ExecutionPlan const & TableView::getExecutionPlanFor(std::string const & sourceName) {
277✔
360
    // Check cache first
361
    auto it = m_planCache.find(sourceName);
277✔
362
    if (it != m_planCache.end()) {
277✔
363
        return it->second;
156✔
364
    }
365

366
    // Generate new plan
367
    ExecutionPlan plan = generateExecutionPlan(sourceName);
121✔
368

369
    // Store in cache and return reference
370
    auto [insertedIt, inserted] = m_planCache.emplace(sourceName, std::move(plan));
121✔
371
    if (!inserted) {
121✔
UNCOV
372
        throw std::runtime_error("Failed to cache ExecutionPlan for source: " + sourceName);
×
373
    }
374

375
    return insertedIt->second;
121✔
376
}
121✔
377

378
void TableView::addColumn(std::shared_ptr<IColumn> column) {
401✔
379
    if (!column) {
401✔
UNCOV
380
        throw std::invalid_argument("Column cannot be null");
×
381
    }
382

383
    std::string const & name = column->getName();
401✔
384

385
    // Check for duplicate names
386
    if (hasColumn(name)) {
401✔
UNCOV
387
        throw std::runtime_error("Column '" + name + "' already exists");
×
388
    }
389

390
    // Add to collections
391
    size_t index = m_columns.size();
401✔
392
    m_columns.push_back(std::move(column));
401✔
393
    m_colNameToIndex[name] = index;
401✔
394
}
802✔
395

396
void TableView::materializeColumn(std::string const & columnName, std::set<std::string> & materializing) {
80✔
397
    // Check for circular dependencies
398
    if (materializing.find(columnName) != materializing.end()) {
80✔
399
        throw std::runtime_error("Circular dependency detected involving column: " + columnName);
×
400
    }
401

402
    // Check if column exists
403
    if (!hasColumn(columnName)) {
80✔
UNCOV
404
        throw std::runtime_error("Column '" + columnName + "' not found");
×
405
    }
406

407
    auto & column = m_columns[m_colNameToIndex[columnName]];
80✔
408

409
    // If already materialized, nothing to do
410
    if (column->isMaterialized()) {
80✔
UNCOV
411
        return;
×
412
    }
413

414
    // Mark as being materialized
415
    materializing.insert(columnName);
80✔
416

417
    // Materialize dependencies first
418
    auto const dependencies = column->getDependencies();
80✔
419
    for (auto const & dependency: dependencies) {
80✔
UNCOV
420
        if (hasColumn(dependency)) {
×
421
            materializeColumn(dependency, materializing);
×
422
        }
423
    }
424

425
    // Materialize this column
426
    column->materialize(this);// Use the IColumn interface method
80✔
427

428
    // Remove from materializing set
429
    materializing.erase(columnName);
80✔
430
}
80✔
431

432
ExecutionPlan TableView::generateExecutionPlan(std::string const & sourceName) {
121✔
433
    // Resolve to a concrete source adapter once, then dispatch with std::visit
434
    auto resolved = m_dataManager->resolveSource(sourceName);
121✔
435
    if (resolved) {
121✔
436
        return std::visit(
437
            Overloaded{
120✔
438
                [&](std::shared_ptr<IAnalogSource> const & a) {
48✔
439
                    return makePlanFromAnalog(a, *m_rowSelector);
48✔
440
                },
441
                [&](std::shared_ptr<IEventSource> const & e) {
24✔
442
                    return makePlanFromEvent(e, *m_rowSelector);
24✔
443
                },
444
                [&](std::shared_ptr<IIntervalSource> const & i) {
30✔
445
                    return makePlanFromInterval(i, *m_rowSelector);
30✔
446
                },
447
                [&](std::shared_ptr<ILineSource> const & l) {
18✔
448
                    return makePlanFromLine(l, *m_rowSelector, m_columns, *m_dataManager);
18✔
449
                },
UNCOV
450
                [&](std::shared_ptr<IPointSource> const & p) {
×
UNCOV
451
                    return makePlanFromPoint(p, *m_rowSelector);
×
452
                }
453
            },
454
            *resolved
455
        );
120✔
456
    }
457

458
    // Fallback: generate plan solely from the selector if source is unknown
459
    return visitSelector(
460
        *m_rowSelector,
1✔
461
        [&](IntervalSelector const & intervalSelector) {
2✔
462
            auto const & intervals = intervalSelector.getIntervals();
×
UNCOV
463
            auto timeFrame = intervalSelector.getTimeFrame();
×
464
            std::cout << "WARNING: Data source '" << sourceName
465
                      << "' not found. Generating plan from IntervalSelector only." << std::endl;
×
UNCOV
466
            return ExecutionPlan(intervals, timeFrame);
×
UNCOV
467
        },
×
468
        [&](TimestampSelector const & timestampSelector) {
1✔
469
            auto const & indices = timestampSelector.getTimestamps();
1✔
470
            auto timeFrame = timestampSelector.getTimeFrame();
1✔
471
            std::cout << "WARNING: Data source '" << sourceName
472
                      << "' not found. Generating plan from TimestampSelector only." << std::endl;
1✔
473
            return ExecutionPlan(indices, timeFrame);
2✔
474
        },
1✔
475
        [&](IndexSelector const & indexSelector) {
1✔
476
            auto const & indices = indexSelector.getIndices();
×
477
            std::vector<TimeFrameIndex> timeFrameIndices;
×
UNCOV
478
            timeFrameIndices.reserve(indices.size());
×
UNCOV
479
            for (size_t index : indices) {
×
UNCOV
480
                timeFrameIndices.emplace_back(static_cast<int64_t>(index));
×
481
            }
482
            std::cout << "WARNING: Data source '" << sourceName
UNCOV
483
                      << "' not found. Generating plan from IndexSelector only." << std::endl;
×
UNCOV
484
            return ExecutionPlan(std::move(timeFrameIndices), nullptr);
×
UNCOV
485
        }
×
486
    );
2✔
487
}
121✔
488

UNCOV
489
RowDescriptor TableView::getRowDescriptor(size_t row_index) const {
×
UNCOV
490
    if (m_rowSelector) {
×
UNCOV
491
        return m_rowSelector->getDescriptor(row_index);
×
492
    }
UNCOV
493
    return std::monostate{};
×
494
}
495

496
std::vector<EntityId> TableView::getRowEntityIds(size_t row_index) const {
20✔
497
    // First check if we have direct EntityIds (for transformed tables)
498
    if (!m_direct_entity_ids.empty()) {
20✔
UNCOV
499
        if (row_index < m_direct_entity_ids.size()) {
×
UNCOV
500
            return m_direct_entity_ids[row_index];
×
501
        }
UNCOV
502
        return {};
×
503
    }
504
    
505
    // Final fallback: collect EntityIDs from all columns (for mixed/derived sources)
506
    std::set<EntityId> entity_set;
20✔
507
    for (auto const & column : m_columns) {
160✔
508
        //if (column->hasEntityIds()) {
509
            // Use the column's getCellEntityIds method
510
            auto cell_entities = column->getCellEntityIds(row_index);
140✔
511
            for (EntityId entity_id : cell_entities) {
280✔
512
                if (entity_id != 0) {
140✔
513
                    entity_set.insert(entity_id);
140✔
514
                }
515
            }
516
        //}
517
    }
140✔
518
    
519
    // Return the unified set of EntityIDs for this row
520
    return std::vector<EntityId>(entity_set.begin(), entity_set.end());
60✔
521
}
20✔
522

UNCOV
523
bool TableView::hasEntityColumn() const {
×
524
    // Check if we have direct EntityIds first
525
    if (!m_direct_entity_ids.empty()) {
×
526
        return true;
×
527
    }
528
    
529
    // Fallback to execution plan-based check
530
    size_t row_count = getRowCount();
×
531
    if (row_count == 0) {
×
UNCOV
532
        return false;
×
533
    }
534
    
535
    // Check the first row to see if EntityIds are available
UNCOV
536
    auto entity_ids = getRowEntityIds(0);
×
UNCOV
537
    return !entity_ids.empty();
×
538
}
×
539

540
std::vector<std::vector<EntityId>> TableView::getEntityIds() const {
5✔
541
    // If we have direct EntityIds, return them
542
    if (!m_direct_entity_ids.empty()) {
5✔
543
        return m_direct_entity_ids;
2✔
544
    }
545
    
546
    // Fallback to execution plan-based EntityIds
547
    std::vector<std::vector<EntityId>> all_entity_ids;
3✔
548
    size_t row_count = getRowCount();
3✔
549
    
550
    for (size_t i = 0; i < row_count; ++i) {
18✔
551
        auto row_entity_ids = getRowEntityIds(i);
15✔
552
        if (!row_entity_ids.empty()) {
15✔
553
            all_entity_ids.push_back(std::move(row_entity_ids));
15✔
554
        } else {
555
            all_entity_ids.push_back({});
×
556
        }
557
    }
15✔
558
    
559
    return all_entity_ids;
3✔
560
}
3✔
561

562
void TableView::setDirectEntityIds(std::vector<std::vector<EntityId>> entity_ids) {
2✔
563
    m_direct_entity_ids = std::move(entity_ids);
2✔
564
}
2✔
565

566
std::unique_ptr<IRowSelector> TableView::cloneRowSelectorFiltered(std::vector<size_t> const & keep_indices) const {
×
UNCOV
567
    if (!m_rowSelector) {
×
UNCOV
568
        return nullptr;
×
569
    }
570

571
    // IndexSelector
UNCOV
572
    if (auto indexSelector = dynamic_cast<IndexSelector const *>(m_rowSelector.get())) {
×
UNCOV
573
        std::vector<size_t> const & indices = indexSelector->getIndices();
×
UNCOV
574
        std::vector<size_t> filtered;
×
575
        filtered.reserve(keep_indices.size());
×
UNCOV
576
        for (size_t k : keep_indices) {
×
UNCOV
577
            if (k < indices.size()) {
×
UNCOV
578
                filtered.push_back(indices[k]);
×
579
            }
580
        }
UNCOV
581
        return std::make_unique<IndexSelector>(std::move(filtered));
×
UNCOV
582
    }
×
583

584
    // TimestampSelector
UNCOV
585
    if (auto timestampSelector = dynamic_cast<TimestampSelector const *>(m_rowSelector.get())) {
×
UNCOV
586
        auto const & timestamps = timestampSelector->getTimestamps();
×
UNCOV
587
        auto timeFrame = timestampSelector->getTimeFrame();
×
UNCOV
588
        std::vector<TimeFrameIndex> filtered;
×
589
        filtered.reserve(keep_indices.size());
×
UNCOV
590
        for (size_t k : keep_indices) {
×
UNCOV
591
            if (k < timestamps.size()) {
×
UNCOV
592
                filtered.push_back(timestamps[k]);
×
593
            }
594
        }
UNCOV
595
        return std::make_unique<TimestampSelector>(std::move(filtered), timeFrame);
×
UNCOV
596
    }
×
597

598
    // IntervalSelector
UNCOV
599
    if (auto intervalSelector = dynamic_cast<IntervalSelector const *>(m_rowSelector.get())) {
×
UNCOV
600
        auto const & intervals = intervalSelector->getIntervals();
×
UNCOV
601
        auto timeFrame = intervalSelector->getTimeFrame();
×
UNCOV
602
        std::vector<TimeFrameInterval> filtered;
×
UNCOV
603
        filtered.reserve(keep_indices.size());
×
UNCOV
604
        for (size_t k : keep_indices) {
×
UNCOV
605
            if (k < intervals.size()) {
×
UNCOV
606
                filtered.push_back(intervals[k]);
×
607
            }
608
        }
UNCOV
609
        return std::make_unique<IntervalSelector>(std::move(filtered), timeFrame);
×
UNCOV
610
    }
×
611

612
    // Fallback: preserve by indices if unknown type
UNCOV
613
    std::vector<size_t> identity;
×
UNCOV
614
    identity.reserve(keep_indices.size());
×
UNCOV
615
    for (size_t k : keep_indices) identity.push_back(k);
×
UNCOV
616
    return std::make_unique<IndexSelector>(std::move(identity));
×
UNCOV
617
}
×
618

619
bool TableView::hasColumnEntityIds(std::string const & columnName) const {
2✔
620
    auto it = m_colNameToIndex.find(columnName);
2✔
621
    if (it == m_colNameToIndex.end()) {
2✔
UNCOV
622
        return false;
×
623
    }
624
    
625
    size_t columnIndex = it->second;
2✔
626
    if (columnIndex >= m_columns.size()) {
2✔
UNCOV
627
        return false;
×
628
    }
629
    
630
    return m_columns[columnIndex]->hasEntityIds();
2✔
631
}
632

633
ColumnEntityIds TableView::getColumnEntityIds(std::string const & columnName) const {
19✔
634
    auto it = m_colNameToIndex.find(columnName);
19✔
635
    if (it == m_colNameToIndex.end()) {
19✔
UNCOV
636
        return {};
×
637
    }
638
    
639
    size_t columnIndex = it->second;
19✔
640
    if (columnIndex >= m_columns.size()) {
19✔
UNCOV
641
        return {};
×
642
    }
643
    
644
    return m_columns[columnIndex]->getColumnEntityIds();
19✔
645
}
646

647
std::vector<EntityId> TableView::getCellEntityIds(std::string const & columnName, size_t rowIndex) const {
40✔
648
    auto it = m_colNameToIndex.find(columnName);
40✔
649
    if (it == m_colNameToIndex.end()) {
40✔
UNCOV
650
        return {};
×
651
    }
652
    
653
    size_t columnIndex = it->second;
40✔
654
    if (columnIndex >= m_columns.size()) {
40✔
UNCOV
655
        return {};
×
656
    }
657
    
658
    return m_columns[columnIndex]->getCellEntityIds(rowIndex);
40✔
659
}
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

© 2026 Coveralls, Inc