Files
gridline/src/lib/changePayload.test.ts
T
adrianbonpin 0c74d77e75 v0.7.6: PostgreSQL object management, keychain toggle, tabbed Objects workspace (#12)
* [P1-T1] Change::Ddl Rust variant + execute_change arm

* [P1-T2] Frontend ddl change type + objectCrud capability

* [P1-T3] use_keychain data model + migration v8

* [P2-T1] object_crud skeleton + validators + build_ddl dispatch

* [P2-T2] Sequence builders

* [P2-T3] Enum builders (no value removal)

* [P2-T4] View / matview / extension builders

* [P2-T5] Index + constraint builders

* [P2-T6] Function / procedure + trigger builders

* [P2-T7] build_object_ddl + get_available_extensions commands + wrappers

* [P3-T1] conditional keychain + session passwords

* [P3-T2] keychain-off password prompt on connect

* [P3-T3] default-ON keychain opt-out + tooltip + modal conditional

* [P3-T4] ddl queue card + after-commit refetch

* [P4-T1] ObjectCrudDialog shell

* [P4-T2] SequenceForm

* [P4-T3] EnumForm with no-removal note

* [P4-T4] ExtensionForm with available-extensions picker

* [P4-T5] ViewForm (view + materialized view)

* [P5-T1] IndexForm with column picker

* [P5-T2] ConstraintForm (check/unique/pk/fk) + ColumnPicker

* [P5-T3] FunctionForm (function + procedure)

* [P5-T4] TriggerForm with trigger-function picker

* [P5-T5] ObjectContextMenu + Explorer/TableOverflowMenu CRUD wiring

* [P6-T1] object tab type + openObjectTab dedup

* [P6-T2] extract ObjectDetail for object tabs

* [P6-T3] Objects view two-pane sidebar + workspace

* [P6-T4] object-tab content + per-type tab icons

* [P7-T1] Version bump 0.7.5 -> 0.7.6

* [P7-T2] docs sync README/ROADMAP/AGENTS for v0.7.6

* [P7-T3] chore: Cargo.lock version sync 0.7.5 -> 0.7.6

* fix(ui): object tab icon stacks above name (preflight svg block)

* fix(ui): optically center object tab icon with name

* fix(ui): object tab icon matches query/table icon handling

* [UI-POLISH-1] objectForm tab type + openFormTab store action

* [UI-POLISH-2] ObjectFormTab + KindForm with Visual/SQL toggle

* [UI-POLISH-3] route create/edit through form tabs; remove modal

* docs: create/edit now open as form tabs (AGENTS sync)

* [FB-1] follow app styling patterns + schema dropdown in forms

* [FB-2] Monaco editor for function body + view definition

* [FB-3] form tabs styled like viewers + in-cell editing

* [FB-5] focus outline scoped to input area (label excluded)

* [FB-6] no amber focus outline on Monaco body/definition rows

* [FB-7] header dedupe + schema default + full edit prefill

* [FB-8] SQL view in read-only Monaco editor

* docs: roadmap — table create/edit + relationships (next)

* docs: roadmap — Admin follow-up is 0.7.7 (next after 0.7.6)
2026-08-06 22:56:49 +08:00

80 lines
4.1 KiB
TypeScript

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"');
});
});
const ddlItem: QueueItem = {
id: "ch-1", type: "ddl",
sql: "CREATE TYPE public.role AS ENUM ('admin')",
status: "pending", createdAt: 0,
};
describe("ddl change", () => {
it("builds a ddl payload with id + type + sql", () => {
expect(buildChangePayload(ddlItem)).toEqual({
id: "ch-1", type: "ddl", sql: "CREATE TYPE public.role AS ENUM ('admin')",
});
});
it("preview SQL is the raw sql", () => {
expect(buildChangeSql(ddlItem)).toBe("CREATE TYPE public.role AS ENUM ('admin')");
});
});