Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,5 @@ node_modules/

# devcontainers
.devcontainer

test-results/
33 changes: 15 additions & 18 deletions arango/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -1898,25 +1898,22 @@ def create_graph(
:param orphan_collections: Names of additional vertex collections that
are not in edge definitions.
:type orphan_collections: [str] | None
:param smart: If set to True, sharding is enabled (see parameter
**smart_field** below). Applies only to enterprise version of
ArangoDB.
:param smart: If set to True, create a SmartGraph when **smart_field**
is specified, or an EnterpriseGraph otherwise. Applies only to enterprise
version of ArangoDB.
:type smart: bool | None
:param disjoint: If set to True, create a disjoint SmartGraph instead
of a regular SmartGraph. Applies only to enterprise version of
ArangoDB.
of a regular SmartGraph. Only has an effect with **smart_field**
or **smart**. Applies only to enterprise version of ArangoDB.
:type disjoint: bool | None
:param smart_field: Document field used to shard the vertices of the
graph. To use this, parameter **smart** must be set to True and
every vertex in the graph must have the smart field. Applies only
to enterprise version of ArangoDB. NOTE: If this field is
None and **smart** is True, an Enterprise Graph will be created.
graph. Setting this creates a SmartGraph, even if **smart** is
omitted or False. Every vertex in the graph must have this field.
Applies only to enterprise version of ArangoDB.
:type smart_field: str | None
:param shard_count: Number of shards used for every collection in the
graph. To use this, parameter **smart** must be set to True and
every vertex in the graph must have the smart field. This number
cannot be modified later once set. Applies only to enterprise
version of ArangoDB.
graph. This number cannot be modified later once set. Used for
clusters only.
:type shard_count: int | None
:param replication_factor: Number of copies of each shard on different
servers in a cluster. Allowed values are 1 (only one copy is kept
Expand Down Expand Up @@ -1969,11 +1966,11 @@ def create_graph(
]
if orphan_collections is not None:
data["orphanCollections"] = orphan_collections
if smart is not None: # pragma: no cover
data["isSmart"] = smart
if disjoint is not None: # pragma: no cover
data["isDisjoint"] = disjoint
if smart_field is not None: # pragma: no cover
if smart is not None:
data["options"]["isSmart"] = smart
if disjoint is not None:
data["options"]["isDisjoint"] = disjoint
if smart_field is not None:
data["options"]["smartGraphAttribute"] = smart_field
if shard_count is not None: # pragma: no cover
data["options"]["numberOfShards"] = shard_count
Expand Down
31 changes: 31 additions & 0 deletions docs/graph.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,37 @@ For more information, refer to `ArangoDB manual`_.
# Delete the graph.
db.delete_graph('school')

Graph creation options
======================

To create an EnterpriseGraph, pass ``smart=True`` and omit ``smart_field``.
EnterpriseGraphs use optimized graph sharding without a user-defined smart
field.

To create a SmartGraph, set ``smart_field`` to the vertex attribute used for
sharding (``smart=True`` is then optional).Set ``disjoint=True`` alongside
``smart_field`` to create a Disjoint SmartGraph, which rejects edges between
vertices with different smart field values.

For example, on an enterprise cluster:

.. code-block:: python

regional = db.create_graph(
'regional',
edge_definitions=[{
'edge_collection': 'routes',
'from_vertex_collections': ['places'],
'to_vertex_collections': ['places'],
}],
smart_field='region',
disjoint=True,
shard_count=3,
)

See :meth:`arango.database.StandardDatabase.create_graph` for all creation
options.

.. _edge-definitions:

Edge Definitions
Expand Down
54 changes: 54 additions & 0 deletions tests/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from packaging import version

from arango.collection import EdgeCollection
from arango.errno import INVALID_DISJOINT_SMART_EDGE
from arango.exceptions import (
DocumentDeleteError,
DocumentGetError,
Expand Down Expand Up @@ -35,6 +36,59 @@
)


@pytest.mark.parametrize(
"smart_field,disjoint",
[(None, False), ("region", False), ("region", True)],
ids=["enterprise", "smart", "disjoint-smart"],
)
def test_graph_create_smart_options(db, cluster, skip_tests, smart_field, disjoint):
if "enterprise" in skip_tests:
pytest.skip("Only for ArangoDB enterprise edition")
if not cluster:
pytest.skip("Only for ArangoDB clusters")

graph_name = generate_graph_name()
vertices = generate_col_name()
edges = generate_col_name()
graph = db.create_graph(
graph_name,
edge_definitions=[
{
"edge_collection": edges,
"from_vertex_collections": [vertices],
"to_vertex_collections": [vertices],
}
],
smart=True,
smart_field=smart_field,
disjoint=disjoint,
shard_count=3,
)
try:
properties = db.graph(graph_name).properties()
assert properties["smart"] is True
assert properties["disjoint"] is disjoint
assert properties.get("smart_field", "") == (smart_field or "")
assert properties["shard_count"] == 3

first = graph.insert_vertex(vertices, {"region": "eu"})
second = graph.insert_vertex(vertices, {"region": "eu"})
third = graph.insert_vertex(vertices, {"region": "us"})
edge = graph.insert_edge(edges, {"_from": first["_id"], "_to": second["_id"]})
assert graph.has_edge(edge["_id"])

cross_region_edge = {"_from": first["_id"], "_to": third["_id"]}
if disjoint:
with pytest.raises(DocumentInsertError) as err:
graph.insert_edge(edges, cross_region_edge)
assert err.value.error_code == INVALID_DISJOINT_SMART_EDGE
else:
edge = graph.insert_edge(edges, cross_region_edge)
assert graph.has_edge(edge["_id"])
finally:
db.delete_graph(graph_name, drop_collections=True)


def test_graph_properties(graph, bad_graph, db):
assert repr(graph) == f"<Graph {graph.name}>"

Expand Down
Loading