Skip to content

Commit 3851a61

Browse files
authored
Listing of collections and databases (#23)
1 parent aad94da commit 3851a61

File tree

7 files changed

+603
-335
lines changed

7 files changed

+603
-335
lines changed

arangoasync/collection.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
__all__ = ["Collection", "CollectionType", "StandardCollection"]
1+
__all__ = ["Collection", "StandardCollection"]
22

33

4-
from enum import Enum
54
from typing import Generic, Optional, Tuple, TypeVar
65

76
from arangoasync.errno import HTTP_NOT_FOUND, HTTP_PRECONDITION_FAILED
@@ -21,13 +20,6 @@
2120
V = TypeVar("V")
2221

2322

24-
class CollectionType(Enum):
25-
"""Collection types."""
26-
27-
DOCUMENT = 2
28-
EDGE = 3
29-
30-
3123
class Collection(Generic[T, U, V]):
3224
"""Base class for collection API wrappers.
3325

arangoasync/database.py

+136-34
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
]
55

66

7-
from typing import Optional, Sequence, TypeVar, cast
7+
from typing import List, Optional, Sequence, TypeVar, cast
88

9-
from arangoasync.collection import CollectionType, StandardCollection
9+
from arangoasync.collection import StandardCollection
1010
from arangoasync.connection import Connection
1111
from arangoasync.errno import HTTP_FORBIDDEN, HTTP_NOT_FOUND
1212
from arangoasync.exceptions import (
@@ -22,8 +22,17 @@
2222
from arangoasync.request import Method, Request
2323
from arangoasync.response import Response
2424
from arangoasync.serialization import Deserializer, Serializer
25-
from arangoasync.typings import Json, Jsons, Params, Result
26-
from arangoasync.wrapper import KeyOptions, ServerStatusInformation, User
25+
from arangoasync.typings import (
26+
CollectionInfo,
27+
CollectionType,
28+
Json,
29+
Jsons,
30+
KeyOptions,
31+
Params,
32+
Result,
33+
ServerStatusInformation,
34+
UserInfo,
35+
)
2736

2837
T = TypeVar("T")
2938
U = TypeVar("U")
@@ -69,7 +78,10 @@ async def status(self) -> Result[ServerStatusInformation]:
6978
7079
Raises:
7180
ServerSatusError: If retrieval fails.
72-
"""
81+
82+
References:
83+
- `get-server-status-information <https://docs.arangodb.com/stable/develop/http-api/administration/#get-server-status-information>`__
84+
""" # noqa: E501
7385
request = Request(method=Method.GET, endpoint="/_admin/status")
7486

7587
def response_handler(resp: Response) -> ServerStatusInformation:
@@ -79,43 +91,80 @@ def response_handler(resp: Response) -> ServerStatusInformation:
7991

8092
return await self._executor.execute(request, response_handler)
8193

94+
async def databases(self) -> Result[List[str]]:
95+
"""Return the names of all databases.
96+
97+
Note:
98+
This method can only be executed in the **_system** database.
99+
100+
Returns:
101+
list: Database names.
102+
103+
Raises:
104+
DatabaseListError: If retrieval fails.
105+
106+
References:
107+
- `list-all-databases <https://docs.arangodb.com/stable/develop/http-api/databases/#list-all-databases>`__
108+
""" # noqa: E501
109+
request = Request(method=Method.GET, endpoint="/_api/database")
110+
111+
def response_handler(resp: Response) -> List[str]:
112+
if resp.is_success:
113+
body = self.deserializer.loads(resp.raw_body)
114+
return cast(List[str], body["result"])
115+
msg: Optional[str] = None
116+
if resp.status_code == HTTP_FORBIDDEN:
117+
msg = "This request can only be executed in the _system database."
118+
raise DatabaseListError(resp, request, msg)
119+
120+
return await self._executor.execute(request, response_handler)
121+
82122
async def has_database(self, name: str) -> Result[bool]:
83123
"""Check if a database exists.
84124
125+
Note:
126+
This method can only be executed from within the **_system** database.
127+
85128
Args:
86129
name (str): Database name.
87130
88131
Returns:
89132
bool: `True` if the database exists, `False` otherwise.
90133
91134
Raises:
92-
DatabaseListError: If failed to retrieve the list of databases.
135+
DatabaseListError: If retrieval fails.
93136
"""
94137
request = Request(method=Method.GET, endpoint="/_api/database")
95138

96139
def response_handler(resp: Response) -> bool:
97-
if not resp.is_success:
98-
raise DatabaseListError(resp, request)
99-
body = self.deserializer.loads(resp.raw_body)
100-
return name in body["result"]
140+
if resp.is_success:
141+
body = self.deserializer.loads(resp.raw_body)
142+
return name in body["result"]
143+
msg: Optional[str] = None
144+
if resp.status_code == HTTP_FORBIDDEN:
145+
msg = "This request can only be executed in the _system database."
146+
raise DatabaseListError(resp, request, msg)
101147

102148
return await self._executor.execute(request, response_handler)
103149

104150
async def create_database(
105151
self,
106152
name: str,
107-
users: Optional[Sequence[Json | User]] = None,
153+
users: Optional[Sequence[Json | UserInfo]] = None,
108154
replication_factor: Optional[int | str] = None,
109155
write_concern: Optional[int] = None,
110156
sharding: Optional[bool] = None,
111157
) -> Result[bool]:
112158
"""Create a new database.
113159
160+
Note:
161+
This method can only be executed from within the **_system** database.
162+
114163
Args:
115164
name (str): Database name.
116165
users (list | None): Optional list of users with access to the new
117166
database, where each user is of :class:`User
118-
<arangoasync.wrapper.User>` type, or a dictionary with fields
167+
<arangoasync.wrapper.UserInfo>` type, or a dictionary with fields
119168
"username", "password" and "active". If not set, the default user
120169
**root** will be used to ensure that the new database will be
121170
accessible after it is created.
@@ -125,12 +174,12 @@ async def create_database(
125174
(Enterprise Edition only), and 1, which disables replication. Used
126175
for clusters only.
127176
write_concern (int | None): Default write concern for collections created
128-
in this database. Determines how many copies of each shard are required
129-
to be in sync on different DB-Servers. If there are less than these many
130-
copies in the cluster a shard will refuse to write. Writes to shards with
131-
enough up-to-date copies will succeed at the same time, however. Value of
132-
this parameter can not be larger than the value of **replication_factor**.
133-
Used for clusters only.
177+
in this database. Determines how many copies of each shard are required
178+
to be in sync on different DB-Servers. If there are less than these many
179+
copies in the cluster a shard will refuse to write. Writes to shards with
180+
enough up-to-date copies will succeed at the same time, however. Value of
181+
this parameter can not be larger than the value of **replication_factor**.
182+
Used for clusters only.
134183
sharding (str | None): Sharding method used for new collections in this
135184
database. Allowed values are: "", "flexible" and "single". The first
136185
two are equivalent. Used for clusters only.
@@ -140,7 +189,10 @@ async def create_database(
140189
141190
Raises:
142191
DatabaseCreateError: If creation fails.
143-
"""
192+
193+
References:
194+
- `create-a-database <https://docs.arangodb.com/stable/develop/http-api/databases/#create-a-database>`__
195+
""" # noqa: E501
144196
data: Json = {"name": name}
145197

146198
options: Json = {}
@@ -173,7 +225,10 @@ async def create_database(
173225
def response_handler(resp: Response) -> bool:
174226
if resp.is_success:
175227
return True
176-
raise DatabaseCreateError(resp, request)
228+
msg: Optional[str] = None
229+
if resp.status_code == HTTP_FORBIDDEN:
230+
msg = "This request can only be executed in the _system database."
231+
raise DatabaseCreateError(resp, request, msg)
177232

178233
return await self._executor.execute(request, response_handler)
179234

@@ -182,6 +237,9 @@ async def delete_database(
182237
) -> Result[bool]:
183238
"""Delete a database.
184239
240+
Note:
241+
This method can only be executed from within the **_system** database.
242+
185243
Args:
186244
name (str): Database name.
187245
ignore_missing (bool): Do not raise an exception on missing database.
@@ -192,21 +250,21 @@ async def delete_database(
192250
193251
Raises:
194252
DatabaseDeleteError: If deletion fails.
195-
"""
253+
254+
References:
255+
- `drop-a-database <https://docs.arangodb.com/stable/develop/http-api/databases/#drop-a-database>`__
256+
""" # noqa: E501
196257
request = Request(method=Method.DELETE, endpoint=f"/_api/database/{name}")
197258

198259
def response_handler(resp: Response) -> bool:
199260
if resp.is_success:
200261
return True
201262
if resp.status_code == HTTP_NOT_FOUND and ignore_missing:
202263
return False
264+
msg: Optional[str] = None
203265
if resp.status_code == HTTP_FORBIDDEN:
204-
raise DatabaseDeleteError(
205-
resp,
206-
request,
207-
"This request can only be executed in the _system database.",
208-
)
209-
raise DatabaseDeleteError(resp, request)
266+
msg = "This request can only be executed in the _system database."
267+
raise DatabaseDeleteError(resp, request, msg)
210268

211269
return await self._executor.execute(request, response_handler)
212270

@@ -241,6 +299,40 @@ def collection(
241299
self._executor, name, serializer, deserializer
242300
)
243301

302+
async def collections(
303+
self,
304+
exclude_system: Optional[bool] = None,
305+
) -> Result[List[CollectionInfo]]:
306+
"""Returns basic information for all collections in the current database,
307+
optionally excluding system collections.
308+
309+
Returns:
310+
list: Collection names.
311+
312+
Raises:
313+
CollectionListError: If retrieval fails.
314+
315+
References:
316+
- `list-all-collections <https://docs.arangodb.com/stable/develop/http-api/collections/#list-all-collections>`__
317+
""" # noqa: E501
318+
params: Params = {}
319+
if exclude_system is not None:
320+
params["excludeSystem"] = exclude_system
321+
322+
request = Request(
323+
method=Method.GET,
324+
endpoint="/_api/collection",
325+
params=params,
326+
)
327+
328+
def response_handler(resp: Response) -> List[CollectionInfo]:
329+
if not resp.is_success:
330+
raise CollectionListError(resp, request)
331+
body = self.deserializer.loads(resp.raw_body)
332+
return [CollectionInfo(c) for c in body["result"]]
333+
334+
return await self._executor.execute(request, response_handler)
335+
244336
async def has_collection(self, name: str) -> Result[bool]:
245337
"""Check if a collection exists in the database.
246338
@@ -249,14 +341,18 @@ async def has_collection(self, name: str) -> Result[bool]:
249341
250342
Returns:
251343
bool: True if the collection exists, False otherwise.
344+
345+
Raises:
346+
CollectionListError: If retrieval fails.
252347
"""
253-
request = Request(method=Method.GET, endpoint="/_api/collection")
348+
request = Request(method=Method.GET, endpoint=f"/_api/collection/{name}")
254349

255350
def response_handler(resp: Response) -> bool:
256-
if not resp.is_success:
257-
raise CollectionListError(resp, request)
258-
body = self.deserializer.loads(resp.raw_body)
259-
return any(c["name"] == name for c in body["result"])
351+
if resp.is_success:
352+
return True
353+
if resp.status_code == HTTP_NOT_FOUND:
354+
return False
355+
raise CollectionListError(resp, request)
260356

261357
return await self._executor.execute(request, response_handler)
262358

@@ -343,7 +439,10 @@ async def create_collection(
343439
Raises:
344440
ValueError: If parameters are invalid.
345441
CollectionCreateError: If the operation fails.
346-
"""
442+
443+
References:
444+
- `create-a-collection <https://docs.arangodb.com/stable/develop/http-api/collections/#create-a-collection>`__
445+
""" # noqa: E501
347446
data: Json = {"name": name}
348447
if col_type is not None:
349448
data["type"] = col_type.value
@@ -430,7 +529,10 @@ async def delete_collection(
430529
431530
Raises:
432531
CollectionDeleteError: If the operation fails.
433-
"""
532+
533+
References:
534+
- `drop-a-collection <https://docs.arangodb.com/stable/develop/http-api/collections/#drop-a-collection>`__
535+
""" # noqa: E501
434536
params: Params = {}
435537
if is_system is not None:
436538
params["isSystem"] = is_system

0 commit comments

Comments
 (0)