Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Contracts/VectorClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public function setPayload(string $collection, array $ids, array $payload, bool
*/
public function count(string $collection, ?array $filter = null): int;

public function createPayloadIndex(string $collection, string $fieldName, ?string $fieldSchema = null): UpsertResult;

public function deletePayloadIndex(string $collection, string $fieldName): UpsertResult;

/**
* @param array<string|int>|null $ids
* @param array<string, mixed>|null $filter
Expand Down
18 changes: 18 additions & 0 deletions src/Qdrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use TheShit\Vector\Requests\Collections\DeleteCollectionRequest;
use TheShit\Vector\Requests\Collections\GetCollectionRequest;
use TheShit\Vector\Requests\Points\CountPointsRequest;
use TheShit\Vector\Requests\Points\CreatePayloadIndexRequest;
use TheShit\Vector\Requests\Points\DeletePayloadIndexRequest;
use TheShit\Vector\Requests\Points\DeletePointsRequest;
use TheShit\Vector\Requests\Points\GetPointsRequest;
use TheShit\Vector\Requests\Points\ScrollPointsRequest;
Expand Down Expand Up @@ -137,6 +139,22 @@ public function count(string $collection, ?array $filter = null): int
return (int) $response->json('result.count');
}

public function createPayloadIndex(string $collection, string $fieldName, ?string $fieldSchema = null): UpsertResult
{
$response = $this->connector->send(new CreatePayloadIndexRequest($collection, $fieldName, $fieldSchema));
$response->throw();

return UpsertResult::fromArray($response->json('result'));
}

public function deletePayloadIndex(string $collection, string $fieldName): UpsertResult
{
$response = $this->connector->send(new DeletePayloadIndexRequest($collection, $fieldName));
$response->throw();

return UpsertResult::fromArray($response->json('result'));
}

/**
* @param array<string|int>|null $ids
* @param array<string, mixed>|null $filter
Expand Down
51 changes: 51 additions & 0 deletions src/Requests/Points/CreatePayloadIndexRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace TheShit\Vector\Requests\Points;

use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;

class CreatePayloadIndexRequest extends Request implements HasBody
{
use HasJsonBody;

protected Method $method = Method::PUT;

public function __construct(
protected readonly string $collection,
protected readonly string $fieldName,
protected readonly ?string $fieldSchema = null,
protected readonly bool $wait = true,
) {}

public function resolveEndpoint(): string
{
return '/collections/'.$this->collection.'/index';
}

/**
* @return array<string, string>
*/
protected function defaultQuery(): array
{
return ['wait' => $this->wait ? 'true' : 'false'];
}

/**
* @return array<string, mixed>
*/
protected function defaultBody(): array
{
$body = ['field_name' => $this->fieldName];

if ($this->fieldSchema !== null) {
$body['field_schema'] = $this->fieldSchema;
}

return $body;
}
}
32 changes: 32 additions & 0 deletions src/Requests/Points/DeletePayloadIndexRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace TheShit\Vector\Requests\Points;

use Saloon\Enums\Method;
use Saloon\Http\Request;

class DeletePayloadIndexRequest extends Request
{
protected Method $method = Method::DELETE;

public function __construct(
protected readonly string $collection,
protected readonly string $fieldName,
protected readonly bool $wait = true,
) {}

public function resolveEndpoint(): string
{
return '/collections/'.$this->collection.'/index/'.$this->fieldName;
}

/**
* @return array<string, string>
*/
protected function defaultQuery(): array
{
return ['wait' => $this->wait ? 'true' : 'false'];
}
}
14 changes: 12 additions & 2 deletions tests/Contract/OpenApiSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ function specRequired(array $schema): array
->and($fields)->toContain('exact');
});

it('CreateFieldIndex requires field_name', function (): void {
$schema = getRequestSchema(loadSpec(), 'put', '/collections/{collection_name}/index');

expect(specFields($schema))->toContain('field_name')
->and(specRequired($schema))->toContain('field_name');
});

it('SetPayload requires payload field', function (): void {
$schema = getRequestSchema(loadSpec(), 'post', '/collections/{collection_name}/points/payload');

Expand Down Expand Up @@ -152,7 +159,8 @@ function specRequired(array $schema): array
->and($paths)->toContain('/collections/{collection_name}/points/scroll')
->and($paths)->toContain('/collections/{collection_name}/points/delete')
->and($paths)->toContain('/collections/{collection_name}/points/count')
->and($paths)->toContain('/collections/{collection_name}/points/payload');
->and($paths)->toContain('/collections/{collection_name}/points/payload')
->and($paths)->toContain('/collections/{collection_name}/index');
});

it('our HTTP methods match', function (): void {
Expand All @@ -167,6 +175,8 @@ function specRequired(array $schema): array
->and($spec['paths']['/collections/{collection_name}/points/scroll'])->toHaveKey('post')
->and($spec['paths']['/collections/{collection_name}/points/delete'])->toHaveKey('post')
->and($spec['paths']['/collections/{collection_name}/points/count'])->toHaveKey('post')
->and($spec['paths']['/collections/{collection_name}/points/payload'])->toHaveKey('post');
->and($spec['paths']['/collections/{collection_name}/points/payload'])->toHaveKey('post')
->and($spec['paths']['/collections/{collection_name}/index'])->toHaveKey('put')
->and($spec['paths']['/collections/{collection_name}/index/{field_name}'])->toHaveKey('delete');
});
});
36 changes: 36 additions & 0 deletions tests/Feature/QdrantTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use TheShit\Vector\Requests\Collections\DeleteCollectionRequest;
use TheShit\Vector\Requests\Collections\GetCollectionRequest;
use TheShit\Vector\Requests\Points\CountPointsRequest;
use TheShit\Vector\Requests\Points\CreatePayloadIndexRequest;
use TheShit\Vector\Requests\Points\DeletePayloadIndexRequest;
use TheShit\Vector\Requests\Points\DeletePointsRequest;
use TheShit\Vector\Requests\Points\GetPointsRequest;
use TheShit\Vector\Requests\Points\ScrollPointsRequest;
Expand Down Expand Up @@ -165,6 +167,40 @@ function makeClient(MockClient $mock): Qdrant
});
});

describe('Qdrant::createPayloadIndex', function (): void {
it('creates an index and returns result', function (): void {
$mock = new MockClient([
CreatePayloadIndexRequest::class => MockResponse::make([
'result' => ['status' => 'completed', 'operation_id' => 20],
'status' => 'ok',
]),
]);

$result = makeClient($mock)->createPayloadIndex('coll', 'artist', 'keyword');

expect($result)->toBeInstanceOf(UpsertResult::class)
->and($result->completed())->toBeTrue();
$mock->assertSent(CreatePayloadIndexRequest::class);
});
});

describe('Qdrant::deletePayloadIndex', function (): void {
it('deletes an index and returns result', function (): void {
$mock = new MockClient([
DeletePayloadIndexRequest::class => MockResponse::make([
'result' => ['status' => 'completed', 'operation_id' => 21],
'status' => 'ok',
]),
]);

$result = makeClient($mock)->deletePayloadIndex('coll', 'artist');

expect($result)->toBeInstanceOf(UpsertResult::class)
->and($result->completed())->toBeTrue();
$mock->assertSent(DeletePayloadIndexRequest::class);
});
});

describe('Qdrant::upsert', function (): void {
it('upserts raw array points', function (): void {
$mock = new MockClient([
Expand Down
46 changes: 46 additions & 0 deletions tests/Unit/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use TheShit\Vector\Requests\Collections\DeleteCollectionRequest;
use TheShit\Vector\Requests\Collections\GetCollectionRequest;
use TheShit\Vector\Requests\Points\CountPointsRequest;
use TheShit\Vector\Requests\Points\CreatePayloadIndexRequest;
use TheShit\Vector\Requests\Points\DeletePayloadIndexRequest;
use TheShit\Vector\Requests\Points\DeletePointsRequest;
use TheShit\Vector\Requests\Points\GetPointsRequest;
use TheShit\Vector\Requests\Points\ScrollPointsRequest;
Expand Down Expand Up @@ -113,6 +115,50 @@
});
});

describe('CreatePayloadIndexRequest', function (): void {
it('resolves endpoint', function (): void {
$request = new CreatePayloadIndexRequest('coll', 'artist');

expect($request->resolveEndpoint())->toBe('/collections/coll/index');
});

it('builds body with field name only', function (): void {
$request = new CreatePayloadIndexRequest('coll', 'artist');
$body = invade($request)->defaultBody();

expect($body)->toBe(['field_name' => 'artist']);
});

it('includes field schema when provided', function (): void {
$request = new CreatePayloadIndexRequest('coll', 'artist', 'keyword');
$body = invade($request)->defaultBody();

expect($body)->toBe(['field_name' => 'artist', 'field_schema' => 'keyword']);
});

it('sets wait query param', function (): void {
$request = new CreatePayloadIndexRequest('coll', 'artist', wait: false);
$query = invade($request)->defaultQuery();

expect($query['wait'])->toBe('false');
});
});

describe('DeletePayloadIndexRequest', function (): void {
it('resolves endpoint with field name', function (): void {
$request = new DeletePayloadIndexRequest('coll', 'artist');

expect($request->resolveEndpoint())->toBe('/collections/coll/index/artist');
});

it('sets wait query param', function (): void {
$request = new DeletePayloadIndexRequest('coll', 'artist', wait: true);
$query = invade($request)->defaultQuery();

expect($query['wait'])->toBe('true');
});
});

describe('DeleteCollectionRequest', function (): void {
it('resolves endpoint', function (): void {
$request = new DeleteCollectionRequest('old_collection');
Expand Down
Loading