python-arango-async 0.0.2__tar.gz → 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/.github/workflows/pypi.yaml +5 -1
  2. {python_arango_async-0.0.2/python_arango_async.egg-info → python_arango_async-0.0.3}/PKG-INFO +7 -29
  3. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/README.md +3 -3
  4. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/aql.py +5 -0
  5. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/client.py +3 -1
  6. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/collection.py +27 -2
  7. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/connection.py +3 -0
  8. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/database.py +0 -4
  9. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/http.py +22 -0
  10. python_arango_async-0.0.3/arangoasync/version.py +1 -0
  11. python_arango_async-0.0.3/docs/aql.rst +171 -0
  12. python_arango_async-0.0.3/docs/async.rst +148 -0
  13. python_arango_async-0.0.3/docs/authentication.rst +117 -0
  14. python_arango_async-0.0.3/docs/certificates.rst +110 -0
  15. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/collection.rst +8 -1
  16. python_arango_async-0.0.3/docs/compression.rst +56 -0
  17. python_arango_async-0.0.3/docs/cursor.rst +217 -0
  18. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/database.rst +2 -0
  19. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/document.rst +16 -14
  20. python_arango_async-0.0.3/docs/errno.rst +22 -0
  21. python_arango_async-0.0.3/docs/errors.rst +119 -0
  22. python_arango_async-0.0.3/docs/helpers.rst +88 -0
  23. python_arango_async-0.0.3/docs/http.rst +136 -0
  24. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/index.rst +18 -8
  25. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/indexes.rst +6 -4
  26. python_arango_async-0.0.3/docs/logging.rst +30 -0
  27. python_arango_async-0.0.3/docs/migration.rst +94 -0
  28. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/overview.rst +23 -0
  29. python_arango_async-0.0.3/docs/serialization.rst +183 -0
  30. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/specs.rst +0 -6
  31. python_arango_async-0.0.3/docs/transaction.rst +81 -0
  32. python_arango_async-0.0.3/docs/user.rst +93 -0
  33. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/pyproject.toml +4 -4
  34. {python_arango_async-0.0.2 → python_arango_async-0.0.3/python_arango_async.egg-info}/PKG-INFO +7 -29
  35. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/python_arango_async.egg-info/SOURCES.txt +9 -0
  36. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_async.py +1 -1
  37. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_client.py +9 -9
  38. python_arango_async-0.0.2/arangoasync/version.py +0 -1
  39. python_arango_async-0.0.2/docs/aql.rst +0 -10
  40. python_arango_async-0.0.2/docs/async.rst +0 -6
  41. python_arango_async-0.0.2/docs/errno.rst +0 -19
  42. python_arango_async-0.0.2/docs/errors.rst +0 -20
  43. python_arango_async-0.0.2/docs/transaction.rst +0 -5
  44. python_arango_async-0.0.2/docs/user.rst +0 -5
  45. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/.circleci/config.yml +0 -0
  46. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/.github/workflows/codeql.yaml +0 -0
  47. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/.github/workflows/docs.yaml +0 -0
  48. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/.gitignore +0 -0
  49. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/.pre-commit-config.yaml +0 -0
  50. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/.readthedocs.yaml +0 -0
  51. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/CONTRIBUTING.md +0 -0
  52. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/LICENSE +0 -0
  53. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/__init__.py +0 -0
  54. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/auth.py +0 -0
  55. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/compression.py +0 -0
  56. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/cursor.py +0 -0
  57. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/errno.py +0 -0
  58. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/exceptions.py +0 -0
  59. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/executor.py +0 -0
  60. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/job.py +0 -0
  61. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/logger.py +0 -0
  62. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/request.py +0 -0
  63. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/resolver.py +0 -0
  64. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/response.py +0 -0
  65. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/result.py +0 -0
  66. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/serialization.py +0 -0
  67. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/arangoasync/typings.py +0 -0
  68. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/conf.py +0 -0
  69. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/docs/static/logo.png +0 -0
  70. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/python_arango_async.egg-info/dependency_links.txt +0 -0
  71. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/python_arango_async.egg-info/requires.txt +0 -0
  72. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/python_arango_async.egg-info/top_level.txt +0 -0
  73. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/setup.cfg +0 -0
  74. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/setup.py +0 -0
  75. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/starter.sh +0 -0
  76. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/__init__.py +0 -0
  77. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/conftest.py +0 -0
  78. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/helpers.py +0 -0
  79. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/static/cluster-3.11.conf +0 -0
  80. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/static/cluster-3.12.conf +0 -0
  81. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/static/keyfile +0 -0
  82. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/static/single-3.11.conf +0 -0
  83. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/static/single-3.12.conf +0 -0
  84. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_aql.py +0 -0
  85. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_collection.py +0 -0
  86. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_compression.py +0 -0
  87. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_connection.py +0 -0
  88. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_cursor.py +0 -0
  89. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_database.py +0 -0
  90. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_document.py +0 -0
  91. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_http.py +0 -0
  92. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_resolver.py +0 -0
  93. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_transaction.py +0 -0
  94. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_typings.py +0 -0
  95. {python_arango_async-0.0.2 → python_arango_async-0.0.3}/tests/test_user.py +0 -0
@@ -9,7 +9,11 @@ jobs:
9
9
  runs-on: ubuntu-latest
10
10
 
11
11
  steps:
12
- - uses: actions/checkout@v3
12
+ - name: Checkout repository
13
+ uses: actions/checkout@v3
14
+ with:
15
+ fetch-depth: 0
16
+ fetch-tags: true
13
17
 
14
18
  - uses: actions/setup-python@v4
15
19
  with:
@@ -1,45 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-arango-async
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Async Python Driver for ArangoDB
5
5
  Author-email: Alexandru Petenchea <alexandru.petenchea@arangodb.com>, Anthony Mahanna <anthony.mahanna@arangodb.com>
6
6
  Maintainer-email: Alexandru Petenchea <alexandru.petenchea@arangodb.com>, Anthony Mahanna <anthony.mahanna@arangodb.com>
7
- License: MIT License
8
-
9
- Copyright (c) 2024 ArangoDB
10
-
11
- Permission is hereby granted, free of charge, to any person obtaining a copy
12
- of this software and associated documentation files (the "Software"), to deal
13
- in the Software without restriction, including without limitation the rights
14
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- copies of the Software, and to permit persons to whom the Software is
16
- furnished to do so, subject to the following conditions:
17
-
18
- The above copyright notice and this permission notice shall be included in all
19
- copies or substantial portions of the Software.
20
-
21
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
- SOFTWARE.
28
-
7
+ License-Expression: MIT
29
8
  Project-URL: homepage, https://github.com/arangodb/python-arango-async
30
9
  Keywords: arangodb,python,driver,async
31
10
  Classifier: Intended Audience :: Developers
32
- Classifier: License :: OSI Approved :: MIT License
33
11
  Classifier: Natural Language :: English
34
12
  Classifier: Operating System :: OS Independent
35
13
  Classifier: Programming Language :: Python :: 3
36
- Classifier: Programming Language :: Python :: 3.9
37
14
  Classifier: Programming Language :: Python :: 3.10
38
15
  Classifier: Programming Language :: Python :: 3.11
39
16
  Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
40
18
  Classifier: Topic :: Documentation :: Sphinx
41
19
  Classifier: Typing :: Typed
42
- Requires-Python: >=3.9
20
+ Requires-Python: >=3.10
43
21
  Description-Content-Type: text/markdown
44
22
  License-File: LICENSE
45
23
  Requires-Dist: packaging>=23.1
@@ -68,7 +46,7 @@ Dynamic: license-file
68
46
  [![Last commit](https://img.shields.io/github/last-commit/arangodb/python-arango-async)](https://github.com/arangodb/python-arango-async/commits/main)
69
47
 
70
48
  [![PyPI version badge](https://img.shields.io/pypi/v/python-arango-async?color=3775A9&style=for-the-badge&logo=pypi&logoColor=FFD43B)](https://pypi.org/project/python-arango-async/)
71
- [![Python versions badge](https://img.shields.io/badge/3.9%2B-3776AB?style=for-the-badge&logo=python&logoColor=FFD43B&label=Python)](https://pypi.org/project/python-arango-async/)
49
+ [![Python versions badge](https://img.shields.io/badge/3.10%2B-3776AB?style=for-the-badge&logo=python&logoColor=FFD43B&label=Python)](https://pypi.org/project/python-arango-async/)
72
50
 
73
51
  [![License](https://img.shields.io/github/license/arangodb/python-arango?color=9E2165&style=for-the-badge)](https://github.com/arangodb/python-arango/blob/main/LICENSE)
74
52
  [![Code style: black](https://img.shields.io/static/v1?style=for-the-badge&label=code%20style&message=black&color=black)](https://github.com/psf/black)
@@ -80,7 +58,7 @@ Dynamic: license-file
80
58
  Python driver for [ArangoDB](https://www.arangodb.com), a scalable multi-model
81
59
  database natively supporting documents, graphs and search.
82
60
 
83
- This is the _asyncio_ alternative of the officially supported [python-arango](https://github.com/arangodb/python-arango)
61
+ This is the _asyncio_ alternative of the [python-arango](https://github.com/arangodb/python-arango)
84
62
  driver.
85
63
 
86
64
  **Note: This project is still in active development, features might be added or removed.**
@@ -88,7 +66,7 @@ driver.
88
66
  ## Requirements
89
67
 
90
68
  - ArangoDB version 3.11+
91
- - Python version 3.9+
69
+ - Python version 3.10+
92
70
 
93
71
  ## Installation
94
72
 
@@ -5,7 +5,7 @@
5
5
  [![Last commit](https://img.shields.io/github/last-commit/arangodb/python-arango-async)](https://github.com/arangodb/python-arango-async/commits/main)
6
6
 
7
7
  [![PyPI version badge](https://img.shields.io/pypi/v/python-arango-async?color=3775A9&style=for-the-badge&logo=pypi&logoColor=FFD43B)](https://pypi.org/project/python-arango-async/)
8
- [![Python versions badge](https://img.shields.io/badge/3.9%2B-3776AB?style=for-the-badge&logo=python&logoColor=FFD43B&label=Python)](https://pypi.org/project/python-arango-async/)
8
+ [![Python versions badge](https://img.shields.io/badge/3.10%2B-3776AB?style=for-the-badge&logo=python&logoColor=FFD43B&label=Python)](https://pypi.org/project/python-arango-async/)
9
9
 
10
10
  [![License](https://img.shields.io/github/license/arangodb/python-arango?color=9E2165&style=for-the-badge)](https://github.com/arangodb/python-arango/blob/main/LICENSE)
11
11
  [![Code style: black](https://img.shields.io/static/v1?style=for-the-badge&label=code%20style&message=black&color=black)](https://github.com/psf/black)
@@ -17,7 +17,7 @@
17
17
  Python driver for [ArangoDB](https://www.arangodb.com), a scalable multi-model
18
18
  database natively supporting documents, graphs and search.
19
19
 
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)
21
21
  driver.
22
22
 
23
23
  **Note: This project is still in active development, features might be added or removed.**
@@ -25,7 +25,7 @@ driver.
25
25
  ## Requirements
26
26
 
27
27
  - ArangoDB version 3.11+
28
- - Python version 3.9+
28
+ - Python version 3.10+
29
29
 
30
30
  ## Installation
31
31
 
@@ -238,6 +238,11 @@ class AQL:
238
238
  """Return the name of the current database."""
239
239
  return self._executor.db_name
240
240
 
241
+ @property
242
+ def context(self) -> str:
243
+ """Return the current API execution context."""
244
+ return self._executor.context
245
+
241
246
  @property
242
247
  def serializer(self) -> Serializer[Json]:
243
248
  """Return the serializer."""
@@ -139,7 +139,9 @@ class ArangoClient:
139
139
 
140
140
  async def close(self) -> None:
141
141
  """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
+ )
143
145
 
144
146
  async def db(
145
147
  self,
@@ -251,6 +251,15 @@ class Collection(Generic[T, U, V]):
251
251
  """
252
252
  return self._name
253
253
 
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
+
254
263
  @property
255
264
  def db_name(self) -> str:
256
265
  """Return the name of the current database.
@@ -270,9 +279,17 @@ class Collection(Generic[T, U, V]):
270
279
  """Return the deserializer."""
271
280
  return self._executor.deserializer
272
281
 
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]]:
274
287
  """Fetch all index descriptions for the given collection.
275
288
 
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
+
276
293
  Returns:
277
294
  list: List of index properties.
278
295
 
@@ -282,10 +299,16 @@ class Collection(Generic[T, U, V]):
282
299
  References:
283
300
  - `list-all-indexes-of-a-collection <https://docs.arangodb.com/stable/develop/http-api/indexes/#list-all-indexes-of-a-collection>`__
284
301
  """ # 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
+
285
308
  request = Request(
286
309
  method=Method.GET,
287
310
  endpoint="/_api/index",
288
- params=dict(collection=self._name),
311
+ params=params,
289
312
  )
290
313
 
291
314
  def response_handler(resp: Response) -> List[IndexProperties]:
@@ -564,6 +587,7 @@ class StandardCollection(Collection[T, U, V]):
564
587
  Raises:
565
588
  DocumentRevisionError: If the revision is incorrect.
566
589
  DocumentGetError: If retrieval fails.
590
+ DocumentParseError: If the document is malformed.
567
591
 
568
592
  References:
569
593
  - `get-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#get-a-document>`__
@@ -707,6 +731,7 @@ class StandardCollection(Collection[T, U, V]):
707
731
 
708
732
  Raises:
709
733
  DocumentInsertError: If insertion fails.
734
+ DocumentParseError: If the document is malformed.
710
735
 
711
736
  References:
712
737
  - `create-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#create-a-document>`__
@@ -177,6 +177,9 @@ class BaseConnection(ABC):
177
177
  host_index = self._host_resolver.get_host_index()
178
178
  for tries in range(self._host_resolver.max_tries):
179
179
  try:
180
+ logger.debug(
181
+ f"Sending request to host {host_index} ({tries}): {request}"
182
+ )
180
183
  resp = await self._http_client.send_request(
181
184
  self._sessions[host_index], request
182
185
  )
@@ -596,7 +596,6 @@ class Database:
596
596
  )
597
597
 
598
598
  def response_handler(resp: Response) -> StandardCollection[T, U, V]:
599
- nonlocal doc_serializer, doc_deserializer
600
599
  if not resp.is_success:
601
600
  raise CollectionCreateError(resp, request)
602
601
  if doc_serializer is None:
@@ -648,7 +647,6 @@ class Database:
648
647
  )
649
648
 
650
649
  def response_handler(resp: Response) -> bool:
651
- nonlocal ignore_missing
652
650
  if resp.is_success:
653
651
  return True
654
652
  if resp.status_code == HTTP_NOT_FOUND and ignore_missing:
@@ -1001,7 +999,6 @@ class Database:
1001
999
  )
1002
1000
 
1003
1001
  def response_handler(resp: Response) -> bool:
1004
- nonlocal ignore_failure
1005
1002
  if resp.is_success:
1006
1003
  return True
1007
1004
  if ignore_failure:
@@ -1046,7 +1043,6 @@ class Database:
1046
1043
  )
1047
1044
 
1048
1045
  def response_handler(resp: Response) -> bool:
1049
- nonlocal ignore_failure
1050
1046
  if resp.is_success:
1051
1047
  return True
1052
1048
  if ignore_failure:
@@ -33,6 +33,8 @@ class HTTPClient(ABC): # pragma: no cover
33
33
  class MyCustomHTTPClient(HTTPClient):
34
34
  def create_session(self, host):
35
35
  pass
36
+ async def close_session(self, session):
37
+ pass
36
38
  async def send_request(self, session, request):
37
39
  pass
38
40
  """
@@ -52,6 +54,18 @@ class HTTPClient(ABC): # pragma: no cover
52
54
  """
53
55
  raise NotImplementedError
54
56
 
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
+
55
69
  @abstractmethod
56
70
  async def send_request(
57
71
  self,
@@ -129,6 +143,14 @@ class AioHTTPClient(HTTPClient):
129
143
  read_bufsize=self._read_bufsize,
130
144
  )
131
145
 
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
+
132
154
  async def send_request(
133
155
  self,
134
156
  session: ClientSession,
@@ -0,0 +1 @@
1
+ __version__ = "0.0.3"
@@ -0,0 +1,171 @@
1
+ AQL
2
+ ----
3
+
4
+ **ArangoDB Query Language (AQL)** is used to read and write data. It is similar
5
+ to SQL for relational databases, but without the support for data definition
6
+ operations such as creating or deleting :doc:`databases <database>`,
7
+ :doc:`collections <collection>` or :doc:`indexes <indexes>`. For more
8
+ information, refer to `ArangoDB Manual`_.
9
+
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,0 +1,148 @@
1
+ Async API Execution
2
+ -------------------
3
+
4
+ In **asynchronous API executions**, the driver sends API requests to ArangoDB in
5
+ fire-and-forget style. The server processes them in the background, and
6
+ the results can be retrieved once available via :class:`arangoasync.job.AsyncJob` objects.
7
+
8
+ **Example:**
9
+
10
+ .. code-block:: python
11
+
12
+ import time
13
+ from arangoasync import ArangoClient
14
+ from arangoasync.auth import Auth
15
+ from arangoasync.errno import HTTP_BAD_PARAMETER
16
+ from arangoasync.exceptions import (
17
+ AQLQueryExecuteError,
18
+ AsyncJobCancelError,
19
+ AsyncJobClearError,
20
+ )
21
+
22
+ # Initialize the client for ArangoDB.
23
+ async with ArangoClient(hosts="http://localhost:8529") as client:
24
+ auth = Auth(username="root", password="passwd")
25
+
26
+ # Connect to "test" database as root user.
27
+ db = await client.db("test", auth=auth)
28
+
29
+ # Begin async execution. This returns an instance of AsyncDatabase, a
30
+ # database-level API wrapper tailored specifically for async execution.
31
+ async_db = db.begin_async_execution(return_result=True)
32
+
33
+ # Child wrappers are also tailored for async execution.
34
+ async_aql = async_db.aql
35
+ async_col = async_db.collection("students")
36
+
37
+ # API execution context is always set to "async".
38
+ assert async_db.context == "async"
39
+ assert async_aql.context == "async"
40
+ assert async_col.context == "async"
41
+
42
+ # On API execution, AsyncJob objects are returned instead of results.
43
+ job1 = await async_col.insert({"_key": "Neal"})
44
+ job2 = await async_col.insert({"_key": "Lily"})
45
+ job3 = await async_aql.execute("RETURN 100000")
46
+ job4 = await async_aql.execute("INVALID QUERY") # Fails due to syntax error.
47
+
48
+ # Retrieve the status of each async job.
49
+ for job in [job1, job2, job3, job4]:
50
+ # Job status can be "pending" or "done".
51
+ assert await job.status() in {"pending", "done"}
52
+
53
+ # Let's wait until the jobs are finished.
54
+ while await job.status() != "done":
55
+ time.sleep(0.1)
56
+
57
+ # Retrieve the results of successful jobs.
58
+ metadata = await job1.result()
59
+ assert metadata["_id"] == "students/Neal"
60
+
61
+ metadata = await job2.result()
62
+ assert metadata["_id"] == "students/Lily"
63
+
64
+ cursor = await job3.result()
65
+ assert await cursor.next() == 100000
66
+
67
+ # If a job fails, the exception is propagated up during result retrieval.
68
+ try:
69
+ result = await job4.result()
70
+ except AQLQueryExecuteError as err:
71
+ assert err.http_code == HTTP_BAD_PARAMETER
72
+
73
+ # Cancel a job. Only pending jobs still in queue may be cancelled.
74
+ # Since job3 is done, there is nothing to cancel and an exception is raised.
75
+ try:
76
+ await job3.cancel()
77
+ except AsyncJobCancelError as err:
78
+ print(err.message)
79
+
80
+ # Clear the result of a job from ArangoDB server to free up resources.
81
+ # Result of job4 was removed from the server automatically upon retrieval,
82
+ # so attempt to clear it raises an exception.
83
+ try:
84
+ await job4.clear()
85
+ except AsyncJobClearError as err:
86
+ print(err.message)
87
+
88
+ # List the IDs of the first 100 async jobs completed.
89
+ jobs_done = await db.async_jobs(status="done", count=100)
90
+
91
+ # List the IDs of the first 100 async jobs still pending.
92
+ jobs_pending = await db.async_jobs(status='pending', count=100)
93
+
94
+ # Clear all async jobs still sitting on the server.
95
+ await db.clear_async_jobs()
96
+
97
+ Cursors returned from async API wrappers will no longer send async requests when they fetch more results, but behave
98
+ like regular cursors instead. This makes sense, because the point of cursors is iteration, whereas async jobs are meant
99
+ for one-shot requests. However, the first result retrieval is still async, and only then the cursor is returned, making
100
+ async AQL requests effective for queries with a long execution time.
101
+
102
+ **Example:**
103
+
104
+ .. code-block:: python
105
+
106
+ from arangoasync import ArangoClient
107
+ from arangoasync.auth import Auth
108
+
109
+ # Initialize the client for ArangoDB.
110
+ async with ArangoClient(hosts="http://localhost:8529") as client:
111
+ auth = Auth(username="root", password="passwd")
112
+
113
+ # Connect to "test" database as root user.
114
+ db = await client.db("test", auth=auth)
115
+
116
+ # Get the API wrapper for "students" collection.
117
+ students = db.collection("students")
118
+
119
+ # Insert some documents into the collection.
120
+ await students.insert_many([{"_key": "Neal"}, {"_key": "Lily"}])
121
+
122
+ # Begin async execution.
123
+ async_db = db.begin_async_execution(return_result=True)
124
+
125
+ aql = async_db.aql
126
+ job = await aql.execute(
127
+ f"FOR d IN {students.name} SORT d._key RETURN d",
128
+ count=True,
129
+ batch_size=1,
130
+ ttl=1000,
131
+ )
132
+ await job.wait()
133
+
134
+ # Iterate through the cursor.
135
+ # Although the request to fetch the cursor is async, its underlying executor is no longer async.
136
+ # Next batches will be fetched in real-time.
137
+ doc_cnt = 0
138
+ cursor = await job.result()
139
+ async with cursor as ctx:
140
+ async for _ in ctx:
141
+ doc_cnt += 1
142
+ assert doc_cnt == 2
143
+
144
+ .. note::
145
+ Be mindful of server-side memory capacity when issuing a large number of
146
+ async requests in small time interval.
147
+
148
+ See :class:`arangoasync.database.AsyncDatabase` and :class:`arangoasync.job.AsyncJob` for API specification.