66]
77
88
9- from typing import Any , Generic , List , Optional , Sequence , Tuple , TypeVar , cast
9+ from typing import Any , Generic , List , Optional , Sequence , TypeVar , cast
1010
1111from arangoasync .cursor import Cursor
1212from arangoasync .errno import (
@@ -75,6 +75,26 @@ def __init__(
7575 self ._doc_deserializer = doc_deserializer
7676 self ._id_prefix = f"{ self ._name } /"
7777
78+ @staticmethod
79+ def get_col_name (doc : str | Json ) -> str :
80+ """Extract the collection name from the document.
81+
82+ Args:
83+ doc (str | dict): Document ID or body with "_id" field.
84+
85+ Returns:
86+ str: Collection name.
87+
88+ Raises:
89+ DocumentParseError: If document ID is missing.
90+ """
91+ try :
92+ doc_id : str = doc ["_id" ] if isinstance (doc , dict ) else doc
93+ except KeyError :
94+ raise DocumentParseError ('field "_id" required' )
95+ else :
96+ return doc_id .split ("/" , 1 )[0 ]
97+
7898 def _validate_id (self , doc_id : str ) -> str :
7999 """Check the collection name in the document ID.
80100
@@ -120,25 +140,21 @@ def _ensure_key_from_id(self, body: Json) -> Json:
120140
121141 Returns:
122142 dict: Document body with "_key" field if it has "_id" field.
143+
144+ Raises:
145+ DocumentParseError: If document is malformed.
123146 """
124147 if "_id" in body and "_key" not in body :
125148 doc_id = self ._validate_id (body ["_id" ])
126149 body = body .copy ()
127150 body ["_key" ] = doc_id [len (self ._id_prefix ) :]
128151 return body
129152
130- def _prep_from_doc (
131- self ,
132- document : str | Json ,
133- rev : Optional [str ] = None ,
134- check_rev : bool = False ,
135- ) -> Tuple [str , Json ]:
136- """Prepare document ID, body and request headers before a query.
153+ def _prep_from_doc (self , document : str | Json ) -> str :
154+ """Prepare document ID before a query.
137155
138156 Args:
139157 document (str | dict): Document ID, key or body.
140- rev (str | None): Document revision.
141- check_rev (bool): Whether to check the revision.
142158
143159 Returns:
144160 Document ID and request headers.
@@ -149,7 +165,6 @@ def _prep_from_doc(
149165 """
150166 if isinstance (document , dict ):
151167 doc_id = self ._extract_id (document )
152- rev = rev or document .get ("_rev" )
153168 elif isinstance (document , str ):
154169 if "/" in document :
155170 doc_id = self ._validate_id (document )
@@ -158,10 +173,7 @@ def _prep_from_doc(
158173 else :
159174 raise TypeError ("Document must be str or a dict" )
160175
161- if not check_rev or rev is None :
162- return doc_id , {}
163- else :
164- return doc_id , {"If-Match" : rev }
176+ return doc_id
165177
166178 def _build_filter_conditions (self , filters : Optional [Json ]) -> str :
167179 """Build filter conditions for an AQL query.
@@ -597,7 +609,7 @@ async def get(
597609 References:
598610 - `get-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#get-a-document>`__
599611 """ # noqa: E501
600- handle , _ = self ._prep_from_doc (document )
612+ handle = self ._prep_from_doc (document )
601613
602614 headers : RequestHeaders = {}
603615 if allow_dirty_read :
@@ -656,7 +668,7 @@ async def has(
656668 References:
657669 - `get-a-document-header <https://docs.arangodb.com/stable/develop/http-api/documents/#get-a-document-header>`__
658670 """ # noqa: E501
659- handle , _ = self ._prep_from_doc (document )
671+ handle = self ._prep_from_doc (document )
660672
661673 headers : RequestHeaders = {}
662674 if allow_dirty_read :
@@ -742,7 +754,6 @@ async def insert(
742754 - `create-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#create-a-document>`__
743755 """ # noqa: E501
744756 if isinstance (document , dict ):
745- # We assume that the document deserializer works with dictionaries.
746757 document = cast (T , self ._ensure_key_from_id (document ))
747758
748759 params : Params = {}
@@ -1752,6 +1763,119 @@ def graph(self) -> str:
17521763 """
17531764 return self ._graph
17541765
1766+ async def get (
1767+ self ,
1768+ vertex : str | Json ,
1769+ if_match : Optional [str ] = None ,
1770+ if_none_match : Optional [str ] = None ,
1771+ ) -> Result [Optional [Json ]]:
1772+ """Return a document.
1773+
1774+ Args:
1775+ vertex (str | dict): Document ID, key or body.
1776+ Document body must contain the "_id" or "_key" field.
1777+ if_match (str | None): The document is returned, if it has the same
1778+ revision as the given ETag.
1779+ if_none_match (str | None): The document is returned, if it has a
1780+ different revision than the given ETag.
1781+
1782+ Returns:
1783+ Document or `None` if not found.
1784+
1785+ Raises:
1786+ DocumentRevisionError: If the revision is incorrect.
1787+ DocumentGetError: If retrieval fails.
1788+ DocumentParseError: If the document is malformed.
1789+
1790+ References:
1791+ - `get-a-vertex <https://docs.arangodb.com/stable/develop/http-api/graphs/named-graphs/#get-a-vertex>`__
1792+ """ # noqa: E501
1793+ handle = self ._prep_from_doc (vertex )
1794+
1795+ headers : RequestHeaders = {}
1796+ if if_match is not None :
1797+ headers ["If-Match" ] = if_match
1798+ if if_none_match is not None :
1799+ headers ["If-None-Match" ] = if_none_match
1800+
1801+ request = Request (
1802+ method = Method .GET ,
1803+ endpoint = f"/_api/gharial/{ self ._graph } /vertex/{ handle } " ,
1804+ headers = headers ,
1805+ )
1806+
1807+ def response_handler (resp : Response ) -> Optional [Json ]:
1808+ if resp .is_success :
1809+ data : Json = self .deserializer .loads (resp .raw_body )
1810+ return cast (Json , data ["vertex" ])
1811+ elif resp .status_code == HTTP_NOT_FOUND :
1812+ if resp .error_code == DOCUMENT_NOT_FOUND :
1813+ return None
1814+ else :
1815+ raise DocumentGetError (resp , request )
1816+ elif resp .status_code == HTTP_PRECONDITION_FAILED :
1817+ raise DocumentRevisionError (resp , request )
1818+ else :
1819+ raise DocumentGetError (resp , request )
1820+
1821+ return await self ._executor .execute (request , response_handler )
1822+
1823+ async def insert (
1824+ self ,
1825+ vertex : T ,
1826+ wait_for_sync : Optional [bool ] = None ,
1827+ return_new : Optional [bool ] = None ,
1828+ ) -> Result [Json ]:
1829+ """Insert a new vertex document.
1830+
1831+ Args:
1832+ vertex (dict): Document to insert. If it contains the "_key" or "_id"
1833+ field, the value is used as the key of the new document (otherwise
1834+ it is auto-generated). Any "_rev" field is ignored.
1835+ wait_for_sync (bool | None): Wait until document has been synced to disk.
1836+ return_new (bool | None): Additionally return the complete new document
1837+ under the attribute `new` in the result.
1838+
1839+ Returns:
1840+ dict: Document metadata (e.g. document id, key, revision).
1841+
1842+ Raises:
1843+ DocumentInsertError: If insertion fails.
1844+ DocumentParseError: If the document is malformed.
1845+
1846+ References:
1847+ - `create-a-vertex <https://docs.arangodb.com/stable/develop/http-api/graphs/named-graphs/#create-a-vertex>`__
1848+ """ # noqa: E501
1849+ if isinstance (vertex , dict ):
1850+ vertex = cast (T , self ._ensure_key_from_id (vertex ))
1851+
1852+ params : Params = {}
1853+ if wait_for_sync is not None :
1854+ params ["waitForSync" ] = wait_for_sync
1855+ if return_new is not None :
1856+ params ["returnNew" ] = return_new
1857+
1858+ request = Request (
1859+ method = Method .POST ,
1860+ endpoint = f"/_api/gharial/{ self ._graph } /vertex/{ self .name } " ,
1861+ params = params ,
1862+ data = self ._doc_serializer .dumps (vertex ),
1863+ )
1864+
1865+ def response_handler (resp : Response ) -> Json :
1866+ if resp .is_success :
1867+ data : Json = self ._executor .deserialize (resp .raw_body )
1868+ return cast (Json , data ["vertex" ])
1869+ msg : Optional [str ] = None
1870+ if resp .status_code == HTTP_NOT_FOUND :
1871+ msg = (
1872+ "The graph cannot be found or the collection is not "
1873+ "part of the graph."
1874+ )
1875+ raise DocumentInsertError (resp , request , msg )
1876+
1877+ return await self ._executor .execute (request , response_handler )
1878+
17551879
17561880class EdgeCollection (Collection [T , U , V ]):
17571881 """Edge collection API wrapper.
0 commit comments