fix(app): 修复 Oracle 表结构已有字段识别

Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
This commit is contained in:
zipgandstaff authored and GitHub committed 2026-07-01 16:05:01 +08:00
1 parent f75597b26a
commit 4da237d955
6 files changed
+488 -6

No files matched your search

@@ -45,6 +45,7 @@ import {
isSqlServerIdentityCompatibleDataType,
isProtectedManticoreIdColumn,
parseExtraToColumnExtra,
rehydrateColumnDraftsFromMetadata,
splitDataType,
toColumnNames,
applyManticoreDdlColumnExtras,
@@ -618,6 +619,7 @@ let skipNextRefreshVersion = false;
let restoringDraft = false;
let syncingDraft = false;
let draftHydrated = false;
let hydratingRestoredDraft = false;
function cloneDraftValue<T>(value: T): T {
return JSON.parse(JSON.stringify(value)) as T;
@@ -647,6 +649,7 @@ function syncDraftToParent() {
function restoreDraft(draft: TableStructureEditorDraft) {
restoringDraft = true;
draftHydrated = false;
activeTab.value = draft.activeTab || "columns";
newTableName.value = draft.newTableName || "";
tableComment.value = draft.tableComment || "";
@@ -656,7 +659,45 @@ function restoreDraft(draft: TableStructureEditorDraft) {
foreignKeys.value = cloneDraftValue(draft.foreignKeys || []);
triggers.value = cloneDraftValue(draft.triggers || []);
restoringDraft = false;
draftHydrated = true;
draftHydrated = !needsColumnDraftMetadataHydration();
}
function needsColumnDraftMetadataHydration() {
return !isCreateMode.value && columns.value.some((column) => !column.original && !column.id.startsWith("new:") && !!column.name.trim());
}
async function hydrateRestoredDraftFromDatabase() {
if (!needsColumnDraftMetadataHydration() || hydratingRestoredDraft) return;
const connectionId = props.connectionId;
const database = props.database;
const schema = metadataSchema.value;
const tableName = props.tableName;
if (!connectionId || !database || !tableName) return;
hydratingRestoredDraft = true;
let shouldRefreshPreview = false;
try {
await store.ensureConnected(connectionId);
let nextColumns = await api.getColumns(connectionId, database, schema, tableName);
if (databaseType.value === "manticoresearch" && tableMetadataCapabilities.value.ddl) {
try {
const ddl = await api.getTableDdl(connectionId, database, schema, tableName);
ddlContent.value = await formatSqlForDisplay(ddl, sqlFormatDialectForDbType(databaseType.value), settingsStore.editorSettings.sqlFormatter);
ddlFetched.value = true;
nextColumns = applyManticoreDdlColumnExtras(nextColumns, ddl);
} catch {
/* ignore — Manticore column properties can still come from SHOW COLUMNS when available */
}
}
columns.value = rehydrateColumnDraftsFromMetadata(columns.value, nextColumns, databaseType.value);
markDraftHydratedAndSync();
shouldRefreshPreview = true;
} catch (e: any) {
console.warn("[DBX][structure-editor:draft-hydration-failed]", e);
} finally {
hydratingRestoredDraft = false;
if (shouldRefreshPreview) scheduleSqlPreviewRefresh();
}
}
function markDraftHydratedAndSync() {
@@ -736,6 +777,18 @@ async function loadDynamicDataTypeOptions() {
}
function scheduleSqlPreviewRefresh() {
if (hydratingRestoredDraft || needsColumnDraftMetadataHydration()) {
if (sqlPreviewDebounceTimer) {
clearTimeout(sqlPreviewDebounceTimer);
sqlPreviewDebounceTimer = undefined;
}
sqlPreviewRequestId++;
deferredSqlPreviewRefresh = false;
pendingStatements.value = [];
warnings.value = [];
sqlPreviewLoading.value = true;
return;
}
if (!hasPendingStructureChanges()) {
clearSqlPreviewState();
return;
@@ -1589,6 +1642,7 @@ onMounted(() => {
if (props.draft?.initialized) {
restoreDraft(props.draft);
applyInitialStructureTab();
void hydrateRestoredDraftFromDatabase();
} else if (isCreateMode.value) {
markDraftHydratedAndSync();
} else {
@@ -1601,6 +1655,7 @@ onActivated(() => {
void loadDynamicDataTypeOptions();
if (props.draft?.initialized && !draftHydrated) {
restoreDraft(props.draft);
void hydrateRestoredDraftFromDatabase();
}
});
onDeactivated(unregisterStructureEditorShortcuts);
@@ -606,6 +606,74 @@ export function createColumnDrafts(columns: ColumnInfo[], databaseType?: Databas
});
}
function existingColumnIdName(id: string): string | undefined {
const prefix = "existing:";
return id.startsWith(prefix) ? id.slice(prefix.length) : undefined;
}
function isNewColumnDraftId(id: string): boolean {
return id.startsWith("new:");
}
function uniqueNames(names: Array<string | undefined>): string[] {
const seen = new Set<string>();
const result: string[] = [];
for (const name of names) {
if (!name) continue;
if (seen.has(name)) continue;
seen.add(name);
result.push(name);
}
return result;
}
function findColumnDraftByName(columns: EditableStructureColumn[], names: string[], usedIndexes: Set<number>): number | undefined {
for (const name of names) {
const exactIndex = columns.findIndex((column, index) => !usedIndexes.has(index) && column.name === name);
if (exactIndex >= 0) return exactIndex;
}
for (const name of names) {
const lowerName = name.toLowerCase();
const matches = columns.map((column, index) => ({ column, index })).filter(({ column, index }) => !usedIndexes.has(index) && column.name.toLowerCase() === lowerName);
if (matches.length === 1) return matches[0]!.index;
}
return undefined;
}
export function rehydrateColumnDraftsFromMetadata(draftColumns: EditableStructureColumn[], columns: ColumnInfo[], databaseType?: DatabaseType): EditableStructureColumn[] {
const metadataDrafts = createColumnDrafts(columns, databaseType);
if (!metadataDrafts.length) return draftColumns;
if (!draftColumns.length) return metadataDrafts;
const usedMetadataIndexes = new Set<number>();
const nextColumns = draftColumns.map((column) => {
if (!column.original && isNewColumnDraftId(column.id)) return column;
const needsHydration = !column.original || column.originalPosition === undefined;
const candidates = uniqueNames([column.original?.name, existingColumnIdName(column.id), column.name]);
const metadataIndex = findColumnDraftByName(metadataDrafts, candidates, usedMetadataIndexes);
if (metadataIndex === undefined) return column;
usedMetadataIndexes.add(metadataIndex);
if (!needsHydration) return column;
const metadataDraft = metadataDrafts[metadataIndex]!;
return {
...column,
original: column.original ?? metadataDraft.original,
originalPosition: column.originalPosition ?? metadataDraft.originalPosition,
};
});
if (usedMetadataIndexes.size === 0) {
return [...metadataDrafts, ...draftColumns];
}
const missingMetadataDrafts = metadataDrafts.filter((_, index) => !usedMetadataIndexes.has(index));
return [...nextColumns, ...missingMetadataDrafts];
}
export function createIndexDrafts(indexes: IndexInfo[]): EditableStructureIndex[] {
return indexes.map((index) => ({
id: `existing:${index.name}`,