Skip to content

Commit 6ea9259

Browse files
committed
Facilitating edge and vertex collection creation
1 parent 7a09541 commit 6ea9259

File tree

3 files changed

+191
-7
lines changed

3 files changed

+191
-7
lines changed

arangoasync/exceptions.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,26 @@ class DocumentUpdateError(ArangoServerError):
263263
"""Failed to update document."""
264264

265265

266+
class EdgeDefinitionListError(ArangoServerError):
267+
"""Failed to retrieve edge definitions."""
268+
269+
270+
class EdgeDefinitionCreateError(ArangoServerError):
271+
"""Failed to create edge definition."""
272+
273+
274+
class EdgeDefinitionReplaceError(ArangoServerError):
275+
"""Failed to replace edge definition."""
276+
277+
278+
class EdgeDefinitionDeleteError(ArangoServerError):
279+
"""Failed to delete edge definition."""
280+
281+
282+
class EdgeListError(ArangoServerError):
283+
"""Failed to retrieve edges coming in and out of a vertex."""
284+
285+
266286
class GraphCreateError(ArangoServerError):
267287
"""Failed to create the graph."""
268288

@@ -389,3 +409,15 @@ class UserReplaceError(ArangoServerError):
389409

390410
class UserUpdateError(ArangoServerError):
391411
"""Failed to update user."""
412+
413+
414+
class VertexCollectionCreateError(ArangoServerError):
415+
"""Failed to create vertex collection."""
416+
417+
418+
class VertexCollectionDeleteError(ArangoServerError):
419+
"""Failed to delete vertex collection."""
420+
421+
422+
class VertexCollectionListError(ArangoServerError):
423+
"""Failed to retrieve vertex collections."""

arangoasync/graph.py

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
__all__ = ["Graph"]
22

33

4-
from typing import Generic, TypeVar
4+
from typing import Generic, Optional, Sequence, TypeVar
55

66
from arangoasync.collection import EdgeCollection, VertexCollection
7-
from arangoasync.exceptions import GraphListError
7+
from arangoasync.exceptions import (
8+
EdgeDefinitionCreateError,
9+
GraphListError,
10+
VertexCollectionCreateError,
11+
)
812
from arangoasync.executor import ApiExecutor
913
from arangoasync.request import Method, Request
1014
from arangoasync.response import Response
1115
from arangoasync.result import Result
1216
from arangoasync.serialization import Deserializer, Serializer
13-
from arangoasync.typings import GraphProperties, Json, Jsons
17+
from arangoasync.typings import (
18+
EdgeDefinitionOptions,
19+
GraphProperties,
20+
Json,
21+
Jsons,
22+
VertexCollectionOptions,
23+
)
1424

1525
T = TypeVar("T") # Serializer type
1626
U = TypeVar("U") # Deserializer loads
@@ -67,7 +77,7 @@ async def properties(self) -> Result[GraphProperties]:
6777
GraphListError: If the operation fails.
6878
6979
References:
70-
- `get-a-graph <https://docs.arangodb.com/3.12/develop/http-api/graphs/named-graphs/#get-a-graph>`__
80+
- `get-a-graph <https://docs.arangodb.com/stable/develop/http-api/graphs/named-graphs/#get-a-graph>`__
7181
""" # noqa: E501
7282
request = Request(method=Method.GET, endpoint=f"/_api/gharial/{self._name}")
7383

@@ -96,6 +106,48 @@ def vertex_collection(self, name: str) -> VertexCollection[T, U, V]:
96106
doc_deserializer=self._doc_deserializer,
97107
)
98108

109+
async def create_vertex_collection(
110+
self,
111+
name: str,
112+
options: Optional[VertexCollectionOptions | Json] = None,
113+
) -> Result[VertexCollection[T, U, V]]:
114+
"""Create a vertex collection in the graph.
115+
116+
Args:
117+
name (str): Vertex collection name.
118+
options (dict | VertexCollectionOptions | None): Extra options for
119+
creating vertex collections.
120+
121+
Returns:
122+
VertexCollection: Vertex collection API wrapper.
123+
124+
Raises:
125+
VertexCollectionCreateError: If the operation fails.
126+
127+
References:
128+
- `add-a-vertex-collection <https://docs.arangodb.com/stable/develop/http-api/graphs/named-graphs/#add-a-vertex-collection>`__
129+
""" # noqa: E501
130+
data: Json = {"collection": name}
131+
132+
if options is not None:
133+
if isinstance(options, VertexCollectionOptions):
134+
data["options"] = options.to_dict()
135+
else:
136+
data["options"] = options
137+
138+
request = Request(
139+
method=Method.POST,
140+
endpoint=f"/_api/gharial/{self._name}/vertex",
141+
data=self.serializer.dumps(data),
142+
)
143+
144+
def response_handler(resp: Response) -> VertexCollection[T, U, V]:
145+
if not resp.is_success:
146+
raise VertexCollectionCreateError(resp, request)
147+
return self.vertex_collection(name)
148+
149+
return await self._executor.execute(request, response_handler)
150+
99151
def edge_collection(self, name: str) -> EdgeCollection[T, U, V]:
100152
"""Returns the edge collection API wrapper.
101153
@@ -112,3 +164,66 @@ def edge_collection(self, name: str) -> EdgeCollection[T, U, V]:
112164
doc_serializer=self._doc_serializer,
113165
doc_deserializer=self._doc_deserializer,
114166
)
167+
168+
async def create_edge_definition(
169+
self,
170+
edge_collection: str,
171+
from_vertex_collections: Sequence[str],
172+
to_vertex_collections: Sequence[str],
173+
options: Optional[EdgeDefinitionOptions | Json] = None,
174+
) -> Result[EdgeCollection[T, U, V]]:
175+
"""Create an edge definition in the graph.
176+
177+
This edge definition has to contain a collection and an array of each from
178+
and to vertex collections.
179+
180+
.. code-block:: python
181+
182+
{
183+
"edge_collection": "edge_collection_name",
184+
"from_vertex_collections": ["from_vertex_collection_name"],
185+
"to_vertex_collections": ["to_vertex_collection_name"]
186+
}
187+
188+
Args:
189+
edge_collection (str): Edge collection name.
190+
from_vertex_collections (list): List of vertex collections
191+
that can be used as the "from" vertex in edges.
192+
to_vertex_collections (list): List of vertex collections
193+
that can be used as the "to" vertex in edges.
194+
options (dict | EdgeDefinitionOptions | None): Extra options for
195+
creating edge definitions.
196+
197+
Returns:
198+
EdgeCollection: Edge collection API wrapper.
199+
200+
Raises:
201+
EdgeDefinitionCreateError: If the operation fails.
202+
203+
References:
204+
- `add-an-edge-definition <https://docs.arangodb.com/stable/develop/http-api/graphs/named-graphs/#add-an-edge-definition>`__
205+
""" # noqa: E501
206+
data: Json = {
207+
"collection": edge_collection,
208+
"from": from_vertex_collections,
209+
"to": to_vertex_collections,
210+
}
211+
212+
if options is not None:
213+
if isinstance(options, VertexCollectionOptions):
214+
data["options"] = options.to_dict()
215+
else:
216+
data["options"] = options
217+
218+
request = Request(
219+
method=Method.POST,
220+
endpoint=f"/_api/gharial/{self._name}/edge",
221+
data=self.serializer.dumps(data),
222+
)
223+
224+
def response_handler(resp: Response) -> EdgeCollection[T, U, V]:
225+
if not resp.is_success:
226+
raise EdgeDefinitionCreateError(resp, request)
227+
return self.edge_collection(edge_collection)
228+
229+
return await self._executor.execute(request, response_handler)

tests/test_graph.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import pytest
22

33
from arangoasync.exceptions import GraphCreateError, GraphDeleteError, GraphListError
4-
from tests.helpers import generate_graph_name
4+
from arangoasync.typings import GraphOptions
5+
from tests.helpers import generate_col_name, generate_graph_name
56

67

78
@pytest.mark.asyncio
@@ -40,11 +41,47 @@ async def test_graph_basic(db, bad_db):
4041
await bad_db.delete_graph(graph1_name)
4142

4243

43-
async def test_graph_properties(db):
44+
async def test_graph_properties(db, cluster, enterprise):
4445
# Create a graph
4546
name = generate_graph_name()
46-
graph = await db.create_graph(name)
47+
is_smart = cluster and enterprise
48+
options = GraphOptions(number_of_shards=3)
49+
graph = await db.create_graph(name, is_smart=is_smart, options=options)
50+
51+
# Create first vertex collection
52+
vcol_name = generate_col_name()
53+
vcol = await graph.create_vertex_collection(vcol_name)
54+
assert vcol.name == vcol_name
4755

4856
# Get the properties of the graph
4957
properties = await graph.properties()
5058
assert properties.name == name
59+
assert properties.is_smart == is_smart
60+
assert properties.number_of_shards == options.number_of_shards
61+
assert properties.orphan_collections == [vcol_name]
62+
63+
# Create second vertex collection
64+
vcol2_name = generate_col_name()
65+
vcol2 = await graph.create_vertex_collection(vcol2_name)
66+
assert vcol2.name == vcol2_name
67+
properties = await graph.properties()
68+
assert len(properties.orphan_collections) == 2
69+
70+
# Create an edge definition
71+
edge_name = generate_col_name()
72+
edge_col = await graph.create_edge_definition(
73+
edge_name,
74+
from_vertex_collections=[vcol_name],
75+
to_vertex_collections=[vcol2_name],
76+
)
77+
assert edge_col.name == edge_name
78+
79+
# There should be no more orphan collections
80+
properties = await graph.properties()
81+
assert len(properties.orphan_collections) == 0
82+
assert len(properties.edge_definitions) == 1
83+
assert properties.edge_definitions[0]["collection"] == edge_name
84+
assert len(properties.edge_definitions[0]["from"]) == 1
85+
assert properties.edge_definitions[0]["from"][0] == vcol_name
86+
assert len(properties.edge_definitions[0]["to"]) == 1
87+
assert properties.edge_definitions[0]["to"][0] == vcol2_name

0 commit comments

Comments
 (0)