LCOV - code coverage report
Current view: top level - dashql-app/src/compute - column_analysis.ts Coverage Total Hit
Test: DashQL 915828b Lines: 98.8 % 86 85
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as arrow from 'apache-arrow';
       2              : 
       3              : import { ArrowTableFormatter } from './arrow_formatter.js';
       4              : import { TableAggregation, OrdinalColumnAnalysis, StringColumnAnalysis, StringGridColumnGroup, OrdinalGridColumnGroup, BinnedValuesTable, FrequentValuesTable } from './computation_types.js';
       5              : import { assert } from '../utils/assert.js';
       6              : import { isTemporalType } from './arrow_columns.js';
       7              : 
       8            1 : export function analyzeOrdinalColumn(tableSummary: TableAggregation, columnEntry: OrdinalGridColumnGroup, binnedValues: BinnedValuesTable, binnedValuesFormatter: ArrowTableFormatter, filteredTotalCount: number | null = null): OrdinalColumnAnalysis {
       9            1 :     const totalCountVector = tableSummary.table.getChild(tableSummary.countStarFieldName!) as arrow.Vector<arrow.Int64>;
      10              : 
      11            1 :     const unfilteredTotalCount = Number(totalCountVector.get(0) ?? BigInt(0));
      12            1 :     const totalCount = filteredTotalCount ?? unfilteredTotalCount;
      13            1 :     const minFieldId = tableSummary.tableFieldsByName.get(columnEntry.statsFields!.minAggregateFieldName!)!;
      14            1 :     const maxFieldId = tableSummary.tableFieldsByName.get(columnEntry.statsFields!.maxAggregateFieldName!)!;
      15            1 :     const minValue = tableSummary.tableFormatter.getValue(0, minFieldId) ?? "";
      16            1 :     const maxValue = tableSummary.tableFormatter.getValue(0, maxFieldId) ?? "";
      17              : 
      18            1 :     assert(binnedValues.schema.fields[0].name == "bin");
      19            1 :     assert(binnedValues.schema.fields[1].name == "count");
      20            1 :     assert(binnedValues.schema.fields[3].name == "binLowerBound");
      21            1 :     const binIdVector = binnedValues.getChildAt(0) as arrow.Vector<arrow.Uint32>;
      22            1 :     const binCountVector = binnedValues.getChildAt(1) as arrow.Vector<arrow.Int64>;
      23              : 
      24            1 :     const nullBinRowIdx = binnedValues.numRows - 1;
      25            1 :     const nullBinId = Number(binIdVector.get(nullBinRowIdx) ?? -1);
      26            1 :     assert(binnedValues.numRows === (columnEntry.binCount + 1));
      27            1 :     assert(nullBinId === columnEntry.binCount);
      28              : 
      29            1 :     const countNull = Number(binCountVector.get(nullBinRowIdx) ?? BigInt(0));
      30            1 :     const countNotNull = filteredTotalCount == null
      31            1 :         ? totalCount - countNull
      32            1 :         : unfilteredTotalCount - countNull;
      33              : 
      34            1 :     const regularBinCount = columnEntry.binCount;
      35            1 :     const binLowerBounds: string[] = [];
      36            1 :     const binPercentages = new Float64Array(regularBinCount);
      37            1 :     const regularBinValueCounts = new BigInt64Array(regularBinCount);
      38              : 
      39            1 :     const isTemporal = isTemporalType(columnEntry.inputFieldType.typeId);
      40            1 :     const temporalFmt = isTemporal ? Intl.DateTimeFormat('en-US', { dateStyle: 'short', timeStyle: 'medium' }) : null;
      41            1 :     const lbCol = isTemporal ? binnedValues.getChildAt(3)! : null;
      42              : 
      43            1 :     for (let i = 0; i < regularBinCount; ++i) {
      44            1 :         const binCount = binCountVector.get(i) ?? BigInt(0);
      45            1 :         let binLB: string;
      46            1 :         if (isTemporal && lbCol) {
      47            1 :             const epochMs = lbCol.get(i);
      48            1 :             binLB = epochMs == null ? "" : temporalFmt!.format(new Date(epochMs));
      49            1 :         } else {
      50            1 :             binLB = binnedValuesFormatter.getValue(i, 3) ?? "";
      51              :         }
      52            1 :         const binPercentage = (totalCount == 0) ? 0 : (Number(binCount) / totalCount);
      53            1 :         binLowerBounds.push(binLB);
      54            1 :         binPercentages[i] = binPercentage;
      55            1 :         regularBinValueCounts[i] = binCount;
      56            1 :     }
      57              : 
      58            1 :     return {
      59            1 :         totalCount,
      60            1 :         countNotNull: countNotNull,
      61            1 :         countNull: countNull,
      62            1 :         minValue: minValue,
      63            1 :         maxValue: maxValue,
      64            1 :         binCount: regularBinCount,
      65            1 :         binValueCounts: regularBinValueCounts,
      66            1 :         binPercentages: binPercentages,
      67            1 :         binLowerBounds: binLowerBounds,
      68            1 :     };
      69            1 : }
      70              : 
      71            1 : export function analyzeStringColumn(tableSummary: TableAggregation, columnEntry: StringGridColumnGroup, frequentValueTable: FrequentValuesTable, frequentValuesFormatter: ArrowTableFormatter, filteredTotalCount: number | null = null): StringColumnAnalysis {
      72            1 :     const totalCountVector = tableSummary.table.getChild(tableSummary.countStarFieldName!) as arrow.Vector<arrow.Int64>;
      73            1 :     const notNullCountVector = tableSummary.table.getChild(columnEntry.statsFields!.countFieldName) as arrow.Vector<arrow.Int64>;
      74            1 :     const distinctCountVector = tableSummary.table.getChild(columnEntry.statsFields!.distinctCountFieldName!) as arrow.Vector<arrow.Int64>;
      75              : 
      76            1 :     const unfilteredTotalCount = Number(totalCountVector.get(0) ?? BigInt(0));
      77            1 :     const totalCount = filteredTotalCount ?? unfilteredTotalCount;
      78            1 :     const notNullCount = Number(notNullCountVector.get(0) ?? BigInt(0));
      79            1 :     const distinctCount = Number(distinctCountVector.get(0) ?? BigInt(0));
      80              : 
      81            1 :     assert(frequentValueTable.schema.fields[0].name == "key");
      82            1 :     assert(frequentValueTable.getChild("count") != null);
      83              : 
      84            1 :     const frequentValueCounts = frequentValueTable.getChild("count")!.toArray();
      85            1 :     const frequentValuePercentages = new Float64Array(frequentValueTable.numRows);
      86            1 :     const frequentValueStrings = [];
      87            1 :     for (let i = 0; i < frequentValueTable.numRows; ++i) {
      88            1 :         frequentValuePercentages[i] = totalCount == 0 ? 0 : (Number(frequentValueCounts[i]) / totalCount);
      89            1 :         frequentValueStrings.push(frequentValuesFormatter.getValue(i, 0));
      90            1 :     }
      91              : 
      92            1 :     const keyIdColumn = (frequentValueTable as arrow.Table).getChild("keyId");
      93            1 :     if (keyIdColumn == null) {
      94            0 :         throw new Error("Missing keyId column in frequent values table");
      95              :     }
      96            1 :     const frequentValueIds = keyIdColumn.toArray() as BigInt64Array;
      97              : 
      98            1 :     return {
      99            1 :         totalCount,
     100            1 :         countNotNull: notNullCount,
     101            1 :         countNull: unfilteredTotalCount - notNullCount,
     102            1 :         countDistinct: distinctCount,
     103            1 :         isUnique: notNullCount == distinctCount,
     104            1 :         frequentValueStrings: frequentValueStrings,
     105            1 :         frequentValueIds: frequentValueIds,
     106            1 :         frequentValueCounts: frequentValueCounts,
     107            1 :         frequentValuePercentages: frequentValuePercentages,
     108            1 :     };
     109            1 : }
        

Generated by: LCOV version 2.0-1