Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.73% covered (warning)
82.73%
91 / 110
34.78% covered (danger)
34.78%
8 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
ControlPlane
82.73% covered (warning)
82.73%
91 / 110
34.78% covered (danger)
34.78%
8 / 23
59.87
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 listIndexes
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 createIndex
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 createForModel
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 describeIndex
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 deleteIndex
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 configureIndex
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 createCollection
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 listCollections
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
2.26
 describeCollection
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 deleteCollection
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 createBackup
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 listBackups
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
2.26
 describeBackup
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 deleteBackup
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 listRestoreJobs
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
3.33
 describeRestoreJob
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 createAssistant
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 listAssistants
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
2.26
 describeAssistant
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 updateAssistant
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 deleteAssistant
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 handleResponse
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5namespace Mbvb1223\Pinecone\Control;
6
7use GuzzleHttp\Client;
8use GuzzleHttp\Exception\GuzzleException;
9use Mbvb1223\Pinecone\Errors\PineconeApiException;
10use Mbvb1223\Pinecone\Errors\PineconeException;
11use Psr\Http\Message\ResponseInterface;
12
13class ControlPlane
14{
15    public function __construct(private readonly Client $httpClient)
16    {
17    }
18
19    public function listIndexes(): array
20    {
21        try {
22            $response = $this->httpClient->get('/indexes');
23            $data = $this->handleResponse($response);
24
25            return $data['indexes'] ?? [];
26        } catch (GuzzleException $e) {
27            throw new PineconeException('Failed to list indexes: ' . $e->getMessage(), 0, $e);
28        }
29    }
30
31    public function createIndex(string $name, array $requestData): array
32    {
33        try {
34            $payload = [
35                'name' => $name,
36                'dimension' => $requestData['dimension'],
37                'metric' => $requestData['metric'] ?? 'cosine',
38                'spec' => $requestData['spec'],
39            ];
40
41            $response = $this->httpClient->post('/indexes', ['json' => $payload]);
42
43            return $this->handleResponse($response);
44        } catch (GuzzleException $e) {
45            throw new PineconeException("Failed to create index: $name{$e->getMessage()}", 0, $e);
46        }
47    }
48
49    public function createForModel(string $name, array $requestData): array
50    {
51        try {
52            $payload = array_merge(['name' => $name], $requestData);
53
54            $response = $this->httpClient->post('/indexes/create-for-model', ['json' => $payload]);
55
56            return $this->handleResponse($response);
57        } catch (GuzzleException $e) {
58            throw new PineconeException("Failed to create index for model: $name{$e->getMessage()}", 0, $e);
59        }
60    }
61
62    public function describeIndex(string $name): array
63    {
64        try {
65            $response = $this->httpClient->get("/indexes/{$name}");
66
67            return $this->handleResponse($response);
68        } catch (GuzzleException $e) {
69            throw new PineconeException("Failed to describe index: $name{$e->getMessage()}", 0, $e);
70        }
71    }
72
73    public function deleteIndex(string $name): void
74    {
75        try {
76            $response = $this->httpClient->delete("/indexes/{$name}");
77            $this->handleResponse($response);
78        } catch (GuzzleException $e) {
79            throw new PineconeException("Failed to delete index: $name{$e->getMessage()}", 0, $e);
80        }
81    }
82
83    public function configureIndex(string $name, array $requestData): array
84    {
85        try {
86            $response = $this->httpClient->patch("/indexes/{$name}", ['json' => $requestData]);
87
88            return $this->handleResponse($response);
89        } catch (GuzzleException $e) {
90            throw new PineconeException("Failed to configure index: $name{$e->getMessage()}", 0, $e);
91        }
92    }
93
94    // Collection methods
95    public function createCollection(array $config): array
96    {
97        try {
98            $response = $this->httpClient->post('/collections', ['json' => $config]);
99
100            return $this->handleResponse($response);
101        } catch (GuzzleException $e) {
102            throw new PineconeException('Failed to create collection: ' . $e->getMessage(), 0, $e);
103        }
104    }
105
106    public function listCollections(): array
107    {
108        try {
109            $response = $this->httpClient->get('/collections');
110            $data = $this->handleResponse($response);
111
112            return $data['collections'] ?? [];
113        } catch (GuzzleException $e) {
114            throw new PineconeException('Failed to list collections: ' . $e->getMessage(), 0, $e);
115        }
116    }
117
118    public function describeCollection(string $name): array
119    {
120        try {
121            $response = $this->httpClient->get("/collections/{$name}");
122
123            return $this->handleResponse($response);
124        } catch (GuzzleException $e) {
125            throw new PineconeException("Failed to describe collection: $name{$e->getMessage()}", 0, $e);
126        }
127    }
128
129    public function deleteCollection(string $name): void
130    {
131        try {
132            $response = $this->httpClient->delete("/collections/{$name}");
133            $this->handleResponse($response);
134        } catch (GuzzleException $e) {
135            throw new PineconeException("Failed to delete collection: $name{$e->getMessage()}", 0, $e);
136        }
137    }
138
139    // Backup methods
140    public function createBackup(array $config): array
141    {
142        try {
143            $response = $this->httpClient->post('/backups', ['json' => $config]);
144
145            return $this->handleResponse($response);
146        } catch (GuzzleException $e) {
147            throw new PineconeException('Failed to create backup: ' . $e->getMessage(), 0, $e);
148        }
149    }
150
151    public function listBackups(): array
152    {
153        try {
154            $response = $this->httpClient->get('/backups');
155            $data = $this->handleResponse($response);
156
157            return $data['backups'] ?? [];
158        } catch (GuzzleException $e) {
159            throw new PineconeException('Failed to list backups: ' . $e->getMessage(), 0, $e);
160        }
161    }
162
163    public function describeBackup(string $id): array
164    {
165        try {
166            $response = $this->httpClient->get("/backups/{$id}");
167
168            return $this->handleResponse($response);
169        } catch (GuzzleException $e) {
170            throw new PineconeException("Failed to describe backup: $id{$e->getMessage()}", 0, $e);
171        }
172    }
173
174    public function deleteBackup(string $id): void
175    {
176        try {
177            $response = $this->httpClient->delete("/backups/{$id}");
178            $this->handleResponse($response);
179        } catch (GuzzleException $e) {
180            throw new PineconeException("Failed to delete backup: $id{$e->getMessage()}", 0, $e);
181        }
182    }
183
184    // Restore methods
185    public function listRestoreJobs(array $params = []): array
186    {
187        try {
188            $query = !empty($params) ? '?' . http_build_query($params) : '';
189            $response = $this->httpClient->get("/restore{$query}");
190            $data = $this->handleResponse($response);
191
192            return $data['jobs'] ?? [];
193        } catch (GuzzleException $e) {
194            throw new PineconeException('Failed to list restore jobs: ' . $e->getMessage(), 0, $e);
195        }
196    }
197
198    public function describeRestoreJob(string $id): array
199    {
200        try {
201            $response = $this->httpClient->get("/restore/{$id}");
202
203            return $this->handleResponse($response);
204        } catch (GuzzleException $e) {
205            throw new PineconeException("Failed to describe restore job: $id{$e->getMessage()}", 0, $e);
206        }
207    }
208
209    // Assistant methods
210    public function createAssistant(array $config): array
211    {
212        try {
213            $response = $this->httpClient->post('/assistants', ['json' => $config]);
214
215            return $this->handleResponse($response);
216        } catch (GuzzleException $e) {
217            throw new PineconeException('Failed to create assistant: ' . $e->getMessage(), 0, $e);
218        }
219    }
220
221    public function listAssistants(): array
222    {
223        try {
224            $response = $this->httpClient->get('/assistants');
225            $data = $this->handleResponse($response);
226
227            return $data['assistants'] ?? [];
228        } catch (GuzzleException $e) {
229            throw new PineconeException('Failed to list assistants: ' . $e->getMessage(), 0, $e);
230        }
231    }
232
233    public function describeAssistant(string $name): array
234    {
235        try {
236            $response = $this->httpClient->get("/assistants/{$name}");
237
238            return $this->handleResponse($response);
239        } catch (GuzzleException $e) {
240            throw new PineconeException("Failed to describe assistant: $name{$e->getMessage()}", 0, $e);
241        }
242    }
243
244    public function updateAssistant(string $name, array $config): array
245    {
246        try {
247            $response = $this->httpClient->patch("/assistants/{$name}", ['json' => $config]);
248
249            return $this->handleResponse($response);
250        } catch (GuzzleException $e) {
251            throw new PineconeException("Failed to update assistant: $name{$e->getMessage()}", 0, $e);
252        }
253    }
254
255    public function deleteAssistant(string $name): void
256    {
257        try {
258            $response = $this->httpClient->delete("/assistants/{$name}");
259            $this->handleResponse($response);
260        } catch (GuzzleException $e) {
261            throw new PineconeException("Failed to delete assistant: $name{$e->getMessage()}", 0, $e);
262        }
263    }
264
265    private function handleResponse(ResponseInterface $response): array
266    {
267        $statusCode = $response->getStatusCode();
268        $body = $response->getBody()->getContents();
269
270        if ($statusCode >= 400) {
271            $data = json_decode($body, true) ?? [];
272            $message = $data['message'] ?? 'API request failed';
273            throw new PineconeApiException($message, $statusCode, $data);
274        }
275
276        if (empty($body)) {
277            return [];
278        }
279
280        $decoded = json_decode($body, true);
281        if (json_last_error() !== JSON_ERROR_NONE) {
282            throw new PineconeException('Failed to decode JSON response: ' . json_last_error_msg());
283        }
284
285        return $decoded;
286    }
287}