mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-20 00:17:44 +00:00
fix(grid): keep table filters available without metadata
This commit is contained in:
@@ -41,6 +41,7 @@ import { useQueryStore } from "@/stores/queryStore";
|
||||
import { canCancelQueryExecution, queryExecutionLabelKey } from "@/lib/queryExecutionState";
|
||||
import { databaseDisplayNameForTab } from "@/lib/tabPresentation";
|
||||
import { isTableDataEditable } from "@/lib/tableEditing";
|
||||
import { tableMetaForDataTab } from "@/lib/tableDataTabMeta";
|
||||
import type { QueryTab, ConnectionConfig } from "@/types/database";
|
||||
import type { SqlFormatDialect } from "@/lib/sqlFormatter";
|
||||
|
||||
@@ -116,6 +117,8 @@ const columnVisibilityOptions = computed(
|
||||
);
|
||||
const redisKeyBrowserRef = ref<SearchableBrowserHandle>();
|
||||
const objectBrowserRef = ref<SearchableBrowserHandle>();
|
||||
const activeTableMeta = computed(() => props.activeTab.tableMeta);
|
||||
const activeDataTabTableMeta = computed(() => tableMetaForDataTab(props.activeTab));
|
||||
|
||||
const activeSqlFormatDialect = computed<SqlFormatDialect>(() => {
|
||||
switch (props.activeConnection?.db_type) {
|
||||
@@ -766,13 +769,13 @@ defineExpose({ focusSearch, refreshData, handleModRTarget });
|
||||
:initial-order-by-input="activeTab.orderByInput"
|
||||
:sql="activeTab.sql"
|
||||
:loading="activeTab.isExecuting"
|
||||
:editable="isTableDataEditable(activeConnection?.db_type, activeTab.tableMeta?.primaryKeys ?? [])"
|
||||
:editable="isTableDataEditable(activeConnection?.db_type, activeTableMeta?.primaryKeys ?? [])"
|
||||
context="table-data"
|
||||
:initial-where-input="activeTab.whereInput"
|
||||
:database-type="activeConnection?.db_type"
|
||||
:connection-id="activeTab.connectionId"
|
||||
:database="activeTab.database"
|
||||
:table-meta="activeTab.tableMeta"
|
||||
:table-meta="activeDataTabTableMeta"
|
||||
:page-offset="activeTab.resultPageOffset"
|
||||
:page-limit="activeTab.resultPageLimit"
|
||||
:on-execute-sql="async (sql: string) => emit('executeSql', sql)"
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useQueryStore } from "@/stores/queryStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
import { buildTableSelectSql, quoteTableIdentifier } from "@/lib/tableSelectSql";
|
||||
import { editablePrimaryKeys, usesSyntheticRowIdKey } from "@/lib/tableEditing";
|
||||
import { tableMetaForDataTab } from "@/lib/tableDataTabMeta";
|
||||
import * as api from "@/lib/api";
|
||||
import type { QueryTab } from "@/types/database";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
@@ -26,20 +27,23 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
||||
options: { orderBy?: string; limit?: number; offset?: number; whereInput?: string } = {},
|
||||
): Promise<string> {
|
||||
const config = connectionStore.getConfig(tab.connectionId);
|
||||
const primaryKeys = tab.tableMeta ? editablePrimaryKeys(config?.db_type, tab.tableMeta.columns) : [];
|
||||
const tableMeta = tableMetaForDataTab(tab);
|
||||
const primaryKeys = tab.tableMeta
|
||||
? editablePrimaryKeys(config?.db_type, tab.tableMeta.columns)
|
||||
: (tableMeta?.primaryKeys ?? []);
|
||||
if (tab.tableMeta && primaryKeys.join("\0") !== tab.tableMeta.primaryKeys.join("\0")) {
|
||||
tab.tableMeta.primaryKeys = primaryKeys;
|
||||
}
|
||||
const fallbackOrderColumns =
|
||||
config?.db_type === "sqlserver" && !primaryKeys.length
|
||||
? tab.tableMeta?.columns.slice(0, 1).map((column) => column.name)
|
||||
? tableMeta?.columns.slice(0, 1).map((column) => column.name)
|
||||
: undefined;
|
||||
const useRowId = usesSyntheticRowIdKey(config?.db_type, primaryKeys);
|
||||
return buildTableSelectSql({
|
||||
databaseType: config?.db_type,
|
||||
schema: tab.tableMeta?.schema,
|
||||
tableName: tab.tableMeta?.tableName ?? "",
|
||||
columns: tab.tableMeta?.columns.map((column) => column.name),
|
||||
schema: tableMeta?.schema,
|
||||
tableName: tableMeta?.tableName ?? "",
|
||||
columns: tableMeta?.columns.map((column) => column.name),
|
||||
primaryKeys,
|
||||
fallbackOrderColumns,
|
||||
includeRowId: useRowId,
|
||||
@@ -65,7 +69,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
||||
) {
|
||||
const tab = activeTab.value;
|
||||
if (!tab) return;
|
||||
if (tab.mode === "data" && tab.tableMeta) {
|
||||
if (tab.mode === "data" && tableMetaForDataTab(tab)) {
|
||||
tab.whereInput = whereInput ?? "";
|
||||
const pageLimit = limit ?? settingsStore.editorSettings.pageSize;
|
||||
const pageOffset = offset ?? 0;
|
||||
@@ -116,7 +120,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tab.tableMeta) return;
|
||||
if (!tableMetaForDataTab(tab)) return;
|
||||
tab.whereInput = whereInput ?? "";
|
||||
const sql = await buildTableSql(tab, { limit, offset, whereInput, orderBy });
|
||||
queryStore.updateSql(tab.id, sql);
|
||||
@@ -134,7 +138,7 @@ export function useDataGridActions(activeTab: ComputedRef<QueryTab | undefined>)
|
||||
tab.resultSortDirection = direction ?? undefined;
|
||||
|
||||
if (tab.mode === "data") {
|
||||
if (!tab.tableMeta) return;
|
||||
if (!tableMetaForDataTab(tab)) return;
|
||||
tab.whereInput = whereInput ?? "";
|
||||
const config = connectionStore.getConfig(tab.connectionId);
|
||||
const quotedColumn = quoteIdent(tab, column);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { QueryTab, ColumnInfo } from "@/types/database";
|
||||
|
||||
export type DataTabTableMeta = NonNullable<QueryTab["tableMeta"]>;
|
||||
|
||||
function fallbackColumnInfo(name: string): ColumnInfo {
|
||||
return {
|
||||
name,
|
||||
data_type: "",
|
||||
is_nullable: true,
|
||||
column_default: null,
|
||||
is_primary_key: false,
|
||||
extra: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function tableMetaForDataTab(tab: QueryTab | undefined): DataTabTableMeta | undefined {
|
||||
if (!tab || tab.mode !== "data") return undefined;
|
||||
if (tab.tableMeta) return tab.tableMeta;
|
||||
const tableName = tab.title.trim();
|
||||
if (!tableName) return undefined;
|
||||
|
||||
return {
|
||||
schema: tab.schema,
|
||||
tableName,
|
||||
columns: (tab.result?.columns ?? []).map(fallbackColumnInfo),
|
||||
primaryKeys: [],
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { strict as assert } from "node:assert";
|
||||
import test from "node:test";
|
||||
import { tableMetaForDataTab } from "../../apps/desktop/src/lib/tableDataTabMeta.ts";
|
||||
import type { QueryTab } from "../../apps/desktop/src/types/database.ts";
|
||||
|
||||
function tab(overrides: Partial<QueryTab> = {}): QueryTab {
|
||||
return {
|
||||
id: "tab-1",
|
||||
title: "users",
|
||||
connectionId: "conn-1",
|
||||
database: "app",
|
||||
schema: "public",
|
||||
sql: "select * from users",
|
||||
isExecuting: false,
|
||||
isCancelling: false,
|
||||
isExplaining: false,
|
||||
mode: "data",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test("returns persisted table metadata for a data tab", () => {
|
||||
const tableMeta = {
|
||||
schema: "public",
|
||||
tableName: "users",
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
data_type: "integer",
|
||||
is_nullable: false,
|
||||
column_default: null,
|
||||
is_primary_key: true,
|
||||
extra: null,
|
||||
},
|
||||
],
|
||||
primaryKeys: ["id"],
|
||||
};
|
||||
|
||||
assert.equal(tableMetaForDataTab(tab({ tableMeta })), tableMeta);
|
||||
});
|
||||
|
||||
test("builds fallback metadata from a data tab when column metadata is unavailable", () => {
|
||||
const meta = tableMetaForDataTab(
|
||||
tab({
|
||||
result: {
|
||||
columns: ["id", "name"],
|
||||
rows: [],
|
||||
affected_rows: 0,
|
||||
execution_time_ms: 1,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
assert.deepEqual(meta, {
|
||||
schema: "public",
|
||||
tableName: "users",
|
||||
columns: [
|
||||
{
|
||||
name: "id",
|
||||
data_type: "",
|
||||
is_nullable: true,
|
||||
column_default: null,
|
||||
is_primary_key: false,
|
||||
extra: null,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
data_type: "",
|
||||
is_nullable: true,
|
||||
column_default: null,
|
||||
is_primary_key: false,
|
||||
extra: null,
|
||||
},
|
||||
],
|
||||
primaryKeys: [],
|
||||
});
|
||||
});
|
||||
|
||||
test("does not infer table metadata for query tabs", () => {
|
||||
assert.equal(tableMetaForDataTab(tab({ mode: "query" })), undefined);
|
||||
});
|
||||
Reference in New Issue
Block a user