LCOV - code coverage report
Current view: top level - dashql-app/src/session - entry_status_model.ts Coverage Total Hit
Test: DashQL 6e74948 Lines: 96.3 % 134 129
Test Date: 2026-11-06 17:46:50

            Line data    Source code
       1              : import { QueryExecutionState, QueryExecutionStatus, queryIsDone } from '../query/query_execution_state.js';
       2              : import { IndicatorStatus } from '../ui/foundations/status_indicator.js';
       3              : import { summarizeQueryProgress } from '../views/query_progress/query_progress_model.js';
       4              : 
       5              : /// Which source produced the status shown in the bar.
       6            1 : export const enum EntryStatusKind {
       7            1 :     Query = 0,
       8            1 :     Idle = 1,
       9            1 : }
      10              : 
      11              : /// The presentation-ready status for one session entry, derived from its latest query execution.
      12              : /// Every entry has a status, including entries that
      13              : /// have not run yet, so the server card always has a stable status header.
      14              : export interface EntryStatus {
      15              :     kind: EntryStatusKind;
      16              :     /// The spinner/check/cross state.
      17              :     indicator: IndicatorStatus;
      18              :     /// The single-line query status message.
      19              :     message: string;
      20              :     /// The trace to reveal in the footer log when the bar is clicked.
      21              :     traceId: number | null;
      22              :     /// Everything known about a failed query, shown in the status bar's error-details overlay.
      23              :     /// Null for non-error statuses.
      24              :     errorDetail: Record<string, unknown> | null;
      25              : }
      26              : 
      27            1 : function compactObject(value: Record<string, unknown>): Record<string, unknown> {
      28            1 :     return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry != null));
      29            1 : }
      30              : 
      31            1 : function getQueryErrorDetail(query: QueryExecutionState, message: string): Record<string, unknown> {
      32            1 :     const error = query.error;
      33            1 :     return compactObject({
      34            1 :         status: query.status === QueryExecutionStatus.FAILED ? 'failed' : 'cancelled',
      35            1 :         message,
      36            1 :         target: error?.target,
      37            1 :         queryId: query.queryId,
      38            1 :         traceId: query.traceId,
      39            1 :         statementIndex: query.statementIndex,
      40            1 :         statementCount: query.statementCount,
      41            1 :         query: query.queryText,
      42            1 :         metadata: query.queryMetadata,
      43            1 :         details: error != null && Object.keys(error.keyValues).length > 0 ? error.keyValues : undefined,
      44            1 :     });
      45            1 : }
      46              : 
      47            1 : function getStatementStatusText(message: string, statementIndex: number | null, statementCount: number | null): string {
      48            1 :     return statementIndex != null && statementCount != null && statementCount > 1
      49            1 :         ? `Statement ${statementIndex} of ${statementCount}: ${message}`
      50            1 :         : message;
      51            1 : }
      52              : 
      53              : /// Human-readable label for a query execution status. Shared by the feed status bar and the Details
      54              : /// query status panel so both stay in sync.
      55            1 : export function getQueryStatusText(
      56            1 :     status: QueryExecutionStatus,
      57            1 :     statementIndex: number | null = null,
      58            1 :     statementCount: number | null = null,
      59            1 :     statementSucceeded: boolean = false,
      60            1 : ): string {
      61            1 :     const hasMultipleStatements = statementIndex != null && statementCount != null && statementCount > 1;
      62            1 :     if (hasMultipleStatements && statementSucceeded && !queryIsDone(status)) {
      63            1 :         return `Statement ${statementIndex} of ${statementCount} executed successfully`;
      64              :     }
      65            1 :     switch (status) {
      66            1 :         case QueryExecutionStatus.REQUESTED:
      67            1 :             return hasMultipleStatements
      68            1 :                 ? `Requested statement ${statementIndex} of ${statementCount}`
      69            1 :                 : 'Requested query';
      70            1 :         case QueryExecutionStatus.PREPARING:
      71            1 :             return hasMultipleStatements
      72            1 :                 ? `Preparing statement ${statementIndex} of ${statementCount}`
      73            0 :                 : 'Preparing query';
      74            1 :         case QueryExecutionStatus.SENDING:
      75            1 :             return hasMultipleStatements
      76            1 :                 ? `Sending statement ${statementIndex} of ${statementCount}`
      77            1 :                 : 'Sending query';
      78            1 :         case QueryExecutionStatus.QUEUED:
      79            1 :             return hasMultipleStatements
      80            1 :                 ? `Statement ${statementIndex} of ${statementCount} queued`
      81            0 :                 : 'Queued query';
      82            1 :         case QueryExecutionStatus.RUNNING:
      83            1 :             return hasMultipleStatements
      84            1 :                 ? `Executing statement ${statementIndex} of ${statementCount}`
      85            1 :                 : 'Executing query';
      86            1 :         case QueryExecutionStatus.RECEIVED_FIRST_BATCH:
      87            1 :             return hasMultipleStatements
      88            1 :                 ? `Executing statement ${statementIndex} of ${statementCount}, fetching results`
      89            1 :                 : 'Executing query, fetching results';
      90            1 :         case QueryExecutionStatus.RECEIVED_ALL_BATCHES:
      91            1 :             return hasMultipleStatements
      92            1 :                 ? `Executing statement ${statementIndex} of ${statementCount}, received all results`
      93            0 :                 : 'Executing query, received all results';
      94            1 :         case QueryExecutionStatus.PROCESSING_RESULTS:
      95            1 :             return hasMultipleStatements
      96            1 :                 ? `Processing results for statement ${statementIndex} of ${statementCount}`
      97            1 :                 : 'Processing results';
      98            1 :         case QueryExecutionStatus.PROCESSED_RESULTS:
      99            1 :             return hasMultipleStatements
     100            1 :                 ? `Processed results for statement ${statementIndex} of ${statementCount}`
     101            1 :                 : 'Processed results';
     102            1 :         case QueryExecutionStatus.FAILED:
     103            1 :             return hasMultipleStatements
     104            1 :                 ? `Statement ${statementIndex} of ${statementCount} execution failed`
     105            0 :                 : 'Statement execution failed';
     106            1 :         case QueryExecutionStatus.CANCELLED:
     107            1 :             return hasMultipleStatements
     108            1 :                 ? `Statement ${statementIndex} of ${statementCount} execution was cancelled`
     109            0 :                 : 'Statement execution was cancelled';
     110            1 :         case QueryExecutionStatus.SUCCEEDED:
     111            1 :             return hasMultipleStatements
     112            1 :                 ? `Statement ${statementIndex} of ${statementCount} executed successfully`
     113            1 :                 : 'Statement executed successfully';
     114            1 :     }
     115            1 : }
     116              : 
     117              : /// Derive the status bar contents for a session entry from its query execution.
     118            1 : export function deriveEntryStatus(query: QueryExecutionState | null): EntryStatus {
     119            1 :     if (query != null && !queryIsDone(query.status)) {
     120            1 :         const statusText = getQueryStatusText(
     121            1 :             query.status,
     122            1 :             query.statementIndex,
     123            1 :             query.statementCount,
     124            1 :             query.statementSucceeded,
     125            1 :         );
     126              :         // Engines with structured progress add the phase, the progress and the throughput
     127            1 :         const progress = summarizeQueryProgress(query.latestProgressUpdate);
     128            1 :         return {
     129            1 :             kind: EntryStatusKind.Query,
     130            1 :             indicator: IndicatorStatus.Running,
     131            1 :             message: progress == null ? statusText : `${statusText} ยท ${progress}`,
     132            1 :             traceId: query.traceId,
     133            1 :             errorDetail: null,
     134            1 :         };
     135            1 :     }
     136            1 :     if (query != null && (query.status === QueryExecutionStatus.FAILED || query.status === QueryExecutionStatus.CANCELLED)) {
     137            1 :         const message = query.error?.message != null
     138            1 :             ? getStatementStatusText(query.error.message, query.statementIndex, query.statementCount)
     139            1 :             : getQueryStatusText(query.status, query.statementIndex, query.statementCount);
     140            1 :         return {
     141            1 :             kind: EntryStatusKind.Query,
     142            1 :             indicator: IndicatorStatus.Failed,
     143            1 :             message,
     144            1 :             traceId: query.traceId,
     145            1 :             errorDetail: getQueryErrorDetail(query, message),
     146            1 :         };
     147            1 :     }
     148            1 :     if (query != null) {
     149            1 :         return {
     150            1 :             kind: EntryStatusKind.Query,
     151            1 :             indicator: IndicatorStatus.Succeeded,
     152            1 :             message: query.status === QueryExecutionStatus.SUCCEEDED && query.servedFromCache
     153            1 :                 ? getStatementStatusText('Result loaded from cache', query.statementIndex, query.statementCount)
     154            1 :                 : getQueryStatusText(query.status, query.statementIndex, query.statementCount),
     155            1 :             traceId: query.traceId,
     156            1 :             errorDetail: null,
     157            1 :         };
     158              :     }
     159            1 :     return {
     160            1 :         kind: EntryStatusKind.Idle,
     161            1 :         indicator: IndicatorStatus.None,
     162            1 :         message: 'Not run yet',
     163            1 :         traceId: null,
     164            1 :         errorDetail: null,
     165            1 :     };
     166            1 : }
        

Generated by: LCOV version 2.0-1