mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 04:47:00 +00:00
feat(table-info): show column default values
This commit is contained in:
@@ -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 ?? "—";
|
||||
}
|
||||
@@ -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\)/);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user