fix(app): 修复 Oracle 表结构已有字段识别
Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
This commit is contained in:
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}`,
|
||||
|
||||
Reference in new issue
Block a user