Skip to content

feat(postgres): browse multiple databases on one connection#402

Draft
debba wants to merge 14 commits into
mainfrom
feat/postgres-multi-database
Draft

feat(postgres): browse multiple databases on one connection#402
debba wants to merge 14 commits into
mainfrom
feat/postgres-multi-database

Conversation

@debba

@debba debba commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Closes #340.

What this does

You can now point a single PostgreSQL connection at several databases and browse them all from the sidebar, the same way MySQL and MariaDB connections already work. Pick the databases you want in the connection dialog's "Databases" tab and each one shows up as a top level node you can expand into its schemas and tables.

Why Postgres needed special handling

MySQL lets one connection see every database, so the old multi database code treated a database name as if it were a schema and qualified table names with it. Postgres does not allow that: a connection is bound to one database and you cannot query across databases in a single session. So this PR keeps a separate connection pool per database and presents a real database to schema to table tree instead of the flat database to table layout MySQL uses.

The pool keying already included the database name, so most of the plumbing was about telling the backend which database a given read or query should run against.

How it works

  • Metadata reads (get_tables, get_views, get_schemas, get_columns, get_indexes, get_foreign_keys, the routine and trigger helpers) and execute_query / execute_query_batch now take an optional database argument. When set, the params get pointed at that database and the matching pool is used. This mirrors the convention the record mutation commands (delete_record, update_record, insert_record) already follow, so it is purely additive.
  • Editor tabs carry the target database alongside the schema, so previews, queries and row edits route to the correct pool while still qualifying tables with the Postgres schema.
  • isMultiDatabaseCapable no longer excludes schema based drivers; a new isSchemaBasedMultiDb helper distinguishes the hierarchical Postgres layout from the flat MySQL one.
  • Empty database selections fall back to the postgres maintenance database, since Postgres cannot connect without a target. This is what makes "Load Databases" work before you have picked anything.

UX change worth a look

Now that PostgreSQL counts as multi database capable, the connection dialog hides the single "database" field on the General tab and shows the "Databases" tab with a checklist instead, exactly like MySQL. Existing single database Postgres connections keep working, but the edit dialog looks different than before. Happy to keep the single field visible for Postgres if reviewers would rather not change that flow.

Known limitations / follow ups

These are not regressions, just things left out of this pass to keep the change focused on browsing and querying (updated after the two routing-fix commits on this branch):

  • Object-creation DDL from the nested schema view is not database aware. Create Index, Create Foreign Key and Create Table / View / Trigger launched from a nested Postgres schema node still route via the connection's global active schema and carry no database, so they can hit the primary database (and the wrong schema). Add/edit column, drop index/foreign key, and the view/routine/trigger context-menu actions (show data, view definition, edit, drop) are now routed to the node's database.
  • AI Query Generation is not database aware. AiQueryModal builds its schema context from the connection's primary database and the generated-query flows (including Visual-Explain deep links from the AI activity panel) carry no database, so AI features target the primary database on multi-database Postgres connections.
  • Clipboard Import is not database aware. The import creates its table on the connection's primary database regardless of which database node it was launched from.
  • SQL autocomplete is not database aware in multi-database mode. registerSqlAutocomplete / getTableColumns take a schema but no database, so get_columns runs against the connection's primary pool — completions for tables in a non-primary database are missing or wrong. It still assumes the flat MySQL shape.
  • Per-database dumps cover one schema at a time. dump_database routes to the selected database's pool and both the dump dialog and the ER diagram window now expose a schema dropdown (defaulting to the active schema, then public) to pick which schema to dump/diagram. Dumping all schemas of a database in one file is still not supported.
  • Sidebar highlight and auto-expand reuse activeSchema for both the database node and the schema node, so the highlight can be slightly off. Navigation works fine.
  • No cap or idle eviction on the per-database pools yet. Each selected database keeps its own pool (max 10 connections) for the lifetime of the connection. Disconnect (and health-check failure) now closes all of a connection's per-database pools, not just the primary one.

Testing

  • New unit tests for the postgres_dbname fallback helper and for the isMultiDatabaseCapable / isSchemaBasedMultiDb changes.
  • Full suites pass locally: 753 Rust tests, 2705 frontend tests, plus tsc and ESLint clean.
  • Still needs a manual pass against a real Postgres server with two or more databases selected.

PostgreSQL Editor Coverage — PR Verification Checklist

Sidebar — Tree & Object Types

  • Databases listed (multi-db, schema-based routing)
  • Schemas listed (system schemas excluded)
  • Tables / Views / Routines (Functions + Procedures split) / Triggers shown
  • Per-table: Columns, Keys (PK/Unique), Foreign Keys, Indexes expand correctly

Sidebar — Connection / Database actions

  • Import Database
  • Dump Database
  • View Schema Diagram (ER)
  • New Console (opens editor on the correct database/schema)
  • Refresh
  • Filter/search: databases, schemas (multi-select), tables, triggers

Sidebar — Schema-level actions

  • Refresh tables
  • Create Table (schema-aware)
  • Create View
  • Create Trigger (gated by triggers capability)

Sidebar — Table context menu

  • Show Data
  • New Console
  • Count Rows
  • View Schema (structure)
  • View ER Diagram
  • Generate SQL (DDL)
  • Clipboard Import
  • Copy Name
  • Add Column
  • Delete Table

Sidebar — Other object context menus

  • View: Show Data / Count Rows / Edit View / Copy Name / Drop View
  • Column: Modify / Copy Name / Delete (disabled on views)
  • Index: Copy Name / Delete; folder → Add Index
  • Foreign Key: folder → Add FK (cross-schema ref_schema qualification)
  • Routine: View Definition (pg_get_functiondef) / Copy Name
  • Trigger: View Definition (pg_get_triggerdef) / Edit / Copy Name / Drop

Sidebar — DDL modals (schema-aware)

  • CreateTable / ModifyColumn / CreateIndex / CreateForeignKey
  • ViewEditor / TriggerEditor
  • Dump / Import / Schema Inspector

Query Editor — Execution

  • Run query / Run selection (Ctrl+Enter)
  • Run multiple statements (batch, shared session state)
  • Multi-statement split dropdown
  • Stop / cancel running query
  • Parametric queries (:param) with input modal

Query Editor — Editing experience

  • SQL syntax highlighting (Monaco)
  • Schema-aware autocomplete (tables/columns/keywords)
  • Line numbers / word wrap / font settings
  • Undo/redo, clipboard paste

Query Editor — AI & Analysis

  • AI Query Generation
  • AI Explain
  • Visual EXPLAIN / EXPLAIN ANALYZE (costs, rows, loops, buffer stats, JSON plan)

Query Editor — Tabs & persistence

  • New / Close / Switch tab, rename, close others/left/right
  • Save Query
  • Query History (status, duration, rows, DB) + re-run

Results Grid — Display & navigation

  • Pagination + Load Count
  • Sort by column header
  • Table toolbar: WHERE filter (SQL + visual builder AND/OR), ORDER BY, LIMIT
  • Multi-row selection (shift/ctrl click, select all)

Results Grid — Data editing (requires PK)

  • Inline cell edit
  • Row Editor sidebar
  • Insert / Duplicate / Delete row (soft)
  • Pending changes tracking
  • Batch transactional commit (Ctrl+S) + revert
  • Set NULL / Default / Empty / NOW()

Results Grid — Postgres-specific types

  • JSON / JSONB (dedicated editor)
  • PostGIS geometry (WKB → WKT preview)
  • Arrays (int[], text[], …)
  • UUID
  • BYTEA (hex/base64 + binary editor)
  • INET/CIDR, range types, NUMERIC arbitrary precision

Results Grid — Navigation & export

  • FK navigation (jump to referenced table with filter) + related records panel
  • Copy cell/row/column (CSV/JSON/SQL INSERT)
  • Export CSV/JSON to file (progress + cancel)
  • Multi-result tabs
  • Detach / minimize / maximize results panel

Known gaps — confirm intentionally out of scope for this PR

  • Materialized Views (list/create/drop/refresh) — NOT implemented
  • Sequences (first-class management) — NOT implemented
  • Custom types / Enums / Domains — NOT implemented
  • Extensions (PostGIS, hstore, …) — NOT listed/managed
  • Check / Unique constraints (dedicated listing) — NOT implemented
  • CREATE/DROP DATABASE, CREATE/DROP SCHEMA — NOT implemented
  • TRUNCATE / RENAME table — NOT implemented
  • Query cancellation cancels app task only, NOT DB-side (pg_cancel_backend)

debba added 4 commits June 30, 2026 19:05
Lets a PostgreSQL connection hold and browse several databases at once,
the same way MySQL/MariaDB connections already can. Because Postgres
binds a connection to one database and cannot query across databases,
each selected database gets its own pool and the sidebar shows a
database to schema to table tree.

Backend reads (get_tables, get_views, get_schemas, get_columns, etc.)
and execute_query now take an optional database argument that routes the
work to the right pool; the convention matches the existing record
mutation commands. Empty selections fall back to the postgres
maintenance database since Postgres cannot connect server-wide.
…nd tab persistence on multi-database connections

On schema-based multi-database (PostgreSQL) connections the backend keeps a
separate pool per database, so every table-scoped call must carry both the
schema and the database. Several paths dropped the database, which made them
hit the connection's primary database and fail with relation-not-found:

- PK/column metadata (fetchPkColumn, new-row, insert validation) omitted the
  database, leaving pkColumns null and silently turning the grid read-only.
  Added buildTableRoutingParams() to centralize schema+database routing.
- Related-records / FK navigation ran execute_query without the database and
  dropped the referenced schema. Added ref_schema to ForeignKey (Rust + TS,
  mapped from foreign_schema_name) so cross-schema FKs qualify correctly, and
  routed the related-records query to the tab's database.
- Editor tabs lost their database on save: cleanTabForStorage didn't persist
  the field, so a restored tab queried the primary database. Also made
  findExistingTableTab database-aware so same-schema tables in different
  databases no longer reuse the wrong tab.

Adds a multi-schema demo database (erp_demo: hr/inventory/sales + cross-schema
FKs) and tests for the routing/persistence regressions.
…ulti-database connections

Replace the per-schema tree nodes under a database with a single compact
schema dropdown: pick one schema and its tables/views/routines render
directly below, like TablePro. Adds a hideHeader mode to SidebarSchemaItem to
render a schema's contents without its collapsible header, a
resolveActiveSchema() helper (picked -> connection-active -> public/first),
and optional triggerClassName/leadingIcon props on the shared Select so the
sidebar trigger is compact with a schema icon. Adds the sidebar.schema key to
all locales and tests for resolveActiveSchema.
The schema-based multi-database tree (database → schema → table) fetched
table metadata against the right connection pool, but right-clicking a
table dropped the database entirely: ContextMenuData and the context-menu
payload only carried schema, so Show Data, New Console, Count Rows,
Delete Table, View Schema, Generate SQL, Add Column, drop index/foreign
key, and the ER Diagram all silently fell back to the connection's
default database.
@NewtTheWolf

Copy link
Copy Markdown
Collaborator

Reviewed locally (tests pass: frontend 140, backend pool_manager 36). The architecture is solid — per-database pool keying (postgres:conn:<id>:<db>), the postgres maintenance-db fallback is contained to connection params (never reaches SQL), and the multi-db logic is capability-driven (no driver === "postgres" conditionals). Nice.

The one real issue is that database threading is incomplete — three call paths still route to the connection's primary DB:

Blockers

  • execute_query_batch (src-tauri/src/commands.rs:3172) never got the database param (only schema), so batch/multi-statement execution runs against the primary DB. execute_query does it right at commands.rs:3104 — mirror that.
  • Export sends the schema as the database — src/pages/Editor.tsx:2704 uses activeTab?.schema as targetDatabase. For Postgres (now multi-db-capable) that routes to the wrong pool. Use the buildTableRoutingParams(...) helper the PR already added (it's used at 575/1959/2132, just not here).
  • count_query has no database — frontend src/pages/Editor.tsx:1141 and backend src/commands.rs:3321 both lack it, so pagination totals run against the primary DB → wrong count or error for non-primary databases.

Nits

  • delete_record/update_record/insert_record (commands.rs:2761, :2792, :3045) use if let Some(db) = database without the .filter(|d| !d.is_empty()) guard the 13 read commands use — with the new maintenance-db fallback, a Some("") write lands on the postgres database.
  • driver === "mysql" added at NewConnectionModal.tsx:1187 (pipes_as_concat) violates .rules/frontend.md no-driver-conditionals.
  • The MySQL/SQLite pk_col → composite pk_map rework + added escape_identifier is a behavioural refactor riding along (.rules/rust.md Does not list databases, have to manually enter database name in connection window #6). Good change on its own (closes an identifier-injection vector, unit-tested) but ideally its own PR.

Repro for the three blockers, on a connection with multiple Postgres DBs selected: run a multi-statement query in a non-primary DB (B1), paginate a large table in a non-primary DB (B3 count), export a non-primary-DB table to CSV (B2) — each hits the primary pool instead.

debba added 8 commits June 30, 2026 22:13
…resh sidebar after table drop

Editing a timestamp/timestamptz/date/time/interval cell failed with
"error serializing parameter N" because tokio-postgres infers a CAST($N
AS type) placeholder's effective type from the cast target, rejecting a
bound Rust String before PostgreSQL's own text-to-temporal parsing ever
runs. The same root cause silently affected uuid-shaped string binds
(#392 was only a partial fix, for varchar PK columns). Every bound
PostgreSQL parameter now declares its wire type explicitly via
prepare_typed/execute_typed, so the client-side type check matches what
is actually sent and the CAST performs the real conversion server-side.
Verified against a live PostgreSQL 16 container (docker), including the
exact UPDATE from the report, with the fix landing in
src-tauri/src/drivers/postgres/{binding,client,mod}.rs and a new
ignored live-DB regression test.

Fixes #401.

Also: deleting a table from the sidebar context menu now refreshes the
schema/database node that actually lists it (PostgreSQL schema-based and
flat multi-database trees), instead of only the flat single-database
table list — the dropped table no longer lingers until a manual refresh.
- ctxDatabase from the context-menu payload is string | null | undefined;
  coerce null -> undefined so it satisfies the string | undefined sinks (tsc -b).
- Wrap schemaDataMap (databaseData?.schemaDataMap ?? {}) in useMemo so the
  lazy-load effect's dependency is stable (react-hooks/exhaustive-deps).
… multi-db

Opening New Console from a database node on a schema-based multi-database
connection (PostgreSQL) produced a tab with schema=<databaseName> and no
database. execute_query then ran on the connection's PRIMARY pool and issued
SET search_path TO "<databaseName>" — but that name is a database, not a
schema — so unqualified relations failed with relation-not-found.

newConsoleForDatabase now takes isSchemaBased: for schema-based drivers it
routes via database (no bogus schema); flat drivers (MySQL) keep overloading
schema as the database name. The sidebar threads spec.database into runQuery.
…ti-db

On a schema-based multi-database connection (PostgreSQL) the editor treated a
console tab like the flat MySQL layout: the active-database dropdown, new
console/notebook creation, and Convert to Console all set tab.schema to the
database name and never set tab.database. execute_query then ran on the
connection primary pool and issued SET search_path TO "<databaseName>" (a
database is not a schema), so console queries failed with relation-not-found
(e.g. SELECT * FROM "public"."app_meta" against the wrong database).

Schema-based connections now route a non-table tab via tab.database (the pool
key) and keep tab.schema as the real schema; flat drivers keep overloading
schema with the database name. Covers: the toolbar db dropdown (label, active
highlight, selection), new console/notebook defaults, Convert to Console
(inherits both schema and database from the source tab), the tab label and the
window title.
Follow-up fixes for schema-based multi-database (PostgreSQL) routing in the
results grid:

- Commit (Ctrl+S) fallback no longer sends the PostgreSQL schema name as
  database on schema-based drivers: isMultiDatabaseCapable now includes
  Postgres, so the flat-driver fallback fired on plain single-database
  connections and routed writes to a pool for a database named after the
  schema (e.g. "public"), breaking every update/insert/delete commit.
- Export CSV/JSON now routes via the tab's database on schema-based drivers
  instead of passing the PostgreSQL schema as the database name.
- count_query accepts a database param and the frontend passes the tab's
  database, so Load Count runs on the correct pool instead of the primary.
- execute_query_batch accepts the database param the frontend was already
  sending (Tauri silently dropped it), so multi-statement scripts on a
  non-primary database console tab run on the correct pool.
- save_blob_to_file / fetch_blob_as_data_url accept a database param, and
  the tab's schema/database are plumbed through DataGrid -> RowEditorSidebar
  -> FieldEditor -> BlobInput so BYTEA preview/download hit the right pool
  and schema.
@debba

debba commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator Author

Results Grid — multi-database routing review + fixes (8664014)

Verified every Results Grid checklist item at code level for Postgres multi-db routing. Most paths were already correct (pagination, sort, toolbar WHERE/ORDER BY/LIMIT, pending changes, FK navigation + related records panel, and the new typed bindings in binding.rs). Five routing gaps were found and fixed in 8664014:

Fixes

  1. Commit (Ctrl+S) regression on plain single-database Postgres — critical (src/pages/Editor.tsx)
    isMultiDatabaseCapable now includes Postgres, so the flat-driver fallback { database: activeTab.schema } fired on ordinary Postgres connections and sent the PostgreSQL schema name (e.g. public) as the database — routing every update/insert/delete commit to a pool for a database literally named public (connection failure, or the wrong database if one with that name exists). The fallback is now gated with !isSchemaBasedConn.

  2. Export CSV/JSON (src/pages/Editor.tsx)
    Same pattern: export passed activeTab.schema ?? activeSchema as database. On schema-based drivers it now routes via activeTab.database (falling back to the primary pool when absent); flat drivers (MySQL) unchanged.

  3. Load Count (src-tauri/src/commands.rs::count_query + Editor.tsx)
    The backend command had no database parameter at all, so counts on a non-primary-DB table ran against the primary pool (relation-not-found, or a silently wrong count on a same-named schema/table). Added the param backend-side and the frontend now passes tab.database.

  4. Multi-statement scripts / multi-result tabs (src-tauri/src/commands.rs::execute_query_batch)
    The frontend already sent database, but the command signature didn't declare it — Tauri silently dropped the argument and the whole batch ran on the primary pool. The param is now accepted and routed.

  5. BYTEA preview/download (commands.rs::save_blob_to_file / fetch_blob_as_data_url + UI plumbing)
    Both blob commands were not db-aware and BlobInput used the connection-global active schema. Added database to both commands and plumbed the tab's schema/database through DataGrid → RowEditorSidebar → FieldEditor → BlobInput (the tab's schema now takes precedence over the global one).

Verified as already correct

  • Pagination, sort, toolbar filters → routed execute_query (database param)
  • PK/column metadata → buildTableRoutingParams (get_columns/get_foreign_keys)
  • FK navigation + related records → ref_schema + tab.database carried through
  • Typed bindings (JSON/JSONB, UUID, NUMERIC, temporal, BYTEA, arrays-as-literals, WKT) — consistent Rust-type/wire-type pairs via prepare_typed

Known non-fixes (pre-existing, out of scope)

  • Ctrl+S commit is not transactional (independent Promise.all invokes — pre-existing design)
  • Editing INET/CIDR/range columns still relies on a text→type assignment cast Postgres doesn't have; it failed before this PR too (client-side serialize error)
  • NewRowModal is dead code (never opened) — left untouched

Checks

pnpm typecheck clean · vitest run 2730 passed · pnpm lint 0 errors · cargo check clean · cargo test 763 passed (4 pre-existing askpass failures are environmental: SUN_LEN socket-path limit in the sandbox)

…leanup to the tab database

Second round of multi-database (PostgreSQL) routing fixes:

- Dump Database: schema-based drivers now fetch the table list for the exact
  schema the backend will dump (default public), routed to the target
  database's pool — previously databaseDataMap[db].tables was always empty
  for Postgres, so validation blocked every dump with 'no tables'.
- Visual EXPLAIN / EXPLAIN ANALYZE: explain_query_plan accepts a database
  param and the modal receives the tab's database from the editor.
- Sidebar context menus: view/routine/trigger items now carry their node's
  schema+database; Show Data, Count Rows, View/Edit/Drop View, routine and
  trigger View Definition / Edit / Drop, and column edit/delete all route to
  the node's database instead of the primary pool or the global active
  schema. drop_view/create_view/alter_view/get_view_definition/
  get_view_columns/create_trigger/drop_trigger accept a database param;
  ViewEditorModal and TriggerEditorModal thread it through.
- Import Database: import_database accepts a database param and the modal
  scopes the import to the database node it was launched from.
- ER Diagram from a database node: pass the node as database (pool key) on
  schema-based drivers instead of letting the page treat the database name
  as a schema on the primary pool.
- Saved queries / favorites / history re-run: on schema-based drivers the
  stored database now goes into the tab's database slot (the pool key)
  instead of overloading schema; Save Query defaults to the tab's database.
- Pool cleanup: disconnect (and health-check failure) now closes every pool
  belonging to the connection id — one per selected database — instead of
  only the primary database's pool. New unit tests cover the key sweep.
@debba

debba commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator Author

Second round of multi-database routing fixes (02d2e77)

Follow-up to the results-grid fixes in 8664014 — this commit addresses the remaining routing gaps found during verification of the sidebar, tooling and lifecycle paths:

Fixed

  1. Dump Database unusable on Postgres (blocker)DumpDatabaseModal read tables from databaseDataMap[db].tables, which is always empty for schema-based drivers (the provider fills schemas/schemaDataMap instead), so validation rejected every dump with "no tables". The dialog now fetches the table list via get_tables for the exact schema the backend will dump (the active schema, defaulting to public), routed to the target database's pool. MySQL flow unchanged.
  2. Visual EXPLAIN / EXPLAIN ANALYZEexplain_query_plan had no database param; added it (standard DatabaseSelection::Single override) and the editor passes activeTab.database through VisualExplainModal. AI-activity deep links still carry no database (part of the AI limitation, see PR body).
  3. Sidebar context menusSidebarSchemaItem forwarded database to table items only. Now views, routines, triggers and columns carry their node's schema+database, and every action routes correctly: view Show Data / Count Rows / Edit / Drop (backend drop_view, create_view, alter_view, get_view_definition, get_view_columns gained database), routine View Definition + parameters, trigger View Definition / Edit / Drop (backend create_trigger/drop_trigger gained database), column Modify (ModifyColumnModal now receives the node's schema/database) and column Delete.
  4. Import Databaseimport_database gained a database param; the modal scopes the import to the database node it was launched from (previously it always ran on the primary pool with the global active schema).
  5. ER Diagram from a database node — the two database-node call sites now pass database on schema-based drivers, and SchemaDiagramPage no longer falls back to treating the database name as a schema when a database param is present. MySQL fallback behavior preserved.
  6. Saved queries / favorites / history re-run — these passed the stored database into runQuery's schema slot, which on Postgres would run SET search_path TO "<db>" on the primary pool. A runSavedSql helper now routes the value into the tab's database (pool key) on schema-based drivers; flat drivers unchanged. Save Query also defaults to activeTab.database instead of the pg schema.
  7. Pool leak on disconnectclose_pool_with_id removed only the primary database's key, leaking every driver:conn:{id}:{otherdb} pool. It now sweeps all pools sharing the connection's key prefix (covers both disconnect_connection and the health-check failure path). Three new unit tests in pool_manager_tests.rs cover the sweep, the no-connection-id case, and the empty-map case.

PR body updated

The "Known limitations / follow ups" section now reflects this work and adds the two remaining known gaps: AI Query Generation and Clipboard Import are not database aware.

Skipped intentionally (declared out of scope in the PR)

Create Table/View/Trigger/Index/FK from nested nodes, autocomplete, sidebar highlight, transactional commit, pg_cancel_backend.

Checks

pnpm typecheck clean · vitest run 2730 passed · pnpm lint 0 errors · cargo check clean · cargo test 766 passed (+3 new; the 4 askpass failures are the sandbox SUN_LEN socket-path issue, pre-existing)

On schema-based drivers (PostgreSQL) both the ER diagram and the database
dump are scoped to a single schema, but neither surface let the user choose
which one — they silently used the connection's global active schema.

- Dump dialog: a schema dropdown lists the target database's schemas
  (get_schemas routed to that database's pool), defaults to the active
  schema (then public), drives both the table list and the schema the
  backend dumps.
- ER diagram window: same dropdown in the header re-scopes the diagram to
  another schema of the target database without reopening the window. The
  opener passes a schemaBased flag through open_er_diagram_window since the
  window has no access to the opener's driver capabilities.
- MySQL and single-database drivers are unchanged (no picker shown).
@debba

debba commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator Author

Schema picker for ER diagram and Dump (3540f99)

Follow-up on reviewer feedback: on PostgreSQL both the ER diagram and the dump were silently scoped to the connection's global active schema. Both surfaces now expose a changeable schema dropdown (schema-based drivers only — MySQL and single-database drivers are unchanged, no picker shown):

  • Dump dialog — a schema Select lists the target database's schemas (get_schemas routed to that database's pool), defaults to the active schema (then public), and drives both the displayed table list and the schema sent to dump_database. Switching schema re-fetches and re-selects the tables.
  • ER diagram window — the same dropdown sits in the window header and re-scopes the diagram to another schema of the target database without reopening it (title follows the picked schema). Since the window runs without the opener's capability context, open_er_diagram_window gained a schema_based flag that all five opener call sites pass when capabilities.schemas === true.

PR body's dump limitation ("scoped via the global active schema") is superseded by this commit for the picker flows.

Checks: pnpm typecheck clean · vitest run 2730 passed · pnpm lint 0 errors · cargo check --tests clean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat]: Browse/access all databases on same connection

2 participants