Skip to content

v1.6.0 — the button says what it is about to do

Latest

Choose a tag to compare

@MR-TABATA MR-TABATA released this 28 Aug 12:02
4215b07

CLI database ops, as buttons. Local-only, no AI — psql operations turned into clicks.

Press it and find out. That was the whole confirmation dialog. Now the button says what it is about to do, before you press it.

Drop table "public.orders"? This cannot be undone.

This runs:
SET lock_timeout = '3s';
DROP TABLE "public"."orders";

Rows: about 1,203,000 (estimated from statistics, last analyzed 2026-08-27)
Referenced by:
  public.order_items (order_items_order_id_fkey)
A DROP … CASCADE would also drop:
  view public.orders_v
  materialized view public.daily_sales

📋 The SQL, composed by the thing that will run it

Not a second rendering of what we think the button does: engine.preview() calls the same method with the same arguments and captures what the executor composed, without sending it. A preview written separately from the executor drifts from it — and the first time you notice is when the button does something the preview did not show.

The SET lock_timeout shows up too. It has always been there, bounding the wait so one clicked button cannot queue behind an open transaction and stall a table until the connection pool runs dry. Nothing in the UI ever said so.

🔢 How many rows, and who points at this table

The count comes from the planner's statistics, not count(*): opening a confirmation dialog must not scan a billion-row table. So it says about, with the date the statistics were last refreshed.

A table that has never been analyzed reports unknown, not zero. "0 rows" reads as "empty, safe to drop", and that is a sentence this cannot honestly say.

Foreign keys pointing at the table are listed, because a TRUNCATE fails without CASCADE while one exists — and finding that out after pressing the button is late.

💥 What CASCADE would take with it

Views and materialized views, by name.

DROP TABLE defaults to RESTRICT: while something depends on the table, the drop simply fails. That is the safe outcome. The dangerous one is reaching for CASCADE after seeing the failure, without knowing what is on the other end.

Implicit dependencies — indexes, constraints, types — are deliberately not listed: they go with the table by definition, and listing them buries the view you actually needed to see. Foreign keys are not repeated here either; they are already on the line above, and the same object in two places reads as two casualties.

Notes

  • A preview that cannot be produced is not rendered at all. An empty SQL box, or a "0 rows" line, would state something untrue.
  • Everything above is catalog reads. Nothing is executed, validated or written to answer these questions.
  • docker compose up -d pulls jiniie/cli2ui:latest (now 1.6.0). Pin with CLI2UI_IMAGE in .env; build from source with cp docker-compose.override.yml.example docker-compose.override.yml.

Full detail in CHANGELOG.md.

Full changelog: v1.5.0...v1.6.0