From e561bd156f89ae1f10e9fb8b0c9115619ef2d53f Mon Sep 17 00:00:00 2001 From: Eve <92513238+Eve-z1@users.noreply.github.com> Date: Mon, 14 Sep 2026 14:28:09 +0800 Subject: [PATCH] feat(query): name result tabs from SQL comments --- .../src/lib/__tests__/sql/queryResultSource.spec.ts | 6 ++++-- apps/desktop/src/lib/sql/queryResultSource.ts | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/lib/__tests__/sql/queryResultSource.spec.ts b/apps/desktop/src/lib/__tests__/sql/queryResultSource.spec.ts index 9e0d1958b0..c153c5ecdc 100644 --- a/apps/desktop/src/lib/__tests__/sql/queryResultSource.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/queryResultSource.spec.ts @@ -5,10 +5,12 @@ 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("ignores unrelated, malformed, and block comments", () => { - expect(queryResultNameFromPreamble("-- Name without colon\n/*\n-- Name: block\n*/\n-- ordinary comment\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(); }); }); diff --git a/apps/desktop/src/lib/sql/queryResultSource.ts b/apps/desktop/src/lib/sql/queryResultSource.ts index f221ff0802..9afd9429c5 100644 --- a/apps/desktop/src/lib/sql/queryResultSource.ts +++ b/apps/desktop/src/lib/sql/queryResultSource.ts @@ -9,12 +9,18 @@ export interface QueryResultSourceLabelOptions { export function queryResultNameFromPreamble(preamble: string): 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 candidate = line.match(/^\s*--\s*name\s*:\s*(.*)$/i)?.[1]?.trim(); + const comment = line.match(/^\s*--\s*(.*)$/)?.[1]?.trim(); + if (!comment) continue; + + const nameMatch = comment.match(/^name\s*:\s*(.*)$/i); + const candidate = nameMatch?.[1]?.trim(); if (candidate) name = candidate; + else if (!nameMatch) fallback = comment; } - return name; + return name ?? fallback; } function firstSourceOfKind(sources: SqlSemanticRowSource[], kind: SqlSemanticRowSource["kind"]): SqlSemanticRowSource | undefined {