From 02027f88193810085374d087e95566159076c7de Mon Sep 17 00:00:00 2001 From: edalzell Date: Wed, 16 Sep 2026 15:26:25 -0700 Subject: [PATCH] Surface per-search multi_search errors --- src/Typesense/Index.php | 7 ++++ tests/Unit/SearchUsingApiTest.php | 69 +++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/Unit/SearchUsingApiTest.php diff --git a/src/Typesense/Index.php b/src/Typesense/Index.php index 54293b6..5563fde 100644 --- a/src/Typesense/Index.php +++ b/src/Typesense/Index.php @@ -11,6 +11,7 @@ use Statamic\Support\Arr; use Typesense\Client; use Typesense\Exceptions\ObjectNotFound; +use Typesense\Exceptions\TypesenseClientError; class Index extends BaseIndex { @@ -121,6 +122,12 @@ public function searchUsingApi($query, array $options = []): array $searchResults = $this->client->multiSearch->perform($searchRequest, []); $searchResults = array_shift($searchResults['results']); + // Typesense answers with a 200 even when an individual search failed, so the error + // only shows up in the result itself. + if (! is_null($error = Arr::get($searchResults, 'error'))) { + throw new TypesenseClientError($error, (int) Arr::get($searchResults, 'code', 0)); + } + $total = count($searchResults['hits']); return [ diff --git a/tests/Unit/SearchUsingApiTest.php b/tests/Unit/SearchUsingApiTest.php new file mode 100644 index 0000000..bdbb4db --- /dev/null +++ b/tests/Unit/SearchUsingApiTest.php @@ -0,0 +1,69 @@ +shouldReceive('get') + ->with('/collections/'.$name, []) + ->andReturn(['name' => $name]); + + $apiCall->shouldReceive('post') + ->with('/multi_search', Mockery::type('array'), true, []) + ->once() + ->andReturn(['results' => [$result]]); + + $client = new Client([ + 'api_key' => 'xyz', + 'nodes' => [['host' => 'localhost', 'port' => '8108', 'path' => '', 'protocol' => 'http']], + ]); + + $client->collections = new Collections($apiCall); + $client->multiSearch = new MultiSearch($apiCall); + + return new Index($client, $name, []); + } + + #[Test] + public function it_throws_the_error_from_a_failed_search() + { + $index = $this->indexWithMultiSearchResult([ + 'code' => 400, + 'error' => 'Could not find a filter field named `foo` in the schema.', + ]); + + $this->expectException(TypesenseClientError::class); + $this->expectExceptionMessage('Could not find a filter field named `foo` in the schema.'); + $this->expectExceptionCode(400); + + $index->searchUsingApi('*'); + } + + #[Test] + public function it_returns_the_hits_from_a_successful_search() + { + $index = $this->indexWithMultiSearchResult([ + 'hits' => [ + ['document' => ['id' => 'entry::test-1', 'title' => 'Entry 1'], 'text_match' => 12], + ], + ]); + + $results = $index->searchUsingApi('*'); + + $this->assertSame(['Entry 1'], $results['results']->pluck('title')->all()); + } +}