feat(table-info): show column default values

This commit is contained in:
LRcoding
2026-07-17 00:10:46 +08:00
committed by GitHub
parent c67cce5654
commit 63ea5f1fd8
4 changed files with 45 additions and 0 deletions
@@ -62,6 +62,7 @@ import TemporalCellEditor from "@/components/grid/TemporalCellEditor.vue";
import EnumCellEditor from "@/components/grid/EnumCellEditor.vue";
import type { QueryResult, ColumnInfo, DatabaseType, ForeignKeyInfo, IndexInfo, TriggerInfo, TableInfoTab } from "@/types/database";
import { tableObjectSourceKind } from "@/lib/table/tableObjectSourceKind";
import { tableColumnDefaultDisplayValue } from "@/lib/table/tableColumnDefaultPresentation";
import * as api from "@/lib/backend/api";
import { formatElapsedSeconds } from "@/lib/common/elapsedTime";
import { dataGridCellDisplayText, dataGridCellEditorText } from "@/lib/dataGrid/dataGridCellCoercion";
@@ -8477,6 +8478,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("grid.columnName") }}</th>
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("grid.columnType") }}</th>
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("grid.tableInfoNullable") }}</th>
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("structureEditor.defaultValue") }}</th>
</tr>
</thead>
<tbody>
@@ -8503,6 +8505,9 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
</td>
<td class="px-3 py-2 font-mono text-[11px] text-muted-foreground">{{ column.data_type }}</td>
<td class="px-3 py-2">{{ column.is_nullable ? "YES" : "NO" }}</td>
<td data-table-info-column-default class="max-w-56 px-3 py-2 font-mono text-[11px]" :class="{ 'text-muted-foreground/70': column.column_default == null }" :title="column.column_default ?? undefined">
<span class="block max-w-56 truncate">{{ tableColumnDefaultDisplayValue(column.column_default) }}</span>
</td>
</tr>
</tbody>
</table>
@@ -96,6 +96,7 @@ import {
import { resolveRowClickAction, shouldDeferSingleClick, type ObjectBrowserRowAction } from "@/lib/table/objectBrowserRowAction";
import { createSidePanelRequestGuard } from "@/lib/table/sidePanelRequestGuard";
import { runBatchTableTruncate } from "@/lib/table/batchTableTruncate";
import { tableColumnDefaultDisplayValue } from "@/lib/table/tableColumnDefaultPresentation";
type ObjectFilter = "all" | "tables" | "views" | "materializedViews" | "procedures" | "functions" | "sequences" | "packages";
type ObjectBrowserColumnKey = "select" | "name" | "type" | "estimatedRows" | "totalBytes" | "created_at" | "updated_at" | "comment";
@@ -2726,6 +2727,7 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("grid.columnName") }}</th>
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("grid.columnType") }}</th>
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("grid.tableInfoNullable") }}</th>
<th class="text-left text-nowrap font-medium px-3 py-2">{{ t("structureEditor.defaultValue") }}</th>
</tr>
</thead>
<tbody>
@@ -2742,6 +2744,9 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
</td>
<td class="px-3 py-2 font-mono text-[11px] text-muted-foreground">{{ column.data_type }}</td>
<td class="px-3 py-2">{{ column.is_nullable ? "YES" : "NO" }}</td>
<td data-table-info-column-default class="max-w-56 px-3 py-2 font-mono text-[11px]" :class="{ 'text-muted-foreground/70': column.column_default == null }" :title="column.column_default ?? undefined">
<span class="block max-w-56 truncate">{{ tableColumnDefaultDisplayValue(column.column_default) }}</span>
</td>
</tr>
</tbody>
</table>
@@ -0,0 +1,4 @@
/** Preserve database-specific default expressions exactly; only absent metadata gets a placeholder. */
export function tableColumnDefaultDisplayValue(value: string | null | undefined): string {
return value ?? "—";
}
+31
View File
@@ -0,0 +1,31 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { test } from "vitest";
import { compileTemplate, parse } from "vue/compiler-sfc";
import { tableColumnDefaultDisplayValue } from "@/lib/table/tableColumnDefaultPresentation";
const tableInfoSurfaces = ["apps/desktop/src/components/objects/ObjectBrowser.vue", "apps/desktop/src/components/grid/DataGrid.vue"];
test("table column defaults preserve raw database expressions", () => {
const values = [null, "''", "0", "CURRENT_TIMESTAMP", "((1))", "('prefix (internal)')", "x".repeat(512)] as const;
assert.deepEqual(values.map(tableColumnDefaultDisplayValue), ["—", ...values.slice(1)]);
assert.equal(tableColumnDefaultDisplayValue(undefined), "—");
assert.equal(tableColumnDefaultDisplayValue(""), "");
});
test("both table information surfaces expose the same default-value column", () => {
for (const path of tableInfoSurfaces) {
const source = readFileSync(path, "utf8");
const { descriptor, errors } = parse(source, { filename: path });
assert.deepEqual(errors, []);
assert.ok(descriptor.template);
const result = compileTemplate({ id: path, filename: path, source: descriptor.template.content });
assert.deepEqual(result.errors, []);
assert.match(descriptor.template.content, /t\("structureEditor\.defaultValue"\)/);
assert.match(descriptor.template.content, /data-table-info-column-default/);
assert.match(descriptor.template.content, /:title="column\.column_default \?\? undefined"/);
assert.match(descriptor.template.content, /tableColumnDefaultDisplayValue\(column\.column_default\)/);
}
});