fix(grid): show comments for joined query results

This commit is contained in:
jearhe authored and GitHub committed 2026-08-16 15:34:03 +08:00
1 parent d5f18034f9
commit 64e5e88c27
11 files changed
+867 -9

No files matched your search

+29 -2
View File
@@ -71,7 +71,7 @@ import DataGridTextFilterWorkbench from "@/components/grid/DataGridTextFilterWor
import TemporalCellEditor from "@/components/grid/TemporalCellEditor.vue";
import EnumCellEditor from "@/components/grid/EnumCellEditor.vue";
import DataGridReadonlyTextSelection from "@/components/grid/DataGridReadonlyTextSelection.vue";
import type { QueryResult, ColumnInfo, DatabaseType, ForeignKeyInfo, IndexInfo, TriggerInfo, TableInfoTab } from "@/types/database";
import type { QueryResult, ColumnInfo, DatabaseType, ForeignKeyInfo, IndexInfo, TriggerInfo, TableInfoTab, QueryResultSourceColumnRef } from "@/types/database";
import { isQueryExecutionErrorResult } from "@/lib/query/queryResultError";
import { tableObjectSourceKind } from "@/lib/table/tableObjectSourceKind";
import { tableColumnDefaultDisplayValue } from "@/lib/table/tableColumnDefaultPresentation";
@@ -346,6 +346,22 @@ interface DataGridProps {
context?: "results" | "table-data";
autoTransposeSingleRow?: boolean;
sourceColumns?: Array<string | undefined>;
/**
* Column comments for a multi-source query result (e.g. JOIN), indexed by
* result-column ordinal (projection order). Populated even when the result is
* not editable, so joined results still show comments. `undefined` for a
* column that cannot be resolved back to exactly one base column (ambiguous
* or computed) — the grid shows no comment instead of a wrong one.
*/
resultColumnComments?: Array<string | undefined>;
/**
* Display-only result-column -> source mapping for multi-source results,
* indexed by result-column ordinal; each entry carries the source identity
* (sourceKey + canonical source column name). Used to resolve column
* comments per source instead of first-source-wins; never used for row
* identity or editing.
*/
queryDisplaySourceColumns?: Array<QueryResultSourceColumnRef | undefined>;
initialWhereInput?: string;
initialOrderByInput?: string;
sortColumn?: string;
@@ -586,6 +602,11 @@ const readonlyTextCell = ref<{
} | null>(null);
function resolvedColumnComment(column: string, actualColIdx: number): string | undefined {
// Multi-source results resolve comments per result ordinal; ambiguous or
// unresolved columns yield undefined instead of falling back to a
// first-source-wins name map.
const ordinalComments = props.resultColumnComments;
if (ordinalComments) return ordinalComments[actualColIdx];
return dataGridColumnCommentFor(columnCommentMap.value, column, props.sourceColumns?.[actualColIdx]);
}
@@ -2116,7 +2137,13 @@ const allColumnTypes = computed(() =>
const visibleColumnTypes = computed(() => visibleColumnIndexes.value.map((index) => allColumnTypes.value[index]));
const allColumnTypeVisualKinds = computed(() => allColumnTypes.value.map((type) => resolveDataGridTypeVisualKind(type, resolvedDatabaseType.value)));
const visibleColumnTypeVisualKinds = computed(() => visibleColumnIndexes.value.map((index) => allColumnTypeVisualKinds.value[index] ?? "unknown"));
const visibleColumnComments = computed(() => visibleColumnIndexes.value.map((index) => dataGridColumnCommentFor(columnCommentMap.value, props.result.columns[index] ?? "", props.sourceColumns?.[index])));
const visibleColumnComments = computed(() =>
visibleColumnIndexes.value.map((index) => {
const ordinalComments = props.resultColumnComments;
if (ordinalComments) return ordinalComments[index];
return dataGridColumnCommentFor(columnCommentMap.value, props.result.columns[index] ?? "", props.sourceColumns?.[index]);
}),
);
const visibleColumnCount = computed(() => visibleColumnIndexes.value.length);
const numericColumnRightAlign = computed(() => (settingsStore.editorSettings.numericColumnRightAlign ?? true) && !showTranspose.value);
@@ -4,8 +4,10 @@ import { describe, expect, it } from "vitest";
const dataGridSource = readFileSync(new URL("../DataGrid.vue", import.meta.url), "utf8");
describe("DataGrid column comments", () => {
it("uses source column metadata for both inline and tooltip header comments", () => {
expect(dataGridSource).toMatch(/function resolvedColumnComment\(column: string, actualColIdx: number\)[\s\S]*?dataGridColumnCommentFor\([\s\S]*?props\.sourceColumns\?\.\[actualColIdx\][\s\S]*?\);\s*\}/);
it("uses per-ordinal multi-source comments, falling back to source metadata for single-source grids", () => {
expect(dataGridSource).toMatch(
/function resolvedColumnComment\(column: string, actualColIdx: number\)[\s\S]*?const ordinalComments = props\.resultColumnComments;[\s\S]*?if \(ordinalComments\) return ordinalComments\[actualColIdx\];[\s\S]*?dataGridColumnCommentFor\([\s\S]*?props\.sourceColumns\?\.\[actualColIdx\][\s\S]*?\);\s*\}/,
);
expect(dataGridSource).toContain(':column-comment="headerColumnComment(col.name, col.actualColIdx)"');
expect(dataGridSource).toContain(':tooltip-column-comment="resolvedColumnComment(col.name, col.actualColIdx)"');
expect(dataGridSource).toContain("(column, index) => headerColumnComment(column, index)");
@@ -1568,6 +1568,8 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
:loading="activeTab.isExecuting"
:editable="!!activeTab.queryAnalysis || !!mongoQueryResultSaveHandler"
:source-columns="activeTab.querySourceColumns"
:result-column-comments="activeTab.resultColumnComments"
:query-display-source-columns="activeTab.queryDisplaySourceColumns"
:custom-save-handler="mongoQueryResultSaveHandler"
:mongo-update-target="mongoQueryResultSaveHandler && activeTab.result.mongo_copy_documents?.length === activeTab.result.rows.length ? activeTab.mongoEditTarget : undefined"
:query-editability-reason="activeTab.queryEditabilityReason"