6
6
]
7
7
8
8
9
- from typing import Any , Generic , List , Optional , Sequence , TypeVar , cast
9
+ from typing import Any , Generic , List , Literal , Optional , Sequence , TypeVar , cast
10
10
11
11
from arangoasync .cursor import Cursor
12
12
from arangoasync .errno import (
26
26
DocumentReplaceError ,
27
27
DocumentRevisionError ,
28
28
DocumentUpdateError ,
29
+ EdgeListError ,
29
30
IndexCreateError ,
30
31
IndexDeleteError ,
31
32
IndexGetError ,
@@ -111,11 +112,13 @@ def _validate_id(self, doc_id: str) -> str:
111
112
raise DocumentParseError (f'Bad collection name in document ID "{ doc_id } "' )
112
113
return doc_id
113
114
114
- def _extract_id (self , body : Json ) -> str :
115
+ def _extract_id (self , body : Json , validate : bool = True ) -> str :
115
116
"""Extract the document ID from document body.
116
117
117
118
Args:
118
119
body (dict): Document body.
120
+ validate (bool): Whether to validate the document ID,
121
+ checking if it belongs to the current collection.
119
122
120
123
Returns:
121
124
str: Document ID.
@@ -125,7 +128,10 @@ def _extract_id(self, body: Json) -> str:
125
128
"""
126
129
try :
127
130
if "_id" in body :
128
- return self ._validate_id (body ["_id" ])
131
+ if validate :
132
+ return self ._validate_id (body ["_id" ])
133
+ else :
134
+ return cast (str , body ["_id" ])
129
135
else :
130
136
key : str = body ["_key" ]
131
137
return self ._id_prefix + key
@@ -150,28 +156,30 @@ def _ensure_key_from_id(self, body: Json) -> Json:
150
156
body ["_key" ] = doc_id [len (self ._id_prefix ) :]
151
157
return body
152
158
153
- def _prep_from_doc (self , document : str | Json ) -> str :
159
+ def _get_doc_id (self , document : str | Json , validate : bool = True ) -> str :
154
160
"""Prepare document ID before a query.
155
161
156
162
Args:
157
163
document (str | dict): Document ID, key or body.
164
+ validate (bool): Whether to validate the document ID,
165
+ checking if it belongs to the current collection.
158
166
159
167
Returns:
160
168
Document ID and request headers.
161
169
162
170
Raises:
163
171
DocumentParseError: On missing ID and key.
164
- TypeError: On bad document type.
165
172
"""
166
- if isinstance (document , dict ):
167
- doc_id = self ._extract_id (document )
168
- elif isinstance (document , str ):
173
+ if isinstance (document , str ):
169
174
if "/" in document :
170
- doc_id = self ._validate_id (document )
175
+ if validate :
176
+ doc_id = self ._validate_id (document )
177
+ else :
178
+ doc_id = document
171
179
else :
172
180
doc_id = self ._id_prefix + document
173
181
else :
174
- raise TypeError ( "Document must be str or a dict" )
182
+ doc_id = self . _extract_id ( document , validate )
175
183
176
184
return doc_id
177
185
@@ -585,7 +593,7 @@ async def has(
585
593
References:
586
594
- `get-a-document-header <https://docs.arangodb.com/stable/develop/http-api/documents/#get-a-document-header>`__
587
595
""" # noqa: E501
588
- handle = self ._prep_from_doc (document )
596
+ handle = self ._get_doc_id (document )
589
597
590
598
headers : RequestHeaders = {}
591
599
if allow_dirty_read :
@@ -1314,7 +1322,7 @@ async def get(
1314
1322
References:
1315
1323
- `get-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#get-a-document>`__
1316
1324
""" # noqa: E501
1317
- handle = self ._prep_from_doc (document )
1325
+ handle = self ._get_doc_id (document )
1318
1326
1319
1327
headers : RequestHeaders = {}
1320
1328
if allow_dirty_read :
@@ -1814,7 +1822,7 @@ async def get(
1814
1822
References:
1815
1823
- `get-a-vertex <https://docs.arangodb.com/stable/develop/http-api/graphs/named-graphs/#get-a-vertex>`__
1816
1824
""" # noqa: E501
1817
- handle = self ._prep_from_doc (vertex )
1825
+ handle = self ._get_doc_id (vertex )
1818
1826
1819
1827
headers : RequestHeaders = {}
1820
1828
if if_match is not None :
@@ -1958,7 +1966,7 @@ async def update(
1958
1966
request = Request (
1959
1967
method = Method .PATCH ,
1960
1968
endpoint = f"/_api/gharial/{ self ._graph } /vertex/"
1961
- f"{ self ._prep_from_doc (cast (Json , vertex ))} " ,
1969
+ f"{ self ._get_doc_id (cast (Json , vertex ))} " ,
1962
1970
params = params ,
1963
1971
headers = headers ,
1964
1972
data = self ._doc_serializer .dumps (vertex ),
@@ -2033,7 +2041,7 @@ async def replace(
2033
2041
request = Request (
2034
2042
method = Method .PUT ,
2035
2043
endpoint = f"/_api/gharial/{ self ._graph } /vertex/"
2036
- f"{ self ._prep_from_doc (cast (Json , vertex ))} " ,
2044
+ f"{ self ._get_doc_id (cast (Json , vertex ))} " ,
2037
2045
params = params ,
2038
2046
headers = headers ,
2039
2047
data = self ._doc_serializer .dumps (vertex ),
@@ -2101,7 +2109,7 @@ async def delete(
2101
2109
request = Request (
2102
2110
method = Method .DELETE ,
2103
2111
endpoint = f"/_api/gharial/{ self ._graph } /vertex/"
2104
- f"{ self ._prep_from_doc (cast (Json , vertex ))} " ,
2112
+ f"{ self ._get_doc_id (cast (Json , vertex ))} " ,
2105
2113
params = params ,
2106
2114
headers = headers ,
2107
2115
)
@@ -2213,7 +2221,7 @@ async def get(
2213
2221
References:
2214
2222
- `get-an-edge <https://docs.arangodb.com/stable/develop/http-api/graphs/named-graphs/#get-an-edge>`__
2215
2223
""" # noqa: E501
2216
- handle = self ._prep_from_doc (edge )
2224
+ handle = self ._get_doc_id (edge )
2217
2225
2218
2226
headers : RequestHeaders = {}
2219
2227
if if_match is not None :
@@ -2362,7 +2370,7 @@ async def update(
2362
2370
request = Request (
2363
2371
method = Method .PATCH ,
2364
2372
endpoint = f"/_api/gharial/{ self ._graph } /edge/"
2365
- f"{ self ._prep_from_doc (cast (Json , edge ))} " ,
2373
+ f"{ self ._get_doc_id (cast (Json , edge ))} " ,
2366
2374
params = params ,
2367
2375
headers = headers ,
2368
2376
data = self ._doc_serializer .dumps (edge ),
@@ -2441,7 +2449,7 @@ async def replace(
2441
2449
request = Request (
2442
2450
method = Method .PUT ,
2443
2451
endpoint = f"/_api/gharial/{ self ._graph } /edge/"
2444
- f"{ self ._prep_from_doc (cast (Json , edge ))} " ,
2452
+ f"{ self ._get_doc_id (cast (Json , edge ))} " ,
2445
2453
params = params ,
2446
2454
headers = headers ,
2447
2455
data = self ._doc_serializer .dumps (edge ),
@@ -2512,7 +2520,7 @@ async def delete(
2512
2520
request = Request (
2513
2521
method = Method .DELETE ,
2514
2522
endpoint = f"/_api/gharial/{ self ._graph } /edge/"
2515
- f"{ self ._prep_from_doc (cast (Json , edge ))} " ,
2523
+ f"{ self ._get_doc_id (cast (Json , edge ))} " ,
2516
2524
params = params ,
2517
2525
headers = headers ,
2518
2526
)
@@ -2536,3 +2544,93 @@ def response_handler(resp: Response) -> bool | Json:
2536
2544
raise DocumentDeleteError (resp , request , msg )
2537
2545
2538
2546
return await self ._executor .execute (request , response_handler )
2547
+
2548
+ async def edges (
2549
+ self ,
2550
+ vertex : str | Json ,
2551
+ direction : Optional [Literal ["in" , "out" ]] = None ,
2552
+ allow_dirty_read : Optional [bool ] = None ,
2553
+ ) -> Result [Json ]:
2554
+ """Return the edges starting or ending at the specified vertex.
2555
+
2556
+ Args:
2557
+ vertex (str | dict): Document ID, key or body.
2558
+ direction (str | None): Direction of the edges to return. Selects `in`
2559
+ or `out` direction for edges. If not set, any edges are returned.
2560
+ allow_dirty_read (bool | None): Allow reads from followers in a cluster.
2561
+
2562
+ Returns:
2563
+ dict: List of edges and statistics.
2564
+
2565
+ Raises:
2566
+ EdgeListError: If retrieval fails.
2567
+
2568
+ References:
2569
+ - `get-inbound-and-outbound-edges <https://docs.arangodb.com/stable/develop/http-api/graphs/edges/#get-inbound-and-outbound-edges>`__
2570
+ """ # noqa: E501
2571
+ params : Params = {
2572
+ "vertex" : self ._get_doc_id (vertex , validate = False ),
2573
+ }
2574
+ if direction is not None :
2575
+ params ["direction" ] = direction
2576
+
2577
+ headers : RequestHeaders = {}
2578
+ if allow_dirty_read is not None :
2579
+ headers ["x-arango-allow-dirty-read" ] = "true" if allow_dirty_read else False
2580
+
2581
+ request = Request (
2582
+ method = Method .GET ,
2583
+ endpoint = f"/_api/edges/{ self ._name } " ,
2584
+ params = params ,
2585
+ headers = headers ,
2586
+ )
2587
+
2588
+ def response_handler (resp : Response ) -> Json :
2589
+ if not resp .is_success :
2590
+ raise EdgeListError (resp , request )
2591
+ body = self .deserializer .loads (resp .raw_body )
2592
+ for key in ("error" , "code" ):
2593
+ body .pop (key )
2594
+ return body
2595
+
2596
+ return await self ._executor .execute (request , response_handler )
2597
+
2598
+ async def link (
2599
+ self ,
2600
+ from_vertex : str | Json ,
2601
+ to_vertex : str | Json ,
2602
+ data : Optional [Json ] = None ,
2603
+ wait_for_sync : Optional [bool ] = None ,
2604
+ return_new : bool = False ,
2605
+ ) -> Result [Json ]:
2606
+ """Insert a new edge document linking the given vertices.
2607
+
2608
+ Args:
2609
+ from_vertex (str | dict): "_from" vertex document ID or body with "_id"
2610
+ field.
2611
+ to_vertex (str | dict): "_to" vertex document ID or body with "_id" field.
2612
+ data (dict | None): Any extra data for the new edge document. If it has
2613
+ "_key" or "_id" field, its value is used as key of the new edge document
2614
+ (otherwise it is auto-generated).
2615
+ wait_for_sync (bool | None): Wait until operation has been synced to disk.
2616
+ return_new: Optional[bool]: Additionally return the complete new document
2617
+ under the attribute `new` in the result.
2618
+
2619
+ Returns:
2620
+ dict: Document metadata (e.g. document id, key, revision).
2621
+ If `return_new` is specified, the result contains the document
2622
+ metadata in the "edge" field and the new document in the "new" field.
2623
+
2624
+ Raises:
2625
+ DocumentInsertError: If insertion fails.
2626
+ DocumentParseError: If the document is malformed.
2627
+ """
2628
+ edge : Json = {
2629
+ "_from" : self ._get_doc_id (from_vertex , validate = False ),
2630
+ "_to" : self ._get_doc_id (to_vertex , validate = False ),
2631
+ }
2632
+ if data is not None :
2633
+ edge .update (self ._ensure_key_from_id (data ))
2634
+ return await self .insert (
2635
+ cast (T , edge ), wait_for_sync = wait_for_sync , return_new = return_new
2636
+ )
0 commit comments