LCOV - code coverage report
Current view: top level - dashql-app/src/views/query_profile - profile_execution_controller.ts Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 57 57
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as dashql from '@ankoh/dashql-core';
       2              : import type { ProfileExecutionState } from '../../query/profile_execution_state.js';
       3              : 
       4            1 : const view = dashql.buffers.profile;
       5              : 
       6              : /// Updates the status markers of a mounted plan in place, without rendering the plan again
       7            1 : export class ProfileExecutionController {
       8            1 :     private operatorElements: Array<SVGGElement | null> = [];
       9            1 :     private pipelinePaths: Array<SVGPathElement | null> = [];
      10            1 :     private statuses = new Uint8Array();
      11              : 
      12            1 :     public reset(operatorCount: number, pipelineCount: number) {
      13            1 :         this.operatorElements.length = operatorCount;
      14            1 :         this.pipelinePaths.length = pipelineCount;
      15            1 :         this.statuses = new Uint8Array(operatorCount);
      16            1 :         for (const element of this.operatorElements) {
      17            1 :             if (element != null) element.dataset.status = `${view.ProfileExecutionStatus.UNKNOWN}`;
      18              :         }
      19            1 :         for (const path of this.pipelinePaths) {
      20            1 :             if (path != null) delete path.dataset.status;
      21              :         }
      22            1 :     }
      23              : 
      24            1 :     public registerOperator(id: number, element: SVGGElement | null) {
      25            1 :         this.operatorElements[id] = element;
      26            1 :         if (element != null) element.dataset.status = `${this.statuses[id] ?? view.ProfileExecutionStatus.UNKNOWN}`;
      27            1 :     }
      28              : 
      29            1 :     public registerPipeline(id: number, path: SVGPathElement | null) {
      30            1 :         this.pipelinePaths[id] = path;
      31            1 :     }
      32              : 
      33            1 :     private setOperatorStatus(id: number, status: dashql.buffers.profile.ProfileExecutionStatus) {
      34            1 :         if (id >= this.statuses.length || this.statuses[id] === status) return;
      35            1 :         this.statuses[id] = status;
      36            1 :         const element = this.operatorElements[id];
      37            1 :         if (element != null) element.dataset.status = `${status}`;
      38            1 :     }
      39              : 
      40            1 :     private setPipelineStatus(id: number, status: dashql.buffers.profile.ProfileExecutionStatus) {
      41            1 :         const path = this.pipelinePaths[id];
      42            1 :         if (path != null) path.dataset.status = `${status}`;
      43            1 :     }
      44              : 
      45              :     /// Apply the output events of the core query profile
      46            1 :     public applyEvents(events: dashql.buffers.profile.QueryProfileEvents) {
      47            1 :         const event = new view.ProfileUpdateEvent();
      48            1 :         for (let i = 0; i < events.eventsLength(); ++i) {
      49            1 :             events.events(i, event);
      50            1 :             switch (event.entity()) {
      51            1 :                 case view.ProfileEntity.OPERATOR:
      52            1 :                     this.setOperatorStatus(event.index(), event.status());
      53            1 :                     break;
      54            1 :                 case view.ProfileEntity.PIPELINE:
      55            1 :                     this.setPipelineStatus(event.index(), event.status());
      56              :                     break;
      57            1 :             }
      58            1 :         }
      59            1 :     }
      60              : 
      61              :     /// Show the statuses of an execution state, after a reset. An operator without status of its own shows the
      62              :     /// status of its fragment (`operatorFragments`, by operator): Trino reports operators of finished stages only.
      63            1 :     public applyState(state: ProfileExecutionState, operatorFragments: readonly number[] = []) {
      64            1 :         for (let id = 0; id < this.statuses.length; ++id) {
      65            1 :             const own = state.operators[id]?.status ?? view.ProfileExecutionStatus.UNKNOWN;
      66            1 :             const fragment = operatorFragments[id];
      67            1 :             const inherited = fragment == null ? undefined : state.fragments[fragment]?.status;
      68            1 :             const status = own !== view.ProfileExecutionStatus.UNKNOWN ? own : inherited;
      69            1 :             if (status != null) this.setOperatorStatus(id, status);
      70            1 :         }
      71            1 :         state.pipelines.forEach((pipeline, id) => {
      72            1 :             if (pipeline != null) this.setPipelineStatus(id, pipeline.status);
      73            1 :         });
      74            1 :     }
      75            1 : }
        

Generated by: LCOV version 2.0-1