From 30433b8c0b310ae4c07585102bda9dcdfb3bc04c Mon Sep 17 00:00:00 2001 From: Salvatore Scalzi Date: Mon, 21 Sep 2026 12:26:51 +0200 Subject: [PATCH] fix: qualify the index list's search columns The Indexes list joins pg_class onto pg_stat_user_indexes, and both of them have a relname. The search columns were unqualified, so the predicate Filament built named a column PostgreSQL could not resolve, and every search on that page ended in SQLSTATE[42702] rather than a result. Qualifying both with the model's table is enough -- Filament passes a column already prefixed with it through untouched -- and it keeps the column's two searches, by index name and by the table the index belongs to, working as they read. Fixes #25 Co-Authored-By: Claude Opus 5 --- src/Filament/Resources/IndexResource.php | 5 ++++- tests/Filament/IndexResourceTest.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Filament/Resources/IndexResource.php b/src/Filament/Resources/IndexResource.php index 10f11fd..4ed3ee9 100644 --- a/src/Filament/Resources/IndexResource.php +++ b/src/Filament/Resources/IndexResource.php @@ -100,7 +100,10 @@ public static function table(Table $table): Table TextColumn::make('indexrelname') ->label('Index') ->description(fn (IndexModel $record): string => $record->schemaname.'.'.$record->relname) - ->searchable(['indexrelname', 'relname']) + // Both search columns are qualified: the query joins pg_class, which + // has a relname of its own, and an unqualified one leaves PostgreSQL + // unable to tell which table is meant. + ->searchable(['pg_stat_user_indexes.indexrelname', 'pg_stat_user_indexes.relname']) ->sortable(), TextColumn::make('index_bytes') diff --git a/tests/Filament/IndexResourceTest.php b/tests/Filament/IndexResourceTest.php index 5c3abfb..44fa04f 100644 --- a/tests/Filament/IndexResourceTest.php +++ b/tests/Filament/IndexResourceTest.php @@ -98,3 +98,21 @@ function indexNamed(string $name): Index ->and(IndexResource::canAccess())->toBeTrue() ->and(array_keys(IndexResource::getPages()))->toBe(['index']); }); + +it('searches an index by its own name and by the table it belongs to', function (): void { + $column = bootedColumns(ListIndexes::class, indexNamed('crates_label_index'))['indexrelname']; + + // pg_stat_user_indexes and the joined pg_class both have a relname, so an + // unqualified search column leaves PostgreSQL unable to tell which is meant. + $byIndexName = IndexResource::getEloquentQuery(); + $isFirst = true; + $column->applySearchConstraint($byIndexName, 'crates_label', $isFirst); + + $byTableName = IndexResource::getEloquentQuery(); + $isFirst = true; + $column->applySearchConstraint($byTableName, 'crates', $isFirst); + + expect($byIndexName->pluck('indexrelname')->all())->toBe(['crates_label_index']) + ->and($byTableName->pluck('indexrelname')->all()) + ->toContain('crates_pkey', 'crates_label_index', 'crates_code_unique'); +});