Add path pop to mgp API (#1249)
This commit is contained in:
parent
b719f0744f
commit
404cdf05d3
@ -477,6 +477,8 @@ inline void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
|
|||||||
|
|
||||||
inline void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
|
inline void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
|
||||||
|
|
||||||
|
inline void path_pop(mgp_path *path) { MgInvokeVoid(mgp_path_pop, path); }
|
||||||
|
|
||||||
inline size_t path_size(mgp_path *path) { return MgInvoke<size_t>(mgp_path_size, path); }
|
inline size_t path_size(mgp_path *path) { return MgInvoke<size_t>(mgp_path_size, path); }
|
||||||
|
|
||||||
inline mgp_vertex *path_vertex_at(mgp_path *path, size_t index) {
|
inline mgp_vertex *path_vertex_at(mgp_path *path, size_t index) {
|
||||||
|
@ -333,6 +333,13 @@ class Path:
|
|||||||
self._vertices.append(edge.end_id)
|
self._vertices.append(edge.end_id)
|
||||||
self._edges.append((edge.start_id, edge.end_id, edge.id))
|
self._edges.append((edge.start_id, edge.end_id, edge.id))
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
if not self._edges:
|
||||||
|
raise IndexError("Path contains no relationships.")
|
||||||
|
|
||||||
|
self._vertices.pop()
|
||||||
|
self._edges.pop()
|
||||||
|
|
||||||
def vertex_at(self, index: int) -> Vertex:
|
def vertex_at(self, index: int) -> Vertex:
|
||||||
return Vertex(self._vertices[index], self._graph)
|
return Vertex(self._vertices[index], self._graph)
|
||||||
|
|
||||||
|
@ -543,6 +543,10 @@ void mgp_path_destroy(struct mgp_path *path);
|
|||||||
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for path extension.
|
/// Return mgp_error::MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for path extension.
|
||||||
enum mgp_error mgp_path_expand(struct mgp_path *path, struct mgp_edge *edge);
|
enum mgp_error mgp_path_expand(struct mgp_path *path, struct mgp_edge *edge);
|
||||||
|
|
||||||
|
/// Remove the last node and the last relationship from the path.
|
||||||
|
/// Return mgp_error::MGP_ERROR_OUT_OF_RANGE if the path contains no relationships.
|
||||||
|
enum mgp_error mgp_path_pop(struct mgp_path *path);
|
||||||
|
|
||||||
/// Get the number of edges in a mgp_path.
|
/// Get the number of edges in a mgp_path.
|
||||||
/// Current implementation always returns without errors.
|
/// Current implementation always returns without errors.
|
||||||
enum mgp_error mgp_path_size(struct mgp_path *path, size_t *result);
|
enum mgp_error mgp_path_size(struct mgp_path *path, size_t *result);
|
||||||
|
@ -886,6 +886,8 @@ class Path {
|
|||||||
|
|
||||||
/// @brief Adds a relationship continuing from the last node on the path.
|
/// @brief Adds a relationship continuing from the last node on the path.
|
||||||
void Expand(const Relationship &relationship);
|
void Expand(const Relationship &relationship);
|
||||||
|
/// @brief Removes the last node and the last relationship from the path.
|
||||||
|
void Pop();
|
||||||
|
|
||||||
/// @exception std::runtime_error Path contains element(s) with unknown value.
|
/// @exception std::runtime_error Path contains element(s) with unknown value.
|
||||||
bool operator==(const Path &other) const;
|
bool operator==(const Path &other) const;
|
||||||
@ -2995,6 +2997,8 @@ inline Relationship Path::GetRelationshipAt(size_t index) const {
|
|||||||
|
|
||||||
inline void Path::Expand(const Relationship &relationship) { mgp::path_expand(ptr_, relationship.ptr_); }
|
inline void Path::Expand(const Relationship &relationship) { mgp::path_expand(ptr_, relationship.ptr_); }
|
||||||
|
|
||||||
|
inline void Path::Pop() { mgp::path_pop(ptr_); }
|
||||||
|
|
||||||
inline bool Path::operator==(const Path &other) const { return util::PathsEqual(ptr_, other.ptr_); }
|
inline bool Path::operator==(const Path &other) const { return util::PathsEqual(ptr_, other.ptr_); }
|
||||||
|
|
||||||
inline bool Path::operator!=(const Path &other) const { return !(*this == other); }
|
inline bool Path::operator!=(const Path &other) const { return !(*this == other); }
|
||||||
|
@ -983,6 +983,24 @@ class Path:
|
|||||||
self._vertices = None
|
self._vertices = None
|
||||||
self._edges = None
|
self._edges = None
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
"""
|
||||||
|
Remove the last node and the last relationship from the path.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidContextError: If using an invalid `Path` instance
|
||||||
|
OutOfRangeError: If the path contains no relationships.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```path.pop()```
|
||||||
|
"""
|
||||||
|
if not self.is_valid():
|
||||||
|
raise InvalidContextError()
|
||||||
|
self._path.pop()
|
||||||
|
# Invalidate our cached tuples
|
||||||
|
self._vertices = None
|
||||||
|
self._edges = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vertices(self) -> typing.Tuple[Vertex, ...]:
|
def vertices(self) -> typing.Tuple[Vertex, ...]:
|
||||||
"""
|
"""
|
||||||
@ -1023,6 +1041,10 @@ class Path:
|
|||||||
self._edges = tuple(Edge(self._path.edge_at(i)) for i in range(num_edges))
|
self._edges = tuple(Edge(self._path.edge_at(i)) for i in range(num_edges))
|
||||||
return self._edges
|
return self._edges
|
||||||
|
|
||||||
|
@property
|
||||||
|
def length(self) -> int:
|
||||||
|
return self._path.size()
|
||||||
|
|
||||||
|
|
||||||
class Record:
|
class Record:
|
||||||
"""Represents a record of resulting field values."""
|
"""Represents a record of resulting field values."""
|
||||||
|
@ -929,6 +929,25 @@ class Path:
|
|||||||
self._vertices = None
|
self._vertices = None
|
||||||
self._edges = None
|
self._edges = None
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
"""
|
||||||
|
Remove the last node and the last relationship from the path.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InvalidContextError: If using an invalid `Path` instance
|
||||||
|
OutOfRangeError: If the path contains no relationships.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```path.pop()```
|
||||||
|
"""
|
||||||
|
if not self.is_valid():
|
||||||
|
raise InvalidContextError()
|
||||||
|
self._path.pop()
|
||||||
|
|
||||||
|
# Invalidate cached tuples
|
||||||
|
self._vertices = None
|
||||||
|
self._edges = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vertices(self) -> typing.Tuple[Vertex, ...]:
|
def vertices(self) -> typing.Tuple[Vertex, ...]:
|
||||||
"""
|
"""
|
||||||
|
@ -1180,6 +1180,17 @@ mgp_error mgp_path_expand(mgp_path *path, mgp_edge *edge) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mgp_error mgp_path_pop(struct mgp_path *path) {
|
||||||
|
return WrapExceptions([path] {
|
||||||
|
if (path->edges.empty()) {
|
||||||
|
throw std::out_of_range("Path contains no relationships.");
|
||||||
|
}
|
||||||
|
|
||||||
|
path->vertices.pop_back();
|
||||||
|
path->edges.pop_back();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
size_t MgpPathSize(const mgp_path &path) noexcept { return path.edges.size(); }
|
size_t MgpPathSize(const mgp_path &path) noexcept { return path.edges.size(); }
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -2204,6 +2204,17 @@ PyObject *PyPathExpand(PyPath *self, PyObject *edge) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *PyPathPop(PyPath *self) {
|
||||||
|
MG_ASSERT(self->path);
|
||||||
|
MG_ASSERT(self->py_graph);
|
||||||
|
MG_ASSERT(self->py_graph->graph);
|
||||||
|
|
||||||
|
if (RaiseExceptionFromErrorCode(mgp_path_pop(self->path))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *PyPathSize(PyPath *self, PyObject *Py_UNUSED(ignored)) {
|
PyObject *PyPathSize(PyPath *self, PyObject *Py_UNUSED(ignored)) {
|
||||||
MG_ASSERT(self->path);
|
MG_ASSERT(self->path);
|
||||||
MG_ASSERT(self->py_graph);
|
MG_ASSERT(self->py_graph);
|
||||||
@ -2251,6 +2262,8 @@ static PyMethodDef PyPathMethods[] = {
|
|||||||
"Create a path with a starting vertex."},
|
"Create a path with a starting vertex."},
|
||||||
{"expand", reinterpret_cast<PyCFunction>(PyPathExpand), METH_O,
|
{"expand", reinterpret_cast<PyCFunction>(PyPathExpand), METH_O,
|
||||||
"Append an edge continuing from the last vertex on the path."},
|
"Append an edge continuing from the last vertex on the path."},
|
||||||
|
{"pop", reinterpret_cast<PyCFunction>(PyPathPop), METH_NOARGS,
|
||||||
|
"Remove the last node and the last relationship from the path."},
|
||||||
{"size", reinterpret_cast<PyCFunction>(PyPathSize), METH_NOARGS, "Return the number of edges in a mgp_path."},
|
{"size", reinterpret_cast<PyCFunction>(PyPathSize), METH_NOARGS, "Return the number of edges in a mgp_path."},
|
||||||
{"vertex_at", reinterpret_cast<PyCFunction>(PyPathVertexAt), METH_VARARGS,
|
{"vertex_at", reinterpret_cast<PyCFunction>(PyPathVertexAt), METH_VARARGS,
|
||||||
"Return the vertex from a path at given index."},
|
"Return the vertex from a path at given index."},
|
||||||
|
@ -33,6 +33,16 @@ def compare_apis(ctx: mgp.ProcCtx) -> mgp.Record(results_dict=mgp.Map):
|
|||||||
(2, 1),
|
(2, 1),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
path.pop()
|
||||||
|
mock_path.pop()
|
||||||
|
results["pop"] = test_utils.all_equal(
|
||||||
|
(len(path.vertices), len(path.edges)),
|
||||||
|
(len(mock_path.vertices), len(mock_path.edges)),
|
||||||
|
(1, 0),
|
||||||
|
)
|
||||||
|
path.expand(edge_to_add)
|
||||||
|
mock_path.expand(mock_edge_to_add)
|
||||||
|
|
||||||
NEXT_ID = 1
|
NEXT_ID = 1
|
||||||
results["vertices"] = test_utils.all_equal(
|
results["vertices"] = test_utils.all_equal(
|
||||||
all(isinstance(vertex, mgp.Vertex) for vertex in path.vertices),
|
all(isinstance(vertex, mgp.Vertex) for vertex in path.vertices),
|
||||||
|
@ -125,6 +125,7 @@ def test_path():
|
|||||||
"__copy__": True,
|
"__copy__": True,
|
||||||
"is_valid": True,
|
"is_valid": True,
|
||||||
"expand": True,
|
"expand": True,
|
||||||
|
"pop": True,
|
||||||
"vertices": True,
|
"vertices": True,
|
||||||
"edges": True,
|
"edges": True,
|
||||||
}
|
}
|
||||||
|
@ -346,6 +346,9 @@ TYPED_TEST(CppApiTestFixture, TestPath) {
|
|||||||
auto value_x = mgp::Value(path);
|
auto value_x = mgp::Value(path);
|
||||||
// Use Value move constructor
|
// Use Value move constructor
|
||||||
auto value_y = mgp::Value(mgp::Path(node_0));
|
auto value_y = mgp::Value(mgp::Path(node_0));
|
||||||
|
|
||||||
|
path.Pop();
|
||||||
|
ASSERT_EQ(path.Length(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(CppApiTestFixture, TestDate) {
|
TYPED_TEST(CppApiTestFixture, TestDate) {
|
||||||
|
Loading…
Reference in New Issue
Block a user