feat(query-editor): enhance current statement framing

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-07-06 23:09:21 +08:00
1 parent 75fcd253cb
commit 18e5df6f5e
18 files changed
+480 -10

No files matched your search

@@ -1,6 +1,6 @@
import { Text } from "@codemirror/state";
import { describe, expect, it, vi } from "vitest";
import { executableStatementRangeCacheForDoc, executableStatementRangeStartingAt, type ExecutableStatementRangeParser } from "@/lib/sql/executableStatementRangeCache";
import { executableStatementRangeAtCursor, executableStatementRangeCacheForDoc, executableStatementRangeStartingAt, type ExecutableStatementRangeParser } from "@/lib/sql/executableStatementRangeCache";
describe("executableStatementRangeCacheForDoc", () => {
it("reuses parsed executable statement ranges for the same document and database type", () => {
@@ -27,6 +27,41 @@ describe("executableStatementRangeCacheForDoc", () => {
expect(executableStatementRangeStartingAt(cache, secondStatementLine.from)?.sql).toBe("SELECT *\nFROM menus AS mn\nLIMIT 100");
});
it("resolves the current statement from a cursor inside a continuation line", () => {
const doc = Text.of(["SELECT *", "FROM apis AS ap", "LIMIT 100;", "", "SELECT *", "FROM menus AS mn", "LIMIT 100;"]);
const cache = executableStatementRangeCacheForDoc(null, doc, "mysql");
const cursor = doc.toString().indexOf("menus");
expect(executableStatementRangeAtCursor(cache, cursor)?.sql).toBe("SELECT *\nFROM menus AS mn\nLIMIT 100");
});
it("keeps indentation and same-line semicolon gaps attached to the current statement", () => {
const doc = Text.of(["SELECT 1;", " SELECT 2;"]);
const cache = executableStatementRangeCacheForDoc(null, doc, "mysql");
const indentationCursor = doc.line(2).from + 2;
const semicolonGapCursor = doc.toString().indexOf(";") + 1;
expect(executableStatementRangeAtCursor(cache, indentationCursor)?.sql).toBe("SELECT 2");
expect(executableStatementRangeAtCursor(cache, semicolonGapCursor)?.sql).toBe("SELECT 1");
});
it("returns null for blank and pure comment cursor lines", () => {
const doc = Text.of(["SELECT 1;", "-- comment", "/* block comment */", "", "SELECT 2;"]);
const cache = executableStatementRangeCacheForDoc(null, doc, "mysql");
expect(executableStatementRangeAtCursor(cache, doc.line(2).from + 3)).toBeNull();
expect(executableStatementRangeAtCursor(cache, doc.line(3).from + 3)).toBeNull();
expect(executableStatementRangeAtCursor(cache, doc.line(4).from)).toBeNull();
});
it("resolves SQL after a leading block comment on the same line", () => {
const doc = Text.of(["/* comment */ SELECT 1;"]);
const cache = executableStatementRangeCacheForDoc(null, doc, "mysql");
expect(executableStatementRangeAtCursor(cache, doc.toString().indexOf("SELECT"))?.sql).toBe("SELECT 1");
expect(executableStatementRangeAtCursor(cache, doc.toString().indexOf("comment"))).toBeNull();
});
it("rebuilds the cache when the document instance changes", () => {
const firstDoc = Text.of(["SELECT 1;"]);
const secondDoc = Text.of(["SELECT 1;"]);