Skip to content

Commit 4e4ac99

Browse files
authored
Adding index API (#30)
* Adding index API * Fixing test * Fixing test
1 parent f51d17a commit 4e4ac99

File tree

4 files changed

+578
-3
lines changed

4 files changed

+578
-3
lines changed

arangoasync/collection.py

+187-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
__all__ = ["Collection", "StandardCollection"]
22

33

4-
from typing import Generic, Optional, Tuple, TypeVar, cast
4+
from typing import Generic, List, Optional, Tuple, TypeVar, cast
55

66
from arangoasync.errno import (
77
HTTP_BAD_PARAMETER,
@@ -14,12 +14,24 @@
1414
DocumentInsertError,
1515
DocumentParseError,
1616
DocumentRevisionError,
17+
IndexCreateError,
18+
IndexDeleteError,
19+
IndexGetError,
20+
IndexListError,
21+
IndexLoadError,
1722
)
1823
from arangoasync.executor import ApiExecutor
1924
from arangoasync.request import Method, Request
2025
from arangoasync.response import Response
2126
from arangoasync.serialization import Deserializer, Serializer
22-
from arangoasync.typings import CollectionProperties, Json, Params, Result
27+
from arangoasync.typings import (
28+
CollectionProperties,
29+
IndexProperties,
30+
Json,
31+
Jsons,
32+
Params,
33+
Result,
34+
)
2335

2436
T = TypeVar("T")
2537
U = TypeVar("U")
@@ -155,6 +167,179 @@ def db_name(self) -> str:
155167
"""
156168
return self._executor.db_name
157169

170+
@property
171+
def serializer(self) -> Serializer[Json]:
172+
"""Return the serializer."""
173+
return self._executor.serializer
174+
175+
@property
176+
def deserializer(self) -> Deserializer[Json, Jsons]:
177+
"""Return the deserializer."""
178+
return self._executor.deserializer
179+
180+
async def indexes(self) -> Result[List[IndexProperties]]:
181+
"""Fetch all index descriptions for the given collection.
182+
183+
Returns:
184+
list: List of index properties.
185+
186+
Raises:
187+
IndexListError: If retrieval fails.
188+
189+
References:
190+
- `list-all-indexes-of-a-collection <https://docs.arangodb.com/stable/develop/http-api/indexes/#list-all-indexes-of-a-collection>`__
191+
""" # noqa: E501
192+
request = Request(
193+
method=Method.GET,
194+
endpoint="/_api/index",
195+
params=dict(collection=self._name),
196+
)
197+
198+
def response_handler(resp: Response) -> List[IndexProperties]:
199+
if not resp.is_success:
200+
raise IndexListError(resp, request)
201+
data = self.deserializer.loads(resp.raw_body)
202+
return [IndexProperties(item) for item in data["indexes"]]
203+
204+
return await self._executor.execute(request, response_handler)
205+
206+
async def get_index(self, id: str | int) -> Result[IndexProperties]:
207+
"""Return the properties of an index.
208+
209+
Args:
210+
id (str): Index ID. Could be either the full ID or just the index number.
211+
212+
Returns:
213+
IndexProperties: Index properties.
214+
215+
Raises:
216+
IndexGetError: If retrieval fails.
217+
218+
References:
219+
`get-an-index <https://docs.arangodb.com/stable/develop/http-api/indexes/#get-an-index>`__
220+
""" # noqa: E501
221+
if isinstance(id, int):
222+
full_id = f"{self._name}/{id}"
223+
else:
224+
full_id = id if "/" in id else f"{self._name}/{id}"
225+
226+
request = Request(
227+
method=Method.GET,
228+
endpoint=f"/_api/index/{full_id}",
229+
)
230+
231+
def response_handler(resp: Response) -> IndexProperties:
232+
if not resp.is_success:
233+
raise IndexGetError(resp, request)
234+
return IndexProperties(self.deserializer.loads(resp.raw_body))
235+
236+
return await self._executor.execute(request, response_handler)
237+
238+
async def add_index(
239+
self,
240+
type: str,
241+
fields: Json | List[str],
242+
options: Optional[Json] = None,
243+
) -> Result[IndexProperties]:
244+
"""Create an index.
245+
246+
Args:
247+
type (str): Type attribute (ex. "persistent", "inverted", "ttl", "mdi",
248+
"geo").
249+
fields (dict | list): Fields to index.
250+
options (dict | None): Additional index options.
251+
252+
Returns:
253+
IndexProperties: New index properties.
254+
255+
Raises:
256+
IndexCreateError: If index creation fails.
257+
258+
References:
259+
- `create-an-index <https://docs.arangodb.com/stable/develop/http-api/indexes/#create-an-index>`__
260+
- `create-a-persistent-index <https://docs.arangodb.com/stable/develop/http-api/indexes/persistent/#create-a-persistent-index>`__
261+
- `create-an-inverted-index <https://docs.arangodb.com/stable/develop/http-api/indexes/inverted/#create-an-inverted-index>`__
262+
- `create-a-ttl-index <https://docs.arangodb.com/stable/develop/http-api/indexes/ttl/#create-a-ttl-index>`__
263+
- `create-a-multi-dimensional-index <https://docs.arangodb.com/stable/develop/http-api/indexes/multi-dimensional/#create-a-multi-dimensional-index>`__
264+
- `create-a-geo-spatial-index <https://docs.arangodb.com/stable/develop/http-api/indexes/geo-spatial/#create-a-geo-spatial-index>`__
265+
""" # noqa: E501
266+
options = options or {}
267+
request = Request(
268+
method=Method.POST,
269+
endpoint="/_api/index",
270+
data=self.serializer.dumps(dict(type=type, fields=fields) | options),
271+
params=dict(collection=self._name),
272+
)
273+
274+
def response_handler(resp: Response) -> IndexProperties:
275+
if not resp.is_success:
276+
raise IndexCreateError(resp, request)
277+
return IndexProperties(self.deserializer.loads(resp.raw_body))
278+
279+
return await self._executor.execute(request, response_handler)
280+
281+
async def delete_index(
282+
self, id: str | int, ignore_missing: bool = False
283+
) -> Result[bool]:
284+
"""Delete an index.
285+
286+
Args:
287+
id (str): Index ID. Could be either the full ID or just the index number.
288+
ignore_missing (bool): Do not raise an exception on missing index.
289+
290+
Returns:
291+
bool: `True` if the operation was successful. `False` if the index was not
292+
found and **ignore_missing** was set to `True`.
293+
294+
Raises:
295+
IndexDeleteError: If deletion fails.
296+
297+
References:
298+
- `delete-an-index <https://docs.arangodb.com/stable/develop/http-api/indexes/#delete-an-index>`__
299+
""" # noqa: E501
300+
if isinstance(id, int):
301+
full_id = f"{self._name}/{id}"
302+
else:
303+
full_id = id if "/" in id else f"{self._name}/{id}"
304+
305+
request = Request(
306+
method=Method.DELETE,
307+
endpoint=f"/_api/index/{full_id}",
308+
)
309+
310+
def response_handler(resp: Response) -> bool:
311+
if resp.is_success:
312+
return True
313+
elif ignore_missing and resp.status_code == HTTP_NOT_FOUND:
314+
return False
315+
raise IndexDeleteError(resp, request)
316+
317+
return await self._executor.execute(request, response_handler)
318+
319+
async def load_indexes(self) -> Result[bool]:
320+
"""Cache this collection’s index entries in the main memory.
321+
322+
Returns:
323+
bool: `True` if the operation was successful.
324+
325+
Raises:
326+
IndexLoadError: If loading fails.
327+
328+
References:
329+
- `load-collection-indexes-into-memory <https://docs.arangodb.com/stable/develop/http-api/collections/#load-collection-indexes-into-memory>`__
330+
""" # noqa: E501
331+
request = Request(
332+
method=Method.PUT,
333+
endpoint=f"/_api/collection/{self._name}/loadIndexesIntoMemory",
334+
)
335+
336+
def response_handler(resp: Response) -> bool:
337+
if resp.is_success:
338+
return True
339+
raise IndexLoadError(resp, request)
340+
341+
return await self._executor.execute(request, response_handler)
342+
158343

159344
class StandardCollection(Collection[T, U, V]):
160345
"""Standard collection API wrapper.

arangoasync/exceptions.py

+20
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,26 @@ class DocumentRevisionError(ArangoServerError):
135135
"""The expected and actual document revisions mismatched."""
136136

137137

138+
class IndexCreateError(ArangoServerError):
139+
"""Failed to create collection index."""
140+
141+
142+
class IndexDeleteError(ArangoServerError):
143+
"""Failed to delete collection index."""
144+
145+
146+
class IndexGetError(ArangoServerError):
147+
"""Failed to retrieve collection index."""
148+
149+
150+
class IndexListError(ArangoServerError):
151+
"""Failed to retrieve collection indexes."""
152+
153+
154+
class IndexLoadError(ArangoServerError):
155+
"""Failed to load indexes into memory."""
156+
157+
138158
class JWTRefreshError(ArangoClientError):
139159
"""Failed to refresh the JWT token."""
140160

0 commit comments

Comments
 (0)