Line data Source code
1 : import * as arrow from 'apache-arrow';
2 :
3 : import { TableComputationState } from '../../compute/computation_state.js';
4 :
5 : /// Visit the values of an integer column as numbers, like `Number(column.get(i))` (nulls become 0).
6 : /// Integer chunks are read from their value buffers directly. A chunk's values are already narrowed
7 : /// to the chunk's window, so value `i` of the chunk is `values[i]`, exactly what `Vector.get` reads.
8 1 : export function forEachIntegerValue(column: arrow.Vector, visit: (value: number, index: number) => void): void {
9 1 : if (column.type.typeId !== arrow.Type.Int) {
10 0 : for (let i = 0; i < column.length; ++i) {
11 0 : visit(Number(column.get(i)), i);
12 : }
13 0 : return;
14 0 : }
15 1 : let index = 0;
16 1 : for (const chunk of column.data) {
17 1 : const values = chunk.values as ArrayLike<number | bigint>;
18 1 : if (chunk.nullCount === 0) {
19 1 : for (let i = 0; i < chunk.length; ++i) {
20 1 : visit(Number(values[i]), index++);
21 : }
22 : } else {
23 0 : for (let i = 0; i < chunk.length; ++i) {
24 0 : visit(chunk.getValid(i) ? Number(values[i]) : 0, index++);
25 : }
26 : }
27 1 : }
28 1 : }
29 :
30 : /// Resolve the active row-id indirection for a table computation.
31 : ///
32 : /// When a cross-filter and/or ordering is active, the compute module produces a
33 : /// single-column table of row numbers (1-based, from `row_number()`) identifying the
34 : /// visible rows in display order. Ordering supersedes filtering when both are present
35 : /// (the ordering task already runs over the filtered subset). Returns `null` when the
36 : /// full, unfiltered table should be shown.
37 : ///
38 : /// The returned array holds 0-based positional indices into the analyzed data table,
39 : /// ready to gather columns/rows for a renderer.
40 1 : export function resolveVisibleRowIndices(computation: TableComputationState | null): Int32Array | null {
41 1 : if (computation == null) {
42 0 : return null;
43 : }
44 1 : const indirection = computation.orderingTable?.dataTable
45 1 : ?? (computation.filterTable == null ? computation.dataSearchTable?.dataTable : computation.filterTable.dataTable)
46 1 : ?? null;
47 1 : if (indirection == null) {
48 1 : return null;
49 : }
50 1 : if (indirection.numCols !== 1) {
51 0 : return null;
52 : }
53 1 : const column = indirection.getChildAt(0) as arrow.Vector<arrow.Int> | null;
54 1 : if (column == null || column.type.typeId !== arrow.Type.Int) {
55 0 : return null;
56 : }
57 1 : const out = new Int32Array(column.length);
58 1 : forEachIntegerValue(column, (rowNumber, i) => {
59 : // Row numbers are 1-based; convert to a 0-based positional index.
60 1 : out[i] = Math.max(rowNumber, 1) - 1;
61 1 : });
62 1 : return out;
63 1 : }
64 :
65 : /// Intersect the current cross-filtered/ordered rows with the active Data search.
66 : /// Search result keys are stable 1-based row numbers from the analyzed data frame.
67 1 : export function resolveSearchedRowIndices(computation: TableComputationState | null): Int32Array | null {
68 1 : if (computation == null || computation.dataSearch.matchingRows == null) {
69 1 : return resolveVisibleRowIndices(computation);
70 : }
71 1 : const visible = computation.orderingTable?.dataSearchRequestId === computation.dataSearchTable?.requestId
72 1 : ? resolveVisibleRowIndices(computation)
73 0 : : resolveVisibleRowIndices(computation == null ? null : { ...computation, dataSearchTable: null });
74 1 : if (visible == null) {
75 0 : const rows = Array.from(computation.dataSearch.matchingRows.keys(), rowNumber => rowNumber - 1);
76 0 : return Int32Array.from(rows);
77 0 : }
78 1 : const rows: number[] = [];
79 1 : for (const row of visible) {
80 1 : if (computation.dataSearch.matchingRows.has(row + 1)) {
81 1 : rows.push(row);
82 : }
83 : }
84 1 : return Int32Array.from(rows);
85 1 : }
|