Skip to content

Commit

Permalink
impl import as for py
Browse files Browse the repository at this point in the history
  • Loading branch information
shivam-880 committed Nov 19, 2024
1 parent 2c61d49 commit 2a898ce
Show file tree
Hide file tree
Showing 3 changed files with 389 additions and 4 deletions.
218 changes: 218 additions & 0 deletions python/tests/test_graphdb/test_graphdb_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,221 @@ def test_import_with_int():
g2.import_node(g.node(1))
g2.import_nodes([g.node(2), g.node(3)])
assert g2.count_nodes() == g.count_nodes()


def test_import_node_as():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})

gg = Graph()
res = gg.import_node_as(a, "X")
assert res.name == "X"
assert res.history().tolist() == [1]

gg.add_node(1, "Y")

with pytest.raises(Exception) as excinfo:
gg.import_node_as(b, "Y")

assert "Node already exists" in str(excinfo.value)

assert gg.nodes.name == ["X", "Y"]
y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [1]
assert y.properties.get("temp") is None
assert y.properties.constant.get("con") is None


def test_import_node_as_force():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})

gg = Graph()
res = gg.import_node_as(a, "X")
assert res.name == "X"
assert res.history().tolist() == [1]

gg.add_node(1, "Y")
gg.import_node_as(b, "Y", True)

assert gg.nodes.name == ["X", "Y"]
y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [1]
assert y.properties.get("temp") == True
assert y.properties.constant.get("con") == 11


def test_import_nodes_as():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})

gg = Graph()
gg.add_node(1, "Y")

with pytest.raises(Exception) as excinfo:
gg.import_nodes_as([a, b], ["X", "Y"])

assert "Node already exists" in str(excinfo.value)

x = gg.node("X")
assert x.name == "X"
assert x.history().tolist() == [1]

assert sorted(gg.nodes.name) == ["X", "Y"]
y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [1]
assert y.properties.get("temp") is None
assert y.properties.constant.get("con") is None


def test_import_nodes_as_force():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})

gg = Graph()
gg.add_node(1, "Y")
gg.import_nodes_as([a, b], ["X", "Y"], True)

assert sorted(gg.nodes.name) == ["X", "Y"]
x = gg.node("X")
assert x.name == "X"
assert x.history().tolist() == [1]

y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [1]
assert y.properties.get("temp") == True
assert y.properties.constant.get("con") == 11


def test_import_edge_as():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})

e_a_b = g.add_edge(2, "A", "B", {"e_temp": True})

gg = Graph()
gg.add_edge(1, "X", "Y")

with pytest.raises(Exception) as excinfo:
gg.import_edge_as(e_a_b, ("X", "Y"))
assert "Edge already exists" in str(excinfo.value)

assert sorted(gg.nodes.name) == ["X", "Y"]
x = gg.node("X")
assert x.name == "X"
assert x.history().tolist() == [1]

y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [1]
assert y.properties.get("temp") is None
assert y.properties.constant.get("con") is None

e = gg.edge("X", "Y")
assert e.properties.get("e_temp") is None


def test_import_edge_as_force():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})

e_a_b = g.add_edge(2, "A", "B", {"e_temp": True})

gg = Graph()
gg.add_edge(3, "X", "Y")
gg.import_edge_as(e_a_b, ("X", "Y"), True)

assert sorted(gg.nodes.name) == ["X", "Y"]
x = gg.node("X")
assert x.name == "X"
print(x.history())
assert x.history().tolist() == [2, 3]

y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [2, 3]
assert y.properties.get("temp") is None
assert y.properties.constant.get("con") is None

e = gg.edge("X", "Y")
assert e.properties.get("e_temp") == True


def test_import_edges_as():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})
c = g.add_node(1, "C")

e_a_b = g.add_edge(2, "A", "B", {"e_temp": True})
e_b_c = g.add_edge(2, "B", "C")

gg = Graph()
gg.add_edge(1, "Y", "Z")

with pytest.raises(Exception) as excinfo:
gg.import_edges_as([e_a_b, e_b_c], [("X", "Y"), ("Y", "Z")])
assert "Edge already exists" in str(excinfo.value)

assert sorted(gg.nodes.name) == ["X", "Y", "Z"]
x = gg.node("X")
assert x.name == "X"
assert x.history().tolist() == [2]

y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [1, 2]
assert y.properties.get("temp") is None
assert y.properties.constant.get("con") is None

z = gg.node("Z")
assert z.name == "Z"
assert z.history().tolist() == [1]


def test_import_edges_as_force():
g = Graph()
a = g.add_node(1, "A")
b = g.add_node(1, "B", {"temp": True})
b.add_constant_properties({"con": 11})
c = g.add_node(1, "C")

e_a_b = g.add_edge(2, "A", "B", {"e_temp": True})
e_b_c = g.add_edge(2, "B", "C")

gg = Graph()
gg.add_edge(3, "Y", "Z")
gg.import_edges_as([e_a_b, e_b_c], [("X", "Y"), ("Y", "Z")], True)

assert sorted(gg.nodes.name) == ["X", "Y", "Z"]

x = gg.node("X")
assert x.name == "X"
assert x.history().tolist() == [2]

y = gg.node("Y")
assert y.name == "Y"
assert y.history().tolist() == [2, 3]
assert y.properties.get("temp") is None
assert y.properties.constant.get("con") is None

z = gg.node("Z")
assert z.name == "Z"
assert z.history().tolist() == [2, 3]
87 changes: 85 additions & 2 deletions raphtory/src/python/graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,34 @@ impl PyGraph {
self.graph.import_node(&node.node, force)
}

/// Import a single node into the graph with new id.
///
/// This function takes a PyNode object, a new id for the node and an optional boolean flag. If the flag is set to true,
/// the function will force the import of the node even if it already exists in the graph.
///
/// Arguments:
/// node (Node): A Node object representing the node to be imported.
/// new_id (str|int): The new node id.
/// force (bool): An optional boolean flag indicating whether to force the import of the node.
///
/// Returns:
/// Node: A Result object which is Ok if the node was successfully imported, and Err otherwise.
#[pyo3(signature = (node, new_id, force = false))]
pub fn import_node_as(
&self,
node: PyNode,
new_id: GID,
force: bool,
) -> Result<NodeView<Graph, Graph>, GraphError> {
self.graph.import_node_as(&node.node, new_id, force)
}

/// Import multiple nodes into the graph.
///
/// This function takes a vector of PyNode objects and an optional boolean flag. If the flag is set to true,
/// the function will force the import of the nodes even if they already exist in the graph.
///
/// Arguments:
///
/// nodes (List[Node]): A vector of PyNode objects representing the nodes to be imported.
/// force (bool): An optional boolean flag indicating whether to force the import of the nodes.
///
Expand All @@ -307,6 +328,27 @@ impl PyGraph {
self.graph.import_nodes(node_views, force)
}

/// Import multiple nodes into the graph with new ids.
///
/// This function takes a vector of PyNode objects, a list of new node ids and an optional boolean flag. If the flag is set to true,
/// the function will force the import of the nodes even if they already exist in the graph.
///
/// Arguments:
/// nodes (List[Node]): A vector of PyNode objects representing the nodes to be imported.
/// new_ids (List[str|int]): A list of node IDs to use for the imported nodes.
/// force (bool): An optional boolean flag indicating whether to force the import of the nodes.
///
#[pyo3(signature = (nodes, new_ids, force = false))]
pub fn import_nodes_as(
&self,
nodes: Vec<PyNode>,
new_ids: Vec<GID>,
force: bool,
) -> Result<(), GraphError> {
let node_views = nodes.iter().map(|node| &node.node);
self.graph.import_nodes_as(node_views, new_ids, force)
}

/// Import a single edge into the graph.
///
/// This function takes a PyEdge object and an optional boolean flag. If the flag is set to true,
Expand All @@ -328,13 +370,34 @@ impl PyGraph {
self.graph.import_edge(&edge.edge, force)
}

/// Import a single edge into the graph with new id.
///
/// This function takes a PyEdge object, a new id for the edge and an optional boolean flag. If the flag is set to true,
/// the function will force the import of the edge even if it already exists in the graph.
///
/// Arguments:
/// edge (Edge): A PyEdge object representing the edge to be imported.
/// new_id (tuple) : The ID of the new edge. It's a tuple of the source and destination node ids.
/// force (bool): An optional boolean flag indicating whether to force the import of the edge.
///
/// Returns:
/// Edge: A Result object which is Ok if the edge was successfully imported, and Err otherwise.
#[pyo3(signature = (edge, new_id, force = false))]
pub fn import_edge_as(
&self,
edge: PyEdge,
new_id: (GID, GID),
force: bool,
) -> Result<EdgeView<Graph, Graph>, GraphError> {
self.graph.import_edge_as(&edge.edge, new_id, force)
}

/// Import multiple edges into the graph.
///
/// This function takes a vector of PyEdge objects and an optional boolean flag. If the flag is set to true,
/// the function will force the import of the edges even if they already exist in the graph.
///
/// Arguments:
///
/// edges (List[Edge]): A list of Edge objects representing the edges to be imported.
/// force (bool): An optional boolean flag indicating whether to force the import of the edges.
#[pyo3(signature = (edges, force = false))]
Expand All @@ -343,6 +406,26 @@ impl PyGraph {
self.graph.import_edges(edge_views, force)
}

/// Import multiple edges into the graph with new ids.
///
/// This function takes a vector of PyEdge objects, a list of new edge ids and an optional boolean flag. If the flag is set to true,
/// the function will force the import of the edges even if they already exist in the graph.
///
/// Arguments:
/// edges (List[Edge]): A list of Edge objects representing the edges to be imported.
/// new_ids (List[tuple]) - The IDs of the new edges. It's a vector of tuples of the source and destination node ids.
/// force (bool): An optional boolean flag indicating whether to force the import of the edges.
#[pyo3(signature = (edges, new_ids, force = false))]
pub fn import_edges_as(
&self,
edges: Vec<PyEdge>,
new_ids: Vec<(GID, GID)>,
force: bool,
) -> Result<(), GraphError> {
let edge_views = edges.iter().map(|edge| &edge.edge);
self.graph.import_edges_as(edge_views, new_ids, force)
}

//FIXME: This is reimplemented here to get mutable views. If we switch the underlying graph to enum dispatch, this won't be necessary!
/// Gets the node with the specified id
///
Expand Down
Loading

0 comments on commit 2a898ce

Please sign in to comment.