Skip to content

Commit e5f2283

Browse files
akoclaude
andcommitted
fix(catalog): SHOW CATALOG TABLES lists every catalog view
The Tables() list backing SHOW CATALOG TABLES was hand-maintained and had drifted: the document-type views added recently (javascript_actions, image_collections, data_transformers, agents, ai_models, knowledge_bases, consumed_mcp_services) plus the pre-existing navigation_profiles view were all built and queryable but never listed, so the command under-reported the catalog. List them, and add a drift-guard test (TestTables_CoversAllViews) that asserts every VIEW in the schema appears in Tables() — the churn is always in views (each cataloged document type adds one), so enforcing this catches the omission at test time instead of in the field. Base tables (projects, snapshots, FTS shadows, catalog_meta) stay intentionally excluded. Verified against test3-app: all eight previously-missing views now appear with correct counts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d92822a commit e5f2283

3 files changed

Lines changed: 52 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
2020

2121
### Fixed
2222

23+
- **`SHOW CATALOG TABLES` lists every catalog view** — the table list was hand-maintained and had drifted: the newly-cataloged document-type views (image collections, JavaScript actions, data transformers, agents, AI models, knowledge bases, consumed MCP services) and the pre-existing `navigation_profiles` view were all built and queryable but never shown. They are now listed, and a drift-guard test (`TestTables_CoversAllViews`) asserts every catalog VIEW appears in the list, so a future document type can't be silently omitted again.
2324
- **`refresh catalog source` no longer O(N²) on large projects** — it resolved each document by re-reading and re-`bson.Unmarshal`ing *every* unit on *every* describe call, so a big app (#651: ~3.3k microflows, ~33k activities) took ~6 hours. The reader now builds a one-time `$Type + qualified-name → unit` index (decoding only the `Name` field, not the whole document), making `GetRawUnitByName` / `GetRawMicroflowByName` O(1); the shared backend means the index is built once across the parallel describe workers. The source phase also reports incremental progress every 2s instead of going silent for the whole build. GraphViewer's source build (993 microflows) dropped to ~3.5 min with live progress; cloud-portal-scale projects go from hours to minutes
2425
- **Marketplace search now scans the whole catalog** — the Content API has no server-side search and caps `limit` at 100 per page, so `marketplace search` previously only filtered the first 100 items and silently missed matches further in (e.g. External Database Connector `219862`, Mendix Business Events `202649`). It now paginates via `offset`, fetching pages **concurrently** (first page alone so a common early match stays a single request; then bounded-parallel batches), and stops at `--limit` matches or end-of-catalog. Measured ~3m45s → ~44s on a slow link for a deep match; combined with the new cache, repeat searches are instant
2526

mdl/catalog/catalog.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ func (c *Catalog) Tables() []string {
111111
"CATALOG.LAYOUTS",
112112
"CATALOG.ENUMERATIONS",
113113
"CATALOG.JAVA_ACTIONS",
114+
"CATALOG.JAVASCRIPT_ACTIONS",
115+
"CATALOG.IMAGE_COLLECTIONS",
116+
"CATALOG.DATA_TRANSFORMERS",
117+
"CATALOG.AGENTS",
118+
"CATALOG.AI_MODELS",
119+
"CATALOG.KNOWLEDGE_BASES",
120+
"CATALOG.CONSUMED_MCP_SERVICES",
121+
"CATALOG.NAVIGATION_PROFILES",
114122
"CATALOG.ACTIVITIES",
115123
"CATALOG.WIDGETS",
116124
"CATALOG.WIDGET_DEFINITIONS",

mdl/catalog/catalog_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"database/sql"
77
"os"
88
"path/filepath"
9+
"strings"
910
"testing"
1011
"time"
1112

@@ -99,6 +100,48 @@ func TestTables(t *testing.T) {
99100
}
100101
}
101102

103+
// TestTables_CoversAllViews is a drift guard: every catalog VIEW created by the
104+
// schema must be listed in Tables(), so SHOW CATALOG TABLES never silently omits
105+
// a document type. The churn is always in views — each new cataloged document
106+
// type adds a viewWithFullSnapshot — so enforcing "every view is listed" catches
107+
// the omission at test time (the failure mode that hid javascript_actions,
108+
// image_collections, data_transformers, the agent-editor views, and
109+
// navigation_profiles from SHOW CATALOG TABLES). Base tables (projects,
110+
// snapshots, FTS shadows, catalog_meta) are type='table' and intentionally
111+
// excluded from this invariant.
112+
func TestTables_CoversAllViews(t *testing.T) {
113+
cat, err := New()
114+
if err != nil {
115+
t.Fatalf("Failed to create catalog: %v", err)
116+
}
117+
defer cat.Close()
118+
119+
listed := make(map[string]bool)
120+
for _, tbl := range cat.Tables() {
121+
listed[strings.ToLower(strings.TrimPrefix(tbl, "CATALOG."))] = true
122+
}
123+
124+
rows, err := cat.CatalogDB().Query(
125+
"SELECT name FROM sqlite_master WHERE type = 'view' ORDER BY name")
126+
if err != nil {
127+
t.Fatalf("Failed to enumerate views: %v", err)
128+
}
129+
defer rows.Close()
130+
for rows.Next() {
131+
var name string
132+
if err := rows.Scan(&name); err != nil {
133+
t.Fatalf("Scan failed: %v", err)
134+
}
135+
if !listed[name] {
136+
t.Errorf("catalog view %q is not listed in Tables() — add CATALOG.%s "+
137+
"so SHOW CATALOG TABLES includes it", name, strings.ToUpper(name))
138+
}
139+
}
140+
if err := rows.Err(); err != nil {
141+
t.Fatalf("rows error: %v", err)
142+
}
143+
}
144+
102145
func TestQueryEmptyTable(t *testing.T) {
103146
cat, err := New()
104147
if err != nil {

0 commit comments

Comments
 (0)