Merge branch 'master' into Implement-constant-time-label-and-edge-type-retrieval

This commit is contained in:
gvolfing
2023-12-04 09:02:51 +01:00
committed by GitHub
34 changed files with 919 additions and 57 deletions

View File

@@ -73,6 +73,7 @@ add_subdirectory(constraints)
add_subdirectory(inspect_query)
add_subdirectory(filter_info)
add_subdirectory(queries)
add_subdirectory(query_modules_storage_modes)
add_subdirectory(garbage_collection)
add_subdirectory(query_planning)

View File

@@ -0,0 +1,8 @@
function(copy_qm_storage_modes_e2e_python_files FILE_NAME)
copy_e2e_python_files(query_modules_storage_modes ${FILE_NAME})
endfunction()
copy_qm_storage_modes_e2e_python_files(common.py)
copy_qm_storage_modes_e2e_python_files(test_query_modules_storage_modes.py)
add_subdirectory(query_modules)

View File

@@ -0,0 +1,37 @@
# Copyright 2023 Memgraph Ltd.
#
# Use of this software is governed by the Business Source License
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
# License, and you may not use this file except in compliance with the Business Source License.
#
# As of the Change Date specified in that file, in accordance with
# the Business Source License, use of this software will be governed
# by the Apache License, Version 2.0, included in the file
# licenses/APL.txt.
import typing
import mgclient
import pytest
@pytest.fixture(scope="function")
def cursor(**kwargs) -> mgclient.Connection:
connection = mgclient.connect(host="localhost", port=7687, **kwargs)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("MATCH (n) DETACH DELETE n;")
cursor.execute("CREATE (m:Component {id: 'A7422'}), (n:Component {id: '7X8X0'});")
cursor.execute("MATCH (m:Component {id: 'A7422'}) MATCH (n:Component {id: '7X8X0'}) CREATE (m)-[:PART_OF]->(n);")
cursor.execute("MATCH (m:Component {id: 'A7422'}) MATCH (n:Component {id: '7X8X0'}) CREATE (n)-[:DEPENDS_ON]->(m);")
yield cursor
cursor.execute("MATCH (n) DETACH DELETE n;")
def connect(**kwargs):
connection = mgclient.connect(host="localhost", port=7687, **kwargs)
connection.autocommit = True
return connection.cursor()

View File

@@ -0,0 +1,4 @@
copy_qm_storage_modes_e2e_python_files(python_api.py)
add_query_module(c_api c_api.cpp)
add_query_module(cpp_api cpp_api.cpp)

View File

@@ -0,0 +1,70 @@
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include <chrono>
#include <thread>
#include "_mgp.hpp"
#include "mg_exceptions.hpp"
#include "mg_procedure.h"
constexpr std::string_view kFunctionPassRelationship = "pass_relationship";
constexpr std::string_view kPassRelationshipArg = "relationship";
constexpr std::string_view kProcedurePassNodeWithId = "pass_node_with_id";
constexpr std::string_view kPassNodeWithIdArg = "node";
constexpr std::string_view kPassNodeWithIdFieldNode = "node";
constexpr std::string_view kPassNodeWithIdFieldId = "id";
// While the query procedure/function sleeps for this amount of time, a parallel transaction will erase a graph element
// (node or relationship) contained in the return value. Any operation in the parallel transaction should take far less
// time than this value.
const int64_t kSleep = 1;
void PassRelationship(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) {
auto *relationship = mgp::list_at(args, 0);
std::this_thread::sleep_for(std::chrono::seconds(kSleep));
mgp::func_result_set_value(res, relationship, memory);
}
void PassNodeWithId(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
auto *node = mgp::value_get_vertex(mgp::list_at(args, 0));
auto node_id = mgp::vertex_get_id(node).as_int;
std::this_thread::sleep_for(std::chrono::seconds(kSleep));
auto *result_record = mgp::result_new_record(result);
mgp::result_record_insert(result_record, kPassNodeWithIdFieldNode.data(), mgp::value_make_vertex(node));
mgp::result_record_insert(result_record, kPassNodeWithIdFieldId.data(), mgp::value_make_int(node_id, memory));
}
extern "C" int mgp_init_module(struct mgp_module *query_module, struct mgp_memory *memory) {
try {
{
auto *func = mgp::module_add_function(query_module, kFunctionPassRelationship.data(), PassRelationship);
mgp::func_add_arg(func, kPassRelationshipArg.data(), mgp::type_relationship());
}
{
auto *proc = mgp::module_add_read_procedure(query_module, kProcedurePassNodeWithId.data(), PassNodeWithId);
mgp::proc_add_arg(proc, kPassNodeWithIdArg.data(), mgp::type_node());
mgp::proc_add_result(proc, kPassNodeWithIdFieldNode.data(), mgp::type_node());
mgp::proc_add_result(proc, kPassNodeWithIdFieldId.data(), mgp::type_int());
}
} catch (const std::exception &e) {
return 1;
}
return 0;
}
extern "C" int mgp_shutdown_module() { return 0; }

View File

@@ -0,0 +1,86 @@
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include <chrono>
#include <thread>
#include <mgp.hpp>
constexpr std::string_view kFunctionPassRelationship = "pass_relationship";
constexpr std::string_view kPassRelationshipArg = "relationship";
constexpr std::string_view kProcedurePassNodeWithId = "pass_node_with_id";
constexpr std::string_view kPassNodeWithIdArg = "node";
constexpr std::string_view kPassNodeWithIdFieldNode = "node";
constexpr std::string_view kPassNodeWithIdFieldId = "id";
// While the query procedure/function sleeps for this amount of time, a parallel transaction will erase a graph element
// (node or relationship) contained in the return value. Any operation in the parallel transaction should take far less
// time than this value.
const int64_t kSleep = 1;
void PassRelationship(mgp_list *args, mgp_func_context *ctx, mgp_func_result *res, mgp_memory *memory) {
try {
mgp::MemoryDispatcherGuard guard{memory};
const auto arguments = mgp::List(args);
auto result = mgp::Result(res);
const auto relationship = arguments[0].ValueRelationship();
std::this_thread::sleep_for(std::chrono::seconds(kSleep));
result.SetValue(relationship);
} catch (const std::exception &e) {
mgp::func_result_set_error_msg(res, e.what(), memory);
return;
}
}
void PassNodeWithId(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
try {
mgp::MemoryDispatcherGuard guard(memory);
const auto arguments = mgp::List(args);
const auto record_factory = mgp::RecordFactory(result);
const auto node = arguments[0].ValueNode();
const auto node_id = node.Id().AsInt();
std::this_thread::sleep_for(std::chrono::seconds(kSleep));
auto record = record_factory.NewRecord();
record.Insert(kPassNodeWithIdFieldNode.data(), node);
record.Insert(kPassNodeWithIdFieldId.data(), node_id);
} catch (const std::exception &e) {
mgp::result_set_error_msg(result, e.what());
return;
}
}
extern "C" int mgp_init_module(struct mgp_module *query_module, struct mgp_memory *memory) {
try {
mgp::MemoryDispatcherGuard guard(memory);
mgp::AddFunction(PassRelationship, kFunctionPassRelationship,
{mgp::Parameter(kPassRelationshipArg, mgp::Type::Relationship)}, query_module, memory);
mgp::AddProcedure(
PassNodeWithId, kProcedurePassNodeWithId, mgp::ProcedureType::Read,
{mgp::Parameter(kPassNodeWithIdArg, mgp::Type::Node)},
{mgp::Return(kPassNodeWithIdFieldNode, mgp::Type::Node), mgp::Return(kPassNodeWithIdFieldId, mgp::Type::Int)},
query_module, memory);
} catch (const std::exception &e) {
return 1;
}
return 0;
}
extern "C" int mgp_shutdown_module() { return 0; }

View File

@@ -0,0 +1,55 @@
# Copyright 2023 Memgraph Ltd.
#
# Use of this software is governed by the Business Source License
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
# License, and you may not use this file except in compliance with the Business Source License.
#
# As of the Change Date specified in that file, in accordance with
# the Business Source License, use of this software will be governed
# by the Apache License, Version 2.0, included in the file
# licenses/APL.txt.
from time import sleep
import mgp
# While the query procedure/function sleeps for this amount of time, a parallel transaction will erase a graph element
# (node or relationship) contained in the return value. Any operation in the parallel transaction should take far less
# time than this value.
SLEEP = 1
@mgp.read_proc
def pass_node_with_id(ctx: mgp.ProcCtx, node: mgp.Vertex) -> mgp.Record(node=mgp.Vertex, id=int):
sleep(SLEEP)
return mgp.Record(node=node, id=node.id)
@mgp.function
def pass_node(ctx: mgp.FuncCtx, node: mgp.Vertex):
sleep(SLEEP)
return node
@mgp.function
def pass_relationship(ctx: mgp.FuncCtx, relationship: mgp.Edge):
sleep(SLEEP)
return relationship
@mgp.function
def pass_path(ctx: mgp.FuncCtx, path: mgp.Path):
sleep(SLEEP)
return path
@mgp.function
def pass_list(ctx: mgp.FuncCtx, list_: mgp.List[mgp.Any]):
sleep(SLEEP)
return list_
@mgp.function
def pass_map(ctx: mgp.FuncCtx, map_: mgp.Map):
sleep(SLEEP)
return map_

View File

@@ -0,0 +1,283 @@
# Copyright 2023 Memgraph Ltd.
#
# Use of this software is governed by the Business Source License
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
# License, and you may not use this file except in compliance with the Business Source License.
#
# As of the Change Date specified in that file, in accordance with
# the Business Source License, use of this software will be governed
# by the Apache License, Version 2.0, included in the file
# licenses/APL.txt.
# isort: off
from multiprocessing import Process
import sys
import pytest
from common import cursor, connect
import time
SWITCH_TO_ANALYTICAL = "STORAGE MODE IN_MEMORY_ANALYTICAL;"
def modify_graph(query):
subprocess_cursor = connect()
time.sleep(0.5) # Time for the parallel transaction to call a query procedure
subprocess_cursor.execute(query)
@pytest.mark.parametrize("api", ["c", "cpp", "python"])
def test_function_delete_result(cursor, api):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(
target=modify_graph,
args=("MATCH (m:Component {id: 'A7422'})-[e:PART_OF]->(n:Component {id: '7X8X0'}) DELETE e;",),
)
deleter.start()
cursor.execute(f"MATCH (m)-[e]->(n) RETURN {api}_api.pass_relationship(e);")
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0].type == "DEPENDS_ON"
@pytest.mark.parametrize("api", ["c", "cpp", "python"])
def test_function_delete_only_result(cursor, api):
cursor.execute(SWITCH_TO_ANALYTICAL)
cursor.execute("MATCH (m:Component {id: '7X8X0'})-[e:DEPENDS_ON]->(n:Component {id: 'A7422'}) DELETE e;")
deleter = Process(
target=modify_graph,
args=("MATCH (m:Component {id: 'A7422'})-[e:PART_OF]->(n:Component {id: '7X8X0'}) DELETE e;",),
)
deleter.start()
cursor.execute(f"MATCH (m)-[e]->(n) RETURN {api}_api.pass_relationship(e);")
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0] is None
@pytest.mark.parametrize("api", ["c", "cpp", "python"])
def test_procedure_delete_result(cursor, api):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(
target=modify_graph,
args=("MATCH (n {id: 'A7422'}) DETACH DELETE n;",),
)
deleter.start()
cursor.execute(
f"""MATCH (n)
CALL {api}_api.pass_node_with_id(n)
YIELD node, id
RETURN node, id;"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 2 and result[0][0].properties["id"] == "7X8X0"
@pytest.mark.parametrize("api", ["c", "cpp", "python"])
def test_procedure_delete_only_result(cursor, api):
cursor.execute(SWITCH_TO_ANALYTICAL)
cursor.execute("MATCH (n {id: '7X8X0'}) DETACH DELETE n;")
deleter = Process(
target=modify_graph,
args=("MATCH (n {id: 'A7422'}) DETACH DELETE n;",),
)
deleter.start()
cursor.execute(
f"""MATCH (n)
CALL {api}_api.pass_node_with_id(n)
YIELD node, id
RETURN node, id;"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 0
def test_deleted_node(cursor):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(target=modify_graph, args=("MATCH (n:Component {id: 'A7422'}) DETACH DELETE n;",))
deleter.start()
cursor.execute(
"""MATCH (n: Component {id: 'A7422'})
RETURN python_api.pass_node(n);"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0] is None
def test_deleted_relationship(cursor):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(
target=modify_graph,
args=("MATCH (:Component {id: 'A7422'})-[e:PART_OF]->(:Component {id: '7X8X0'}) DELETE e;",),
)
deleter.start()
cursor.execute(
"""MATCH (:Component {id: 'A7422'})-[e:PART_OF]->(:Component {id: '7X8X0'})
RETURN python_api.pass_relationship(e);"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0] is None
def test_deleted_node_in_path(cursor):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(target=modify_graph, args=("MATCH (n:Component {id: 'A7422'}) DETACH DELETE n;",))
deleter.start()
cursor.execute(
"""MATCH path=(n {id: 'A7422'})-[e]->(m)
RETURN python_api.pass_path(path);"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0] is None
def test_deleted_relationship_in_path(cursor):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(
target=modify_graph,
args=("MATCH (:Component {id: 'A7422'})-[e:PART_OF]->(:Component {id: '7X8X0'}) DELETE e;",),
)
deleter.start()
cursor.execute(
"""MATCH path=(n {id: 'A7422'})-[e]->(m)
RETURN python_api.pass_path(path);"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0] is None
def test_deleted_value_in_list(cursor):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(
target=modify_graph,
args=("MATCH (:Component {id: 'A7422'})-[e:PART_OF]->(:Component {id: '7X8X0'}) DELETE e;",),
)
deleter.start()
cursor.execute(
"""MATCH (n)-[e]->()
WITH collect(n) + collect(e) as list
RETURN python_api.pass_list(list);"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0] is None
def test_deleted_value_in_map(cursor):
cursor.execute(SWITCH_TO_ANALYTICAL)
deleter = Process(
target=modify_graph,
args=("MATCH (:Component {id: 'A7422'})-[e:PART_OF]->(:Component {id: '7X8X0'}) DELETE e;",),
)
deleter.start()
cursor.execute(
"""MATCH (n {id: 'A7422'})-[e]->()
WITH {node: n, relationship: e} AS map
RETURN python_api.pass_map(map);"""
)
deleter.join()
result = cursor.fetchall()
assert len(result) == 1 and len(result[0]) == 1 and result[0][0] is None
@pytest.mark.parametrize("storage_mode", ["IN_MEMORY_TRANSACTIONAL", "IN_MEMORY_ANALYTICAL"])
def test_function_none_deleted(storage_mode):
cursor = connect()
cursor.execute(f"STORAGE MODE {storage_mode};")
cursor.execute("CREATE (m:Component {id: 'A7422'}), (n:Component {id: '7X8X0'});")
cursor.execute(
"""MATCH (n)
RETURN python_api.pass_node(n);"""
)
result = cursor.fetchall()
cursor.execute("MATCH (n) DETACH DELETE n;")
assert len(result) == 2
@pytest.mark.parametrize("storage_mode", ["IN_MEMORY_TRANSACTIONAL", "IN_MEMORY_ANALYTICAL"])
def test_procedure_none_deleted(storage_mode):
cursor = connect()
cursor.execute(f"STORAGE MODE {storage_mode};")
cursor.execute("CREATE (m:Component {id: 'A7422'}), (n:Component {id: '7X8X0'});")
cursor.execute(
"""MATCH (n)
CALL python_api.pass_node_with_id(n)
YIELD node, id
RETURN node, id;"""
)
result = cursor.fetchall()
cursor.execute("MATCH (n) DETACH DELETE n;")
assert len(result) == 2
if __name__ == "__main__":
sys.exit(pytest.main([__file__, "-rA"]))

View File

@@ -0,0 +1,14 @@
query_modules_storage_modes_cluster: &query_modules_storage_modes_cluster
cluster:
main:
args: ["--bolt-port", "7687", "--log-level=TRACE"]
log_file: "query_modules_storage_modes.log"
setup_queries: []
validation_queries: []
workloads:
- name: "Test query module API behavior in Memgraph storage modes"
binary: "tests/e2e/pytest_runner.sh"
proc: "tests/e2e/query_modules_storage_modes/query_modules/"
args: ["query_modules_storage_modes/test_query_modules_storage_modes.py"]
<<: *query_modules_storage_modes_cluster

View File

@@ -104,7 +104,7 @@ class MemgraphRunner:
memgraph_binary = os.path.join(self.build_directory, "memgraph")
args_mg = [
memgraph_binary,
"--storage-properties-on-edges",
"--storage-properties-on-edges=true",
"--data-directory",
self.data_directory.name,
"--log-file",

View File

@@ -38,7 +38,8 @@ struct CppApiTestFixture : public ::testing::Test {
mgp_graph CreateGraph(const memgraph::storage::View view = memgraph::storage::View::NEW) {
// the execution context can be null as it shouldn't be used in these tests
return mgp_graph{&CreateDbAccessor(memgraph::storage::IsolationLevel::SNAPSHOT_ISOLATION), view, ctx_.get()};
return mgp_graph{&CreateDbAccessor(memgraph::storage::IsolationLevel::SNAPSHOT_ISOLATION), view, ctx_.get(),
memgraph::storage::StorageMode::IN_MEMORY_TRANSACTIONAL};
}
memgraph::query::DbAccessor &CreateDbAccessor(const memgraph::storage::IsolationLevel isolationLevel) {
@@ -499,6 +500,7 @@ TYPED_TEST(CppApiTestFixture, TestValueOperatorLessThan) {
ASSERT_THROW(list_test < map_test, mgp::ValueException);
ASSERT_THROW(list_test < list_test, mgp::ValueException);
}
TYPED_TEST(CppApiTestFixture, TestNumberEquality) {
mgp::Value double_1{1.0};
mgp::Value int_1{static_cast<int64_t>(1)};

View File

@@ -249,7 +249,7 @@ TYPED_TEST(CypherType, VertexSatisfiesType) {
auto vertex = dba.InsertVertex();
mgp_memory memory{memgraph::utils::NewDeleteResource()};
memgraph::utils::Allocator<mgp_vertex> alloc(memory.impl);
mgp_graph graph{&dba, memgraph::storage::View::NEW, nullptr};
mgp_graph graph{&dba, memgraph::storage::View::NEW, nullptr, dba.GetStorageMode()};
auto *mgp_vertex_v =
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_vertex, alloc.new_object<mgp_vertex>(vertex, &graph));
const memgraph::query::TypedValue tv_vertex(vertex);
@@ -274,7 +274,7 @@ TYPED_TEST(CypherType, EdgeSatisfiesType) {
auto edge = *dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("edge_type"));
mgp_memory memory{memgraph::utils::NewDeleteResource()};
memgraph::utils::Allocator<mgp_edge> alloc(memory.impl);
mgp_graph graph{&dba, memgraph::storage::View::NEW, nullptr};
mgp_graph graph{&dba, memgraph::storage::View::NEW, nullptr, dba.GetStorageMode()};
auto *mgp_edge_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_edge, alloc.new_object<mgp_edge>(edge, &graph));
const memgraph::query::TypedValue tv_edge(edge);
CheckSatisfiesTypesAndNullable(
@@ -298,7 +298,7 @@ TYPED_TEST(CypherType, PathSatisfiesType) {
auto edge = *dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("edge_type"));
mgp_memory memory{memgraph::utils::NewDeleteResource()};
memgraph::utils::Allocator<mgp_path> alloc(memory.impl);
mgp_graph graph{&dba, memgraph::storage::View::NEW, nullptr};
mgp_graph graph{&dba, memgraph::storage::View::NEW, nullptr, dba.GetStorageMode()};
auto *mgp_vertex_v = alloc.new_object<mgp_vertex>(v1, &graph);
auto path = EXPECT_MGP_NO_ERROR(mgp_path *, mgp_path_make_with_start, mgp_vertex_v, &memory);
ASSERT_TRUE(path);

View File

@@ -132,7 +132,7 @@ TYPED_TEST(PyModule, PyVertex) {
auto storage_dba = this->db->Access();
memgraph::query::DbAccessor dba(storage_dba.get());
mgp_memory memory{memgraph::utils::NewDeleteResource()};
mgp_graph graph{&dba, memgraph::storage::View::OLD, nullptr};
mgp_graph graph{&dba, memgraph::storage::View::OLD, nullptr, dba.GetStorageMode()};
auto *vertex = EXPECT_MGP_NO_ERROR(mgp_vertex *, mgp_graph_get_vertex_by_id, &graph, mgp_vertex_id{0}, &memory);
ASSERT_TRUE(vertex);
auto *vertex_value = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_vertex,
@@ -182,7 +182,7 @@ TYPED_TEST(PyModule, PyEdge) {
auto storage_dba = this->db->Access();
memgraph::query::DbAccessor dba(storage_dba.get());
mgp_memory memory{memgraph::utils::NewDeleteResource()};
mgp_graph graph{&dba, memgraph::storage::View::OLD, nullptr};
mgp_graph graph{&dba, memgraph::storage::View::OLD, nullptr, dba.GetStorageMode()};
auto *start_v = EXPECT_MGP_NO_ERROR(mgp_vertex *, mgp_graph_get_vertex_by_id, &graph, mgp_vertex_id{0}, &memory);
ASSERT_TRUE(start_v);
auto *edges_it = EXPECT_MGP_NO_ERROR(mgp_edges_iterator *, mgp_vertex_iter_out_edges, start_v, &memory);
@@ -228,7 +228,7 @@ TYPED_TEST(PyModule, PyPath) {
auto storage_dba = this->db->Access();
memgraph::query::DbAccessor dba(storage_dba.get());
mgp_memory memory{memgraph::utils::NewDeleteResource()};
mgp_graph graph{&dba, memgraph::storage::View::OLD, nullptr};
mgp_graph graph{&dba, memgraph::storage::View::OLD, nullptr, dba.GetStorageMode()};
auto *start_v = EXPECT_MGP_NO_ERROR(mgp_vertex *, mgp_graph_get_vertex_by_id, &graph, mgp_vertex_id{0}, &memory);
ASSERT_TRUE(start_v);
auto *path = EXPECT_MGP_NO_ERROR(mgp_path *, mgp_path_make_with_start, start_v, &memory);

View File

@@ -120,7 +120,8 @@ class MgpGraphTest : public ::testing::Test {
public:
mgp_graph CreateGraph(const memgraph::storage::View view = memgraph::storage::View::NEW) {
// the execution context can be null as it shouldn't be used in these tests
return mgp_graph{&CreateDbAccessor(memgraph::storage::IsolationLevel::SNAPSHOT_ISOLATION), view, ctx_.get()};
return mgp_graph{&CreateDbAccessor(memgraph::storage::IsolationLevel::SNAPSHOT_ISOLATION), view, ctx_.get(),
memgraph::storage::StorageMode::IN_MEMORY_TRANSACTIONAL};
}
std::array<memgraph::storage::Gid, 2> CreateEdge() {