feat(query): support custom result names from SQL comments
This commit is contained in:
parent
b43480c6bc
commit
086e20f878
|
|
@ -1,5 +1,16 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { queryResultSourceLabel } from "@/lib/sql/queryResultSource";
|
||||
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");
|
||||
});
|
||||
|
||||
it("ignores unrelated, malformed, and block comments", () => {
|
||||
expect(queryResultNameFromPreamble("-- Name without colon\n/*\n-- Name: block\n*/\n-- ordinary comment\n")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("queryResultSourceLabel", () => {
|
||||
it("uses the current database for an unqualified table", () => {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,16 @@ export interface QueryResultSourceLabelOptions {
|
|||
databaseType?: DatabaseType;
|
||||
}
|
||||
|
||||
export function queryResultNameFromPreamble(preamble: string): string | undefined {
|
||||
let name: 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();
|
||||
if (candidate) name = candidate;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
function firstSourceOfKind(sources: SqlSemanticRowSource[], kind: SqlSemanticRowSource["kind"]): SqlSemanticRowSource | undefined {
|
||||
return sources.filter((source) => source.kind === kind).sort((left, right) => left.sourceSpan.start - right.sourceSpan.start)[0];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,21 @@ describe("queryStore multi-statement errors", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("uses Name comments for their indexed query results", async () => {
|
||||
mocks.executeMulti.mockResolvedValue([
|
||||
{ columns: ["id"], rows: [[2]], affected_rows: 0, execution_time_ms: 1, statement_index: 1 },
|
||||
{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1, statement_index: 0 },
|
||||
]);
|
||||
const { useQueryStore } = await import("@/stores/queryStore");
|
||||
const store = useQueryStore();
|
||||
const tabId = store.createTab("mysql-1", "app", "Query");
|
||||
const sql = "-- Name: Users\nSELECT * FROM users;\n-- name : Orders\nSELECT * FROM orders";
|
||||
|
||||
await store.executeTabSql(tabId, sql);
|
||||
|
||||
expect(store.tabs.find((item) => item.id === tabId)?.results?.map((result) => result.sourceLabel)).toEqual(["Orders", "Users"]);
|
||||
});
|
||||
|
||||
it("does not promote an unmarked Error alias without type metadata as a batch failure", async () => {
|
||||
mocks.executeMulti.mockResolvedValue([
|
||||
{ columns: ["value"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 },
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import { loadTableMetadata } from "@/lib/metadata/tableMetadataCache";
|
|||
import { buildTableSelectSql, quoteTableDataIdentifier } from "@/lib/table/tableSelectSql";
|
||||
import { connectionQueryExecutionSchema, effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/database/jdbcDialect";
|
||||
import { frontendQueryTimeoutSecsForSql, queryTimeoutSecsForConnection } from "@/lib/sql/queryTimeout";
|
||||
import { queryResultSourceLabel } from "@/lib/sql/queryResultSource";
|
||||
import { queryResultNameFromPreamble, queryResultSourceLabel } from "@/lib/sql/queryResultSource";
|
||||
import { sortDataGridRowIndexes, type DataGridSortDirection } from "@/lib/dataGrid/dataGridSort";
|
||||
import { normalizeResultPageSize } from "@/lib/dataGrid/paginationPageSize";
|
||||
import { executableStatementRanges, splitSqlStatementRanges } from "@/lib/sql/sqlStatementRanges";
|
||||
|
|
@ -155,6 +155,8 @@ function annotateQueryResultSources(results: QueryResult[], sql: string, databas
|
|||
const statement = statements[sourceIndex];
|
||||
if (!statement) continue;
|
||||
annotateQueryResultSource(result, statement.sql, database, databaseType, sourceOffset === undefined ? undefined : { from: sourceOffset + statement.from, to: sourceOffset + statement.to });
|
||||
const customName = queryResultNameFromPreamble(sql.slice(statement.hitFrom, statement.from));
|
||||
if (customName) result.sourceLabel = customName;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue