Editor settings, SSH/SSL runtime, data import + table-menu loose ends (#7)
* feat: editor settings model + typed clamped defaults (Task 1) * feat: carry SSH config + ssh_password to backend DbConfig (Task 2) * feat: Change enum bulk/drop/empty + type-specific change payload builder (Task 3) * feat: csv parser + shared export util (Task 4) * feat: rustls TLS connector factory with modes + client auth (Task 5) * feat: real SSH tunnel manager (testable backend) + pool eviction hook (Task 6) * feat: table DDL fetch (sqlite + pg_dump arg builder) (Task 7) * feat: keychain SSH secrets + connection delete purge + tunnel lifecycle (Task 8) * feat: real SSH tunnel + TLS connect path for postgres/mysql (Task 9) * feat: execute_change bulk/drop/empty + get_table_ddl command (Task 10) * feat: fetch SSH secrets into dbConnect + save on connection form (Task 11) * feat: Editor settings tab UI (Task 12) * feat: QueryEditor applies editor settings live (Task 13) * feat: ImportDialog with CSV/JSON preview + column mapping (Task 14) * feat: table-menu export/empty/delete/import + queue labels + payload builder (Task 15) * fix: error sanitization, encrypted-key guard, row-indexed import errors, caps (Task 16) * docs: mark Editor Settings, SSH/SSL runtime, Data Import, table-menu loose ends shipped (Task 17) * feat: auto-refresh schema tree after schema-modifying SQL (query + queue drop) * fix: use theme-consistent red classes for danger menu items (text-error was undefined) * feat: changes queue as tab-bar popover + amber pending border * feat: redesign changes popover (visual/SQL toggle, cards, footer actions, Cmd+S) * refactor: drop per-card status label from changes popover cards * feat: green completion indicator on committed cards + auto-close tabs of dropped tables * docs: changes queue popover UX + auto schema refresh statuses
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { buildChangePayload, buildChangeSql } from "./changePayload";
|
||||
import type { QueueItem } from "../stores/dbViewerStore";
|
||||
|
||||
const base = { id: "c1", status: "pending" as const, createdAt: 0 };
|
||||
|
||||
describe("buildChangePayload", () => {
|
||||
it("insert -> {schema, table, data}", () => {
|
||||
const item: QueueItem = { ...base, type: "insert", sql: "", schema: "public", table: "t",
|
||||
newData: { a: 1 } } as unknown as QueueItem;
|
||||
const p = buildChangePayload(item);
|
||||
expect(p).toEqual({ id: "c1", type: "insert", schema: "public", table: "t", data: "{\"a\":1}" });
|
||||
});
|
||||
|
||||
it("delete -> {schema, table, primary_key}", () => {
|
||||
const item = { ...base, type: "delete", sql: "", schema: "public", table: "t",
|
||||
primaryKey: { id: 5 } } as unknown as QueueItem;
|
||||
expect(buildChangePayload(item)).toEqual({ id: "c1", type: "delete", schema: "public", table: "t", primary_key: "{\"id\":5}" });
|
||||
});
|
||||
|
||||
it("bulk_insert -> {schema, table, columns, rows}", () => {
|
||||
const item = { ...base, type: "bulk_insert", sql: "", schema: "public", table: "t",
|
||||
columns: ["a", "b"], rows: [[1, 2], [3, 4]] } as unknown as QueueItem;
|
||||
expect(buildChangePayload(item)).toEqual({ id: "c1", type: "bulk_insert", schema: "public", table: "t", columns: ["a", "b"], rows: [[1, 2], [3, 4]] });
|
||||
});
|
||||
|
||||
it("drop_table -> {schema, table}", () => {
|
||||
const item = { ...base, type: "drop_table", sql: "", schema: "public", table: "t" } as unknown as QueueItem;
|
||||
expect(buildChangePayload(item)).toEqual({ id: "c1", type: "drop_table", schema: "public", table: "t" });
|
||||
});
|
||||
|
||||
it("empty_table -> {schema, table}", () => {
|
||||
const item = { ...base, type: "empty_table", sql: "", schema: "public", table: "t" } as unknown as QueueItem;
|
||||
expect(buildChangePayload(item)).toEqual({ id: "c1", type: "empty_table", schema: "public", table: "t" });
|
||||
});
|
||||
|
||||
it("alter_table -> {schema, table, sql, rollback_sql}", () => {
|
||||
const item = { ...base, type: "alter_table", sql: "ALTER TABLE t ADD c int", schema: "public", table: "t" } as unknown as QueueItem;
|
||||
expect(buildChangePayload(item)).toEqual({ id: "c1", type: "alter_table", schema: "public", table: "t", sql: "ALTER TABLE t ADD c int", rollback_sql: "" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildChangeSql", () => {
|
||||
it("insert", () => {
|
||||
const item = { id: "1", type: "insert", schema: "public", table: "t", newData: { a: 1, b: "x" } } as any;
|
||||
expect(buildChangeSql(item)).toBe('INSERT INTO "public"."t" ("a", "b") VALUES (1, \'x\')');
|
||||
});
|
||||
it("update", () => {
|
||||
const item = { id: "1", type: "update", schema: "public", table: "t", primaryKey: { id: 5 }, newData: { name: "O'Brien" } } as any;
|
||||
expect(buildChangeSql(item)).toBe('UPDATE "public"."t" SET "name" = \'O\'\'Brien\' WHERE "id" = 5');
|
||||
});
|
||||
it("delete", () => {
|
||||
const item = { id: "1", type: "delete", schema: "public", table: "t", primaryKey: { id: 5 } } as any;
|
||||
expect(buildChangeSql(item)).toBe('DELETE FROM "public"."t" WHERE "id" = 5');
|
||||
});
|
||||
it("bulk_insert", () => {
|
||||
const item = { id: "1", type: "bulk_insert", schema: "public", table: "t", columns: ["a", "b"], rows: [[1, "y"], [2, null]] } as any;
|
||||
expect(buildChangeSql(item)).toBe('INSERT INTO "public"."t" ("a", "b") VALUES (1, \'y\'), (2, NULL)');
|
||||
});
|
||||
it("empty_table / drop_table", () => {
|
||||
expect(buildChangeSql({ id: "1", type: "empty_table", schema: "public", table: "t" } as any)).toBe('DELETE FROM "public"."t"');
|
||||
expect(buildChangeSql({ id: "1", type: "drop_table", schema: "public", table: "t" } as any)).toBe('DROP TABLE "public"."t"');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user