dbx/apps/desktop/src/lib/sql/sqlExecutionTarget.ts

77 lines
2.7 KiB
TypeScript

import * as api from "@/lib/backend/api";
import { mongoCommandRangeAtCursor } from "@/lib/sql/sqlStatementRanges";
import type { DatabaseType } from "@/types/database";
export type ExecuteMode = "all" | "current";
export interface SqlExecutionSnapshot {
fullSql: string;
selectedSql: string;
cursorPos: number;
selectionFrom: number;
selectionTo: number;
}
export type SqlExecutionOverride = string | SqlExecutionSnapshot;
export type SqlExecutionTargetKind = "cursor" | "all";
/**
* A candidate execution target surfaced by the execution target picker.
* `from`/`to` are offsets into the full document so the editor can highlight
* the corresponding range as a preview while the picker is open.
*/
export interface SqlExecutionCandidate {
kind: SqlExecutionTargetKind;
supportedKinds: SqlExecutionTargetKind[];
label: string;
sql: string;
from: number;
to: number;
}
export interface SqlExecutionChoiceRequest {
fullSql: string;
selectedSql: string;
cursorPos: number;
candidates: SqlExecutionCandidate[];
}
export function isSqlExecutionSnapshot(value: SqlExecutionOverride | undefined): value is SqlExecutionSnapshot {
return typeof value === "object" && value !== null && typeof value.fullSql === "string" && typeof value.selectedSql === "string" && typeof value.cursorPos === "number" && typeof value.selectionFrom === "number" && typeof value.selectionTo === "number";
}
export function executionCandidateForMode(candidates: SqlExecutionCandidate[], mode: ExecuteMode): SqlExecutionCandidate | null {
const targetKind: SqlExecutionTargetKind = mode === "current" ? "cursor" : "all";
return candidates.find((candidate) => candidate.supportedKinds.includes(targetKind)) ?? null;
}
export function resolveExecutableSql(fullSql: string, selectedSql: string, options?: { mode?: ExecuteMode; cursorPos?: number }): string {
const trimmedSelection = selectedSql.trim();
if (trimmedSelection) return trimmedSelection;
if (options?.mode === "current" && options.cursorPos !== undefined) {
return fullSql;
}
return fullSql;
}
export async function resolveExecutableSqlWithBackend(fullSql: string, selectedSql: string, options?: { mode?: ExecuteMode; cursorPos?: number; databaseType?: DatabaseType }): Promise<string> {
const trimmedSelection = selectedSql.trim();
if (trimmedSelection) return trimmedSelection;
if (options?.databaseType === "mongodb") {
if (options.mode === "current" && options.cursorPos !== undefined) {
return mongoCommandRangeAtCursor(fullSql, options.cursorPos)?.sql ?? fullSql;
}
return fullSql;
}
if (options?.mode === "current" && options.cursorPos !== undefined) {
return await api.findStatementAtCursor(fullSql, options.cursorPos, options.databaseType);
}
return fullSql;
}