LCOV - code coverage report
Current view: top level - dashql-app/src/session/dataflow - dataflow_source.ts Coverage Total Hit
Test: DashQL 915828b Lines: 95.5 % 67 64
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import type * as core from '@ankoh/dashql-core';
       2              : 
       3              : import type { ModifySessionScripts } from '../scripts/session_scripts_registry.js';
       4              : import { CREATE_SCRIPT, DELETE_SCRIPT, SET_SCRIPT_TEXT, type ScriptData } from '../scripts/session_scripts.js';
       5              : import { scriptDisplayName, type FlowPosition } from '../scripts/script_types.js';
       6              : 
       7              : /// The placement of the `@flow` tag of a script, null without a tag
       8            1 : function placementOf(flow: FlowPosition | null | undefined): core.DataflowPlacement | null {
       9            1 :     if (flow == null) return null;
      10            1 :     return { position: flow.x != null && flow.y != null ? { x: flow.x, y: flow.y } : null, width: flow.width, height: flow.height };
      11            1 : }
      12              : 
      13              : /// Write a placement into the `@flow` tag of a script, the tag is removed if the placement is empty. Returns whether
      14              : /// the script has the placement, a script that does not parse or has no statement can't be placed.
      15            1 : function writeFlow(script: ScriptData, placement: core.DataflowPlacement, modifySessionScripts: ModifySessionScripts): boolean {
      16            1 :     const round = (value: number | null | undefined) => (value == null ? null : Math.round(value));
      17            1 :     const next = {
      18            1 :         position: placement.position == null ? null : { x: Math.round(placement.position.x), y: Math.round(placement.position.y) },
      19            1 :         width: round(placement.width),
      20            1 :         height: round(placement.height),
      21            1 :     };
      22            1 :     const empty = next.position == null && next.width == null && next.height == null;
      23            1 :     const current = placementOf(script.annotations.flowPosition);
      24            1 :     const unchanged = current == null
      25            1 :         ? empty
      26            1 :         : current.position?.x === next.position?.x && current.position?.y === next.position?.y
      27            1 :             && (current.width ?? null) === next.width && (current.height ?? null) === next.height;
      28            1 :     if (unchanged) return true;
      29            1 :     let text: string;
      30            1 :     try {
      31            1 :         text = empty ? script.scriptSession.removeVisFlow() : script.scriptSession.rewriteVisFlow(next);
      32            1 :     } catch (e) {
      33            0 :         console.warn('cannot write the placement of the script', e);
      34            0 :         return false;
      35            0 :     }
      36            1 :     modifySessionScripts({ type: SET_SCRIPT_TEXT, value: { scriptKey: script.scriptKey, text } });
      37            1 :     return true;
      38            1 : }
      39              : 
      40              : /// Write the position of a script into its `@flow` tag, the size of the box stays. Returns whether the script has
      41              : /// the position.
      42              : export function persistFlowPosition(script: ScriptData, x: number, y: number, modifySessionScripts: ModifySessionScripts): boolean {
      43              :     const current = placementOf(script.annotations.flowPosition);
      44              :     return writeFlow(script, { ...current, position: { x, y } }, modifySessionScripts);
      45              : }
      46              : 
      47              : /// Write the position and the size of a box into the `@flow` tag of its script at once: its width and the height of
      48              : /// its chart, null for the default. Returns whether the script has the placement.
      49            1 : export function persistFlowPlacement(
      50            1 :     script: ScriptData,
      51            1 :     position: { x: number; y: number },
      52            1 :     width: number | null,
      53            1 :     height: number | null,
      54            1 :     modifySessionScripts: ModifySessionScripts,
      55            1 : ): boolean {
      56            1 :     return writeFlow(script, { position, width, height }, modifySessionScripts);
      57            1 : }
      58              : 
      59              : /// Write the size of a box into the `@flow` tag of its script: its width and the height of its chart, null for the
      60              : /// default. The position stays, a box without one is still placed by the layout. Returns whether the script has
      61              : /// the size.
      62              : export function persistFlowSize(script: ScriptData, width: number | null, height: number | null, modifySessionScripts: ModifySessionScripts): boolean {
      63              :     const current = placementOf(script.annotations.flowPosition);
      64              :     return writeFlow(script, { position: current?.position ?? null, width, height }, modifySessionScripts);
      65              : }
      66              : 
      67              : /// Remove the positions from the `@flow` tags of scripts, the layout places them again. The sizes of the boxes stay.
      68            1 : export function removeFlowPositions(scripts: ScriptData[], modifySessionScripts: ModifySessionScripts): void {
      69            1 :     for (const script of scripts) {
      70            1 :         const current = placementOf(script.annotations.flowPosition);
      71            1 :         if (current?.position == null) continue;
      72            1 :         writeFlow(script, { ...current, position: null }, modifySessionScripts);
      73            1 :     }
      74            1 : }
      75              : 
      76              : /// The text of a new script, at a position of the canvas if given, a query of the result of `producer` if given
      77            1 : export function newFlowScriptText(position: { x: number; y: number } | null, producer: ScriptData | null, quoteIdentifier: (name: string) => string): string {
      78            1 :     const tag = position != null ? `/** @flow x=${Math.round(position.x)} y=${Math.round(position.y)} */\n` : '';
      79            1 :     if (producer == null) return `${tag}select 1`;
      80            1 :     return `${tag}select * from :${quoteIdentifier(scriptDisplayName(producer.fileName))}`;
      81            1 : }
      82              : 
      83              : /// Create a script: a query of the result of `producer` on its connection, or a query on the connection of the last
      84              : /// script. A script without a position is placed by the layout, one that reads `producer` right of it.
      85            1 : export function createFlowScript(
      86            1 :     position: { x: number; y: number } | null,
      87            1 :     producer: ScriptData | null,
      88            1 :     quoteIdentifier: (name: string) => string,
      89            1 :     modifySessionScripts: ModifySessionScripts,
      90            1 : ): ReturnType<ModifySessionScripts> {
      91            1 :     return modifySessionScripts({
      92            1 :         type: CREATE_SCRIPT,
      93            1 :         value: {
      94            1 :             index: null,
      95            1 :             text: newFlowScriptText(position, producer, quoteIdentifier),
      96            1 :             ...(producer != null ? { connection: producer.connection } : {}),
      97            1 :         },
      98            1 :     });
      99            1 : }
     100              : 
     101              : /// Delete a script
     102            1 : export function deleteFlowScript(script: ScriptData, modifySessionScripts: ModifySessionScripts): void {
     103            1 :     modifySessionScripts({ type: DELETE_SCRIPT, value: script.fileName });
     104            1 : }
        

Generated by: LCOV version 2.0-1