fix(query): use adjacent comments for result labels
This commit is contained in:
3 files changed
+31
-25
No files matched your search
+14
-10
@@ -2,21 +2,25 @@ import { describe, expect, it } from "vitest";
|
||||
import { queryResultNameFromPreamble, queryResultSourceLabel } from "@/lib/sql/queryResultSource";
|
||||
|
||||
describe("queryResultNameFromPreamble", () => {
|
||||
it("uses the nearest non-empty Name line comment", () => {
|
||||
expect(queryResultNameFromPreamble("-- Name: Old name\n-- unrelated\r\n -- NAME : Latest name \r\n")).toBe("Latest name");
|
||||
expect(queryResultNameFromPreamble("-- Name: kept\n-- Name: \n")).toBe("kept");
|
||||
expect(queryResultNameFromPreamble("-- Name: explicit\n-- nearest ordinary comment\n")).toBe("explicit");
|
||||
it("uses only the immediately preceding line comment", () => {
|
||||
expect(queryResultNameFromPreamble("-- Name: Latest name\r\n")).toBe("Latest name");
|
||||
expect(queryResultNameFromPreamble("-- unrelated\n")).toBe("unrelated");
|
||||
expect(queryResultNameFromPreamble("-- indented\n ")).toBe("indented");
|
||||
expect(queryResultNameFromPreamble("-- Name: Old name\n-- unrelated\n")).toBe("unrelated");
|
||||
expect(queryResultNameFromPreamble("-- Name: explicit\n-- \n")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("falls back to the nearest non-empty line comment", () => {
|
||||
expect(queryResultNameFromPreamble("-- older comment\n/*\n-- Name: block\n*/\n-- 当前时间\n")).toBe("当前时间");
|
||||
expect(queryResultNameFromPreamble("/* -- block only */\n-- \n")).toBeUndefined();
|
||||
it("stops at a blank line and ignores non-line comments", () => {
|
||||
expect(queryResultNameFromPreamble("-- older comment\n\n")).toBeUndefined();
|
||||
expect(queryResultNameFromPreamble("/* Name: block */\n")).toBeUndefined();
|
||||
expect(queryResultNameFromPreamble("-- earlier comment\n/* block */\n")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("accepts hash comments for MySQL without treating them as portable SQL comments", () => {
|
||||
expect(queryResultNameFromPreamble("# MySQL report\nSELECT 1", { databaseType: "mysql" })).toBe("MySQL report");
|
||||
expect(queryResultNameFromPreamble("# temporary table\nSELECT 1", { databaseType: "sqlserver" })).toBeUndefined();
|
||||
expect(queryResultNameFromPreamble("# portable comment\nSELECT 1")).toBeUndefined();
|
||||
expect(queryResultNameFromPreamble("# MySQL report\n", { databaseType: "mysql" })).toBe("MySQL report");
|
||||
expect(queryResultNameFromPreamble("# temporary table\n", { databaseType: "sqlserver" })).toBeUndefined();
|
||||
expect(queryResultNameFromPreamble("# portable comment\n")).toBeUndefined();
|
||||
expect(queryResultNameFromPreamble("# MySQL report\n\n", { databaseType: "mysql" })).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -10,21 +10,19 @@ export interface QueryResultSourceLabelOptions {
|
||||
const HASH_COMMENT_DATABASE_TYPES = new Set<DatabaseType>(["mysql"]);
|
||||
|
||||
export function queryResultNameFromPreamble(preamble: string, options: Pick<QueryResultSourceLabelOptions, "databaseType"> = {}): string | undefined {
|
||||
let name: string | undefined;
|
||||
let fallback: string | undefined;
|
||||
const withoutBlockComments = preamble.replace(/\/\*[\s\S]*?\*\//g, "");
|
||||
for (const line of withoutBlockComments.split(/\r?\n/)) {
|
||||
const commentMatch = line.match(/^\s*(--|#)\s*(.*)$/);
|
||||
if (commentMatch?.[1] === "#" && !HASH_COMMENT_DATABASE_TYPES.has(options.databaseType!)) continue;
|
||||
const comment = commentMatch?.[2]?.trim();
|
||||
if (!comment) continue;
|
||||
const beforeStatementLine = preamble.replace(/[ \t]*$/, "");
|
||||
const previousLine =
|
||||
beforeStatementLine
|
||||
.replace(/\r?\n$/, "")
|
||||
.split(/\r?\n/)
|
||||
.pop() ?? "";
|
||||
const commentMatch = previousLine.match(/^\s*(--|#)\s*(.*)$/);
|
||||
if (commentMatch?.[1] === "#" && !HASH_COMMENT_DATABASE_TYPES.has(options.databaseType!)) return undefined;
|
||||
const comment = commentMatch?.[2]?.trim();
|
||||
if (!comment) return undefined;
|
||||
|
||||
const nameMatch = comment.match(/^name\s*:\s*(.*)$/i);
|
||||
const candidate = nameMatch?.[1]?.trim();
|
||||
if (candidate) name = candidate;
|
||||
else if (!nameMatch) fallback = comment;
|
||||
}
|
||||
return name ?? fallback;
|
||||
const nameMatch = comment.match(/^name\s*:\s*(.*)$/i);
|
||||
return nameMatch ? nameMatch[1]?.trim() || undefined : comment;
|
||||
}
|
||||
|
||||
function firstSourceOfKind(sources: SqlSemanticRowSource[], kind: SqlSemanticRowSource["kind"]): SqlSemanticRowSource | undefined {
|
||||
|
||||
Reference in new issue
Block a user