Skip to content

Commit 8b7fd30

Browse files
refacto: overhaul exception handling and expand negative test coverage
- Simplify `Api::handleErrorResponse` to align with Chroma v2 API consistency, utilizing direct JSON decoding and status code mapping (e.g., mapping 409 to `UniqueConstraintException`). - Rename exception classes to remove redundant prefixes (e.g., `ChromaConnectionException` → `ConnectionException`). - Standardize exception instantiation via the `ChromaException::create()` factory. - Implement robust client-side validation in Collection methods for embeddings, `nResults`, IDs, and metadata. - update `ApiTest`, `CollectionTest`, and `QueryFilteringTest` with comprehensive negative test scenarios.
1 parent 351b5c1 commit 8b7fd30

25 files changed

Lines changed: 373 additions & 306 deletions

src/Api.php

Lines changed: 18 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44

55
namespace Codewithkyrian\ChromaDB;
66

7-
use Codewithkyrian\ChromaDB\Exceptions\ChromaAuthorizationException;
8-
use Codewithkyrian\ChromaDB\Exceptions\ChromaConnectionException;
7+
use Codewithkyrian\ChromaDB\Exceptions\ConnectionException;
98
use Codewithkyrian\ChromaDB\Exceptions\ChromaException;
109
use Codewithkyrian\ChromaDB\Models\Collection;
1110
use Codewithkyrian\ChromaDB\Models\Database;
@@ -393,7 +392,7 @@ public function getCollectionItems(string $collectionId, string $database, strin
393392
$response = $this->sendRequest('POST', "/api/v2/tenants/$tenant/databases/$database/collections/$collectionId/get", [
394393
'json' => $request->toArray(),
395394
]);
396-
395+
397396
$result = json_decode($response->getBody()->getContents(), true);
398397

399398
return GetItemsResponse::fromArray($result);
@@ -435,72 +434,6 @@ public function queryCollectionItems(string $collectionId, string $database, str
435434
return QueryItemsResponse::fromArray($result);
436435
}
437436

438-
439-
private function handleErrorResponse(ResponseInterface $response): void
440-
{
441-
$statusCode = $response->getStatusCode();
442-
443-
if ($statusCode === 401 || $statusCode === 403) {
444-
throw new ChromaAuthorizationException($response->getReasonPhrase(), $statusCode);
445-
}
446-
447-
$errorString = $response->getBody()->getContents();
448-
449-
if (preg_match('/(?<={"\"error\"\:\")([^"]*)/', $errorString, $matches)) {
450-
$errorString = $matches[1];
451-
}
452-
453-
$error = json_decode($errorString, true);
454-
455-
if ($error !== null) {
456-
457-
// If the structure is 'error' => 'NotFoundError("Collection not found")'
458-
if (
459-
preg_match(
460-
'/^(?P<error_type>\w+)\((?P<message>.*)\)$/',
461-
$error['error'] ?? '',
462-
$matches
463-
)
464-
) {
465-
if (isset($matches['message'])) {
466-
$error_type = $matches['error_type'] ?? 'UnknownError';
467-
$message = $matches['message'];
468-
469-
// Remove trailing and leading quotes
470-
if (str_starts_with($message, "'") && str_ends_with($message, "'")) {
471-
$message = substr($message, 1, -1);
472-
}
473-
474-
ChromaException::throwSpecific($message, $error_type, $statusCode);
475-
}
476-
}
477-
478-
// If the structure is 'detail' => 'Collection not found'
479-
if (isset($error['detail'])) {
480-
$message = $error['detail'];
481-
$error_type = ChromaException::inferTypeFromMessage($message);
482-
483-
484-
ChromaException::throwSpecific($message, $error_type, $statusCode);
485-
}
486-
487-
// If the structure is {'error': 'Error Type', 'message' : 'Error message'}
488-
if (isset($error['error']) && isset($error['message'])) {
489-
ChromaException::throwSpecific($error['message'], $error['error'], $statusCode);
490-
}
491-
492-
// If the structure is 'error' => 'Collection not found'
493-
if (isset($error['error'])) {
494-
$message = $error['error'];
495-
$error_type = ChromaException::inferTypeFromMessage($message);
496-
497-
ChromaException::throwSpecific($message, $error_type, $statusCode);
498-
}
499-
}
500-
501-
throw new ChromaException($errorString ?: $response->getReasonPhrase(), $statusCode);
502-
}
503-
504437
private function sendRequest(string $method, string $path, array $options = []): ResponseInterface
505438
{
506439
$uri = $this->baseUri . $path;
@@ -524,7 +457,7 @@ private function sendRequest(string $method, string $path, array $options = []):
524457
try {
525458
$response = $this->client->sendRequest($request);
526459
} catch (ClientExceptionInterface $e) {
527-
throw new ChromaConnectionException($e->getMessage(), $e->getCode());
460+
throw new ConnectionException($e->getMessage(), $e->getCode());
528461
}
529462

530463
if ($response->getStatusCode() >= 400) {
@@ -533,4 +466,19 @@ private function sendRequest(string $method, string $path, array $options = []):
533466

534467
return $response;
535468
}
469+
470+
private function handleErrorResponse(ResponseInterface $response): void
471+
{
472+
$statusCode = $response->getStatusCode();
473+
$body = json_decode($response->getBody()->getContents(), true);
474+
475+
$errorType = $body['error'] ?? 'UnknownError';
476+
$message = $body['message'] ?? 'Unknown error occurred';
477+
478+
if ($statusCode === 409) {
479+
$errorType = 'UniqueConstraintError';
480+
}
481+
482+
throw ChromaException::create($message, $errorType, $statusCode);
483+
}
536484
}

src/Client.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Codewithkyrian\ChromaDB\Embeddings\EmbeddingFunction;
88
use Codewithkyrian\ChromaDB\Api;
9-
use Codewithkyrian\ChromaDB\Exceptions\ChromaNotFoundException;
9+
use Codewithkyrian\ChromaDB\Exceptions\NotFoundException;
1010
use Codewithkyrian\ChromaDB\Models\Collection;
1111
use Codewithkyrian\ChromaDB\Requests\CreateDatabaseRequest;
1212
use Codewithkyrian\ChromaDB\Requests\CreateTenantRequest;
@@ -15,9 +15,9 @@
1515
class Client
1616
{
1717
public function __construct(
18-
public readonly Api $api,
19-
public readonly string $database,
20-
public readonly string $tenant,
18+
public readonly Api $api,
19+
public readonly string $database,
20+
public readonly string $tenant,
2121
) {
2222
$this->initDatabaseAndTenant();
2323
}
@@ -26,14 +26,14 @@ public function initDatabaseAndTenant(): void
2626
{
2727
try {
2828
$this->api->getTenant($this->tenant);
29-
} catch (ChromaNotFoundException) {
29+
} catch (NotFoundException) {
3030
$createTenantRequest = new CreateTenantRequest($this->tenant);
3131
$this->api->createTenant($createTenantRequest);
3232
}
3333

3434
try {
3535
$this->api->getDatabase($this->database, $this->tenant);
36-
} catch (ChromaNotFoundException) {
36+
} catch (NotFoundException) {
3737
$createDatabaseRequest = new CreateDatabaseRequest($this->database);
3838
$this->api->createDatabase($this->tenant, $createDatabaseRequest);
3939
}
@@ -65,7 +65,7 @@ public function heartbeat(): int
6565
*/
6666
public function listCollections(): array
6767
{
68-
return $this->api->listCollections($this->database, $this->tenant);
68+
return $this->api->listCollections($this->database, $this->tenant);
6969
}
7070

7171

@@ -104,7 +104,7 @@ public function getOrCreateCollection(string $name, ?array $metadata = null, ?Em
104104
{
105105
$request = new CreateCollectionRequest($name, $metadata, true);
106106

107-
$collection = $this->api->createCollection($this->database, $this->tenant, $request);
107+
$collection = $this->api->createCollection($this->database, $this->tenant, $request);
108108

109109
if ($embeddingFunction) {
110110
$collection->setEmbeddingFunction($embeddingFunction);

src/Exceptions/ChromaAuthorizationException.php

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/Exceptions/ChromaDimensionalityException.php

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/Exceptions/ChromaException.php

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,21 @@
22

33
declare(strict_types=1);
44

5-
65
namespace Codewithkyrian\ChromaDB\Exceptions;
76

87
class ChromaException extends \Exception
98
{
109

11-
public static function throwSpecific(string $message, string $type, int $code)
10+
public static function create(string $message, string $type, int $code): self
1211
{
13-
throw match ($type) {
14-
'NotFoundError' => new ChromaNotFoundException($message, $code),
15-
'AuthorizationError' => new ChromaAuthorizationException($message, $code),
16-
'ValueError' => new ChromaValueException($message, $code),
17-
'UniqueConstraintError' => new ChromaUniqueConstraintException($message, $code),
18-
'DimensionalityError' => new ChromaDimensionalityException($message, $code),
19-
'InvalidCollection' => new ChromaInvalidCollectionException($message, $code),
20-
'TypeError' => new ChromaTypeException($message, $code),
21-
'InvalidArgumentError' => new ChromaInvalidArgumentException($message, $code),
12+
return match ($type) {
13+
'NotFoundError' => new NotFoundException($message, $code),
14+
'ValueError' => new ValueException($message, $code),
15+
'UniqueConstraintError' => new UniqueConstraintException($message, $code),
16+
'DimensionalityError' => new DimensionalityException($message, $code),
17+
'InvalidCollection' => new InvalidCollectionException($message, $code),
18+
'TypeError' => new TypeException($message, $code),
19+
'InvalidArgumentError' => new InvalidArgumentException($message, $code),
2220
default => new self($message, $code),
2321
};
2422
}

src/Exceptions/ChromaInvalidArgumentException.php

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/Exceptions/ChromaInvalidCollectionException.php

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/Exceptions/ChromaUniqueConstraintException.php

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
declare(strict_types=1);
44

5-
65
namespace Codewithkyrian\ChromaDB\Exceptions;
76

8-
class ChromaTypeException extends ChromaException
7+
class ConnectionException extends ChromaException
98
{
109

1110
}

src/Exceptions/ChromaNotFoundException.php renamed to src/Exceptions/DimensionalityException.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
declare(strict_types=1);
44

5-
65
namespace Codewithkyrian\ChromaDB\Exceptions;
76

8-
class ChromaNotFoundException extends ChromaException
7+
class DimensionalityException extends ChromaException
98
{
109

1110
}

0 commit comments

Comments
 (0)