fix(editor): preserve view type in object navigation

This commit is contained in:
t8y2 committed 2026-07-14 18:41:26 +08:00
1 parent 39aa506e44
commit 69dd363417
8 files changed
+108 -25

No files matched your search

@@ -40,7 +40,7 @@ import { mergeSqlSemanticReferenceAnalysis, resolveSqlSemanticNavigationTarget }
import { buildElasticsearchCompletionItemsFromContext, getElasticsearchCompletionContext, getElasticsearchCompletionResultValidFor, shouldAutoOpenElasticsearchCompletion, type ElasticsearchCompletionItem } from "@/lib/elasticsearch/elasticsearchCompletion";
import { buildMongoCompletionItemsFromContext, getMongoCompletionContext, getMongoCompletionResultValidFor, shouldAutoOpenMongoCompletion, type MongoCompletionItem } from "@/lib/mongo/mongoCompletion";
import { resolveSqlCompletionTableLookupTarget } from "@/lib/sql/sqlCompletionLookupTarget";
import { extractIdentifierDetailsAt, isSqlKeyword, matchTable, splitQualifiedIdentifier } from "@/lib/sql/sqlNavigation";
import { extractIdentifierDetailsAt, isSqlKeyword, matchTable, splitQualifiedIdentifier, sqlObjectHoverDetail, sqlObjectNavigationTarget, type SqlObjectNavigationTarget } from "@/lib/sql/sqlNavigation";
import { lineColumnToOffset, parseSqlErrorLocation } from "@/lib/sql/sqlDiagnostics";
import {
DBX_TABLE_REFERENCE_MIME,
@@ -69,7 +69,7 @@ import * as api from "@/lib/backend/api";
import { areSqlSemanticDiagnosticsEqual, buildSqlParserErrorDiagnostic, buildSqlSemanticDiagnostics, isSqlSemanticDiagnosticInputContext, shouldRunSqlSemanticDiagnostics, sqlSemanticDiagnosticRangesForViewport, tableReferenceKey, type SqlSemanticDiagnostic } from "@/lib/sql/semantic/diagnostics";
import { buildRedisSyntaxDiagnostics, shouldRunRedisDiagnostics } from "@/lib/redis/redisSyntaxDiagnostics";
import { buildRedisCompletionItemsFromContext, getRedisCompletionContext, getRedisCompletionResultValidFor, shouldAutoOpenRedisCompletion, takesKeyArgument, type RedisCompletionItem } from "@/lib/redis/redisCompletion";
import type { SqlCompletionColumn, SqlCompletionForeignKey, SqlCompletionItem, SqlCompletionObject, SqlCompletionTable } from "@/lib/sql/sqlCompletion";
import type { SqlCompletionColumn, SqlCompletionForeignKey, SqlCompletionItem, SqlCompletionObject, SqlCompletionReferencedTable, SqlCompletionTable } from "@/lib/sql/sqlCompletion";
import type { DatabaseType, SqlReferenceAnalysis, SqlTableReference, SqlTextSpan } from "@/types/database";
const props = defineProps<{
@@ -102,7 +102,7 @@ const emit = defineEmits<{
formatError: [message: string];
execute: [source: SqlExecutionOverride];
save: [];
clickTable: [tableName: string];
clickTable: [target: SqlObjectNavigationTarget];
viewTableData: [tableName: string];
viewTableDdl: [tableName: string];
editTableStructure: [tableName: string];
@@ -1376,7 +1376,7 @@ async function resolveSqlHoverTooltip(currentView: EditorViewType, pos: number)
pos: range.from,
end: range.to,
create: () => ({
dom: createHoverDom(table.name, table.schema ? `table in ${table.schema}` : "table"),
dom: createHoverDom(table.name, sqlObjectHoverDetail(table)),
}),
};
}
@@ -3149,20 +3149,22 @@ onMounted(async () => {
// 1. Check if it's a table name
const matchedTable = matchTable(identifier, cachedTables);
if (matchedTable) {
emit("clickTable", matchedTable.schema ? `${matchedTable.schema}.${matchedTable.name}` : matchedTable.name);
emit("clickTable", sqlObjectNavigationTarget(matchedTable));
return;
}
// 2. Parse SQL at click position to get referenced tables
const context = getSqlCompletionContext(doc, pos);
let referencedTables = context.referencedTables;
let referencedTables: Array<SqlCompletionReferencedTable & Pick<SqlCompletionTable, "type">> = context.referencedTables;
// Enrich referenced tables with schema from cachedTables
referencedTables = referencedTables.map((rt) => {
const cached = cachedTables.find((ct) => ct.name.toLowerCase() === rt.name.toLowerCase());
if (cached && cached.schema && !rt.schema) {
return { ...rt, schema: cached.schema };
}
return rt;
const cached = cachedTables.find((ct) => ct.name.toLowerCase() === rt.name.toLowerCase() && (!rt.schema || !ct.schema || ct.schema.toLowerCase() === rt.schema.toLowerCase()));
if (!cached) return rt;
return {
...rt,
...(!rt.schema && cached.schema ? { schema: cached.schema } : {}),
...(cached.type ? { type: cached.type } : {}),
};
});
// Check if identifier has a qualifier (e.g., c.card_name or schema.table)
@@ -3170,7 +3172,7 @@ onMounted(async () => {
const matchedRef = matchTable(identifier, referencedTables);
if (matchedRef) {
emit("clickTable", matchedRef.schema ? `${matchedRef.schema}.${matchedRef.name}` : matchedRef.name);
emit("clickTable", sqlObjectNavigationTarget(matchedRef));
return;
}
const colName = identifierParts[identifierParts.length - 1] ?? identifier;
@@ -84,6 +84,7 @@ import ImagePreviewDialog from "@/components/grid/ImagePreviewDialog.vue";
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 * as api from "@/lib/backend/api";
import { formatElapsedSeconds } from "@/lib/common/elapsedTime";
import { dataGridCellDisplayText, dataGridCellEditorText } from "@/lib/dataGrid/dataGridCellCoercion";
@@ -8289,7 +8290,8 @@ async function fetchDdl() {
showTableInfo.value = true;
ddlLoading.value = true;
try {
ddlContent.value = await api.getTableDdl(props.connectionId, props.database || "", props.tableMeta.schema || props.database || "", props.tableMeta.tableName, undefined, props.tableMeta.catalog);
// Preserve view identity so the backend loads the stored view source instead of synthesizing table DDL.
ddlContent.value = await api.getTableDdl(props.connectionId, props.database || "", props.tableMeta.schema || props.database || "", props.tableMeta.tableName, tableObjectSourceKind(props.tableMeta.tableType), props.tableMeta.catalog);
} catch (e: any) {
ddlContent.value = `-- Error: ${e}`;
} finally {
@@ -83,6 +83,7 @@ import { useTabScroll } from "@/composables/useTabScroll";
import { formatElapsedSeconds } from "@/lib/common/elapsedTime";
import type { CustomSaveHandler } from "@/composables/useDataGridEditor";
import type { QueryTab, ConnectionConfig, TableInfoTab, TreeNode, VectorCollectionMeta, ObjectBrowserViewport } from "@/types/database";
import type { SqlObjectNavigationTarget } from "@/lib/sql/sqlNavigation";
import { sqlFormatDialectForDbType, type SqlFormatDialect } from "@/lib/sql/sqlFormatter";
import { productionContextForDatabase } from "@/lib/database/productionSafety";
@@ -148,7 +149,7 @@ const emit = defineEmits<{
paginate: [offset: number, limit: number, whereInput?: string, orderBy?: string];
sort: [column: string, columnIndex: number, direction: "asc" | "desc" | null, whereInput?: string, mode?: DataGridSortMode];
executeSql: [sql: string];
clickTable: [tableName: string];
clickTable: [target: SqlObjectNavigationTarget];
viewTableData: [tableName: string];
viewTableDdl: [tableName: string];
editTableStructure: [tableName: string];
@@ -646,8 +647,8 @@ function closeColumnInfo() {
columnInfoError.value = undefined;
}
function onHandleClickTable(tableName: string) {
emit("clickTable", tableName);
function onHandleClickTable(target: SqlObjectNavigationTarget) {
emit("clickTable", target);
}
function onHandleViewTableData(tableName: string) {