LCOV - code coverage report
Current view: top level - dashql-app/src/views/query_result - data_table_ordering.ts Coverage Total Hit
Test: DashQL 915828b Lines: 94.4 % 90 85
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as React from 'react';
       2              : 
       3              : import { CLEAR_TABLE_ORDERING, type ComputationAction, type TableComputationState } from '../../compute/computation_state.js';
       4              : import { scheduleTask } from '../../compute/computation_tasks.js';
       5              : import type { TableOrderingTask } from '../../compute/computation_types.js';
       6              : import { TABLE_ORDERING_TASK, TaskStatus } from '../../compute/computation_types.js';
       7              : import type { OrderByConstraint } from '../../compute/sql/sqlframe_builder.js';
       8              : import type { Dispatch } from '../../utils/variant.js';
       9              : 
      10            1 : export function getColumnSortDirection(field: string, ordering: OrderByConstraint[]): boolean | null {
      11            1 :     if (ordering.length !== 1 || ordering[0].field !== field) return null;
      12            1 :     return ordering[0].ascending ?? true;
      13            1 : }
      14              : 
      15            1 : export function getNextColumnSortDirection(field: string, ordering: OrderByConstraint[]): boolean | null {
      16            1 :     const currentDirection = getColumnSortDirection(field, ordering);
      17            1 :     if (currentDirection == null) return true;
      18            1 :     return currentDirection ? false : null;
      19            1 : }
      20              : 
      21            1 : function areOrderingConstraintsEqual(left: OrderByConstraint[], right: OrderByConstraint[]): boolean {
      22            1 :     if (left.length !== right.length) return false;
      23            1 :     for (let i = 0; i < left.length; ++i) {
      24            1 :         const a = left[i];
      25            1 :         const b = right[i];
      26            1 :         if (
      27            1 :             a.field !== b.field
      28            1 :             || (a.ascending ?? true) !== (b.ascending ?? true)
      29            1 :             || (a.nullsFirst ?? false) !== (b.nullsFirst ?? false)
      30              :         ) {
      31            0 :             return false;
      32              :         }
      33            1 :     }
      34            1 :     return true;
      35            1 : }
      36              : 
      37            1 : export function createOrderingTask(
      38            1 :     table: TableComputationState,
      39            1 :     orderingConstraints: OrderByConstraint[],
      40            1 : ): TableOrderingTask | null {
      41            1 :     if (!table.dataFrame || !table.rowNumberColumnName) return null;
      42            1 :     return {
      43            1 :         tableId: table.tableId,
      44            1 :         tableVersion: table.version,
      45            1 :         inputDataTable: table.dataTable,
      46            1 :         inputDataTableFieldIndex: table.dataTableFieldsByName,
      47            1 :         inputDataFrame: table.dataFrame,
      48            1 :         filterTable: table.filterTable,
      49            1 :         dataSearchTable: table.dataSearchTable,
      50            1 :         rowNumberColumnName: table.rowNumberColumnName,
      51            1 :         orderingConstraints,
      52            1 :     };
      53            1 : }
      54              : 
      55            1 : export function useDataTableOrdering(
      56            1 :     table: TableComputationState,
      57            1 :     dispatchComputation: Dispatch<ComputationAction>,
      58            1 : ) {
      59            1 :     const activeOrderingConstraints = React.useMemo<OrderByConstraint[]>(() => {
      60            1 :         const taskOrdering = table.tasks.orderingTask?.orderingConstraints;
      61            1 :         return taskOrdering != null && taskOrdering.length > 0 ? taskOrdering : table.dataTableOrdering;
      62            1 :     }, [table.dataTableOrdering, table.tasks.orderingTask?.orderingConstraints]);
      63              : 
      64            1 :     React.useEffect(() => {
      65            1 :         if (activeOrderingConstraints.length === 0) return;
      66            1 :         const orderingTask = createOrderingTask(table, activeOrderingConstraints);
      67            1 :         if (orderingTask == null) return;
      68              : 
      69            1 :         const currentTask = table.tasks.orderingTask;
      70            1 :         const currentOrdering = table.orderingTable;
      71            1 :         const filterVersion = table.filterTable?.version ?? null;
      72            1 :         const dataSearchRequestId = table.dataSearchTable?.requestId ?? null;
      73            1 :         const taskMatchesInput = currentTask?.tableVersion.filterMatches(table.version)
      74            1 :             && (filterVersion
      75            0 :                 ? (currentTask.filterTable?.version?.filterMatches(filterVersion) ?? false)
      76            1 :                 : currentTask.filterTable === null)
      77            1 :             && (currentTask.dataSearchTable?.requestId ?? null) === dataSearchRequestId;
      78            1 :         const hasUpToDateOrdering = currentOrdering != null
      79            0 :             && currentTask?.progress.status === TaskStatus.TASK_SUCCEEDED
      80            0 :             && taskMatchesInput
      81            0 :             && areOrderingConstraintsEqual(currentOrdering.orderingConstraints, activeOrderingConstraints);
      82            1 :         const hasUpToDateRunningTask = currentTask?.progress.status === TaskStatus.TASK_RUNNING
      83            1 :             && taskMatchesInput
      84            1 :             && areOrderingConstraintsEqual(currentTask.orderingConstraints, activeOrderingConstraints);
      85            1 :         if (hasUpToDateOrdering || hasUpToDateRunningTask) return;
      86            1 :         void scheduleTask(TABLE_ORDERING_TASK, orderingTask, dispatchComputation);
      87            1 :     }, [activeOrderingConstraints, table, dispatchComputation]);
      88              : 
      89            1 :     const orderByColumn = React.useCallback((fieldId: number) => {
      90            1 :         const fieldName = table.dataTable.schema.fields[fieldId].name;
      91            1 :         const nextSortDirection = getNextColumnSortDirection(fieldName, activeOrderingConstraints);
      92            1 :         if (nextSortDirection == null) {
      93            1 :             dispatchComputation({ type: CLEAR_TABLE_ORDERING, value: table.tableId });
      94            1 :             return;
      95            1 :         }
      96            1 :         const orderingTask = createOrderingTask(table, [{
      97            1 :             field: fieldName,
      98            1 :             ascending: nextSortDirection,
      99            1 :             nullsFirst: false,
     100            1 :         }]);
     101            1 :         if (orderingTask != null) void scheduleTask(TABLE_ORDERING_TASK, orderingTask, dispatchComputation);
     102            1 :     }, [activeOrderingConstraints, table, dispatchComputation]);
     103              : 
     104            1 :     const getSortDirection = React.useCallback((fieldId: number) => {
     105            1 :         const fieldName = table.dataTable.schema.fields[fieldId].name;
     106            1 :         return getColumnSortDirection(fieldName, activeOrderingConstraints);
     107            1 :     }, [activeOrderingConstraints, table.dataTable.schema.fields]);
     108              : 
     109            1 :     return { orderByColumn, getSortDirection };
     110            1 : }
        

Generated by: LCOV version 2.0-1