|
8 | 8 |
|
9 | 9 | from arangoasync.collection import CollectionType, StandardCollection
|
10 | 10 | from arangoasync.connection import Connection
|
11 |
| -from arangoasync.errno import HTTP_NOT_FOUND |
| 11 | +from arangoasync.errno import HTTP_FORBIDDEN, HTTP_NOT_FOUND |
12 | 12 | from arangoasync.exceptions import (
|
13 | 13 | CollectionCreateError,
|
14 | 14 | CollectionDeleteError,
|
15 | 15 | CollectionListError,
|
| 16 | + DatabaseCreateError, |
| 17 | + DatabaseDeleteError, |
| 18 | + DatabaseListError, |
16 | 19 | ServerStatusError,
|
17 | 20 | )
|
18 | 21 | from arangoasync.executor import ApiExecutor, DefaultApiExecutor
|
19 | 22 | from arangoasync.request import Method, Request
|
20 | 23 | from arangoasync.response import Response
|
21 | 24 | from arangoasync.serialization import Deserializer, Serializer
|
22 | 25 | from arangoasync.typings import Json, Jsons, Params, Result
|
23 |
| -from arangoasync.wrapper import KeyOptions, ServerStatusInformation |
| 26 | +from arangoasync.wrapper import KeyOptions, ServerStatusInformation, User |
24 | 27 |
|
25 | 28 | T = TypeVar("T")
|
26 | 29 | U = TypeVar("U")
|
@@ -76,6 +79,137 @@ def response_handler(resp: Response) -> ServerStatusInformation:
|
76 | 79 |
|
77 | 80 | return await self._executor.execute(request, response_handler)
|
78 | 81 |
|
| 82 | + async def has_database(self, name: str) -> Result[bool]: |
| 83 | + """Check if a database exists. |
| 84 | +
|
| 85 | + Args: |
| 86 | + name (str): Database name. |
| 87 | +
|
| 88 | + Returns: |
| 89 | + bool: `True` if the database exists, `False` otherwise. |
| 90 | +
|
| 91 | + Raises: |
| 92 | + DatabaseListError: If failed to retrieve the list of databases. |
| 93 | + """ |
| 94 | + request = Request(method=Method.GET, endpoint="/_api/database") |
| 95 | + |
| 96 | + 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"] |
| 101 | + |
| 102 | + return await self._executor.execute(request, response_handler) |
| 103 | + |
| 104 | + async def create_database( |
| 105 | + self, |
| 106 | + name: str, |
| 107 | + users: Optional[Sequence[Json | User]] = None, |
| 108 | + replication_factor: Optional[int | str] = None, |
| 109 | + write_concern: Optional[int] = None, |
| 110 | + sharding: Optional[bool] = None, |
| 111 | + ) -> Result[bool]: |
| 112 | + """Create a new database. |
| 113 | +
|
| 114 | + Args: |
| 115 | + name (str): Database name. |
| 116 | + users (list | None): Optional list of users with access to the new |
| 117 | + database, where each user is of :class:`User |
| 118 | + <arangoasync.wrapper.User>` type, or a dictionary with fields |
| 119 | + "username", "password" and "active". If not set, the default user |
| 120 | + **root** will be used to ensure that the new database will be |
| 121 | + accessible after it is created. |
| 122 | + replication_factor (int | str | None): Default replication factor for new |
| 123 | + collections created in this database. Special values include |
| 124 | + “satellite”, which will replicate the collection to every DB-Server |
| 125 | + (Enterprise Edition only), and 1, which disables replication. Used |
| 126 | + for clusters only. |
| 127 | + 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. |
| 134 | + sharding (str | None): Sharding method used for new collections in this |
| 135 | + database. Allowed values are: "", "flexible" and "single". The first |
| 136 | + two are equivalent. Used for clusters only. |
| 137 | +
|
| 138 | + Returns: |
| 139 | + bool: True if the database was created successfully. |
| 140 | +
|
| 141 | + Raises: |
| 142 | + DatabaseCreateError: If creation fails. |
| 143 | + """ |
| 144 | + data: Json = {"name": name} |
| 145 | + |
| 146 | + options: Json = {} |
| 147 | + if replication_factor is not None: |
| 148 | + options["replicationFactor"] = replication_factor |
| 149 | + if write_concern is not None: |
| 150 | + options["writeConcern"] = write_concern |
| 151 | + if sharding is not None: |
| 152 | + options["sharding"] = sharding |
| 153 | + if options: |
| 154 | + data["options"] = options |
| 155 | + |
| 156 | + if users is not None: |
| 157 | + data["users"] = [ |
| 158 | + { |
| 159 | + "username": user["username"], |
| 160 | + "passwd": user["password"], |
| 161 | + "active": user.get("active", True), |
| 162 | + "extra": user.get("extra", {}), |
| 163 | + } |
| 164 | + for user in users |
| 165 | + ] |
| 166 | + |
| 167 | + request = Request( |
| 168 | + method=Method.POST, |
| 169 | + endpoint="/_api/database", |
| 170 | + data=self.serializer.dumps(data), |
| 171 | + ) |
| 172 | + |
| 173 | + def response_handler(resp: Response) -> bool: |
| 174 | + if resp.is_success: |
| 175 | + return True |
| 176 | + raise DatabaseCreateError(resp, request) |
| 177 | + |
| 178 | + return await self._executor.execute(request, response_handler) |
| 179 | + |
| 180 | + async def delete_database( |
| 181 | + self, name: str, ignore_missing: bool = False |
| 182 | + ) -> Result[bool]: |
| 183 | + """Delete a database. |
| 184 | +
|
| 185 | + Args: |
| 186 | + name (str): Database name. |
| 187 | + ignore_missing (bool): Do not raise an exception on missing database. |
| 188 | +
|
| 189 | + Returns: |
| 190 | + bool: True if the database was deleted successfully, `False` if the |
| 191 | + database was not found but **ignore_missing** was set to `True`. |
| 192 | +
|
| 193 | + Raises: |
| 194 | + DatabaseDeleteError: If deletion fails. |
| 195 | + """ |
| 196 | + request = Request(method=Method.DELETE, endpoint=f"/_api/database/{name}") |
| 197 | + |
| 198 | + def response_handler(resp: Response) -> bool: |
| 199 | + if resp.is_success: |
| 200 | + return True |
| 201 | + if resp.status_code == HTTP_NOT_FOUND and ignore_missing: |
| 202 | + return False |
| 203 | + 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) |
| 210 | + |
| 211 | + return await self._executor.execute(request, response_handler) |
| 212 | + |
79 | 213 | def collection(
|
80 | 214 | self,
|
81 | 215 | name: str,
|
@@ -231,7 +365,7 @@ async def create_collection(
|
231 | 365 | data["isSystem"] = is_system
|
232 | 366 | if key_options is not None:
|
233 | 367 | if isinstance(key_options, dict):
|
234 |
| - key_options = KeyOptions(key_options) |
| 368 | + key_options = KeyOptions(data=key_options) |
235 | 369 | key_options.validate()
|
236 | 370 | data["keyOptions"] = key_options.to_dict()
|
237 | 371 | if schema is not None:
|
@@ -311,7 +445,7 @@ def response_handler(resp: Response) -> bool:
|
311 | 445 | nonlocal ignore_missing
|
312 | 446 | if resp.is_success:
|
313 | 447 | return True
|
314 |
| - if resp.error_code == HTTP_NOT_FOUND and ignore_missing: |
| 448 | + if resp.status_code == HTTP_NOT_FOUND and ignore_missing: |
315 | 449 | return False
|
316 | 450 | raise CollectionDeleteError(resp, request)
|
317 | 451 |
|
|
0 commit comments