feat: add metadata catalog cleanup commands
This commit is contained in:
@@ -3,6 +3,8 @@ import {
|
||||
CatalogConflictError,
|
||||
CatalogConnectorError,
|
||||
type CatalogColumn,
|
||||
type CatalogDatabaseMetadataDeleteTarget,
|
||||
type CatalogMetadataDeleteCounts,
|
||||
type CatalogRelationship,
|
||||
type CatalogSchemaDiff,
|
||||
type CatalogSyncCounts,
|
||||
@@ -11,6 +13,7 @@ import {
|
||||
type CatalogSyncRunUpdate,
|
||||
type CatalogSyncScope,
|
||||
type CatalogTable,
|
||||
type CatalogTableMetadataDeleteTarget,
|
||||
type CatalogRepository,
|
||||
type DatabaseConfigurationInput,
|
||||
type DatabaseTestResult,
|
||||
@@ -199,6 +202,71 @@ export class MemoryCatalogRepository implements CatalogRepository {
|
||||
.map((relationship) => structuredClone(relationship));
|
||||
}
|
||||
|
||||
async deleteDatabaseMetadata(
|
||||
databaseIds: readonly string[],
|
||||
target: CatalogDatabaseMetadataDeleteTarget,
|
||||
): Promise<CatalogMetadataDeleteCounts | undefined> {
|
||||
const selectedDatabaseIds = [...new Set(databaseIds)];
|
||||
if (selectedDatabaseIds.length === 0 || selectedDatabaseIds.some((id) => !this.records.has(id))) {
|
||||
return undefined;
|
||||
}
|
||||
const selected = new Set(selectedDatabaseIds);
|
||||
const tables = [...this.tables.values()].filter((table) => selected.has(table.databaseId));
|
||||
const tableIds = new Set(tables.map((table) => table.id));
|
||||
const columns = [...this.columns.values()].filter((column) => tableIds.has(column.tableId));
|
||||
const relationships = [...this.relationships.values()]
|
||||
.filter((relationship) => selected.has(relationship.databaseId));
|
||||
|
||||
if (target === "tables") {
|
||||
for (const table of tables) this.deleteTable(table.id);
|
||||
this.markCatalogIncomplete(selectedDatabaseIds);
|
||||
return { tables: tables.length, columns: columns.length, relationships: relationships.length };
|
||||
}
|
||||
for (const relationship of relationships) this.relationships.delete(relationship.id);
|
||||
for (const databaseId of selectedDatabaseIds) this.refreshForeignKeyFlags(databaseId);
|
||||
this.markCatalogIncomplete(selectedDatabaseIds);
|
||||
return { tables: 0, columns: 0, relationships: relationships.length };
|
||||
}
|
||||
|
||||
async deleteTableMetadata(
|
||||
databaseId: string,
|
||||
tableIds: readonly string[],
|
||||
target: CatalogTableMetadataDeleteTarget,
|
||||
): Promise<CatalogMetadataDeleteCounts | undefined> {
|
||||
const selectedTableIds = [...new Set(tableIds)];
|
||||
if (!this.records.has(databaseId) || selectedTableIds.length === 0) return undefined;
|
||||
const tables = selectedTableIds.map((id) => this.tables.get(id));
|
||||
if (tables.some((table) => !table || table.databaseId !== databaseId)) return undefined;
|
||||
const selected = new Set(selectedTableIds);
|
||||
|
||||
if (target === "columns") {
|
||||
const columns = [...this.columns.values()].filter((column) => selected.has(column.tableId));
|
||||
const deletedColumnIds = new Set(columns.map((column) => column.id));
|
||||
for (const column of columns) this.columns.delete(column.id);
|
||||
for (const [relationshipId, relationship] of this.relationships) {
|
||||
if (relationship.databaseId !== databaseId) continue;
|
||||
this.relationships.set(relationshipId, {
|
||||
...relationship,
|
||||
columns: relationship.columns.filter((pair) => (
|
||||
!deletedColumnIds.has(pair.sourceColumnId) && !deletedColumnIds.has(pair.targetColumnId)
|
||||
)),
|
||||
});
|
||||
}
|
||||
this.refreshForeignKeyFlags(databaseId);
|
||||
this.markCatalogIncomplete([databaseId]);
|
||||
return { tables: 0, columns: columns.length, relationships: 0 };
|
||||
}
|
||||
|
||||
const relationships = [...this.relationships.values()].filter((relationship) => (
|
||||
relationship.databaseId === databaseId
|
||||
&& (selected.has(relationship.sourceTableId) || selected.has(relationship.targetTableId))
|
||||
));
|
||||
for (const relationship of relationships) this.relationships.delete(relationship.id);
|
||||
this.refreshForeignKeyFlags(databaseId);
|
||||
this.markCatalogIncomplete([databaseId]);
|
||||
return { tables: 0, columns: 0, relationships: relationships.length };
|
||||
}
|
||||
|
||||
async planSchemaSync(
|
||||
databaseId: string,
|
||||
scope: CatalogSyncScope,
|
||||
@@ -675,6 +743,18 @@ export class MemoryCatalogRepository implements CatalogRepository {
|
||||
}
|
||||
}
|
||||
|
||||
private markCatalogIncomplete(databaseIds: readonly string[]): void {
|
||||
for (const databaseId of databaseIds) {
|
||||
const database = this.records.get(databaseId);
|
||||
if (!database) continue;
|
||||
this.records.set(databaseId, {
|
||||
...database,
|
||||
schemaSyncedVersion: undefined,
|
||||
schemaSyncedAt: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private refreshForeignKeyFlags(databaseId: string): void {
|
||||
const counts = new Map<string, number>();
|
||||
for (const relationship of this.relationships.values()) {
|
||||
|
||||
Reference in New Issue
Block a user