feat: compare_schemas command + diff staging into the changes queue (Task 15)
This commit is contained in:
@@ -2,6 +2,7 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
import type { Connection, ConnectionInput, ConnectionTestResult, Folder, FolderInput, Tag, TagInput, Settings, ImportResult, TableInfo, QueryResult, BackupOptions, RestoreOptions, SyncOptions, PgToolStatus, MySqlToolStatus, MySqlBackupOptions, MySqlRestoreOptions, SqliteBackupOptions, SqliteRestoreOptions, FunctionInfo, TriggerInfo, SequenceInfo, EnumInfo, ExtensionInfo, SchemaGraph, IndexInfo, ConstraintInfo, RecentConnection, ObjectSearchHit, DependencyInfo, RoleInfo, PrivilegeEntry, RebuildReadiness, MaintenanceResult, TablespaceInfo, ColumnInfo, HypertableListResponse, MultiQueryResult } from "./types";
|
||||
import type { FilterRule, SortRule } from "../stores/dbViewerStore";
|
||||
import type { ChangePayload } from "./changePayload";
|
||||
import type { DiffReport } from "./types";
|
||||
import { buildObjectDdl as buildObjectDdlImpl, type ObjectKind, type DdlParams } from "./objectCrud";
|
||||
|
||||
export { type ObjectKind, type DdlParams };
|
||||
@@ -418,4 +419,14 @@ export async function getTablespaces(connectionId: string): Promise<TablespaceIn
|
||||
}
|
||||
export async function buildRebuildScript<C extends { name: string; type: string; nullable: boolean; default: string | null; is_pk: boolean }[]>(connectionId: string, schema: string, table: string, newColumns: C): Promise<string> {
|
||||
return invoke<string>("build_rebuild_script", { connectionId, schema, table, newColumns });
|
||||
}
|
||||
}
|
||||
export async function compareSchemas(
|
||||
sourceConnectionId: string,
|
||||
sourceSchema: string,
|
||||
targetConnectionId: string,
|
||||
targetSchema: string,
|
||||
): Promise<DiffReport> {
|
||||
return invoke<DiffReport>("compare_schemas", {
|
||||
sourceConnectionId, sourceSchema, targetConnectionId, targetSchema,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -506,4 +506,25 @@ export interface Relationship {
|
||||
export interface SchemaGraph {
|
||||
tables: TableNode[];
|
||||
relationships: Relationship[];
|
||||
}
|
||||
}
|
||||
export interface DiffDetailLine {
|
||||
label: string;
|
||||
old: string;
|
||||
new: string;
|
||||
}
|
||||
|
||||
export interface DiffItem {
|
||||
object_type: string;
|
||||
name: string;
|
||||
kind: "added" | "removed" | "changed";
|
||||
detail: DiffDetailLine[];
|
||||
sync_sql: string[];
|
||||
destructive: boolean;
|
||||
}
|
||||
|
||||
export interface DiffReport {
|
||||
items: DiffItem[];
|
||||
source_label: string;
|
||||
target_label: string;
|
||||
truncated: boolean;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { useDbViewerStore } from "./dbViewerStore";
|
||||
import type { DiffItem } from "../lib/types";
|
||||
|
||||
const item = (name: string, sql: string, destructive: boolean): DiffItem => ({
|
||||
object_type: "table",
|
||||
name,
|
||||
kind: "added",
|
||||
detail: [],
|
||||
sync_sql: [sql],
|
||||
destructive,
|
||||
});
|
||||
|
||||
describe("addDiffItems", () => {
|
||||
beforeEach(() => useDbViewerStore.getState().clearChanges());
|
||||
|
||||
it("stages one ddl change per non-destructive item, skipping destructive and empty", () => {
|
||||
const items = [
|
||||
item("users", "CREATE TABLE users (id int);", false),
|
||||
item("old", "DROP TABLE old;", true),
|
||||
{ ...item("weird", "", false), sync_sql: [] },
|
||||
];
|
||||
useDbViewerStore.getState().addDiffItems(items);
|
||||
const queue = useDbViewerStore.getState().changesQueue;
|
||||
expect(queue).toHaveLength(1);
|
||||
expect(queue[0].type).toBe("ddl");
|
||||
expect(queue[0].sql).toBe("CREATE TABLE users (id int);");
|
||||
expect(queue[0].description).toContain("users");
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { create } from "zustand";
|
||||
import type { QueryResult, TableInfo, ChangeItemType, FunctionInfo, TriggerInfo, SequenceInfo, EnumInfo, ExtensionInfo, HypertableInfo, IndexInfo, ConstraintInfo, ObjectType, RoleInfo, MultiQueryResult } from "../lib/types";
|
||||
import type { QueryResult, TableInfo, ChangeItemType, FunctionInfo, TriggerInfo, SequenceInfo, EnumInfo, ExtensionInfo, HypertableInfo, IndexInfo, ConstraintInfo, ObjectType, RoleInfo, MultiQueryResult, DiffItem } from "../lib/types";
|
||||
import { getDatabases, getSchemas, getTables } from "../lib/commands";
|
||||
import type { ObjectKind, DdlParams } from "../lib/objectCrud";
|
||||
|
||||
@@ -169,6 +169,7 @@ interface DbViewerState {
|
||||
rows?: unknown[][];
|
||||
description?: string | null;
|
||||
}) => void;
|
||||
addDiffItems: (items: DiffItem[]) => void;
|
||||
cancelChange: (changeId: string) => void;
|
||||
removeChange: (changeId: string) => void;
|
||||
updateChange: (changeId: string, patch: Partial<QueueItem>) => void;
|
||||
@@ -549,6 +550,19 @@ export const useDbViewerStore = create<DbViewerState>((set, get) => ({
|
||||
set((state) => ({ changesQueue: [...state.changesQueue, item] }));
|
||||
},
|
||||
|
||||
addDiffItems: (items) => {
|
||||
for (const it of items) {
|
||||
if (it.destructive || it.sync_sql.length === 0) continue;
|
||||
for (const sql of it.sync_sql) {
|
||||
get().addChange({
|
||||
type: "ddl",
|
||||
sql,
|
||||
description: `Schema diff: ${it.object_type} ${it.name} (${it.kind})`,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
cancelChange: (changeId) =>
|
||||
set((state) => ({
|
||||
changesQueue: state.changesQueue.map((c) =>
|
||||
|
||||
Reference in New Issue
Block a user