LCOV - code coverage report
Current view: top level - dashql-app/src/session/scripts - rerun_query.ts Coverage Total Hit
Test: DashQL 915828b Lines: 90.4 % 83 75
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import type * as arrow from 'apache-arrow';
       2              : 
       3              : import type { QueryExecutor } from '../../connections/query_executor.js';
       4              : import { SessionScripts, ScriptData, isAnalysisOutdated } from './session_scripts.js';
       5              : import { ensureSessionScriptAnalyzed, ModifySessionScripts } from './session_scripts_registry.js';
       6              : import { stringifyError, type LoggerLike } from '../../platform/logger/logger.js';
       7              : import { isSessionExecutionRunning, releaseSessionExecution, waitForSessionExecution } from './session_execution.js';
       8              : import { runPlannedScript, scriptRunServices, type ScriptRunOptions } from './script_run.js';
       9              : 
      10              : /// Run a script on its connection, resolves when the run ended. A failed statement and a plan that fails, e.g. with an
      11              : /// unknown script, show their errors in the script. A refresh reads no cached results, neither of the script nor of
      12              : /// the scripts it references.
      13            1 : export async function runSessionScript(
      14            1 :     sessionScripts: SessionScripts,
      15            1 :     scriptData: ScriptData,
      16            1 :     executeQuery: QueryExecutor,
      17            1 :     modifySessionScripts: ModifySessionScripts,
      18            1 :     logger: LoggerLike,
      19            1 :     options: ScriptRunOptions = {},
      20            1 : ): Promise<void> {
      21            1 :     if (isSessionExecutionRunning(sessionScripts)) return;
      22            1 :     logger?.info('Session script execution requested', {
      23            1 :         connectionId: scriptData.connection.connectionId,
      24            1 :         sessionId: sessionScripts.sessionId,
      25            1 :         scriptKey: scriptData.scriptKey.toString(),
      26            1 :         analysisOutdated: scriptData.analysisOutdated.toString(),
      27            1 :         analysisAvailable: scriptData.editorUpdate?.analysisAvailable.toString(),
      28            1 :         textVersion: scriptData.editorUpdate?.textVersion.toString(),
      29            1 :         nativeTextVersion: scriptData.scriptSession.getTextVersion?.().toString(),
      30            1 :         textLength: scriptData.scriptSession.getText?.().length.toString(),
      31            1 :     }, 'session_execution');
      32            1 :     if (isAnalysisOutdated(scriptData)) {
      33            1 :         const analyzed = await ensureSessionScriptAnalyzed(sessionScripts, scriptData.scriptKey, modifySessionScripts);
      34            1 :         if (analyzed == null) {
      35            0 :             logger?.warn('Session execution stopped because analysis returned no script', {
      36            0 :                 sessionId: sessionScripts.sessionId,
      37            0 :                 scriptKey: scriptData.scriptKey.toString(),
      38            0 :             }, 'session_execution');
      39            0 :             return;
      40            0 :         }
      41            1 :         logger?.info('Outdated session script analysis completed', {
      42            1 :             sessionId: sessionScripts.sessionId,
      43            1 :             scriptKey: scriptData.scriptKey.toString(),
      44            1 :             analysisAvailable: analyzed.editorUpdate?.analysisAvailable.toString(),
      45            1 :         }, 'session_execution');
      46            1 :         scriptData = analyzed;
      47            1 :     }
      48            1 :     await executeSessionScript(scriptData, sessionScripts, executeQuery, modifySessionScripts, logger, false, options);
      49            1 : }
      50              : 
      51              : /// Run a script on its connection and wait for its result, e.g. a run of the agent. The run waits for the run of
      52              : /// another script of the session to end. Fails when the whole session runs, the script is gone, can't be planned,
      53              : /// holds no statement, or a statement fails or is cancelled.
      54            1 : export async function runSessionScriptForResult(
      55            1 :     getSession: () => SessionScripts | null,
      56            1 :     scriptKey: number,
      57            1 :     executeQuery: QueryExecutor,
      58            1 :     modifySessionScripts: ModifySessionScripts,
      59            1 :     logger: LoggerLike,
      60            1 : ): Promise<arrow.Table | null> {
      61            1 :     const sessionId = getSession()?.sessionId;
      62            1 :     if (sessionId == null) throw new Error('The session is gone');
      63            1 :     await waitForSessionExecution(sessionId);
      64            1 :     let handedOver = false;
      65            1 :     try {
      66              :         // The session as the runs before left it, e.g. with analyzed scripts
      67            1 :         const waited = getSession();
      68            1 :         const scriptData = waited?.scripts[scriptKey];
      69            1 :         if (waited == null || scriptData == null) throw new Error('The script is gone');
      70            1 :         const analyzed = isAnalysisOutdated(scriptData)
      71            1 :             ? await ensureSessionScriptAnalyzed(waited, scriptKey, modifySessionScripts)
      72            0 :             : scriptData;
      73            1 :         if (analyzed == null) {
      74            0 :             throw new Error('The script could not be analyzed');
      75              :         }
      76              :         // The run releases the session. The caller reports the failure, e.g. to the agent, the script shows it as well.
      77            1 :         handedOver = true;
      78            1 :         return await executeSessionScript(analyzed, getSession() ?? waited, executeQuery, modifySessionScripts, logger, true, { held: true });
      79            1 :     } finally {
      80            1 :         if (!handedOver) releaseSessionExecution(sessionId);
      81            1 :     }
      82            1 : }
      83              : 
      84              : /// Run a script through a plan of the script and the scripts it references (docs/design/script_references.md)
      85            1 : function executeSessionScript(
      86            1 :     scriptData: ScriptData,
      87            1 :     sessionScripts: SessionScripts,
      88            1 :     executeQuery: QueryExecutor,
      89            1 :     modifySessionScripts: ModifySessionScripts,
      90            1 :     logger: LoggerLike,
      91            1 :     throwOnError: boolean = false,
      92            1 :     options: ScriptRunOptions = {},
      93            1 : ): Promise<arrow.Table | null> {
      94            1 :     const services = scriptRunServices(sessionScripts.instance);
      95            1 :     return runPlannedScript(services, sessionScripts, scriptData, executeQuery, modifySessionScripts, { logger, ...options }).catch(error => {
      96            1 :         if (throwOnError) throw error;
      97            1 :         logger?.warn('Session script run failed', {
      98            1 :             sessionId: sessionScripts.sessionId,
      99            1 :             scriptKey: scriptData.scriptKey.toString(),
     100            1 :             error: stringifyError(error),
     101            1 :         }, 'session_execution');
     102            1 :         return null;
     103            1 :     });
     104            1 : }
        

Generated by: LCOV version 2.0-1