From 9433eb2aeefc0de740a2618bc2097870fae4308f Mon Sep 17 00:00:00 2001 From: lucassamir Date: Mon, 20 Apr 2026 11:02:45 -0700 Subject: [PATCH] Show foreign tables in the sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Foreign tables (pg_class.relkind = 'f') currently don't appear in the sidebar even though the CASE in objects.sql already maps 'f' to 'foreign_table' — the relkind IN (...) filter excludes 'f', and the Go/JS layers have no handling for the type. This wires them through end-to-end: - pkg/statements/sql/objects.sql: add 'f' to the relkind filter - pkg/client/result.go: add ObjTypeForeignTable, a ForeignTables slice on the Objects struct, and a case in ObjectsFromResult - static/js/app.js: add "Foreign Tables" title/icon, include it in the schema render order, the emptyObjectList, and the autocomplete filter Foreign tables are rendered and behave like regular tables in the sidebar — clicking one fetches rows via the usual SELECT-LIMIT path, which works unchanged for FDW-backed relations. Co-Authored-By: Claude Opus 4.7 --- pkg/client/result.go | 5 +++++ pkg/statements/sql/objects.sql | 2 +- static/js/app.js | 7 +++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pkg/client/result.go b/pkg/client/result.go index 0db791247..4f5633cbf 100644 --- a/pkg/client/result.go +++ b/pkg/client/result.go @@ -19,6 +19,7 @@ const ( ObjTypeMaterializedView = "materialized_view" ObjTypeSequence = "sequence" ObjTypeFunction = "function" + ObjTypeForeignTable = "foreign_table" ) type ( @@ -68,6 +69,7 @@ type ( MaterializedViews []Object `json:"materialized_view"` Functions []Object `json:"function"` Sequences []Object `json:"sequence"` + ForeignTables []Object `json:"foreign_table"` } ) @@ -189,6 +191,7 @@ func ObjectsFromResult(res *Result) map[string]*Objects { MaterializedViews: []Object{}, Functions: []Object{}, Sequences: []Object{}, + ForeignTables: []Object{}, } } @@ -205,6 +208,8 @@ func ObjectsFromResult(res *Result) map[string]*Objects { objects[schema].Functions = append(objects[schema].Functions, obj) case ObjTypeSequence: objects[schema].Sequences = append(objects[schema].Sequences, obj) + case ObjTypeForeignTable: + objects[schema].ForeignTables = append(objects[schema].ForeignTables, obj) } } diff --git a/pkg/statements/sql/objects.sql b/pkg/statements/sql/objects.sql index f550cdb64..bf457b568 100644 --- a/pkg/statements/sql/objects.sql +++ b/pkg/statements/sql/objects.sql @@ -19,7 +19,7 @@ WITH all_objects AS ( LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE - c.relkind IN ('r','v','m','S','s','') + c.relkind IN ('r','v','m','S','s','f','') AND n.nspname !~ '^pg_(toast|temp)' AND n.nspname NOT IN ('information_schema', 'pg_catalog') AND has_schema_privilege(n.nspname, 'USAGE') diff --git a/static/js/app.js b/static/js/app.js index d5b26d4ef..3da539a2a 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -139,6 +139,7 @@ function buildSchemaSection(name, objects) { "table": "Tables", "view": "Views", "materialized_view": "Materialized Views", + "foreign_table": "Foreign Tables", "function": "Functions", "sequence": "Sequences" }; @@ -147,6 +148,7 @@ function buildSchemaSection(name, objects) { "table": '', "view": '', "materialized_view": '', + "foreign_table": '', "function": '', "sequence": '' }; @@ -158,7 +160,7 @@ function buildSchemaSection(name, objects) { section += "
" + name + "
"; section += "
"; - ["table", "view", "materialized_view", "function", "sequence"].forEach(function(group) { + ["table", "view", "materialized_view", "foreign_table", "function", "sequence"].forEach(function(group) { group_klass = ""; if (name == "public" && group == "table") group_klass = "expanded"; @@ -221,6 +223,7 @@ function loadSchemas() { table: [], view: [], materialized_view: [], + foreign_table: [], function: [], sequence: [] } @@ -259,7 +262,7 @@ function loadSchemas() { autocompleteObjects = []; for (schema in data) { for (kind in data[schema]) { - if (!(kind == "table" || kind == "view" || kind == "materialized_view" || kind == "function")) { + if (!(kind == "table" || kind == "view" || kind == "materialized_view" || kind == "foreign_table" || kind == "function")) { continue }