Skip to content

Commit 5e0f1b6

Browse files
authored
Adding more documentation (#45)
* Adding more documentation * Minor edit * No longer using testcode * Completed transactions documentation * Completed async documentation * Completed user documentation * Completed overview documentation * Completed overview documentation * Completed cursor documentation * Completed errno documentation * Completed errors documentation * Completed compression documentation * Completed logging documentation * Completed helpers documentation * Fixing test and lint * Added authentication documentation * Minor fixes * TLS docs * HTTP docs * Serialization docs * Migration docs
1 parent 85ce40a commit 5e0f1b6

31 files changed

+1756
-63
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@
1717
Python driver for [ArangoDB](https://www.arangodb.com), a scalable multi-model
1818
database natively supporting documents, graphs and search.
1919

20-
This is the _asyncio_ alternative of the officially supported [python-arango](https://github.com/arangodb/python-arango)
20+
This is the _asyncio_ alternative of the [python-arango](https://github.com/arangodb/python-arango)
2121
driver.
2222

2323
**Note: This project is still in active development, features might be added or removed.**
2424

2525
## Requirements
2626

2727
- ArangoDB version 3.11+
28-
- Python version 3.9+
28+
- Python version 3.10+
2929

3030
## Installation
3131

arangoasync/aql.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@ def name(self) -> str:
238238
"""Return the name of the current database."""
239239
return self._executor.db_name
240240

241+
@property
242+
def context(self) -> str:
243+
"""Return the current API execution context."""
244+
return self._executor.context
245+
241246
@property
242247
def serializer(self) -> Serializer[Json]:
243248
"""Return the serializer."""

arangoasync/client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ def version(self) -> str:
139139

140140
async def close(self) -> None:
141141
"""Close HTTP sessions."""
142-
await asyncio.gather(*(session.close() for session in self._sessions))
142+
await asyncio.gather(
143+
*(self._http_client.close_session(session) for session in self._sessions)
144+
)
143145

144146
async def db(
145147
self,

arangoasync/collection.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,15 @@ def name(self) -> str:
251251
"""
252252
return self._name
253253

254+
@property
255+
def context(self) -> str:
256+
"""Return the context of the collection.
257+
258+
Returns:
259+
str: Context.
260+
"""
261+
return self._executor.context
262+
254263
@property
255264
def db_name(self) -> str:
256265
"""Return the name of the current database.
@@ -270,9 +279,17 @@ def deserializer(self) -> Deserializer[Json, Jsons]:
270279
"""Return the deserializer."""
271280
return self._executor.deserializer
272281

273-
async def indexes(self) -> Result[List[IndexProperties]]:
282+
async def indexes(
283+
self,
284+
with_stats: Optional[bool] = None,
285+
with_hidden: Optional[bool] = None,
286+
) -> Result[List[IndexProperties]]:
274287
"""Fetch all index descriptions for the given collection.
275288
289+
Args:
290+
with_stats (bool | None): Whether to include figures and estimates in the result.
291+
with_hidden (bool | None): Whether to include hidden indexes in the result.
292+
276293
Returns:
277294
list: List of index properties.
278295
@@ -282,10 +299,16 @@ async def indexes(self) -> Result[List[IndexProperties]]:
282299
References:
283300
- `list-all-indexes-of-a-collection <https://docs.arangodb.com/stable/develop/http-api/indexes/#list-all-indexes-of-a-collection>`__
284301
""" # noqa: E501
302+
params: Params = dict(collection=self._name)
303+
if with_stats is not None:
304+
params["withStats"] = with_stats
305+
if with_hidden is not None:
306+
params["withHidden"] = with_hidden
307+
285308
request = Request(
286309
method=Method.GET,
287310
endpoint="/_api/index",
288-
params=dict(collection=self._name),
311+
params=params,
289312
)
290313

291314
def response_handler(resp: Response) -> List[IndexProperties]:
@@ -564,6 +587,7 @@ async def get(
564587
Raises:
565588
DocumentRevisionError: If the revision is incorrect.
566589
DocumentGetError: If retrieval fails.
590+
DocumentParseError: If the document is malformed.
567591
568592
References:
569593
- `get-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#get-a-document>`__
@@ -707,6 +731,7 @@ async def insert(
707731
708732
Raises:
709733
DocumentInsertError: If insertion fails.
734+
DocumentParseError: If the document is malformed.
710735
711736
References:
712737
- `create-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#create-a-document>`__

arangoasync/connection.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ async def process_request(self, request: Request) -> Response:
177177
host_index = self._host_resolver.get_host_index()
178178
for tries in range(self._host_resolver.max_tries):
179179
try:
180+
logger.debug(
181+
f"Sending request to host {host_index} ({tries}): {request}"
182+
)
180183
resp = await self._http_client.send_request(
181184
self._sessions[host_index], request
182185
)

arangoasync/database.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,6 @@ async def create_collection(
596596
)
597597

598598
def response_handler(resp: Response) -> StandardCollection[T, U, V]:
599-
nonlocal doc_serializer, doc_deserializer
600599
if not resp.is_success:
601600
raise CollectionCreateError(resp, request)
602601
if doc_serializer is None:
@@ -648,7 +647,6 @@ async def delete_collection(
648647
)
649648

650649
def response_handler(resp: Response) -> bool:
651-
nonlocal ignore_missing
652650
if resp.is_success:
653651
return True
654652
if resp.status_code == HTTP_NOT_FOUND and ignore_missing:
@@ -1001,7 +999,6 @@ async def update_permission(
1001999
)
10021000

10031001
def response_handler(resp: Response) -> bool:
1004-
nonlocal ignore_failure
10051002
if resp.is_success:
10061003
return True
10071004
if ignore_failure:
@@ -1046,7 +1043,6 @@ async def reset_permission(
10461043
)
10471044

10481045
def response_handler(resp: Response) -> bool:
1049-
nonlocal ignore_failure
10501046
if resp.is_success:
10511047
return True
10521048
if ignore_failure:

arangoasync/http.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class HTTPClient(ABC): # pragma: no cover
3333
class MyCustomHTTPClient(HTTPClient):
3434
def create_session(self, host):
3535
pass
36+
async def close_session(self, session):
37+
pass
3638
async def send_request(self, session, request):
3739
pass
3840
"""
@@ -52,6 +54,18 @@ def create_session(self, host: str) -> Any:
5254
"""
5355
raise NotImplementedError
5456

57+
@abstractmethod
58+
async def close_session(self, session: Any) -> None:
59+
"""Close the session.
60+
61+
Note:
62+
This method must be overridden by the user.
63+
64+
Args:
65+
session (Any): Client session object.
66+
"""
67+
raise NotImplementedError
68+
5569
@abstractmethod
5670
async def send_request(
5771
self,
@@ -129,6 +143,14 @@ def create_session(self, host: str) -> ClientSession:
129143
read_bufsize=self._read_bufsize,
130144
)
131145

146+
async def close_session(self, session: ClientSession) -> None:
147+
"""Close the session.
148+
149+
Args:
150+
session (Any): Client session object.
151+
"""
152+
await session.close()
153+
132154
async def send_request(
133155
self,
134156
session: ClientSession,

docs/aql.rst

Lines changed: 163 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,167 @@ AQL
55
to SQL for relational databases, but without the support for data definition
66
operations such as creating or deleting :doc:`databases <database>`,
77
:doc:`collections <collection>` or :doc:`indexes <indexes>`. For more
8-
information, refer to `ArangoDB manual`_.
8+
information, refer to `ArangoDB Manual`_.
99

10-
.. _ArangoDB manual: https://docs.arangodb.com
10+
.. _ArangoDB Manual: https://docs.arangodb.com
11+
12+
AQL Queries
13+
===========
14+
15+
AQL queries are invoked from AQL wrapper. Executing queries returns
16+
:doc:`cursors <cursor>`.
17+
18+
**Example:**
19+
20+
.. code-block:: python
21+
22+
from arangoasync import ArangoClient, AQLQueryKillError
23+
from arangoasync.auth import Auth
24+
25+
# Initialize the client for ArangoDB.
26+
async with ArangoClient(hosts="http://localhost:8529") as client:
27+
auth = Auth(username="root", password="passwd")
28+
29+
# Connect to "test" database as root user.
30+
db = await client.db("test", auth=auth)
31+
32+
# Get the API wrapper for "students" collection.
33+
students = db.collection("students")
34+
35+
# Insert some test documents into "students" collection.
36+
await students.insert_many([
37+
{"_key": "Abby", "age": 22},
38+
{"_key": "John", "age": 18},
39+
{"_key": "Mary", "age": 21}
40+
])
41+
42+
# Get the AQL API wrapper.
43+
aql = db.aql
44+
45+
# Retrieve the execution plan without running the query.
46+
plan = await aql.explain("FOR doc IN students RETURN doc")
47+
48+
# Validate the query without executing it.
49+
validate = await aql.validate("FOR doc IN students RETURN doc")
50+
51+
# Execute the query
52+
cursor = await db.aql.execute(
53+
"FOR doc IN students FILTER doc.age < @value RETURN doc",
54+
bind_vars={"value": 19}
55+
)
56+
57+
# Iterate through the result cursor
58+
student_keys = []
59+
async for doc in cursor:
60+
student_keys.append(doc)
61+
62+
# List currently running queries.
63+
queries = await aql.queries()
64+
65+
# List any slow queries.
66+
slow_queries = await aql.slow_queries()
67+
68+
# Clear slow AQL queries if any.
69+
await aql.clear_slow_queries()
70+
71+
# Retrieve AQL query tracking properties.
72+
await aql.tracking()
73+
74+
# Configure AQL query tracking properties.
75+
await aql.set_tracking(
76+
max_slow_queries=10,
77+
track_bind_vars=True,
78+
track_slow_queries=True
79+
)
80+
81+
# Kill a running query (this should fail due to invalid ID).
82+
try:
83+
await aql.kill("some_query_id")
84+
except AQLQueryKillError as err:
85+
assert err.http_code == 404
86+
87+
See :class:`arangoasync.aql.AQL` for API specification.
88+
89+
90+
AQL User Functions
91+
==================
92+
93+
**AQL User Functions** are custom functions you define in Javascript to extend
94+
AQL functionality. They are somewhat similar to SQL procedures.
95+
96+
**Example:**
97+
98+
.. code-block:: python
99+
100+
from arangoasync import ArangoClient
101+
from arangoasync.auth import Auth
102+
103+
# Initialize the client for ArangoDB.
104+
async with ArangoClient(hosts="http://localhost:8529") as client:
105+
auth = Auth(username="root", password="passwd")
106+
107+
# Connect to "test" database as root user.
108+
db = await client.db("test", auth=auth)
109+
110+
# Get the AQL API wrapper.
111+
aql = db.aql
112+
113+
# Create a new AQL user function.
114+
await aql.create_function(
115+
# Grouping by name prefix is supported.
116+
name="functions::temperature::converter",
117+
code="function (celsius) { return celsius * 1.8 + 32; }"
118+
)
119+
120+
# List AQL user functions.
121+
functions = await aql.functions()
122+
123+
# Delete an existing AQL user function.
124+
await aql.delete_function("functions::temperature::converter")
125+
126+
See :class:`arangoasync.aql.AQL` for API specification.
127+
128+
129+
AQL Query Cache
130+
===============
131+
132+
**AQL Query Cache** is used to minimize redundant calculation of the same query
133+
results. It is useful when read queries are issued frequently and write queries
134+
are not.
135+
136+
**Example:**
137+
138+
.. code-block:: python
139+
140+
from arangoasync import ArangoClient
141+
from arangoasync.auth import Auth
142+
143+
# Initialize the client for ArangoDB.
144+
async with ArangoClient(hosts="http://localhost:8529") as client:
145+
auth = Auth(username="root", password="passwd")
146+
147+
# Connect to "test" database as root user.
148+
db = await client.db("test", auth=auth)
149+
150+
# Get the AQL API wrapper.
151+
aql = db.aql
152+
153+
# Retrieve AQL query cache properties.
154+
await aql.cache.properties()
155+
156+
# Configure AQL query cache properties.
157+
await aql.cache.configure(mode="demand", max_results=10000)
158+
159+
# List results cache entries.
160+
entries = await aql.cache.entries()
161+
162+
# List plan cache entries.
163+
plan_entries = await aql.cache.plan_entries()
164+
165+
# Clear results in AQL query cache.
166+
await aql.cache.clear()
167+
168+
# Clear results in AQL query plan cache.
169+
await aql.cache.clear_plan()
170+
171+
See :class:`arangoasync.aql.AQLQueryCache` for API specification.

0 commit comments

Comments
 (0)