From 02ef954e5134d79e0831d28796bec50c96721de8 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Mon, 7 Nov 2022 18:28:35 +0200 Subject: [PATCH 01/26] Add mg-functions lib and integrated with SE and QE --- src/CMakeLists.txt | 1 + src/expr/CMakeLists.txt | 2 +- src/expr/interpret/eval.hpp | 3 +- src/functions/CMakeLists.txt | 2 + src/functions/awesome_memgraph_functions.hpp | 1463 +++++++++++++++++ src/query/v2/CMakeLists.txt | 3 +- src/query/v2/accessors.hpp | 19 +- src/query/v2/conversions.hpp | 4 + src/query/v2/frontend/ast/ast.lcp | 13 +- .../interpret/awesome_memgraph_functions.cpp | 1108 ------------- .../interpret/awesome_memgraph_functions.hpp | 55 - src/query/v2/plan/preprocess.cpp | 2 +- src/storage/v3/CMakeLists.txt | 2 +- src/storage/v3/bindings/ast/ast.lcp | 28 +- src/storage/v3/bindings/db_accessor.hpp | 2 +- src/storage/v3/conversions.hpp | 4 + src/storage/v3/edge_accessor.cpp | 7 +- src/storage/v3/edge_accessor.hpp | 7 +- src/storage/v3/expr.cpp | 9 +- src/storage/v3/shard.cpp | 4 +- src/storage/v3/shard_rsm.cpp | 10 +- src/storage/v3/vertex_accessor.cpp | 3 + src/storage/v3/vertex_accessor.hpp | 3 + tests/unit/storage_v3_edge.cpp | 846 +++++----- 24 files changed, 1970 insertions(+), 1630 deletions(-) create mode 100644 src/functions/CMakeLists.txt create mode 100644 src/functions/awesome_memgraph_functions.hpp delete mode 100644 src/query/v2/interpret/awesome_memgraph_functions.cpp delete mode 100644 src/query/v2/interpret/awesome_memgraph_functions.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b84bb26a..81fc61836 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,6 +21,7 @@ add_subdirectory(auth) add_subdirectory(parser) add_subdirectory(expr) add_subdirectory(coordinator) +add_subdirectory(functions) if (MG_ENTERPRISE) add_subdirectory(audit) diff --git a/src/expr/CMakeLists.txt b/src/expr/CMakeLists.txt index e529512b7..31cbfa493 100644 --- a/src/expr/CMakeLists.txt +++ b/src/expr/CMakeLists.txt @@ -17,4 +17,4 @@ target_include_directories(mg-expr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(mg-expr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ast) target_include_directories(mg-expr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/interpret) target_include_directories(mg-expr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/semantic) -target_link_libraries(mg-expr cppitertools Boost::headers mg-utils mg-parser) +target_link_libraries(mg-expr cppitertools Boost::headers mg-utils mg-parser mg-functions) diff --git a/src/expr/interpret/eval.hpp b/src/expr/interpret/eval.hpp index 70127c023..139e37514 100644 --- a/src/expr/interpret/eval.hpp +++ b/src/expr/interpret/eval.hpp @@ -24,6 +24,7 @@ #include "expr/exceptions.hpp" #include "expr/interpret/frame.hpp" #include "expr/semantic/symbol_table.hpp" +#include "functions/awesome_memgraph_functions.hpp" #include "utils/exceptions.hpp" namespace memgraph::expr { @@ -479,7 +480,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { } TypedValue Visit(Function &function) override { - FunctionContext function_ctx{dba_, ctx_->memory, ctx_->timestamp, &ctx_->counters, view_}; + functions::FunctionContext<DbAccessor> function_ctx{dba_, ctx_->memory, ctx_->timestamp, &ctx_->counters, view_}; // Stack allocate evaluated arguments when there's a small number of them. if (function.arguments_.size() <= 8) { TypedValue arguments[8] = {TypedValue(ctx_->memory), TypedValue(ctx_->memory), TypedValue(ctx_->memory), diff --git a/src/functions/CMakeLists.txt b/src/functions/CMakeLists.txt new file mode 100644 index 000000000..09720c862 --- /dev/null +++ b/src/functions/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(mg-functions INTERFACE) +target_include_directories(mg-functions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/functions/awesome_memgraph_functions.hpp b/src/functions/awesome_memgraph_functions.hpp new file mode 100644 index 000000000..ca415c69b --- /dev/null +++ b/src/functions/awesome_memgraph_functions.hpp @@ -0,0 +1,1463 @@ +// Copyright 2022 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. + +#pragma once + +#include <functional> +#include <string> +#include <type_traits> +#include <unordered_map> + +#include "storage/v3/result.hpp" +#include "storage/v3/view.hpp" +#include "utils/algorithm.hpp" +#include "utils/cast.hpp" +#include "utils/concepts.hpp" +#include "utils/memory.hpp" +#include "utils/pmr/string.hpp" +#include "utils/string.hpp" +#include "utils/temporal.hpp" + +namespace memgraph::functions { + +class FunctionRuntimeException : public utils::BasicException { + using utils::BasicException::BasicException; +}; + +template <typename TAccessor> +struct FunctionContext { + TAccessor *db_accessor; + utils::MemoryResource *memory; + int64_t timestamp; + std::unordered_map<std::string, int64_t> *counters; + storage::v3::View view; +}; + +// Tags for the NameToFunction() function template +struct StorageEngineTag {}; +struct QueryEngineTag {}; + +namespace impl { +struct SinkCallable { + void operator()() {} +}; +} // namespace impl + +/// Return the function implementation with the given name. +/// +/// Note, returned function signature uses C-style access to an array to allow +/// having an array stored anywhere the caller likes, as long as it is +/// contiguous in memory. Since most functions don't take many arguments, it's +/// convenient to have them stored in the calling stack frame. +template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv = impl::SinkCallable> +std::function<TypedValueT(const TypedValueT *arguments, int64_t num_arguments, const FunctionContextT &context)> +NameToFunction(const std::string &function_name); + +namespace { +const char kStartsWith[] = "STARTSWITH"; +const char kEndsWith[] = "ENDSWITH"; +const char kContains[] = "CONTAINS"; +const char kId[] = "ID"; +} // namespace + +} // namespace memgraph::functions + +namespace memgraph::functions::impl { + +//////////////////////////////////////////////////////////////////////////////// +// eDSL using template magic for describing a type of an awesome memgraph +// function and checking if the passed in arguments match the description. +// +// To use the type checking eDSL, you should put a `FType` invocation in the +// body of your awesome Memgraph function. `FType` takes type arguments as the +// description of the function type signature. Each runtime argument will be +// checked in order corresponding to given compile time type arguments. These +// type arguments can come in two forms: +// +// * final, primitive type descriptor and +// * combinator type descriptor. +// +// The primitive type descriptors are defined as empty structs, they are right +// below this documentation. +// +// Combinator type descriptors are defined as structs taking additional type +// parameters, you can find these further below in the implementation. Of +// primary interest are `Or` and `Optional` type combinators. +// +// With `Or` you can describe that an argument can be any of the types listed in +// `Or`. For example, `Or<Null, Bool, Integer>` allows an argument to be either +// `Null` or a boolean or an integer. +// +// The `Optional` combinator is used to define optional arguments to a function. +// These must come as the last positional arguments. Naturally, you can use `Or` +// inside `Optional`. So for example, `Optional<Or<Null, Bool>, Integer>` +// describes that a function takes 2 optional arguments. The 1st one must be +// either a `Null` or a boolean, while the 2nd one must be an integer. The type +// signature check will succeed in the following cases. +// +// * No optional arguments were supplied. +// * One argument was supplied and it passes `Or<Null, Bool>` check. +// * Two arguments were supplied, the 1st one passes `Or<Null, Bool>` check +// and the 2nd one passes `Integer` check. +// +// Runtime arguments to `FType` are: function name, pointer to arguments and the +// number of received arguments. +// +// Full example. +// +// FType<Or<Null, String>, NonNegativeInteger, +// Optional<NonNegativeInteger>>("substring", args, nargs); +// +// The above will check that `substring` function received the 2 required +// arguments. Optionally, the function may take a 3rd argument. The 1st argument +// must be either a `Null` or a character string. The 2nd argument is required +// to be a non-negative integer. If the 3rd argument was supplied, it will also +// be checked that it is a non-negative integer. If any of these checks fail, +// `FType` will throw a `FunctionRuntimeException` with an appropriate error +// message. +//////////////////////////////////////////////////////////////////////////////// + +struct Null {}; +struct Bool {}; +struct Integer {}; +struct PositiveInteger {}; +struct NonZeroInteger {}; +struct NonNegativeInteger {}; +struct Double {}; +struct Number {}; +struct List {}; +struct String {}; +struct Map {}; +struct Edge {}; +struct Vertex {}; +struct Path {}; +struct Date {}; +struct LocalTime {}; +struct LocalDateTime {}; +struct Duration {}; + +template <typename ArgType, typename TypedValueT> +bool ArgIsType(const TypedValueT &arg) { + if constexpr (std::is_same_v<ArgType, Null>) { + return arg.IsNull(); + } else if constexpr (std::is_same_v<ArgType, Bool>) { + return arg.IsBool(); + } else if constexpr (std::is_same_v<ArgType, Integer>) { + return arg.IsInt(); + } else if constexpr (std::is_same_v<ArgType, PositiveInteger>) { + return arg.IsInt() && arg.ValueInt() > 0; + } else if constexpr (std::is_same_v<ArgType, NonZeroInteger>) { + return arg.IsInt() && arg.ValueInt() != 0; + } else if constexpr (std::is_same_v<ArgType, NonNegativeInteger>) { + return arg.IsInt() && arg.ValueInt() >= 0; + } else if constexpr (std::is_same_v<ArgType, Double>) { + return arg.IsDouble(); + } else if constexpr (std::is_same_v<ArgType, Number>) { + return arg.IsNumeric(); + } else if constexpr (std::is_same_v<ArgType, List>) { + return arg.IsList(); + } else if constexpr (std::is_same_v<ArgType, String>) { + return arg.IsString(); + } else if constexpr (std::is_same_v<ArgType, Map>) { + return arg.IsMap(); + } else if constexpr (std::is_same_v<ArgType, Vertex>) { + return arg.IsVertex(); + } else if constexpr (std::is_same_v<ArgType, Edge>) { + return arg.IsEdge(); + } else if constexpr (std::is_same_v<ArgType, Path>) { + return arg.IsPath(); + } else if constexpr (std::is_same_v<ArgType, Date>) { + return arg.IsDate(); + } else if constexpr (std::is_same_v<ArgType, LocalTime>) { + return arg.IsLocalTime(); + } else if constexpr (std::is_same_v<ArgType, LocalDateTime>) { + return arg.IsLocalDateTime(); + } else if constexpr (std::is_same_v<ArgType, Duration>) { + return arg.IsDuration(); + } else if constexpr (std::is_same_v<ArgType, void>) { + return true; + } else { + static_assert(std::is_same_v<ArgType, Null>, "Unknown ArgType"); + } + return false; +} + +template <typename ArgType> +constexpr const char *ArgTypeName() { + // The type names returned should be standardized openCypher type names. + // https://github.com/opencypher/openCypher/blob/master/docs/openCypher9.pdf + if constexpr (std::is_same_v<ArgType, Null>) { + return "null"; + } else if constexpr (std::is_same_v<ArgType, Bool>) { + return "boolean"; + } else if constexpr (std::is_same_v<ArgType, Integer>) { + return "integer"; + } else if constexpr (std::is_same_v<ArgType, PositiveInteger>) { + return "positive integer"; + } else if constexpr (std::is_same_v<ArgType, NonZeroInteger>) { + return "non-zero integer"; + } else if constexpr (std::is_same_v<ArgType, NonNegativeInteger>) { + return "non-negative integer"; + } else if constexpr (std::is_same_v<ArgType, Double>) { + return "float"; + } else if constexpr (std::is_same_v<ArgType, Number>) { + return "number"; + } else if constexpr (std::is_same_v<ArgType, List>) { + return "list"; + } else if constexpr (std::is_same_v<ArgType, String>) { + return "string"; + } else if constexpr (std::is_same_v<ArgType, Map>) { + return "map"; + } else if constexpr (std::is_same_v<ArgType, Vertex>) { + return "node"; + } else if constexpr (std::is_same_v<ArgType, Edge>) { + return "relationship"; + } else if constexpr (std::is_same_v<ArgType, Path>) { + return "path"; + } else if constexpr (std::is_same_v<ArgType, void>) { + return "void"; + } else if constexpr (std::is_same_v<ArgType, Date>) { + return "Date"; + } else if constexpr (std::is_same_v<ArgType, LocalTime>) { + return "LocalTime"; + } else if constexpr (std::is_same_v<ArgType, LocalDateTime>) { + return "LocalDateTime"; + } else if constexpr (std::is_same_v<ArgType, Duration>) { + return "Duration"; + } else { + static_assert(std::is_same_v<ArgType, Null>, "Unknown ArgType"); + } + return "<unknown-type>"; +} + +template <typename... ArgType> +struct Or; + +template <typename ArgType> +struct Or<ArgType> { + template <typename TypedValueT> + static bool Check(const TypedValueT &arg) { + return ArgIsType<ArgType>(arg); + } + + static std::string TypeNames() { return ArgTypeName<ArgType>(); } +}; + +template <typename ArgType, typename... ArgTypes> +struct Or<ArgType, ArgTypes...> { + template <typename TypedValueT> + static bool Check(const TypedValueT &arg) { + if (ArgIsType<ArgType>(arg)) return true; + return Or<ArgTypes...>::Check(arg); + } + + static std::string TypeNames() { + if constexpr (sizeof...(ArgTypes) > 1) { + return fmt::format("'{}', {}", ArgTypeName<ArgType>(), Or<ArgTypes...>::TypeNames()); + } else { + return fmt::format("'{}' or '{}'", ArgTypeName<ArgType>(), Or<ArgTypes...>::TypeNames()); + } + } +}; + +template <class T> +struct IsOrType { + static constexpr bool value = false; +}; + +template <class... ArgTypes> +struct IsOrType<Or<ArgTypes...>> { + static constexpr bool value = true; +}; + +template <typename... ArgTypes> +struct Optional; + +template <typename ArgType> +struct Optional<ArgType> { + static constexpr size_t size = 1; + + template <typename TypedValueT> + static void Check(const char *name, const TypedValueT *args, int64_t nargs, int64_t pos) { + if (nargs == 0) return; + const TypedValueT &arg = args[0]; + if constexpr (IsOrType<ArgType>::value) { + if (!ArgType::Check(arg)) { + throw FunctionRuntimeException("Optional '{}' argument at position {} must be either {}.", name, pos, + ArgType::TypeNames()); + } + } else { + if (!ArgIsType<ArgType>(arg)) + throw FunctionRuntimeException("Optional '{}' argument at position {} must be '{}'.", name, pos, + ArgTypeName<ArgType>()); + } + } +}; + +template <class ArgType, class... ArgTypes> +struct Optional<ArgType, ArgTypes...> { + static constexpr size_t size = 1 + sizeof...(ArgTypes); + + template <typename TypedValueT> + static void Check(const char *name, const TypedValueT *args, int64_t nargs, int64_t pos) { + if (nargs == 0) return; + Optional<ArgType>::Check(name, args, nargs, pos); + Optional<ArgTypes...>::Check(name, args + 1, nargs - 1, pos + 1); + } +}; + +template <class T> +struct IsOptional { + static constexpr bool value = false; +}; + +template <class... ArgTypes> +struct IsOptional<Optional<ArgTypes...>> { + static constexpr bool value = true; +}; + +template <class ArgType, class... ArgTypes> +constexpr size_t FTypeRequiredArgs() { + if constexpr (IsOptional<ArgType>::value) { + static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); + return 0; + } else if constexpr (sizeof...(ArgTypes) == 0) { + return 1; + } else { + return 1U + FTypeRequiredArgs<ArgTypes...>(); + } +} + +template <class ArgType, class... ArgTypes> +constexpr size_t FTypeOptionalArgs() { + if constexpr (IsOptional<ArgType>::value) { + static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); + return ArgType::size; + } else if constexpr (sizeof...(ArgTypes) == 0) { + return 0; + } else { + return FTypeOptionalArgs<ArgTypes...>(); + } +} + +template <typename TypedValueT, typename ArgType, typename... ArgTypes> +void FType(const char *name, const TypedValueT *args, int64_t nargs, int64_t pos = 1) { + if constexpr (std::is_same_v<ArgType, void>) { + if (nargs != 0) { + throw FunctionRuntimeException("'{}' requires no arguments.", name); + } + return; + } + static constexpr int64_t required_args = FTypeRequiredArgs<ArgType, ArgTypes...>(); + static constexpr int64_t optional_args = FTypeOptionalArgs<ArgType, ArgTypes...>(); + static constexpr int64_t total_args = required_args + optional_args; + if constexpr (optional_args > 0) { + if (nargs < required_args || nargs > total_args) { + throw FunctionRuntimeException("'{}' requires between {} and {} arguments.", name, required_args, total_args); + } + } else { + if (nargs != required_args) { + throw FunctionRuntimeException("'{}' requires exactly {} {}.", name, required_args, + required_args == 1 ? "argument" : "arguments"); + } + } + const TypedValueT &arg = args[0]; + if constexpr (IsOrType<ArgType>::value) { + if (!ArgType::Check(arg)) { + throw FunctionRuntimeException("'{}' argument at position {} must be either {}.", name, pos, + ArgType::TypeNames()); + } + } else if constexpr (IsOptional<ArgType>::value) { + static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); + ArgType::Check(name, args, nargs, pos); + } else { + if (!ArgIsType<ArgType>(arg)) { + throw FunctionRuntimeException("'{}' argument at position {} must be '{}'", name, pos, ArgTypeName<ArgType>()); + } + } + if constexpr (sizeof...(ArgTypes) > 0) { + FType<TypedValueT, ArgTypes...>(name, args + 1, nargs - 1, pos + 1); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// END function type description eDSL +//////////////////////////////////////////////////////////////////////////////// + +// Predicate functions. +// Neo4j has all, any, exists, none, single +// Those functions are a little bit different since they take a filterExpression +// as an argument. +// There is all, any, none and single productions in opencypher grammar, but it +// will be trivial to also add exists. +// TODO: Implement this. + +// Scalar functions. +// We don't have a way to implement id function since we don't store any. If it +// is really neccessary we could probably map vlist* to id. +// TODO: Implement length (it works on a path, but we didn't define path +// structure yet). +// TODO: Implement size(pattern), for example size((a)-[:X]-()) should return +// number of results of this pattern. I don't think we will ever do this. +// TODO: Implement rest of the list functions. +// TODO: Implement degrees, haversin, radians +// TODO: Implement spatial functions + +template <typename TypedValueT, typename FunctionContextT, typename Tag> +TypedValueT EndNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Edge>>("endNode", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + if constexpr (std::is_same_v<Tag, StorageEngineTag>) { + const auto to = args[0].ValueEdge().To(); + auto pk = to.primary_key; + auto maybe_vertex_accessor = ctx.db_accessor->FindVertex(pk, ctx.view); + if (!maybe_vertex_accessor) { + throw functions::FunctionRuntimeException("Trying to get properties from a deleted object."); + } + return TypedValueT(*maybe_vertex_accessor, ctx.memory); + } else { + return TypedValueT(args[0].ValueEdge().To(), ctx.memory); + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Head(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, List>>("head", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &list = args[0].ValueList(); + if (list.empty()) return TypedValueT(ctx.memory); + return TypedValueT(list[0], ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Last(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, List>>("last", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &list = args[0].ValueList(); + if (list.empty()) return TypedValueT(ctx.memory); + return TypedValueT(list.back(), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv> +TypedValueT Properties(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Vertex, Edge>>("properties", args, nargs); + auto *dba = ctx.db_accessor; + auto get_properties = [&](const auto &record_accessor) { + typename TypedValueT::TMap properties(ctx.memory); + if constexpr (std::is_same_v<Tag, StorageEngineTag>) { + auto maybe_props = record_accessor.Properties(ctx.view); + if (maybe_props.HasError()) { + switch (maybe_props.GetError()) { + case storage::v3::Error::DELETED_OBJECT: + throw functions::FunctionRuntimeException("Trying to get properties from a deleted object."); + case storage::v3::Error::NONEXISTENT_OBJECT: + throw functions::FunctionRuntimeException("Trying to get properties from an object that doesn't exist."); + case storage::v3::Error::SERIALIZATION_ERROR: + case storage::v3::Error::VERTEX_HAS_EDGES: + case storage::v3::Error::PROPERTIES_DISABLED: + case storage::v3::Error::VERTEX_ALREADY_INSERTED: + throw functions::FunctionRuntimeException("Unexpected error when getting properties."); + } + } + for (const auto &property : *maybe_props) { + Conv conv; + properties.emplace(dba->PropertyToName(property.first), conv(property.second)); + } + } else { + Conv conv; + for (const auto &property : record_accessor.Properties()) { + properties.emplace(utils::pmr::string(dba->PropertyToName(property.first), ctx.memory), + conv(property.second, dba)); + } + } + return TypedValueT(std::move(properties)); + }; + + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsVertex()) { + return get_properties(value.ValueVertex()); + } else { + return get_properties(value.ValueEdge()); + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Size(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, List, String, Map, Path>>("size", args, nargs); + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsList()) { + return TypedValueT(static_cast<int64_t>(value.ValueList().size()), ctx.memory); + } else if (value.IsString()) { + return TypedValueT(static_cast<int64_t>(value.ValueString().size()), ctx.memory); + } else if (value.IsMap()) { + // neo4j doesn't implement size for map, but I don't see a good reason not + // to do it. + return TypedValueT(static_cast<int64_t>(value.ValueMap().size()), ctx.memory); + } else { + return TypedValueT(static_cast<int64_t>(value.ValuePath().edges().size()), ctx.memory); + } +} + +template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv> +TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Edge>>("startNode", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + if constexpr (std::is_same_v<Tag, StorageEngineTag>) { + const auto to = args[0].ValueEdge().From(); + auto pk = to.primary_key; + auto maybe_vertex_accessor = ctx.db_accessor->FindVertex(pk, ctx.view); + if (!maybe_vertex_accessor) { + throw functions::FunctionRuntimeException("Trying to get properties from a deleted object."); + } + return TypedValueT(*maybe_vertex_accessor, ctx.memory); + } else { + return TypedValueT(args[0].ValueEdge().From(), ctx.memory); + } +} + +namespace { + +size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) { + if (maybe_degree.HasError()) { + switch (maybe_degree.GetError()) { + case storage::v3::Error::DELETED_OBJECT: + throw functions::FunctionRuntimeException("Trying to get degree of a deleted node."); + case storage::v3::Error::NONEXISTENT_OBJECT: + throw functions::FunctionRuntimeException("Trying to get degree of a node that doesn't exist."); + case storage::v3::Error::SERIALIZATION_ERROR: + case storage::v3::Error::VERTEX_HAS_EDGES: + case storage::v3::Error::PROPERTIES_DISABLED: + case storage::v3::Error::VERTEX_ALREADY_INSERTED: + throw functions::FunctionRuntimeException("Unexpected error when getting node degree."); + } + } + return *maybe_degree; +} + +} // namespace + +template <typename TypedValueT, typename FunctionContextT, typename Tag> +TypedValueT Degree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Vertex>>("degree", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &vertex = args[0].ValueVertex(); + size_t out_degree = 0; + size_t in_degree = 0; + if constexpr (std::same_as<Tag, StorageEngineTag>) { + out_degree = UnwrapDegreeResult(vertex.OutDegree(ctx.view)); + in_degree = UnwrapDegreeResult(vertex.InDegree(ctx.view)); + } else { + out_degree = vertex.OutDegree(); + in_degree = vertex.InDegree(); + } + return TypedValueT(static_cast<int64_t>(out_degree + in_degree), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT, typename Tag> +TypedValueT InDegree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Vertex>>("inDegree", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &vertex = args[0].ValueVertex(); + size_t in_degree = 0; + if constexpr (std::same_as<Tag, StorageEngineTag>) { + in_degree = UnwrapDegreeResult(vertex.InDegree(ctx.view)); + } else { + in_degree = vertex.InDegree(); + } + return TypedValueT(static_cast<int64_t>(in_degree), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT, typename Tag> +TypedValueT OutDegree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Vertex>>("outDegree", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &vertex = args[0].ValueVertex(); + size_t out_degree = 0; + if constexpr (std::same_as<Tag, StorageEngineTag>) { + out_degree = UnwrapDegreeResult(vertex.OutDegree(ctx.view)); + } else { + out_degree = vertex.OutDegree(); + } + return TypedValueT(static_cast<int64_t>(out_degree), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ToBoolean(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Bool, Integer, String>>("toBoolean", args, nargs); + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsBool()) { + return TypedValueT(value.ValueBool(), ctx.memory); + } else if (value.IsInt()) { + return TypedValueT(value.ValueInt() != 0L, ctx.memory); + } else { + auto s = utils::ToUpperCase(utils::Trim(value.ValueString())); + if (s == "TRUE") return TypedValueT(true, ctx.memory); + if (s == "FALSE") return TypedValueT(false, ctx.memory); + // I think this is just stupid and that exception should be thrown, but + // neo4j does it this way... + return TypedValueT(ctx.memory); + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ToFloat(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Number, String>>("toFloat", args, nargs); + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsInt()) { + return TypedValueT(static_cast<double>(value.ValueInt()), ctx.memory); + } else if (value.IsDouble()) { + return TypedValueT(value, ctx.memory); + } else { + try { + return TypedValueT(utils::ParseDouble(utils::Trim(value.ValueString())), ctx.memory); + } catch (const utils::BasicException &) { + return TypedValueT(ctx.memory); + } + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ToInteger(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Bool, Number, String>>("toInteger", args, nargs); + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsBool()) { + return TypedValueT(value.ValueBool() ? 1L : 0L, ctx.memory); + } else if (value.IsInt()) { + return TypedValueT(value, ctx.memory); + } else if (value.IsDouble()) { + return TypedValueT(static_cast<int64_t>(value.ValueDouble()), ctx.memory); + } else { + try { + // Yup, this is correct. String is valid if it has floating point + // number, then it is parsed and converted to int. + return TypedValueT(static_cast<int64_t>(utils::ParseDouble(utils::Trim(value.ValueString()))), ctx.memory); + } catch (const utils::BasicException &) { + return TypedValueT(ctx.memory); + } + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Type(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Edge>>("type", args, nargs); + auto *dba = ctx.db_accessor; + if (args[0].IsNull()) return TypedValueT(ctx.memory); + return TypedValueT(dba->EdgeTypeToName(args[0].ValueEdge().EdgeType()), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ValueType(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Bool, Integer, Double, String, List, Map, Vertex, Edge, Path>>("type", args, nargs); + // The type names returned should be standardized openCypher type names. + // https://github.com/opencypher/openCypher/blob/master/docs/openCypher9.pdf + switch (args[0].type()) { + case TypedValueT::Type::Null: + return TypedValueT("NULL", ctx.memory); + case TypedValueT::Type::Bool: + return TypedValueT("BOOLEAN", ctx.memory); + case TypedValueT::Type::Int: + return TypedValueT("INTEGER", ctx.memory); + case TypedValueT::Type::Double: + return TypedValueT("FLOAT", ctx.memory); + case TypedValueT::Type::String: + return TypedValueT("STRING", ctx.memory); + case TypedValueT::Type::List: + return TypedValueT("LIST", ctx.memory); + case TypedValueT::Type::Map: + return TypedValueT("MAP", ctx.memory); + case TypedValueT::Type::Vertex: + return TypedValueT("NODE", ctx.memory); + case TypedValueT::Type::Edge: + return TypedValueT("RELATIONSHIP", ctx.memory); + case TypedValueT::Type::Path: + return TypedValueT("PATH", ctx.memory); + case TypedValueT::Type::Date: + return TypedValueT("DATE", ctx.memory); + case TypedValueT::Type::LocalTime: + return TypedValueT("LOCAL_TIME", ctx.memory); + case TypedValueT::Type::LocalDateTime: + return TypedValueT("LOCAL_DATE_TIME", ctx.memory); + case TypedValueT::Type::Duration: + return TypedValueT("DURATION", ctx.memory); + } +} + +// TODO: How is Keys different from Properties function? +template <typename TypedValueT, typename FunctionContextT, typename Tag> +TypedValueT Keys(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Vertex, Edge>>("keys", args, nargs); + auto *dba = ctx.db_accessor; + auto get_keys = [&](const auto &record_accessor) { + typename TypedValueT::TVector keys(ctx.memory); + if constexpr (std::same_as<Tag, StorageEngineTag>) { + auto maybe_props = record_accessor.Properties(ctx.view); + if (maybe_props.HasError()) { + switch (maybe_props.GetError()) { + case storage::v3::Error::DELETED_OBJECT: + throw functions::FunctionRuntimeException("Trying to get keys from a deleted object."); + case storage::v3::Error::NONEXISTENT_OBJECT: + throw functions::FunctionRuntimeException("Trying to get keys from an object that doesn't exist."); + case storage::v3::Error::SERIALIZATION_ERROR: + case storage::v3::Error::VERTEX_HAS_EDGES: + case storage::v3::Error::PROPERTIES_DISABLED: + case storage::v3::Error::VERTEX_ALREADY_INSERTED: + throw functions::FunctionRuntimeException("Unexpected error when getting keys."); + } + } + for (const auto &property : *maybe_props) { + keys.emplace_back(dba->PropertyToName(property.first)); + } + } else { + for (const auto &property : record_accessor.Properties()) { + keys.emplace_back(dba->PropertyToName(property.first)); + } + } + return TypedValueT(std::move(keys)); + }; + + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsVertex()) { + return get_keys(value.ValueVertex()); + } else { + return get_keys(value.ValueEdge()); + } +} + +template <typename TypedValueT, typename FunctionContextT, typename Tag> +TypedValueT Labels(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Vertex>>("labels", args, nargs); + auto *dba = ctx.db_accessor; + if (args[0].IsNull()) return TypedValueT(ctx.memory); + typename TypedValueT::TVector labels(ctx.memory); + if constexpr (std::is_same_v<Tag, StorageEngineTag>) { + auto maybe_labels = args[0].ValueVertex().Labels(ctx.view); + if (maybe_labels.HasError()) { + switch (maybe_labels.GetError()) { + case storage::v3::Error::DELETED_OBJECT: + throw functions::FunctionRuntimeException("Trying to get labels from a deleted node."); + case storage::v3::Error::NONEXISTENT_OBJECT: + throw functions::FunctionRuntimeException("Trying to get labels from a node that doesn't exist."); + case storage::v3::Error::SERIALIZATION_ERROR: + case storage::v3::Error::VERTEX_HAS_EDGES: + case storage::v3::Error::PROPERTIES_DISABLED: + case storage::v3::Error::VERTEX_ALREADY_INSERTED: + throw functions::FunctionRuntimeException("Unexpected error when getting labels."); + } + } + for (const auto &label : *maybe_labels) { + labels.emplace_back(dba->LabelToName(label)); + } + } else { + auto vertex = args[0].ValueVertex(); + for (const auto &label : vertex.Labels()) { + labels.emplace_back(dba->LabelToName(label.id)); + } + } + return TypedValueT(std::move(labels)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Nodes(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Path>>("nodes", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &vertices = args[0].ValuePath().vertices(); + typename TypedValueT::TVector values(ctx.memory); + values.reserve(vertices.size()); + for (const auto &v : vertices) values.emplace_back(v); + return TypedValueT(std::move(values)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Relationships(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Path>>("relationships", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &edges = args[0].ValuePath().edges(); + typename TypedValueT::TVector values(ctx.memory); + values.reserve(edges.size()); + for (const auto &e : edges) values.emplace_back(e); + return TypedValueT(std::move(values)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Range(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Integer>, Or<Null, Integer>, Optional<Or<Null, NonZeroInteger>>>("range", args, nargs); + for (int64_t i = 0; i < nargs; ++i) + if (args[i].IsNull()) return TypedValueT(ctx.memory); + auto lbound = args[0].ValueInt(); + auto rbound = args[1].ValueInt(); + int64_t step = nargs == 3 ? args[2].ValueInt() : 1; + typename TypedValueT::TVector list(ctx.memory); + if (lbound <= rbound && step > 0) { + for (auto i = lbound; i <= rbound; i += step) { + list.emplace_back(i); + } + } else if (lbound >= rbound && step < 0) { + for (auto i = lbound; i >= rbound; i += step) { + list.emplace_back(i); + } + } + return TypedValueT(std::move(list)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Tail(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, List>>("tail", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + typename TypedValueT::TVector list(args[0].ValueList(), ctx.memory); + if (list.empty()) return TypedValueT(std::move(list)); + list.erase(list.begin()); + return TypedValueT(std::move(list)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT UniformSample(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, List>, Or<Null, NonNegativeInteger>>("uniformSample", args, nargs); + static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()}; + if (args[0].IsNull() || args[1].IsNull()) return TypedValueT(ctx.memory); + const auto &population = args[0].ValueList(); + auto population_size = population.size(); + if (population_size == 0) return TypedValueT(ctx.memory); + auto desired_length = args[1].ValueInt(); + std::uniform_int_distribution<uint64_t> rand_dist{0, population_size - 1}; + typename TypedValueT::TVector sampled(ctx.memory); + sampled.reserve(desired_length); + for (int64_t i = 0; i < desired_length; ++i) { + sampled.emplace_back(population[rand_dist(pseudo_rand_gen_)]); + } + return TypedValueT(std::move(sampled)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Abs(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Number>>("abs", args, nargs); + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsInt()) { + return TypedValueT(std::abs(value.ValueInt()), ctx.memory); + } else { + return TypedValueT(std::abs(value.ValueDouble()), ctx.memory); + } +} + +#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \ + template <typename TypedValueT, typename FunctionContextT> \ + TypedValueT name(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { \ + FType<TypedValueT, Or<Null, Number>>(#lowercased_name, args, nargs); \ + const auto &value = args[0]; \ + if (value.IsNull()) { \ + return TypedValueT(ctx.memory); \ + } else if (value.IsInt()) { \ + return TypedValueT(lowercased_name(value.ValueInt()), ctx.memory); \ + } else { \ + return TypedValueT(lowercased_name(value.ValueDouble()), ctx.memory); \ + } \ + } + +WRAP_CMATH_FLOAT_FUNCTION(Ceil, ceil) +WRAP_CMATH_FLOAT_FUNCTION(Floor, floor) +// We are not completely compatible with neoj4 in this function because, +// neo4j rounds -0.5, -1.5, -2.5... to 0, -1, -2... +WRAP_CMATH_FLOAT_FUNCTION(Round, round) +WRAP_CMATH_FLOAT_FUNCTION(Exp, exp) +WRAP_CMATH_FLOAT_FUNCTION(Log, log) +WRAP_CMATH_FLOAT_FUNCTION(Log10, log10) +WRAP_CMATH_FLOAT_FUNCTION(Sqrt, sqrt) +WRAP_CMATH_FLOAT_FUNCTION(Acos, acos) +WRAP_CMATH_FLOAT_FUNCTION(Asin, asin) +WRAP_CMATH_FLOAT_FUNCTION(Atan, atan) +WRAP_CMATH_FLOAT_FUNCTION(Cos, cos) +WRAP_CMATH_FLOAT_FUNCTION(Sin, sin) +WRAP_CMATH_FLOAT_FUNCTION(Tan, tan) + +#undef WRAP_CMATH_FLOAT_FUNCTION + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Atan2(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Number>, Or<Null, Number>>("atan2", args, nargs); + if (args[0].IsNull() || args[1].IsNull()) return TypedValueT(ctx.memory); + auto to_double = [](const TypedValueT &t) -> double { + if (t.IsInt()) { + return t.ValueInt(); + } else { + return t.ValueDouble(); + } + }; + double y = to_double(args[0]); + double x = to_double(args[1]); + return TypedValueT(atan2(y, x), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Sign(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Number>>("sign", args, nargs); + auto sign = [&](auto x) { return TypedValueT((0 < x) - (x < 0), ctx.memory); }; + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsInt()) { + return sign(value.ValueInt()); + } else { + return sign(value.ValueDouble()); + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT E(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, void>("e", args, nargs); + return TypedValueT(M_E, ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Pi(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, void>("pi", args, nargs); + return TypedValueT(M_PI, ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Rand(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, void>("rand", args, nargs); + static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()}; + static thread_local std::uniform_real_distribution<> rand_dist_{0, 1}; + return TypedValueT(rand_dist_(pseudo_rand_gen_), ctx.memory); +} + +template <class TPredicate, typename TypedValueT, typename FunctionContextT> +TypedValueT StringMatchOperator(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, String>, Or<Null, String>>(TPredicate::name, args, nargs); + if (args[0].IsNull() || args[1].IsNull()) return TypedValueT(ctx.memory); + const auto &s1 = args[0].ValueString(); + const auto &s2 = args[1].ValueString(); + return TypedValueT(TPredicate{}(s1, s2), ctx.memory); +} + +// Check if s1 starts with s2. +template <typename TypedValueT> +struct StartsWithPredicate { + static constexpr const char *name = "startsWith"; + bool operator()(const typename TypedValueT::TString &s1, const typename TypedValueT::TString &s2) const { + if (s1.size() < s2.size()) return false; + return std::equal(s2.begin(), s2.end(), s1.begin()); + } +}; + +template <typename TypedValueT, typename FunctionContextT> +inline auto StartsWith = StringMatchOperator<StartsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>; + +// Check if s1 ends with s2. +template <typename TypedValueT> +struct EndsWithPredicate { + static constexpr const char *name = "endsWith"; + bool operator()(const typename TypedValueT::TString &s1, const typename TypedValueT::TString &s2) const { + if (s1.size() < s2.size()) return false; + return std::equal(s2.rbegin(), s2.rend(), s1.rbegin()); + } +}; + +template <typename TypedValueT, typename FunctionContextT> +inline auto EndsWith = StringMatchOperator<EndsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>; + +// Check if s1 contains s2. +template <typename TypedValueT> +struct ContainsPredicate { + static constexpr const char *name = "contains"; + bool operator()(const typename TypedValueT::TString &s1, const typename TypedValueT::TString &s2) const { + if (s1.size() < s2.size()) return false; + return s1.find(s2) != std::string::npos; + } +}; + +template <typename TypedValueT, typename FunctionContextT> +inline auto Contains = StringMatchOperator<ContainsPredicate<TypedValueT>, TypedValueT, FunctionContextT>; + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Assert(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Bool, Optional<String>>("assert", args, nargs); + if (!args[0].ValueBool()) { + std::string message("Assertion failed"); + if (nargs == 2) { + message += ": "; + message += args[1].ValueString(); + } + message += "."; + throw FunctionRuntimeException(message); + } + return TypedValueT(args[0], ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Counter(const TypedValueT *args, int64_t nargs, const FunctionContextT &context) { + FType<TypedValueT, String, Integer, Optional<NonZeroInteger>>("counter", args, nargs); + int64_t step = 1; + if (nargs == 3) { + step = args[2].ValueInt(); + } + + auto [it, inserted] = context.counters->emplace(args[0].ValueString(), args[1].ValueInt()); + auto value = it->second; + it->second += step; + + return TypedValueT(value, context.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, Vertex, Edge>>("id", args, nargs); + const auto &arg = args[0]; + if (arg.IsNull()) { + return TypedValueT(ctx.memory); + } else if (arg.IsVertex()) { + return TypedValueT(static_cast<int64_t>(arg.ValueVertex().CypherId()), ctx.memory); + } else { + return TypedValueT(static_cast<int64_t>(arg.ValueEdge().CypherId()), ctx.memory); + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ToString(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, String, Number, Date, LocalTime, LocalDateTime, Duration, Bool>>("toString", args, nargs); + const auto &arg = args[0]; + if (arg.IsNull()) { + return TypedValueT(ctx.memory); + } + if (arg.IsString()) { + return TypedValueT(arg, ctx.memory); + } + if (arg.IsInt()) { + // TODO: This is making a pointless copy of std::string, we may want to + // use a different conversion to string + return TypedValueT(std::to_string(arg.ValueInt()), ctx.memory); + } + if (arg.IsDouble()) { + return TypedValueT(std::to_string(arg.ValueDouble()), ctx.memory); + } + if (arg.IsDate()) { + return TypedValueT(arg.ValueDate().ToString(), ctx.memory); + } + if (arg.IsLocalTime()) { + return TypedValueT(arg.ValueLocalTime().ToString(), ctx.memory); + } + if (arg.IsLocalDateTime()) { + return TypedValueT(arg.ValueLocalDateTime().ToString(), ctx.memory); + } + if (arg.IsDuration()) { + return TypedValueT(arg.ValueDuration().ToString(), ctx.memory); + } + + return TypedValueT(arg.ValueBool() ? "true" : "false", ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Timestamp(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Optional<Or<Date, LocalTime, LocalDateTime, Duration>>>("timestamp", args, nargs); + const auto &arg = *args; + if (arg.IsDate()) { + return TypedValueT(arg.ValueDate().MicrosecondsSinceEpoch(), ctx.memory); + } + if (arg.IsLocalTime()) { + return TypedValueT(arg.ValueLocalTime().MicrosecondsSinceEpoch(), ctx.memory); + } + if (arg.IsLocalDateTime()) { + return TypedValueT(arg.ValueLocalDateTime().MicrosecondsSinceEpoch(), ctx.memory); + } + if (arg.IsDuration()) { + return TypedValueT(arg.ValueDuration().microseconds, ctx.memory); + } + return TypedValueT(ctx.timestamp, ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Left(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, String>, Or<Null, NonNegativeInteger>>("left", args, nargs); + if (args[0].IsNull() || args[1].IsNull()) return TypedValueT(ctx.memory); + return TypedValueT(utils::Substr(args[0].ValueString(), 0, args[1].ValueInt()), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Right(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, String>, Or<Null, NonNegativeInteger>>("right", args, nargs); + if (args[0].IsNull() || args[1].IsNull()) return TypedValueT(ctx.memory); + const auto &str = args[0].ValueString(); + auto len = args[1].ValueInt(); + return len <= str.size() ? TypedValueT(utils::Substr(str, str.size() - len, len), ctx.memory) + : TypedValueT(str, ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT CallStringFunction( + const TypedValueT *args, int64_t nargs, utils::MemoryResource *memory, const char *name, + std::function<typename TypedValueT::TString(const typename TypedValueT::TString &)> fun) { + FType<TypedValueT, Or<Null, String>>(name, args, nargs); + if (args[0].IsNull()) return TypedValueT(memory); + return TypedValueT(fun(args[0].ValueString()), memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT LTrim(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction<TypedValueT, FunctionContextT>(args, nargs, ctx.memory, "lTrim", [&](const auto &str) { + return typename TypedValueT::TString(utils::LTrim(str), ctx.memory); + }); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT RTrim(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction<TypedValueT, FunctionContextT>(args, nargs, ctx.memory, "rTrim", [&](const auto &str) { + return typename TypedValueT::TString(utils::RTrim(str), ctx.memory); + }); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Trim(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction<TypedValueT, FunctionContextT>(args, nargs, ctx.memory, "trim", [&](const auto &str) { + return typename TypedValueT::TString(utils::Trim(str), ctx.memory); + }); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Reverse(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction<TypedValueT, FunctionContextT>( + args, nargs, ctx.memory, "reverse", [&](const auto &str) { return utils::Reversed(str, ctx.memory); }); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ToLower(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction<TypedValueT, FunctionContextT>(args, nargs, ctx.memory, "toLower", [&](const auto &str) { + typename TypedValueT::TString res(ctx.memory); + utils::ToLowerCase(&res, str); + return res; + }); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ToUpper(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction<TypedValueT, FunctionContextT>(args, nargs, ctx.memory, "toUpper", [&](const auto &str) { + typename TypedValueT::TString res(ctx.memory); + utils::ToUpperCase(&res, str); + return res; + }); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Replace(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, String>, Or<Null, String>, Or<Null, String>>("replace", args, nargs); + if (args[0].IsNull() || args[1].IsNull() || args[2].IsNull()) { + return TypedValueT(ctx.memory); + } + typename TypedValueT::TString replaced(ctx.memory); + utils::Replace(&replaced, args[0].ValueString(), args[1].ValueString(), args[2].ValueString()); + return TypedValueT(std::move(replaced)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Split(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, String>, Or<Null, String>>("split", args, nargs); + if (args[0].IsNull() || args[1].IsNull()) { + return TypedValueT(ctx.memory); + } + typename TypedValueT::TVector result(ctx.memory); + utils::Split(&result, args[0].ValueString(), args[1].ValueString()); + return TypedValueT(std::move(result)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Substring(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<Null, String>, NonNegativeInteger, Optional<NonNegativeInteger>>("substring", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + const auto &str = args[0].ValueString(); + auto start = args[1].ValueInt(); + if (nargs == 2) return TypedValueT(utils::Substr(str, start), ctx.memory); + auto len = args[2].ValueInt(); + return TypedValueT(utils::Substr(str, start, len), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT ToByteString(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, String>("toByteString", args, nargs); + const auto &str = args[0].ValueString(); + if (str.empty()) return TypedValueT("", ctx.memory); + if (!utils::StartsWith(str, "0x") && !utils::StartsWith(str, "0X")) { + throw FunctionRuntimeException("'toByteString' argument must start with '0x'"); + } + const auto &hex_str = utils::Substr(str, 2); + auto read_hex = [](const char ch) -> unsigned char { + if (ch >= '0' && ch <= '9') return ch - '0'; + if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; + if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; + throw FunctionRuntimeException("'toByteString' argument has an invalid character '{}'", ch); + }; + utils::pmr::string bytes(ctx.memory); + bytes.reserve((1 + hex_str.size()) / 2); + size_t i = 0; + // Treat odd length hex string as having a leading zero. + if (hex_str.size() % 2) bytes.append(1, read_hex(hex_str[i++])); + for (; i < hex_str.size(); i += 2) { + unsigned char byte = read_hex(hex_str[i]) * 16U + read_hex(hex_str[i + 1]); + // MemcpyCast in case we are converting to a signed value, so as to avoid + // undefined behaviour. + bytes.append(1, utils::MemcpyCast<decltype(bytes)::value_type>(byte)); + } + return TypedValueT(std::move(bytes)); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT FromByteString(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, String, Optional<PositiveInteger>>("fromByteString", args, nargs); + const auto &bytes = args[0].ValueString(); + if (bytes.empty()) return TypedValueT("", ctx.memory); + size_t min_length = bytes.size(); + if (nargs == 2) min_length = std::max(min_length, static_cast<size_t>(args[1].ValueInt())); + utils::pmr::string str(ctx.memory); + str.reserve(min_length * 2 + 2); + str.append("0x"); + for (size_t pad = 0; pad < min_length - bytes.size(); ++pad) str.append(2, '0'); + // Convert the bytes to a character string in hex representation. + // Unfortunately, we don't know whether the default `char` is signed or + // unsigned, so we have to work around any potential undefined behaviour when + // conversions between the 2 occur. That's why this function is more + // complicated than it should be. + auto to_hex = [](const unsigned char val) -> char { + unsigned char ch = val < 10U ? static_cast<unsigned char>('0') + val : static_cast<unsigned char>('a') + val - 10U; + return utils::MemcpyCast<char>(ch); + }; + for (unsigned char byte : bytes) { + str.append(1, to_hex(byte / 16U)); + str.append(1, to_hex(byte % 16U)); + } + return TypedValueT(std::move(str)); +} + +template <typename T> +concept IsNumberOrInteger = utils::SameAsAnyOf<T, Number, Integer>; + +template <IsNumberOrInteger ArgType> +void MapNumericParameters(auto ¶meter_mappings, const auto &input_parameters) { + for (const auto &[key, value] : input_parameters) { + if (auto it = parameter_mappings.find(key); it != parameter_mappings.end()) { + if (value.IsInt()) { + *it->second = value.ValueInt(); + } else if (std::is_same_v<ArgType, Number> && value.IsDouble()) { + *it->second = value.ValueDouble(); + } else { + std::string_view error = std::is_same_v<ArgType, Integer> ? "an integer." : "a numeric value."; + throw FunctionRuntimeException("Invalid value for key '{}'. Expected {}", key, error); + } + } else { + throw FunctionRuntimeException("Unknown key '{}'.", key); + } + } +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Date(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Optional<Or<String, Map>>>("date", args, nargs); + if (nargs == 0) { + return TypedValueT(utils::LocalDateTime(ctx.timestamp).date, ctx.memory); + } + + if (args[0].IsString()) { + const auto &[date_parameters, is_extended] = utils::ParseDateParameters(args[0].ValueString()); + return TypedValueT(utils::Date(date_parameters), ctx.memory); + } + + utils::DateParameters date_parameters; + + using namespace std::literals; + std::unordered_map parameter_mappings = {std::pair{"year"sv, &date_parameters.year}, + std::pair{"month"sv, &date_parameters.month}, + std::pair{"day"sv, &date_parameters.day}}; + + MapNumericParameters<Integer>(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::Date(date_parameters), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT LocalTime(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Optional<Or<String, Map>>>("localtime", args, nargs); + + if (nargs == 0) { + return TypedValueT(utils::LocalDateTime(ctx.timestamp).local_time, ctx.memory); + } + + if (args[0].IsString()) { + const auto &[local_time_parameters, is_extended] = utils::ParseLocalTimeParameters(args[0].ValueString()); + return TypedValueT(utils::LocalTime(local_time_parameters), ctx.memory); + } + + utils::LocalTimeParameters local_time_parameters; + + using namespace std::literals; + std::unordered_map parameter_mappings{ + std::pair{"hour"sv, &local_time_parameters.hour}, + std::pair{"minute"sv, &local_time_parameters.minute}, + std::pair{"second"sv, &local_time_parameters.second}, + std::pair{"millisecond"sv, &local_time_parameters.millisecond}, + std::pair{"microsecond"sv, &local_time_parameters.microsecond}, + }; + + MapNumericParameters<Integer>(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::LocalTime(local_time_parameters), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT LocalDateTime(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Optional<Or<String, Map>>>("localdatetime", args, nargs); + + if (nargs == 0) { + return TypedValueT(utils::LocalDateTime(ctx.timestamp), ctx.memory); + } + + if (args[0].IsString()) { + const auto &[date_parameters, local_time_parameters] = ParseLocalDateTimeParameters(args[0].ValueString()); + return TypedValueT(utils::LocalDateTime(date_parameters, local_time_parameters), ctx.memory); + } + + utils::DateParameters date_parameters; + utils::LocalTimeParameters local_time_parameters; + using namespace std::literals; + std::unordered_map parameter_mappings{ + std::pair{"year"sv, &date_parameters.year}, + std::pair{"month"sv, &date_parameters.month}, + std::pair{"day"sv, &date_parameters.day}, + std::pair{"hour"sv, &local_time_parameters.hour}, + std::pair{"minute"sv, &local_time_parameters.minute}, + std::pair{"second"sv, &local_time_parameters.second}, + std::pair{"millisecond"sv, &local_time_parameters.millisecond}, + std::pair{"microsecond"sv, &local_time_parameters.microsecond}, + }; + + MapNumericParameters<Integer>(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::LocalDateTime(date_parameters, local_time_parameters), ctx.memory); +} + +template <typename TypedValueT, typename FunctionContextT> +TypedValueT Duration(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType<TypedValueT, Or<String, Map>>("duration", args, nargs); + + if (args[0].IsString()) { + return TypedValueT(utils::Duration(ParseDurationParameters(args[0].ValueString())), ctx.memory); + } + + utils::DurationParameters duration_parameters; + using namespace std::literals; + std::unordered_map parameter_mappings{std::pair{"day"sv, &duration_parameters.day}, + std::pair{"hour"sv, &duration_parameters.hour}, + std::pair{"minute"sv, &duration_parameters.minute}, + std::pair{"second"sv, &duration_parameters.second}, + std::pair{"millisecond"sv, &duration_parameters.millisecond}, + std::pair{"microsecond"sv, &duration_parameters.microsecond}}; + MapNumericParameters<Number>(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::Duration(duration_parameters), ctx.memory); +} + +} // namespace memgraph::functions::impl + +namespace memgraph::functions { + +template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv> +std::function<TypedValueT(const TypedValueT *arguments, int64_t num_arguments, const FunctionContextT &context)> +NameToFunction(const std::string &function_name) { + // Scalar functions + if (function_name == "DEGREE") return functions::impl::Degree<TypedValueT, FunctionContextT, Tag>; + if (function_name == "INDEGREE") return functions::impl::InDegree<TypedValueT, FunctionContextT, Tag>; + if (function_name == "OUTDEGREE") return functions::impl::OutDegree<TypedValueT, FunctionContextT, Tag>; + if (function_name == "ENDNODE") return functions::impl::EndNode<TypedValueT, FunctionContextT, Tag>; + if (function_name == "HEAD") return functions::impl::Head<TypedValueT, FunctionContextT>; + if (function_name == kId) return functions::impl::Id<TypedValueT, FunctionContextT>; + if (function_name == "LAST") return functions::impl::Last<TypedValueT, FunctionContextT>; + if (function_name == "PROPERTIES") return functions::impl::Properties<TypedValueT, FunctionContextT, Tag, Conv>; + if (function_name == "SIZE") return functions::impl::Size<TypedValueT, FunctionContextT>; + if (function_name == "STARTNODE") return functions::impl::StartNode<TypedValueT, FunctionContextT, Tag, Conv>; + if (function_name == "TIMESTAMP") return functions::impl::Timestamp<TypedValueT, FunctionContextT>; + if (function_name == "TOBOOLEAN") return functions::impl::ToBoolean<TypedValueT, FunctionContextT>; + if (function_name == "TOFLOAT") return functions::impl::ToFloat<TypedValueT, FunctionContextT>; + if (function_name == "TOINTEGER") return functions::impl::ToInteger<TypedValueT, FunctionContextT>; + if (function_name == "TYPE") return functions::impl::Type<TypedValueT, FunctionContextT>; + if (function_name == "VALUETYPE") return functions::impl::ValueType<TypedValueT, FunctionContextT>; + + // List functions + if (function_name == "KEYS") return functions::impl::Keys<TypedValueT, FunctionContextT, Tag>; + if (function_name == "LABELS") return functions::impl::Labels<TypedValueT, FunctionContextT, Tag>; + if (function_name == "NODES") return functions::impl::Nodes<TypedValueT, FunctionContextT>; + if (function_name == "RANGE") return functions::impl::Range<TypedValueT, FunctionContextT>; + if (function_name == "RELATIONSHIPS") return functions::impl::Relationships<TypedValueT, FunctionContextT>; + if (function_name == "TAIL") return functions::impl::Tail<TypedValueT, FunctionContextT>; + if (function_name == "UNIFORMSAMPLE") return functions::impl::UniformSample<TypedValueT, FunctionContextT>; + + // Mathematical functions - numeric + if (function_name == "ABS") return functions::impl::Abs<TypedValueT, FunctionContextT>; + if (function_name == "CEIL") return functions::impl::Ceil<TypedValueT, FunctionContextT>; + if (function_name == "FLOOR") return functions::impl::Floor<TypedValueT, FunctionContextT>; + if (function_name == "RAND") return functions::impl::Rand<TypedValueT, FunctionContextT>; + if (function_name == "ROUND") return functions::impl::Round<TypedValueT, FunctionContextT>; + if (function_name == "SIGN") return functions::impl::Sign<TypedValueT, FunctionContextT>; + + // Mathematical functions - logarithmic + if (function_name == "E") return functions::impl::E<TypedValueT, FunctionContextT>; + if (function_name == "EXP") return functions::impl::Exp<TypedValueT, FunctionContextT>; + if (function_name == "LOG") return functions::impl::Log<TypedValueT, FunctionContextT>; + if (function_name == "LOG10") return functions::impl::Log10<TypedValueT, FunctionContextT>; + if (function_name == "SQRT") return functions::impl::Sqrt<TypedValueT, FunctionContextT>; + + // Mathematical functions - trigonometric + if (function_name == "ACOS") return functions::impl::Acos<TypedValueT, FunctionContextT>; + if (function_name == "ASIN") return functions::impl::Asin<TypedValueT, FunctionContextT>; + if (function_name == "ATAN") return functions::impl::Atan<TypedValueT, FunctionContextT>; + if (function_name == "ATAN2") return functions::impl::Atan2<TypedValueT, FunctionContextT>; + if (function_name == "COS") return functions::impl::Cos<TypedValueT, FunctionContextT>; + if (function_name == "PI") return functions::impl::Pi<TypedValueT, FunctionContextT>; + if (function_name == "SIN") return functions::impl::Sin<TypedValueT, FunctionContextT>; + if (function_name == "TAN") return functions::impl::Tan<TypedValueT, FunctionContextT>; + + // String functions + if (function_name == kContains) return functions::impl::Contains<TypedValueT, FunctionContextT>; + if (function_name == kEndsWith) return functions::impl::EndsWith<TypedValueT, FunctionContextT>; + if (function_name == "LEFT") return functions::impl::Left<TypedValueT, FunctionContextT>; + if (function_name == "LTRIM") return functions::impl::LTrim<TypedValueT, FunctionContextT>; + if (function_name == "REPLACE") return functions::impl::Replace<TypedValueT, FunctionContextT>; + if (function_name == "REVERSE") return functions::impl::Reverse<TypedValueT, FunctionContextT>; + if (function_name == "RIGHT") return functions::impl::Right<TypedValueT, FunctionContextT>; + if (function_name == "RTRIM") return functions::impl::RTrim<TypedValueT, FunctionContextT>; + if (function_name == "SPLIT") return functions::impl::Split<TypedValueT, FunctionContextT>; + if (function_name == kStartsWith) return functions::impl::StartsWith<TypedValueT, FunctionContextT>; + if (function_name == "SUBSTRING") return functions::impl::Substring<TypedValueT, FunctionContextT>; + if (function_name == "TOLOWER") return functions::impl::ToLower<TypedValueT, FunctionContextT>; + if (function_name == "TOSTRING") return functions::impl::ToString<TypedValueT, FunctionContextT>; + if (function_name == "TOUPPER") return functions::impl::ToUpper<TypedValueT, FunctionContextT>; + if (function_name == "TRIM") return functions::impl::Trim<TypedValueT, FunctionContextT>; + + // Memgraph specific functions + if (function_name == "ASSERT") return functions::impl::Assert<TypedValueT, FunctionContextT>; + if (function_name == "COUNTER") return functions::impl::Counter<TypedValueT, FunctionContextT>; + if (function_name == "TOBYTESTRING") return functions::impl::ToByteString<TypedValueT, FunctionContextT>; + if (function_name == "FROMBYTESTRING") return functions::impl::FromByteString<TypedValueT, FunctionContextT>; + + // Functions for temporal types + if (function_name == "DATE") return functions::impl::Date<TypedValueT, FunctionContextT>; + if (function_name == "LOCALTIME") return functions::impl::LocalTime<TypedValueT, FunctionContextT>; + if (function_name == "LOCALDATETIME") return functions::impl::LocalDateTime<TypedValueT, FunctionContextT>; + if (function_name == "DURATION") return functions::impl::Duration<TypedValueT, FunctionContextT>; + + return nullptr; +} + +} // namespace memgraph::functions diff --git a/src/query/v2/CMakeLists.txt b/src/query/v2/CMakeLists.txt index 3c3f780c8..3ecaf63f9 100644 --- a/src/query/v2/CMakeLists.txt +++ b/src/query/v2/CMakeLists.txt @@ -11,7 +11,6 @@ set(mg_query_v2_sources cypher_query_interpreter.cpp frontend/semantic/required_privileges.cpp frontend/stripped.cpp - interpret/awesome_memgraph_functions.cpp interpreter.cpp metadata.cpp plan/operator.cpp @@ -34,7 +33,7 @@ target_include_directories(mg-query-v2 PUBLIC ${CMAKE_SOURCE_DIR}/include) target_include_directories(mg-query-v2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bindings) target_link_libraries(mg-query-v2 dl cppitertools Boost::headers) target_link_libraries(mg-query-v2 mg-integrations-pulsar mg-integrations-kafka mg-storage-v3 mg-license mg-utils mg-kvstore mg-memory mg-coordinator) -target_link_libraries(mg-query-v2 mg-expr) +target_link_libraries(mg-query-v2 mg-expr mg-functions) if(NOT "${MG_PYTHON_PATH}" STREQUAL "") set(Python3_ROOT_DIR "${MG_PYTHON_PATH}") diff --git a/src/query/v2/accessors.hpp b/src/query/v2/accessors.hpp index 8e10c865d..73cc24ba2 100644 --- a/src/query/v2/accessors.hpp +++ b/src/query/v2/accessors.hpp @@ -136,9 +136,11 @@ class VertexAccessor final { // return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges)); // } - // storage::Result<size_t> InDegree(storage::View view) const { return impl_.InDegree(view); } - // - // storage::Result<size_t> OutDegree(storage::View view) const { return impl_.OutDegree(view); } + // NOLINTNEXTLINE(readability-convert-member-functions-to-static) + [[nodiscard]] size_t InDegree() const { return 0; } + + // NOLINTNEXTLINE(readability-convert-member-functions-to-static) + [[nodiscard]] size_t OutDegree() const { return 0; } // friend bool operator==(const VertexAccessor &lhs, const VertexAccessor &rhs) { @@ -153,10 +155,6 @@ class VertexAccessor final { const msgs::ShardRequestManagerInterface *manager_; }; -// inline VertexAccessor EdgeAccessor::To() const { return VertexAccessor(impl_.ToVertex()); } - -// inline VertexAccessor EdgeAccessor::From() const { return VertexAccessor(impl_.FromVertex()); } - // Highly mocked interface. Won't work if used. class Path { public: @@ -197,7 +195,14 @@ class Path { friend bool operator==(const Path & /*lhs*/, const Path & /*rhs*/) { return true; }; utils::MemoryResource *GetMemoryResource() { return mem; } + auto &vertices() { return vertices_; } + auto &edges() { return edges_; } + const auto &vertices() const { return vertices_; } + const auto &edges() const { return edges_; } + private: + std::vector<VertexAccessor> vertices_; + std::vector<EdgeAccessor> edges_; utils::MemoryResource *mem = utils::NewDeleteResource(); }; } // namespace memgraph::query::v2::accessors diff --git a/src/query/v2/conversions.hpp b/src/query/v2/conversions.hpp index 10299c919..4556e46bc 100644 --- a/src/query/v2/conversions.hpp +++ b/src/query/v2/conversions.hpp @@ -56,6 +56,10 @@ inline TypedValue ValueToTypedValue(const msgs::Value &value, msgs::ShardRequest throw std::runtime_error("Incorrect type in conversion"); } +inline const auto ValueToTypedValueFunctor = [](const msgs::Value &value, msgs::ShardRequestManagerInterface *manager) { + return ValueToTypedValue(value, manager); +}; + inline msgs::Value TypedValueToValue(const TypedValue &value) { using Value = msgs::Value; switch (value.type()) { diff --git a/src/query/v2/frontend/ast/ast.lcp b/src/query/v2/frontend/ast/ast.lcp index e30e623ea..209bdfd50 100644 --- a/src/query/v2/frontend/ast/ast.lcp +++ b/src/query/v2/frontend/ast/ast.lcp @@ -20,11 +20,13 @@ #include "query/v2/bindings/ast_visitor.hpp" #include "common/types.hpp" #include "query/v2/bindings/symbol.hpp" -#include "query/v2/interpret/awesome_memgraph_functions.hpp" +#include "functions/awesome_memgraph_functions.hpp" #include "query/v2/bindings/typed_value.hpp" #include "query/v2/db_accessor.hpp" #include "query/v2/path.hpp" +#include "query/v2/shard_request_manager.hpp" #include "utils/typeinfo.hpp" +#include "query/v2/conversions.hpp" cpp<# @@ -836,13 +838,15 @@ cpp<# :slk-load (slk-load-ast-vector "Expression")) (function-name "std::string" :scope :public) (function "std::function<TypedValue(const TypedValue *, int64_t, - const FunctionContext &)>" + const functions::FunctionContext<msgs::ShardRequestManagerInterface> &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp - self->${member} = query::v2::NameToFunction(self->function_name_); + self->${member} = functions::NameToFunction<TypedValue, + functions::FunctionContext<msgs::ShardRequestManagerInterface>, + functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(self->function_name_); cpp<#))) (:public #>cpp @@ -865,7 +869,8 @@ cpp<# const std::vector<Expression *> &arguments) : arguments_(arguments), function_name_(function_name), - function_(NameToFunction(function_name_)) { + function_(functions::NameToFunction<TypedValue, functions::FunctionContext<msgs::ShardRequestManagerInterface>, + functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(function_name_)) { if (!function_) { throw SemanticException("Function '{}' doesn't exist.", function_name); } diff --git a/src/query/v2/interpret/awesome_memgraph_functions.cpp b/src/query/v2/interpret/awesome_memgraph_functions.cpp deleted file mode 100644 index 8768736b2..000000000 --- a/src/query/v2/interpret/awesome_memgraph_functions.cpp +++ /dev/null @@ -1,1108 +0,0 @@ -// Copyright 2022 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 "query/v2/interpret/awesome_memgraph_functions.hpp" - -#include <algorithm> -#include <cctype> -#include <cmath> -#include <cstdlib> -#include <functional> -#include <random> -#include <string_view> -#include <type_traits> - -#include "query/v2/bindings/typed_value.hpp" -#include "query/v2/conversions.hpp" -#include "query/v2/exceptions.hpp" -#include "query/v2/shard_request_manager.hpp" -#include "storage/v3/conversions.hpp" -#include "utils/string.hpp" -#include "utils/temporal.hpp" - -namespace memgraph::query::v2 { -namespace { - -//////////////////////////////////////////////////////////////////////////////// -// eDSL using template magic for describing a type of an awesome memgraph -// function and checking if the passed in arguments match the description. -// -// To use the type checking eDSL, you should put a `FType` invocation in the -// body of your awesome Memgraph function. `FType` takes type arguments as the -// description of the function type signature. Each runtime argument will be -// checked in order corresponding to given compile time type arguments. These -// type arguments can come in two forms: -// -// * final, primitive type descriptor and -// * combinator type descriptor. -// -// The primitive type descriptors are defined as empty structs, they are right -// below this documentation. -// -// Combinator type descriptors are defined as structs taking additional type -// parameters, you can find these further below in the implementation. Of -// primary interest are `Or` and `Optional` type combinators. -// -// With `Or` you can describe that an argument can be any of the types listed in -// `Or`. For example, `Or<Null, Bool, Integer>` allows an argument to be either -// `Null` or a boolean or an integer. -// -// The `Optional` combinator is used to define optional arguments to a function. -// These must come as the last positional arguments. Naturally, you can use `Or` -// inside `Optional`. So for example, `Optional<Or<Null, Bool>, Integer>` -// describes that a function takes 2 optional arguments. The 1st one must be -// either a `Null` or a boolean, while the 2nd one must be an integer. The type -// signature check will succeed in the following cases. -// -// * No optional arguments were supplied. -// * One argument was supplied and it passes `Or<Null, Bool>` check. -// * Two arguments were supplied, the 1st one passes `Or<Null, Bool>` check -// and the 2nd one passes `Integer` check. -// -// Runtime arguments to `FType` are: function name, pointer to arguments and the -// number of received arguments. -// -// Full example. -// -// FType<Or<Null, String>, NonNegativeInteger, -// Optional<NonNegativeInteger>>("substring", args, nargs); -// -// The above will check that `substring` function received the 2 required -// arguments. Optionally, the function may take a 3rd argument. The 1st argument -// must be either a `Null` or a character string. The 2nd argument is required -// to be a non-negative integer. If the 3rd argument was supplied, it will also -// be checked that it is a non-negative integer. If any of these checks fail, -// `FType` will throw a `QueryRuntimeException` with an appropriate error -// message. -//////////////////////////////////////////////////////////////////////////////// - -struct Null {}; -struct Bool {}; -struct Integer {}; -struct PositiveInteger {}; -struct NonZeroInteger {}; -struct NonNegativeInteger {}; -struct Double {}; -struct Number {}; -struct List {}; -struct String {}; -struct Map {}; -struct Edge {}; -struct Vertex {}; -struct Path {}; -struct Date {}; -struct LocalTime {}; -struct LocalDateTime {}; -struct Duration {}; - -template <class ArgType> -bool ArgIsType(const TypedValue &arg) { - if constexpr (std::is_same_v<ArgType, Null>) { - return arg.IsNull(); - } else if constexpr (std::is_same_v<ArgType, Bool>) { - return arg.IsBool(); - } else if constexpr (std::is_same_v<ArgType, Integer>) { - return arg.IsInt(); - } else if constexpr (std::is_same_v<ArgType, PositiveInteger>) { - return arg.IsInt() && arg.ValueInt() > 0; - } else if constexpr (std::is_same_v<ArgType, NonZeroInteger>) { - return arg.IsInt() && arg.ValueInt() != 0; - } else if constexpr (std::is_same_v<ArgType, NonNegativeInteger>) { - return arg.IsInt() && arg.ValueInt() >= 0; - } else if constexpr (std::is_same_v<ArgType, Double>) { - return arg.IsDouble(); - } else if constexpr (std::is_same_v<ArgType, Number>) { - return arg.IsNumeric(); - } else if constexpr (std::is_same_v<ArgType, List>) { - return arg.IsList(); - } else if constexpr (std::is_same_v<ArgType, String>) { - return arg.IsString(); - } else if constexpr (std::is_same_v<ArgType, Map>) { - return arg.IsMap(); - } else if constexpr (std::is_same_v<ArgType, Vertex>) { - return arg.IsVertex(); - } else if constexpr (std::is_same_v<ArgType, Edge>) { - return arg.IsEdge(); - } else if constexpr (std::is_same_v<ArgType, Path>) { - return arg.IsPath(); - } else if constexpr (std::is_same_v<ArgType, Date>) { - return arg.IsDate(); - } else if constexpr (std::is_same_v<ArgType, LocalTime>) { - return arg.IsLocalTime(); - } else if constexpr (std::is_same_v<ArgType, LocalDateTime>) { - return arg.IsLocalDateTime(); - } else if constexpr (std::is_same_v<ArgType, Duration>) { - return arg.IsDuration(); - } else if constexpr (std::is_same_v<ArgType, void>) { - return true; - } else { - static_assert(std::is_same_v<ArgType, Null>, "Unknown ArgType"); - } - return false; -} - -template <class ArgType> -constexpr const char *ArgTypeName() { - // The type names returned should be standardized openCypher type names. - // https://github.com/opencypher/openCypher/blob/master/docs/openCypher9.pdf - if constexpr (std::is_same_v<ArgType, Null>) { - return "null"; - } else if constexpr (std::is_same_v<ArgType, Bool>) { - return "boolean"; - } else if constexpr (std::is_same_v<ArgType, Integer>) { - return "integer"; - } else if constexpr (std::is_same_v<ArgType, PositiveInteger>) { - return "positive integer"; - } else if constexpr (std::is_same_v<ArgType, NonZeroInteger>) { - return "non-zero integer"; - } else if constexpr (std::is_same_v<ArgType, NonNegativeInteger>) { - return "non-negative integer"; - } else if constexpr (std::is_same_v<ArgType, Double>) { - return "float"; - } else if constexpr (std::is_same_v<ArgType, Number>) { - return "number"; - } else if constexpr (std::is_same_v<ArgType, List>) { - return "list"; - } else if constexpr (std::is_same_v<ArgType, String>) { - return "string"; - } else if constexpr (std::is_same_v<ArgType, Map>) { - return "map"; - } else if constexpr (std::is_same_v<ArgType, Vertex>) { - return "node"; - } else if constexpr (std::is_same_v<ArgType, Edge>) { - return "relationship"; - } else if constexpr (std::is_same_v<ArgType, Path>) { - return "path"; - } else if constexpr (std::is_same_v<ArgType, void>) { - return "void"; - } else if constexpr (std::is_same_v<ArgType, Date>) { - return "Date"; - } else if constexpr (std::is_same_v<ArgType, LocalTime>) { - return "LocalTime"; - } else if constexpr (std::is_same_v<ArgType, LocalDateTime>) { - return "LocalDateTime"; - } else if constexpr (std::is_same_v<ArgType, Duration>) { - return "Duration"; - } else { - static_assert(std::is_same_v<ArgType, Null>, "Unknown ArgType"); - } - return "<unknown-type>"; -} - -template <class... ArgType> -struct Or; - -template <class ArgType> -struct Or<ArgType> { - static bool Check(const TypedValue &arg) { return ArgIsType<ArgType>(arg); } - - static std::string TypeNames() { return ArgTypeName<ArgType>(); } -}; - -template <class ArgType, class... ArgTypes> -struct Or<ArgType, ArgTypes...> { - static bool Check(const TypedValue &arg) { - if (ArgIsType<ArgType>(arg)) return true; - return Or<ArgTypes...>::Check(arg); - } - - static std::string TypeNames() { - if constexpr (sizeof...(ArgTypes) > 1) { - return fmt::format("'{}', {}", ArgTypeName<ArgType>(), Or<ArgTypes...>::TypeNames()); - } else { - return fmt::format("'{}' or '{}'", ArgTypeName<ArgType>(), Or<ArgTypes...>::TypeNames()); - } - } -}; - -template <class T> -struct IsOrType { - static constexpr bool value = false; -}; - -template <class... ArgTypes> -struct IsOrType<Or<ArgTypes...>> { - static constexpr bool value = true; -}; - -template <class... ArgTypes> -struct Optional; - -template <class ArgType> -struct Optional<ArgType> { - static constexpr size_t size = 1; - - static void Check(const char *name, const TypedValue *args, int64_t nargs, int64_t pos) { - if (nargs == 0) return; - const TypedValue &arg = args[0]; - if constexpr (IsOrType<ArgType>::value) { - if (!ArgType::Check(arg)) { - throw QueryRuntimeException("Optional '{}' argument at position {} must be either {}.", name, pos, - ArgType::TypeNames()); - } - } else { - if (!ArgIsType<ArgType>(arg)) - throw QueryRuntimeException("Optional '{}' argument at position {} must be '{}'.", name, pos, - ArgTypeName<ArgType>()); - } - } -}; - -template <class ArgType, class... ArgTypes> -struct Optional<ArgType, ArgTypes...> { - static constexpr size_t size = 1 + sizeof...(ArgTypes); - - static void Check(const char *name, const TypedValue *args, int64_t nargs, int64_t pos) { - if (nargs == 0) return; - Optional<ArgType>::Check(name, args, nargs, pos); - Optional<ArgTypes...>::Check(name, args + 1, nargs - 1, pos + 1); - } -}; - -template <class T> -struct IsOptional { - static constexpr bool value = false; -}; - -template <class... ArgTypes> -struct IsOptional<Optional<ArgTypes...>> { - static constexpr bool value = true; -}; - -template <class ArgType, class... ArgTypes> -constexpr size_t FTypeRequiredArgs() { - if constexpr (IsOptional<ArgType>::value) { - static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); - return 0; - } else if constexpr (sizeof...(ArgTypes) == 0) { - return 1; - } else { - return 1U + FTypeRequiredArgs<ArgTypes...>(); - } -} - -template <class ArgType, class... ArgTypes> -constexpr size_t FTypeOptionalArgs() { - if constexpr (IsOptional<ArgType>::value) { - static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); - return ArgType::size; - } else if constexpr (sizeof...(ArgTypes) == 0) { - return 0; - } else { - return FTypeOptionalArgs<ArgTypes...>(); - } -} - -template <class ArgType, class... ArgTypes> -void FType(const char *name, const TypedValue *args, int64_t nargs, int64_t pos = 1) { - if constexpr (std::is_same_v<ArgType, void>) { - if (nargs != 0) { - throw QueryRuntimeException("'{}' requires no arguments.", name); - } - return; - } - static constexpr int64_t required_args = FTypeRequiredArgs<ArgType, ArgTypes...>(); - static constexpr int64_t optional_args = FTypeOptionalArgs<ArgType, ArgTypes...>(); - static constexpr int64_t total_args = required_args + optional_args; - if constexpr (optional_args > 0) { - if (nargs < required_args || nargs > total_args) { - throw QueryRuntimeException("'{}' requires between {} and {} arguments.", name, required_args, total_args); - } - } else { - if (nargs != required_args) { - throw QueryRuntimeException("'{}' requires exactly {} {}.", name, required_args, - required_args == 1 ? "argument" : "arguments"); - } - } - const TypedValue &arg = args[0]; - if constexpr (IsOrType<ArgType>::value) { - if (!ArgType::Check(arg)) { - throw QueryRuntimeException("'{}' argument at position {} must be either {}.", name, pos, ArgType::TypeNames()); - } - } else if constexpr (IsOptional<ArgType>::value) { - static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); - ArgType::Check(name, args, nargs, pos); - } else { - if (!ArgIsType<ArgType>(arg)) { - throw QueryRuntimeException("'{}' argument at position {} must be '{}'", name, pos, ArgTypeName<ArgType>()); - } - } - if constexpr (sizeof...(ArgTypes) > 0) { - FType<ArgTypes...>(name, args + 1, nargs - 1, pos + 1); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// END function type description eDSL -//////////////////////////////////////////////////////////////////////////////// - -// Predicate functions. -// Neo4j has all, any, exists, none, single -// Those functions are a little bit different since they take a filterExpression -// as an argument. -// There is all, any, none and single productions in opencypher grammar, but it -// will be trivial to also add exists. -// TODO: Implement this. - -// Scalar functions. -// We don't have a way to implement id function since we don't store any. If it -// is really neccessary we could probably map vlist* to id. -// TODO: Implement length (it works on a path, but we didn't define path -// structure yet). -// TODO: Implement size(pattern), for example size((a)-[:X]-()) should return -// number of results of this pattern. I don't think we will ever do this. -// TODO: Implement rest of the list functions. -// TODO: Implement degrees, haversin, radians -// TODO: Implement spatial functions - -TypedValue EndNode(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Edge>>("endNode", args, nargs); - if (args[0].IsNull()) return TypedValue(ctx.memory); - return TypedValue(args[0].ValueEdge().To(), ctx.memory); -} - -TypedValue Head(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, List>>("head", args, nargs); - if (args[0].IsNull()) return TypedValue(ctx.memory); - const auto &list = args[0].ValueList(); - if (list.empty()) return TypedValue(ctx.memory); - return TypedValue(list[0], ctx.memory); -} - -TypedValue Last(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, List>>("last", args, nargs); - if (args[0].IsNull()) return TypedValue(ctx.memory); - const auto &list = args[0].ValueList(); - if (list.empty()) return TypedValue(ctx.memory); - return TypedValue(list.back(), ctx.memory); -} - -TypedValue Properties(const TypedValue * /*args*/, int64_t /*nargs*/, const FunctionContext & /*ctx*/) { return {}; } - -TypedValue Size(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, List, String, Map, Path>>("size", args, nargs); - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsList()) { - return TypedValue(static_cast<int64_t>(value.ValueList().size()), ctx.memory); - } else if (value.IsString()) { - return TypedValue(static_cast<int64_t>(value.ValueString().size()), ctx.memory); - } else if (value.IsMap()) { - // neo4j doesn't implement size for map, but I don't see a good reason not - // to do it. - return TypedValue(static_cast<int64_t>(value.ValueMap().size()), ctx.memory); - } else { - // TODO(kostasrim) Fix the dummy return - return TypedValue(int64_t(0), ctx.memory); - } -} - -TypedValue StartNode(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Edge>>("startNode", args, nargs); - if (args[0].IsNull()) return TypedValue(ctx.memory); - return TypedValue(args[0].ValueEdge().From(), ctx.memory); -} - -TypedValue ToBoolean(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Bool, Integer, String>>("toBoolean", args, nargs); - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsBool()) { - return TypedValue(value.ValueBool(), ctx.memory); - } else if (value.IsInt()) { - return TypedValue(value.ValueInt() != 0L, ctx.memory); - } else { - auto s = utils::ToUpperCase(utils::Trim(value.ValueString())); - if (s == "TRUE") return TypedValue(true, ctx.memory); - if (s == "FALSE") return TypedValue(false, ctx.memory); - // I think this is just stupid and that exception should be thrown, but - // neo4j does it this way... - return TypedValue(ctx.memory); - } -} - -TypedValue ToFloat(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Number, String>>("toFloat", args, nargs); - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsInt()) { - return TypedValue(static_cast<double>(value.ValueInt()), ctx.memory); - } else if (value.IsDouble()) { - return TypedValue(value, ctx.memory); - } else { - try { - return TypedValue(utils::ParseDouble(utils::Trim(value.ValueString())), ctx.memory); - } catch (const utils::BasicException &) { - return TypedValue(ctx.memory); - } - } -} - -TypedValue ToInteger(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Bool, Number, String>>("toInteger", args, nargs); - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsBool()) { - return TypedValue(value.ValueBool() ? 1L : 0L, ctx.memory); - } else if (value.IsInt()) { - return TypedValue(value, ctx.memory); - } else if (value.IsDouble()) { - return TypedValue(static_cast<int64_t>(value.ValueDouble()), ctx.memory); - } else { - try { - // Yup, this is correct. String is valid if it has floating point - // number, then it is parsed and converted to int. - return TypedValue(static_cast<int64_t>(utils::ParseDouble(utils::Trim(value.ValueString()))), ctx.memory); - } catch (const utils::BasicException &) { - return TypedValue(ctx.memory); - } - } -} - -TypedValue Type(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Edge>>("type", args, nargs); - if (args[0].IsNull()) return TypedValue(ctx.memory); - return TypedValue(args[0].ValueEdge().EdgeType().AsInt(), ctx.memory); -} - -TypedValue ValueType(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Bool, Integer, Double, String, List, Map, Vertex, Edge, Path>>("type", args, nargs); - // The type names returned should be standardized openCypher type names. - // https://github.com/opencypher/openCypher/blob/master/docs/openCypher9.pdf - switch (args[0].type()) { - case TypedValue::Type::Null: - return TypedValue("NULL", ctx.memory); - case TypedValue::Type::Bool: - return TypedValue("BOOLEAN", ctx.memory); - case TypedValue::Type::Int: - return TypedValue("INTEGER", ctx.memory); - case TypedValue::Type::Double: - return TypedValue("FLOAT", ctx.memory); - case TypedValue::Type::String: - return TypedValue("STRING", ctx.memory); - case TypedValue::Type::List: - return TypedValue("LIST", ctx.memory); - case TypedValue::Type::Map: - return TypedValue("MAP", ctx.memory); - case TypedValue::Type::Vertex: - return TypedValue("NODE", ctx.memory); - case TypedValue::Type::Edge: - return TypedValue("RELATIONSHIP", ctx.memory); - case TypedValue::Type::Path: - return TypedValue("PATH", ctx.memory); - case TypedValue::Type::Date: - return TypedValue("DATE", ctx.memory); - case TypedValue::Type::LocalTime: - return TypedValue("LOCAL_TIME", ctx.memory); - case TypedValue::Type::LocalDateTime: - return TypedValue("LOCAL_DATE_TIME", ctx.memory); - case TypedValue::Type::Duration: - return TypedValue("DURATION", ctx.memory); - } -} - -TypedValue Range(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Integer>, Or<Null, Integer>, Optional<Or<Null, NonZeroInteger>>>("range", args, nargs); - for (int64_t i = 0; i < nargs; ++i) - if (args[i].IsNull()) return TypedValue(ctx.memory); - auto lbound = args[0].ValueInt(); - auto rbound = args[1].ValueInt(); - int64_t step = nargs == 3 ? args[2].ValueInt() : 1; - TypedValue::TVector list(ctx.memory); - if (lbound <= rbound && step > 0) { - for (auto i = lbound; i <= rbound; i += step) { - list.emplace_back(i); - } - } else if (lbound >= rbound && step < 0) { - for (auto i = lbound; i >= rbound; i += step) { - list.emplace_back(i); - } - } - return TypedValue(std::move(list)); -} - -TypedValue Tail(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, List>>("tail", args, nargs); - if (args[0].IsNull()) return TypedValue(ctx.memory); - TypedValue::TVector list(args[0].ValueList(), ctx.memory); - if (list.empty()) return TypedValue(std::move(list)); - list.erase(list.begin()); - return TypedValue(std::move(list)); -} - -TypedValue UniformSample(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, List>, Or<Null, NonNegativeInteger>>("uniformSample", args, nargs); - static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()}; - if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); - const auto &population = args[0].ValueList(); - auto population_size = population.size(); - if (population_size == 0) return TypedValue(ctx.memory); - auto desired_length = args[1].ValueInt(); - std::uniform_int_distribution<uint64_t> rand_dist{0, population_size - 1}; - TypedValue::TVector sampled(ctx.memory); - sampled.reserve(desired_length); - for (int64_t i = 0; i < desired_length; ++i) { - sampled.emplace_back(population[rand_dist(pseudo_rand_gen_)]); - } - return TypedValue(std::move(sampled)); -} - -TypedValue Abs(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Number>>("abs", args, nargs); - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsInt()) { - return TypedValue(std::abs(value.ValueInt()), ctx.memory); - } else { - return TypedValue(std::abs(value.ValueDouble()), ctx.memory); - } -} - -#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \ - TypedValue name(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { \ - FType<Or<Null, Number>>(#lowercased_name, args, nargs); \ - const auto &value = args[0]; \ - if (value.IsNull()) { \ - return TypedValue(ctx.memory); \ - } else if (value.IsInt()) { \ - return TypedValue(lowercased_name(value.ValueInt()), ctx.memory); \ - } else { \ - return TypedValue(lowercased_name(value.ValueDouble()), ctx.memory); \ - } \ - } - -WRAP_CMATH_FLOAT_FUNCTION(Ceil, ceil) -WRAP_CMATH_FLOAT_FUNCTION(Floor, floor) -// We are not completely compatible with neoj4 in this function because, -// neo4j rounds -0.5, -1.5, -2.5... to 0, -1, -2... -WRAP_CMATH_FLOAT_FUNCTION(Round, round) -WRAP_CMATH_FLOAT_FUNCTION(Exp, exp) -WRAP_CMATH_FLOAT_FUNCTION(Log, log) -WRAP_CMATH_FLOAT_FUNCTION(Log10, log10) -WRAP_CMATH_FLOAT_FUNCTION(Sqrt, sqrt) -WRAP_CMATH_FLOAT_FUNCTION(Acos, acos) -WRAP_CMATH_FLOAT_FUNCTION(Asin, asin) -WRAP_CMATH_FLOAT_FUNCTION(Atan, atan) -WRAP_CMATH_FLOAT_FUNCTION(Cos, cos) -WRAP_CMATH_FLOAT_FUNCTION(Sin, sin) -WRAP_CMATH_FLOAT_FUNCTION(Tan, tan) - -#undef WRAP_CMATH_FLOAT_FUNCTION - -TypedValue Atan2(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Number>, Or<Null, Number>>("atan2", args, nargs); - if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); - auto to_double = [](const TypedValue &t) -> double { - if (t.IsInt()) { - return t.ValueInt(); - } else { - return t.ValueDouble(); - } - }; - double y = to_double(args[0]); - double x = to_double(args[1]); - return TypedValue(atan2(y, x), ctx.memory); -} - -TypedValue Sign(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Number>>("sign", args, nargs); - auto sign = [&](auto x) { return TypedValue((0 < x) - (x < 0), ctx.memory); }; - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsInt()) { - return sign(value.ValueInt()); - } else { - return sign(value.ValueDouble()); - } -} - -TypedValue E(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<void>("e", args, nargs); - return TypedValue(M_E, ctx.memory); -} - -TypedValue Pi(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<void>("pi", args, nargs); - return TypedValue(M_PI, ctx.memory); -} - -TypedValue Rand(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<void>("rand", args, nargs); - static thread_local std::mt19937 pseudo_rand_gen_{std::random_device{}()}; - static thread_local std::uniform_real_distribution<> rand_dist_{0, 1}; - return TypedValue(rand_dist_(pseudo_rand_gen_), ctx.memory); -} - -template <class TPredicate> -TypedValue StringMatchOperator(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, String>, Or<Null, String>>(TPredicate::name, args, nargs); - if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); - const auto &s1 = args[0].ValueString(); - const auto &s2 = args[1].ValueString(); - return TypedValue(TPredicate{}(s1, s2), ctx.memory); -} - -// Check if s1 starts with s2. -struct StartsWithPredicate { - static constexpr const char *name = "startsWith"; - bool operator()(const TypedValue::TString &s1, const TypedValue::TString &s2) const { - if (s1.size() < s2.size()) return false; - return std::equal(s2.begin(), s2.end(), s1.begin()); - } -}; -auto StartsWith = StringMatchOperator<StartsWithPredicate>; - -// Check if s1 ends with s2. -struct EndsWithPredicate { - static constexpr const char *name = "endsWith"; - bool operator()(const TypedValue::TString &s1, const TypedValue::TString &s2) const { - if (s1.size() < s2.size()) return false; - return std::equal(s2.rbegin(), s2.rend(), s1.rbegin()); - } -}; -auto EndsWith = StringMatchOperator<EndsWithPredicate>; - -// Check if s1 contains s2. -struct ContainsPredicate { - static constexpr const char *name = "contains"; - bool operator()(const TypedValue::TString &s1, const TypedValue::TString &s2) const { - if (s1.size() < s2.size()) return false; - return s1.find(s2) != std::string::npos; - } -}; -auto Contains = StringMatchOperator<ContainsPredicate>; - -TypedValue Assert(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Bool, Optional<String>>("assert", args, nargs); - if (!args[0].ValueBool()) { - std::string message("Assertion failed"); - if (nargs == 2) { - message += ": "; - message += args[1].ValueString(); - } - message += "."; - throw QueryRuntimeException(message); - } - return TypedValue(args[0], ctx.memory); -} - -TypedValue Counter(const TypedValue *args, int64_t nargs, const FunctionContext &context) { - FType<String, Integer, Optional<NonZeroInteger>>("counter", args, nargs); - int64_t step = 1; - if (nargs == 3) { - step = args[2].ValueInt(); - } - - auto [it, inserted] = context.counters->emplace(args[0].ValueString(), args[1].ValueInt()); - auto value = it->second; - it->second += step; - - return TypedValue(value, context.memory); -} - -TypedValue Id(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, Vertex, Edge>>("id", args, nargs); - const auto &arg = args[0]; - if (arg.IsNull()) { - return TypedValue(ctx.memory); - } else if (arg.IsVertex()) { - return TypedValue(int64_t(arg.ValueVertex().CypherId()), ctx.memory); - } else { - return TypedValue(int64_t(arg.ValueEdge().CypherId()), ctx.memory); - } -} - -TypedValue ToString(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, String, Number, Bool>>("toString", args, nargs); - const auto &arg = args[0]; - if (arg.IsNull()) { - return TypedValue(ctx.memory); - } else if (arg.IsString()) { - return TypedValue(arg, ctx.memory); - } else if (arg.IsInt()) { - // TODO: This is making a pointless copy of std::string, we may want to - // use a different conversion to string - return TypedValue(std::to_string(arg.ValueInt()), ctx.memory); - } else if (arg.IsDouble()) { - return TypedValue(std::to_string(arg.ValueDouble()), ctx.memory); - } else { - return TypedValue(arg.ValueBool() ? "true" : "false", ctx.memory); - } -} - -TypedValue Timestamp(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Optional<Or<Date, LocalTime, LocalDateTime, Duration>>>("timestamp", args, nargs); - const auto &arg = *args; - if (arg.IsDate()) { - return TypedValue(arg.ValueDate().MicrosecondsSinceEpoch(), ctx.memory); - } - if (arg.IsLocalTime()) { - return TypedValue(arg.ValueLocalTime().MicrosecondsSinceEpoch(), ctx.memory); - } - if (arg.IsLocalDateTime()) { - return TypedValue(arg.ValueLocalDateTime().MicrosecondsSinceEpoch(), ctx.memory); - } - if (arg.IsDuration()) { - return TypedValue(arg.ValueDuration().microseconds, ctx.memory); - } - return TypedValue(ctx.timestamp, ctx.memory); -} - -TypedValue Left(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, String>, Or<Null, NonNegativeInteger>>("left", args, nargs); - if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); - return TypedValue(utils::Substr(args[0].ValueString(), 0, args[1].ValueInt()), ctx.memory); -} - -TypedValue Right(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, String>, Or<Null, NonNegativeInteger>>("right", args, nargs); - if (args[0].IsNull() || args[1].IsNull()) return TypedValue(ctx.memory); - const auto &str = args[0].ValueString(); - auto len = args[1].ValueInt(); - return len <= str.size() ? TypedValue(utils::Substr(str, str.size() - len, len), ctx.memory) - : TypedValue(str, ctx.memory); -} - -TypedValue CallStringFunction(const TypedValue *args, int64_t nargs, utils::MemoryResource *memory, const char *name, - std::function<TypedValue::TString(const TypedValue::TString &)> fun) { - FType<Or<Null, String>>(name, args, nargs); - if (args[0].IsNull()) return TypedValue(memory); - return TypedValue(fun(args[0].ValueString()), memory); -} - -TypedValue LTrim(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - return CallStringFunction(args, nargs, ctx.memory, "lTrim", - [&](const auto &str) { return TypedValue::TString(utils::LTrim(str), ctx.memory); }); -} - -TypedValue RTrim(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - return CallStringFunction(args, nargs, ctx.memory, "rTrim", - [&](const auto &str) { return TypedValue::TString(utils::RTrim(str), ctx.memory); }); -} - -TypedValue Trim(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - return CallStringFunction(args, nargs, ctx.memory, "trim", - [&](const auto &str) { return TypedValue::TString(utils::Trim(str), ctx.memory); }); -} - -TypedValue Reverse(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - return CallStringFunction(args, nargs, ctx.memory, "reverse", - [&](const auto &str) { return utils::Reversed(str, ctx.memory); }); -} - -TypedValue ToLower(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - return CallStringFunction(args, nargs, ctx.memory, "toLower", [&](const auto &str) { - TypedValue::TString res(ctx.memory); - utils::ToLowerCase(&res, str); - return res; - }); -} - -TypedValue ToUpper(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - return CallStringFunction(args, nargs, ctx.memory, "toUpper", [&](const auto &str) { - TypedValue::TString res(ctx.memory); - utils::ToUpperCase(&res, str); - return res; - }); -} - -TypedValue Replace(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, String>, Or<Null, String>, Or<Null, String>>("replace", args, nargs); - if (args[0].IsNull() || args[1].IsNull() || args[2].IsNull()) { - return TypedValue(ctx.memory); - } - TypedValue::TString replaced(ctx.memory); - utils::Replace(&replaced, args[0].ValueString(), args[1].ValueString(), args[2].ValueString()); - return TypedValue(std::move(replaced)); -} - -TypedValue Split(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, String>, Or<Null, String>>("split", args, nargs); - if (args[0].IsNull() || args[1].IsNull()) { - return TypedValue(ctx.memory); - } - TypedValue::TVector result(ctx.memory); - utils::Split(&result, args[0].ValueString(), args[1].ValueString()); - return TypedValue(std::move(result)); -} - -TypedValue Substring(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<Null, String>, NonNegativeInteger, Optional<NonNegativeInteger>>("substring", args, nargs); - if (args[0].IsNull()) return TypedValue(ctx.memory); - const auto &str = args[0].ValueString(); - auto start = args[1].ValueInt(); - if (nargs == 2) return TypedValue(utils::Substr(str, start), ctx.memory); - auto len = args[2].ValueInt(); - return TypedValue(utils::Substr(str, start, len), ctx.memory); -} - -TypedValue ToByteString(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<String>("toByteString", args, nargs); - const auto &str = args[0].ValueString(); - if (str.empty()) return TypedValue("", ctx.memory); - if (!utils::StartsWith(str, "0x") && !utils::StartsWith(str, "0X")) { - throw QueryRuntimeException("'toByteString' argument must start with '0x'"); - } - const auto &hex_str = utils::Substr(str, 2); - auto read_hex = [](const char ch) -> unsigned char { - if (ch >= '0' && ch <= '9') return ch - '0'; - if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; - if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; - throw QueryRuntimeException("'toByteString' argument has an invalid character '{}'", ch); - }; - utils::pmr::string bytes(ctx.memory); - bytes.reserve((1 + hex_str.size()) / 2); - size_t i = 0; - // Treat odd length hex string as having a leading zero. - if (hex_str.size() % 2) bytes.append(1, read_hex(hex_str[i++])); - for (; i < hex_str.size(); i += 2) { - unsigned char byte = read_hex(hex_str[i]) * 16U + read_hex(hex_str[i + 1]); - // MemcpyCast in case we are converting to a signed value, so as to avoid - // undefined behaviour. - bytes.append(1, utils::MemcpyCast<decltype(bytes)::value_type>(byte)); - } - return TypedValue(std::move(bytes)); -} - -TypedValue FromByteString(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<String, Optional<PositiveInteger>>("fromByteString", args, nargs); - const auto &bytes = args[0].ValueString(); - if (bytes.empty()) return TypedValue("", ctx.memory); - size_t min_length = bytes.size(); - if (nargs == 2) min_length = std::max(min_length, static_cast<size_t>(args[1].ValueInt())); - utils::pmr::string str(ctx.memory); - str.reserve(min_length * 2 + 2); - str.append("0x"); - for (size_t pad = 0; pad < min_length - bytes.size(); ++pad) str.append(2, '0'); - // Convert the bytes to a character string in hex representation. - // Unfortunately, we don't know whether the default `char` is signed or - // unsigned, so we have to work around any potential undefined behaviour when - // conversions between the 2 occur. That's why this function is more - // complicated than it should be. - auto to_hex = [](const unsigned char val) -> char { - unsigned char ch = val < 10U ? static_cast<unsigned char>('0') + val : static_cast<unsigned char>('a') + val - 10U; - return utils::MemcpyCast<char>(ch); - }; - for (unsigned char byte : bytes) { - str.append(1, to_hex(byte / 16U)); - str.append(1, to_hex(byte % 16U)); - } - return TypedValue(std::move(str)); -} - -template <typename T> -concept IsNumberOrInteger = utils::SameAsAnyOf<T, Number, Integer>; - -template <IsNumberOrInteger ArgType> -void MapNumericParameters(auto ¶meter_mappings, const auto &input_parameters) { - for (const auto &[key, value] : input_parameters) { - if (auto it = parameter_mappings.find(key); it != parameter_mappings.end()) { - if (value.IsInt()) { - *it->second = value.ValueInt(); - } else if (std::is_same_v<ArgType, Number> && value.IsDouble()) { - *it->second = value.ValueDouble(); - } else { - std::string_view error = std::is_same_v<ArgType, Integer> ? "an integer." : "a numeric value."; - throw QueryRuntimeException("Invalid value for key '{}'. Expected {}", key, error); - } - } else { - throw QueryRuntimeException("Unknown key '{}'.", key); - } - } -} - -TypedValue Date(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Optional<Or<String, Map>>>("date", args, nargs); - if (nargs == 0) { - return TypedValue(utils::LocalDateTime(ctx.timestamp).date, ctx.memory); - } - - if (args[0].IsString()) { - const auto &[date_parameters, is_extended] = utils::ParseDateParameters(args[0].ValueString()); - return TypedValue(utils::Date(date_parameters), ctx.memory); - } - - utils::DateParameters date_parameters; - - using namespace std::literals; - std::unordered_map parameter_mappings = {std::pair{"year"sv, &date_parameters.year}, - std::pair{"month"sv, &date_parameters.month}, - std::pair{"day"sv, &date_parameters.day}}; - - MapNumericParameters<Integer>(parameter_mappings, args[0].ValueMap()); - return TypedValue(utils::Date(date_parameters), ctx.memory); -} - -TypedValue LocalTime(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Optional<Or<String, Map>>>("localtime", args, nargs); - - if (nargs == 0) { - return TypedValue(utils::LocalDateTime(ctx.timestamp).local_time, ctx.memory); - } - - if (args[0].IsString()) { - const auto &[local_time_parameters, is_extended] = utils::ParseLocalTimeParameters(args[0].ValueString()); - return TypedValue(utils::LocalTime(local_time_parameters), ctx.memory); - } - - utils::LocalTimeParameters local_time_parameters; - - using namespace std::literals; - std::unordered_map parameter_mappings{ - std::pair{"hour"sv, &local_time_parameters.hour}, - std::pair{"minute"sv, &local_time_parameters.minute}, - std::pair{"second"sv, &local_time_parameters.second}, - std::pair{"millisecond"sv, &local_time_parameters.millisecond}, - std::pair{"microsecond"sv, &local_time_parameters.microsecond}, - }; - - MapNumericParameters<Integer>(parameter_mappings, args[0].ValueMap()); - return TypedValue(utils::LocalTime(local_time_parameters), ctx.memory); -} - -TypedValue LocalDateTime(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Optional<Or<String, Map>>>("localdatetime", args, nargs); - - if (nargs == 0) { - return TypedValue(utils::LocalDateTime(ctx.timestamp), ctx.memory); - } - - if (args[0].IsString()) { - const auto &[date_parameters, local_time_parameters] = ParseLocalDateTimeParameters(args[0].ValueString()); - return TypedValue(utils::LocalDateTime(date_parameters, local_time_parameters), ctx.memory); - } - - utils::DateParameters date_parameters; - utils::LocalTimeParameters local_time_parameters; - using namespace std::literals; - std::unordered_map parameter_mappings{ - std::pair{"year"sv, &date_parameters.year}, - std::pair{"month"sv, &date_parameters.month}, - std::pair{"day"sv, &date_parameters.day}, - std::pair{"hour"sv, &local_time_parameters.hour}, - std::pair{"minute"sv, &local_time_parameters.minute}, - std::pair{"second"sv, &local_time_parameters.second}, - std::pair{"millisecond"sv, &local_time_parameters.millisecond}, - std::pair{"microsecond"sv, &local_time_parameters.microsecond}, - }; - - MapNumericParameters<Integer>(parameter_mappings, args[0].ValueMap()); - return TypedValue(utils::LocalDateTime(date_parameters, local_time_parameters), ctx.memory); -} - -TypedValue Duration(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType<Or<String, Map>>("duration", args, nargs); - - if (args[0].IsString()) { - return TypedValue(utils::Duration(ParseDurationParameters(args[0].ValueString())), ctx.memory); - } - - utils::DurationParameters duration_parameters; - using namespace std::literals; - std::unordered_map parameter_mappings{std::pair{"day"sv, &duration_parameters.day}, - std::pair{"hour"sv, &duration_parameters.hour}, - std::pair{"minute"sv, &duration_parameters.minute}, - std::pair{"second"sv, &duration_parameters.second}, - std::pair{"millisecond"sv, &duration_parameters.millisecond}, - std::pair{"microsecond"sv, &duration_parameters.microsecond}}; - MapNumericParameters<Number>(parameter_mappings, args[0].ValueMap()); - return TypedValue(utils::Duration(duration_parameters), ctx.memory); -} - -} // namespace - -std::function<TypedValue(const TypedValue *, int64_t, const FunctionContext &ctx)> NameToFunction( - const std::string &function_name) { - // Scalar functions - if (function_name == "ENDNODE") return EndNode; - if (function_name == "HEAD") return Head; - if (function_name == kId) return Id; - if (function_name == "LAST") return Last; - if (function_name == "PROPERTIES") return Properties; - if (function_name == "SIZE") return Size; - if (function_name == "STARTNODE") return StartNode; - if (function_name == "TIMESTAMP") return Timestamp; - if (function_name == "TOBOOLEAN") return ToBoolean; - if (function_name == "TOFLOAT") return ToFloat; - if (function_name == "TOINTEGER") return ToInteger; - if (function_name == "TYPE") return Type; - if (function_name == "VALUETYPE") return ValueType; - - // List functions - if (function_name == "RANGE") return Range; - if (function_name == "TAIL") return Tail; - if (function_name == "UNIFORMSAMPLE") return UniformSample; - - // Mathematical functions - numeric - if (function_name == "ABS") return Abs; - if (function_name == "CEIL") return Ceil; - if (function_name == "FLOOR") return Floor; - if (function_name == "RAND") return Rand; - if (function_name == "ROUND") return Round; - if (function_name == "SIGN") return Sign; - - // Mathematical functions - logarithmic - if (function_name == "E") return E; - if (function_name == "EXP") return Exp; - if (function_name == "LOG") return Log; - if (function_name == "LOG10") return Log10; - if (function_name == "SQRT") return Sqrt; - - // Mathematical functions - trigonometric - if (function_name == "ACOS") return Acos; - if (function_name == "ASIN") return Asin; - if (function_name == "ATAN") return Atan; - if (function_name == "ATAN2") return Atan2; - if (function_name == "COS") return Cos; - if (function_name == "PI") return Pi; - if (function_name == "SIN") return Sin; - if (function_name == "TAN") return Tan; - - // String functions - if (function_name == kContains) return Contains; - if (function_name == kEndsWith) return EndsWith; - if (function_name == "LEFT") return Left; - if (function_name == "LTRIM") return LTrim; - if (function_name == "REPLACE") return Replace; - if (function_name == "REVERSE") return Reverse; - if (function_name == "RIGHT") return Right; - if (function_name == "RTRIM") return RTrim; - if (function_name == "SPLIT") return Split; - if (function_name == kStartsWith) return StartsWith; - if (function_name == "SUBSTRING") return Substring; - if (function_name == "TOLOWER") return ToLower; - // TODO(kostasrim) fix function lookup here - if (function_name == "TOSTRING") return ToString; - if (function_name == "TOUPPER") return ToUpper; - if (function_name == "TRIM") return Trim; - - // Memgraph specific functions - if (function_name == "ASSERT") return Assert; - if (function_name == "COUNTER") return Counter; - if (function_name == "TOBYTESTRING") return ToByteString; - if (function_name == "FROMBYTESTRING") return FromByteString; - - // Functions for temporal types - if (function_name == "DATE") return Date; - if (function_name == "LOCALTIME") return LocalTime; - if (function_name == "LOCALDATETIME") return LocalDateTime; - if (function_name == "DURATION") return Duration; - - return nullptr; -} - -} // namespace memgraph::query::v2 diff --git a/src/query/v2/interpret/awesome_memgraph_functions.hpp b/src/query/v2/interpret/awesome_memgraph_functions.hpp deleted file mode 100644 index 134f05d7d..000000000 --- a/src/query/v2/interpret/awesome_memgraph_functions.hpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2022 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. - -#pragma once - -#include <functional> -#include <string> -#include <unordered_map> - -#include "query/v2/bindings/typed_value.hpp" -#include "query/v2/db_accessor.hpp" -#include "storage/v3/view.hpp" -#include "utils/memory.hpp" - -namespace memgraph::msgs { -class ShardRequestManagerInterface; -} // namespace memgraph::msgs - -namespace memgraph::query::v2 { - -namespace { -const char kStartsWith[] = "STARTSWITH"; -const char kEndsWith[] = "ENDSWITH"; -const char kContains[] = "CONTAINS"; -const char kId[] = "ID"; -} // namespace - -struct FunctionContext { - // TODO(kostasrim) consider optional here. ShardRequestManager does not exist on the storage. - // DbAccessor *db_accessor; - msgs::ShardRequestManagerInterface *manager; - utils::MemoryResource *memory; - int64_t timestamp; - std::unordered_map<std::string, int64_t> *counters; - storage::v3::View view; -}; - -/// Return the function implementation with the given name. -/// -/// Note, returned function signature uses C-style access to an array to allow -/// having an array stored anywhere the caller likes, as long as it is -/// contiguous in memory. Since most functions don't take many arguments, it's -/// convenient to have them stored in the calling stack frame. -std::function<TypedValue(const TypedValue *arguments, int64_t num_arguments, const FunctionContext &context)> -NameToFunction(const std::string &function_name); - -} // namespace memgraph::query::v2 diff --git a/src/query/v2/plan/preprocess.cpp b/src/query/v2/plan/preprocess.cpp index 1037f3fe6..765066079 100644 --- a/src/query/v2/plan/preprocess.cpp +++ b/src/query/v2/plan/preprocess.cpp @@ -398,7 +398,7 @@ void Filters::AnalyzeAndStoreFilter(Expression *expr, const SymbolTable &symbol_ auto add_id_equal = [&](auto *maybe_id_fun, auto *val_expr) -> bool { auto *id_fun = utils::Downcast<Function>(maybe_id_fun); if (!id_fun) return false; - if (id_fun->function_name_ != kId) return false; + if (id_fun->function_name_ != functions::kId) return false; if (id_fun->arguments_.size() != 1U) return false; auto *ident = utils::Downcast<Identifier>(id_fun->arguments_.front()); if (!ident) return false; diff --git a/src/storage/v3/CMakeLists.txt b/src/storage/v3/CMakeLists.txt index 0f359c702..dccbe2356 100644 --- a/src/storage/v3/CMakeLists.txt +++ b/src/storage/v3/CMakeLists.txt @@ -33,4 +33,4 @@ target_link_libraries(mg-storage-v3 Threads::Threads mg-utils gflags) target_include_directories(mg-storage-v3 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bindings) add_dependencies(mg-storage-v3 generate_lcp_storage) -target_link_libraries(mg-storage-v3 mg-slk mg-expr mg-io) +target_link_libraries(mg-storage-v3 mg-slk mg-expr mg-io mg-functions) diff --git a/src/storage/v3/bindings/ast/ast.lcp b/src/storage/v3/bindings/ast/ast.lcp index 3be1830ae..8a3484a58 100644 --- a/src/storage/v3/bindings/ast/ast.lcp +++ b/src/storage/v3/bindings/ast/ast.lcp @@ -24,6 +24,8 @@ #include "storage/v3/conversions.hpp" #include "storage/v3/path.hpp" #include "utils/typeinfo.hpp" +#include "utils/exceptions.hpp" +#include "functions/awesome_memgraph_functions.hpp" cpp<# @@ -178,14 +180,6 @@ cpp<# (:serialize (:slk :load-args '((storage "storage::v3::AstStorage *"))))) #>cpp -struct FunctionContext { - DbAccessor *db_accessor; - utils::MemoryResource *memory; - int64_t timestamp; - std::unordered_map<std::string, int64_t> *counters; - View view; -}; - inline bool operator==(const LabelIx &a, const LabelIx &b) { return a.ix == b.ix && a.name == b.name; } @@ -845,16 +839,24 @@ cpp<# :slk-load (slk-load-ast-vector "Expression")) (function-name "std::string" :scope :public) (function "std::function<TypedValue(const TypedValue *, int64_t, - const FunctionContext &)>" + const functions::FunctionContext<memgraph::storage::v3::DbAccessor> &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp + self->${member} = functions::NameToFunction<memgraph::storage::v3::TypedValue, + functions::FunctionContext<memgraph::storage::v3::DbAccessor>, + functions::StorageEngineTag, Conv>(self->function_name_); cpp<#))) (:public #>cpp Function() = default; + using Conv = decltype(PropertyToTypedValueFunctor<TypedValue>); + class SemanticException : public memgraph::utils::BasicException { + using utils::BasicException::BasicException; + }; + DEFVISITABLE(ExpressionVisitor<TypedValue>); DEFVISITABLE(ExpressionVisitor<void>); @@ -872,7 +874,13 @@ cpp<# Function(const std::string &function_name, const std::vector<Expression *> &arguments) : arguments_(arguments), - function_name_(function_name) { + function_name_(function_name), + function_(functions::NameToFunction<memgraph::storage::v3::TypedValue, + functions::FunctionContext<memgraph::storage::v3::DbAccessor>, + functions::StorageEngineTag, Conv>(function_name_)) { + if (!function_) { + throw SemanticException("Function '{}' doesn't exist.", function_name); + } } cpp<#) (:private diff --git a/src/storage/v3/bindings/db_accessor.hpp b/src/storage/v3/bindings/db_accessor.hpp index 186a1b5c5..2a4f91fe0 100644 --- a/src/storage/v3/bindings/db_accessor.hpp +++ b/src/storage/v3/bindings/db_accessor.hpp @@ -88,7 +88,7 @@ class DbAccessor final { } storage::v3::Result<std::optional<EdgeAccessor>> RemoveEdge(EdgeAccessor *edge) { - auto res = accessor_->DeleteEdge(edge->FromVertex(), edge->ToVertex(), edge->Gid()); + auto res = accessor_->DeleteEdge(edge->From(), edge->To(), edge->Gid()); if (res.HasError()) { return res.GetError(); } diff --git a/src/storage/v3/conversions.hpp b/src/storage/v3/conversions.hpp index 3ff804b6a..dfb190ac1 100644 --- a/src/storage/v3/conversions.hpp +++ b/src/storage/v3/conversions.hpp @@ -69,6 +69,10 @@ TTypedValue PropertyToTypedValue(const PropertyValue &value) { LOG_FATAL("Unsupported type"); } +template <typename TypedValueT> +inline const auto PropertyToTypedValueFunctor = + [](const PropertyValue &value) { return PropertyToTypedValue<TypedValueT>(value); }; + template <typename TTypedValue> TTypedValue PropertyToTypedValue(const PropertyValue &value, utils::MemoryResource *mem) { switch (value.type()) { diff --git a/src/storage/v3/edge_accessor.cpp b/src/storage/v3/edge_accessor.cpp index ed4abd1fe..d60cdeebc 100644 --- a/src/storage/v3/edge_accessor.cpp +++ b/src/storage/v3/edge_accessor.cpp @@ -50,9 +50,9 @@ bool EdgeAccessor::IsVisible(const View view) const { return exists && (for_deleted_ || !deleted); } -const VertexId &EdgeAccessor::FromVertex() const { return from_vertex_; } +const VertexId &EdgeAccessor::From() const { return from_vertex_; } -const VertexId &EdgeAccessor::ToVertex() const { return to_vertex_; } +const VertexId &EdgeAccessor::To() const { return to_vertex_; } Result<PropertyValue> EdgeAccessor::SetProperty(PropertyId property, const PropertyValue &value) { utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception; @@ -179,4 +179,7 @@ Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View view) return std::move(properties); } +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +size_t EdgeAccessor::CypherId() const { return 10; } + } // namespace memgraph::storage::v3 diff --git a/src/storage/v3/edge_accessor.hpp b/src/storage/v3/edge_accessor.hpp index 546a09200..0c9235b14 100644 --- a/src/storage/v3/edge_accessor.hpp +++ b/src/storage/v3/edge_accessor.hpp @@ -48,9 +48,9 @@ class EdgeAccessor final { /// @return true if the object is visible from the current transaction bool IsVisible(View view) const; - const VertexId &FromVertex() const; + const VertexId &From() const; - const VertexId &ToVertex() const; + const VertexId &To() const; EdgeTypeId EdgeType() const { return edge_type_; } @@ -84,6 +84,9 @@ class EdgeAccessor final { } bool operator!=(const EdgeAccessor &other) const noexcept { return !(*this == other); } + // Dummy function + size_t CypherId() const; + private: EdgeRef edge_; EdgeTypeId edge_type_; diff --git a/src/storage/v3/expr.cpp b/src/storage/v3/expr.cpp index 1d6739433..074e9f15f 100644 --- a/src/storage/v3/expr.cpp +++ b/src/storage/v3/expr.cpp @@ -52,13 +52,12 @@ msgs::Value ConstructValueEdge(const EdgeAccessor &acc, View view) { msgs::EdgeType type = {.id = acc.EdgeType()}; msgs::EdgeId gid = {.gid = acc.Gid().AsUint()}; - msgs::Label src_prim_label = {.id = acc.FromVertex().primary_label}; + msgs::Label src_prim_label = {.id = acc.From().primary_label}; memgraph::msgs::VertexId src_vertex = - std::make_pair(src_prim_label, conversions::ConvertValueVector(acc.FromVertex().primary_key)); + std::make_pair(src_prim_label, conversions::ConvertValueVector(acc.From().primary_key)); - msgs::Label dst_prim_label = {.id = acc.ToVertex().primary_label}; - msgs::VertexId dst_vertex = - std::make_pair(dst_prim_label, conversions::ConvertValueVector(acc.ToVertex().primary_key)); + msgs::Label dst_prim_label = {.id = acc.To().primary_label}; + msgs::VertexId dst_vertex = std::make_pair(dst_prim_label, conversions::ConvertValueVector(acc.To().primary_key)); auto properties = acc.Properties(view); diff --git a/src/storage/v3/shard.cpp b/src/storage/v3/shard.cpp index 0e596172d..49c692134 100644 --- a/src/storage/v3/shard.cpp +++ b/src/storage/v3/shard.cpp @@ -441,7 +441,7 @@ Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shar for (const auto &item : in_edges) { auto [edge_type, from_vertex, edge] = item; EdgeAccessor e(edge, edge_type, from_vertex, vertex_id, transaction_, &shard_->indices_, config_); - auto ret = DeleteEdge(e.FromVertex(), e.ToVertex(), e.Gid()); + auto ret = DeleteEdge(e.From(), e.To(), e.Gid()); if (ret.HasError()) { MG_ASSERT(ret.GetError() == Error::SERIALIZATION_ERROR, "Invalid database state!"); return ret.GetError(); @@ -454,7 +454,7 @@ Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shar for (const auto &item : out_edges) { auto [edge_type, to_vertex, edge] = item; EdgeAccessor e(edge, edge_type, vertex_id, to_vertex, transaction_, &shard_->indices_, config_); - auto ret = DeleteEdge(e.FromVertex(), e.ToVertex(), e.Gid()); + auto ret = DeleteEdge(e.From(), e.To(), e.Gid()); if (ret.HasError()) { MG_ASSERT(ret.GetError() == Error::SERIALIZATION_ERROR, "Invalid database state!"); return ret.GetError(); diff --git a/src/storage/v3/shard_rsm.cpp b/src/storage/v3/shard_rsm.cpp index f288e5e27..781ab67ed 100644 --- a/src/storage/v3/shard_rsm.cpp +++ b/src/storage/v3/shard_rsm.cpp @@ -376,7 +376,7 @@ EdgeUniqunessFunction InitializeEdgeUniqunessFunction(bool only_unique_neighbor_ case msgs::EdgeDirection::OUT: { is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set, const storage::v3::EdgeAccessor &edge_acc) { - auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.ToVertex()); + auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.To()); return insertion_happened; }; break; @@ -384,7 +384,7 @@ EdgeUniqunessFunction InitializeEdgeUniqunessFunction(bool only_unique_neighbor_ case msgs::EdgeDirection::IN: { is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set, const storage::v3::EdgeAccessor &edge_acc) { - auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.FromVertex()); + auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.From()); return insertion_happened; }; break; @@ -429,8 +429,8 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) { value_properties.insert(std::make_pair(prop_key, FromPropertyValueToValue(std::move(prop_val)))); } using EdgeWithAllProperties = msgs::ExpandOneResultRow::EdgeWithAllProperties; - EdgeWithAllProperties edges{ToMsgsVertexId(edge.FromVertex()), msgs::EdgeType{edge.EdgeType()}, - edge.Gid().AsUint(), std::move(value_properties)}; + EdgeWithAllProperties edges{ToMsgsVertexId(edge.From()), msgs::EdgeType{edge.EdgeType()}, edge.Gid().AsUint(), + std::move(value_properties)}; if (is_in_edge) { result_row.in_edges_with_all_properties.push_back(std::move(edges)); } else { @@ -454,7 +454,7 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) { value_properties.emplace_back(FromPropertyValueToValue(std::move(property_result.GetValue()))); } using EdgeWithSpecificProperties = msgs::ExpandOneResultRow::EdgeWithSpecificProperties; - EdgeWithSpecificProperties edges{ToMsgsVertexId(edge.FromVertex()), msgs::EdgeType{edge.EdgeType()}, + EdgeWithSpecificProperties edges{ToMsgsVertexId(edge.From()), msgs::EdgeType{edge.EdgeType()}, edge.Gid().AsUint(), std::move(value_properties)}; if (is_in_edge) { result_row.in_edges_with_specific_properties.push_back(std::move(edges)); diff --git a/src/storage/v3/vertex_accessor.cpp b/src/storage/v3/vertex_accessor.cpp index 543caa88a..10c39dba6 100644 --- a/src/storage/v3/vertex_accessor.cpp +++ b/src/storage/v3/vertex_accessor.cpp @@ -733,4 +733,7 @@ Result<size_t> VertexAccessor::OutDegree(View view) const { return degree; } +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +size_t VertexAccessor::CypherId() const { return 10; } + } // namespace memgraph::storage::v3 diff --git a/src/storage/v3/vertex_accessor.hpp b/src/storage/v3/vertex_accessor.hpp index 682a04e39..d708f723e 100644 --- a/src/storage/v3/vertex_accessor.hpp +++ b/src/storage/v3/vertex_accessor.hpp @@ -118,6 +118,9 @@ class VertexAccessor final { } bool operator!=(const VertexAccessor &other) const noexcept { return !(*this == other); } + // Dummy function + size_t CypherId() const; + private: /// Add a label and return `true` if insertion took place. /// `false` is returned if the label already existed. diff --git a/tests/unit/storage_v3_edge.cpp b/tests/unit/storage_v3_edge.cpp index 21c4214ce..5c0759e98 100644 --- a/tests/unit/storage_v3_edge.cpp +++ b/tests/unit/storage_v3_edge.cpp @@ -98,8 +98,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { auto edge = res.GetValue(); ASSERT_EQ(edge.EdgeType(), et); ASSERT_EQ(edge.Gid(), edge_id); - ASSERT_EQ(edge.FromVertex(), from_id); - ASSERT_EQ(edge.ToVertex(), to_id); + ASSERT_EQ(edge.From(), from_id); + ASSERT_EQ(edge.To(), to_id); // Check edges without filters ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -117,8 +117,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -131,8 +131,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -188,8 +188,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_from->OutEdges(View::NEW); @@ -200,8 +200,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_to->InEdges(View::OLD); @@ -212,8 +212,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_to->InEdges(View::NEW); @@ -224,8 +224,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -309,8 +309,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex_from); -// ASSERT_EQ(edge.ToVertex(), *vertex_to); +// ASSERT_EQ(edge.From(), *vertex_from); +// ASSERT_EQ(edge.To(), *vertex_to); // // Check edges without filters // ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -327,8 +327,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -340,8 +340,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -386,8 +386,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_from->OutEdges(View::NEW); @@ -397,8 +397,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::OLD); @@ -408,8 +408,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::NEW); @@ -419,8 +419,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -476,8 +476,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex); -// ASSERT_EQ(edge.ToVertex(), *vertex); +// ASSERT_EQ(edge.From(), *vertex); +// ASSERT_EQ(edge.To(), *vertex); // // Check edges without filters // ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); @@ -490,8 +490,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); @@ -503,8 +503,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -539,8 +539,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->InEdges(View::NEW); @@ -550,8 +550,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::OLD); @@ -561,8 +561,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::NEW); @@ -572,8 +572,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -626,8 +626,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex_from); -// ASSERT_EQ(edge.ToVertex(), *vertex_to); +// ASSERT_EQ(edge.From(), *vertex_from); +// ASSERT_EQ(edge.To(), *vertex_to); // // Check edges without filters // ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -644,8 +644,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -657,8 +657,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -723,8 +723,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex_from); -// ASSERT_EQ(edge.ToVertex(), *vertex_to); +// ASSERT_EQ(edge.From(), *vertex_from); +// ASSERT_EQ(edge.To(), *vertex_to); // // Check edges without filters // ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -741,8 +741,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -754,8 +754,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -800,8 +800,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_from->OutEdges(View::NEW); @@ -811,8 +811,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::OLD); @@ -822,8 +822,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::NEW); @@ -833,8 +833,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -901,8 +901,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto edge = res.GetValue(); ASSERT_EQ(edge.EdgeType(), et); ASSERT_EQ(edge.Gid(), edge_id); - ASSERT_EQ(edge.FromVertex(), from_id); - ASSERT_EQ(edge.ToVertex(), to_id); + ASSERT_EQ(edge.From(), from_id); + ASSERT_EQ(edge.To(), to_id); // Check edges without filters ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -920,8 +920,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -934,8 +934,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -1013,8 +1013,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto edge = res.GetValue(); ASSERT_EQ(edge.EdgeType(), et); ASSERT_EQ(edge.Gid(), edge_id); - ASSERT_EQ(edge.FromVertex(), from_id); - ASSERT_EQ(edge.ToVertex(), to_id); + ASSERT_EQ(edge.From(), from_id); + ASSERT_EQ(edge.To(), to_id); // Check edges without filters ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -1032,8 +1032,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -1046,8 +1046,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -1105,8 +1105,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_from->OutEdges(View::NEW); @@ -1117,8 +1117,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_to->InEdges(View::OLD); @@ -1129,8 +1129,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_to->InEdges(View::NEW); @@ -1141,8 +1141,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -1199,8 +1199,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex); -// ASSERT_EQ(edge.ToVertex(), *vertex); +// ASSERT_EQ(edge.From(), *vertex); +// ASSERT_EQ(edge.To(), *vertex); // // Check edges without filters // ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); @@ -1213,8 +1213,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); @@ -1226,8 +1226,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -1276,8 +1276,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex); -// ASSERT_EQ(edge.ToVertex(), *vertex); +// ASSERT_EQ(edge.From(), *vertex); +// ASSERT_EQ(edge.To(), *vertex); // // Check edges without filters // ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); @@ -1290,8 +1290,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); @@ -1303,8 +1303,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -1339,8 +1339,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->InEdges(View::NEW); @@ -1350,8 +1350,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::OLD); @@ -1361,8 +1361,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::NEW); @@ -1372,8 +1372,8 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -1433,8 +1433,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { auto edge = res.GetValue(); ASSERT_EQ(edge.EdgeType(), et); ASSERT_EQ(edge.Gid(), edge_id); - ASSERT_EQ(edge.FromVertex(), from_id); - ASSERT_EQ(edge.ToVertex(), to_id); + ASSERT_EQ(edge.From(), from_id); + ASSERT_EQ(edge.To(), to_id); // Check edges without filters ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -1452,8 +1452,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } // Check edges with filters @@ -1491,8 +1491,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_from->OutEdges(View::NEW); @@ -1503,8 +1503,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } // Check edges with filters @@ -1531,7 +1531,7 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { const auto edge = vertex_from->OutEdges(View::NEW).GetValue()[0]; - const auto res = acc.DeleteEdge(edge.FromVertex(), edge.ToVertex(), edge.Gid()); + const auto res = acc.DeleteEdge(edge.From(), edge.To(), edge.Gid()); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); @@ -1549,8 +1549,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); @@ -1620,8 +1620,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex_from); -// ASSERT_EQ(edge.ToVertex(), *vertex_to); +// ASSERT_EQ(edge.From(), *vertex_from); +// ASSERT_EQ(edge.To(), *vertex_to); // // Check edges without filters // ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -1638,8 +1638,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -1651,8 +1651,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -1697,8 +1697,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_from->OutEdges(View::NEW); @@ -1708,8 +1708,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::OLD); @@ -1719,8 +1719,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::NEW); @@ -1730,8 +1730,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -1790,8 +1790,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); @@ -1803,8 +1803,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -1883,8 +1883,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex); -// ASSERT_EQ(edge.ToVertex(), *vertex); +// ASSERT_EQ(edge.From(), *vertex); +// ASSERT_EQ(edge.To(), *vertex); // // Check edges without filters // ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); @@ -1897,8 +1897,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); @@ -1910,8 +1910,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -1946,8 +1946,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->InEdges(View::NEW); @@ -1957,8 +1957,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::OLD); @@ -1968,8 +1968,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::NEW); @@ -1979,8 +1979,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -2029,8 +2029,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex->InDegree(View::NEW), 0); @@ -2042,8 +2042,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); @@ -2113,8 +2113,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex_from); -// ASSERT_EQ(edge.ToVertex(), *vertex_to); +// ASSERT_EQ(edge.From(), *vertex_from); +// ASSERT_EQ(edge.To(), *vertex_to); // // Check edges without filters // ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); @@ -2131,8 +2131,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); @@ -2144,8 +2144,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -2190,8 +2190,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_from->OutEdges(View::NEW); @@ -2201,8 +2201,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::OLD); @@ -2212,8 +2212,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::NEW); @@ -2223,8 +2223,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -2283,8 +2283,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); @@ -2296,8 +2296,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -2344,8 +2344,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_from->OutEdges(View::NEW); @@ -2355,8 +2355,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::OLD); @@ -2366,8 +2366,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::NEW); @@ -2377,8 +2377,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -2437,8 +2437,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); @@ -2450,8 +2450,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -2533,8 +2533,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { auto edge = res.GetValue(); ASSERT_EQ(edge.EdgeType(), et); ASSERT_EQ(edge.Gid(), edge_id); - ASSERT_EQ(edge.FromVertex(), from_id); - ASSERT_EQ(edge.ToVertex(), to_id); + ASSERT_EQ(edge.From(), from_id); + ASSERT_EQ(edge.To(), to_id); // Check edges without filters ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); @@ -2548,8 +2548,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -2586,8 +2586,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_to->InEdges(View::NEW); @@ -2598,8 +2598,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -2639,7 +2639,7 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { const auto edge = vertex_to->InEdges(View::NEW).GetValue()[0]; - auto res = acc.DeleteEdge(edge.FromVertex(), edge.ToVertex(), edge.Gid()); + auto res = acc.DeleteEdge(edge.From(), edge.To(), edge.Gid()); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); @@ -2654,8 +2654,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -2693,8 +2693,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_to->InEdges(View::NEW); @@ -2705,8 +2705,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); @@ -2746,7 +2746,7 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { const auto edge = vertex_to->InEdges(View::NEW).GetValue()[0]; - auto res = acc.DeleteEdge(edge.FromVertex(), edge.ToVertex(), edge.Gid()); + auto res = acc.DeleteEdge(edge.From(), edge.To(), edge.Gid()); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); @@ -2759,8 +2759,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -2839,8 +2839,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), *vertex); -// ASSERT_EQ(edge.ToVertex(), *vertex); +// ASSERT_EQ(edge.From(), *vertex); +// ASSERT_EQ(edge.To(), *vertex); // // Check edges without filters // ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); @@ -2853,8 +2853,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); @@ -2866,8 +2866,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -2902,8 +2902,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->InEdges(View::NEW); @@ -2913,8 +2913,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::OLD); @@ -2924,8 +2924,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::NEW); @@ -2935,8 +2935,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -2985,8 +2985,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex->InDegree(View::NEW), 0); @@ -2998,8 +2998,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); @@ -3036,8 +3036,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->InEdges(View::NEW); @@ -3047,8 +3047,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::OLD); @@ -3058,8 +3058,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // { // auto ret = vertex->OutEdges(View::NEW); @@ -3069,8 +3069,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // auto other_et = acc.NameToEdgeType("other"); @@ -3119,8 +3119,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex->InDegree(View::NEW), 0); @@ -3132,8 +3132,8 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex); -// ASSERT_EQ(e.ToVertex(), *vertex); +// ASSERT_EQ(e.From(), *vertex); +// ASSERT_EQ(e.To(), *vertex); // } // ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); @@ -3196,8 +3196,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { auto edge = res.GetValue(); ASSERT_EQ(edge.EdgeType(), et); ASSERT_EQ(edge.Gid(), edge_id); - ASSERT_EQ(edge.FromVertex(), from_id); - ASSERT_EQ(edge.ToVertex(), to_id); + ASSERT_EQ(edge.From(), from_id); + ASSERT_EQ(edge.To(), to_id); // Check edges ASSERT_EQ(vertex_from.InEdges(View::NEW)->size(), 0); @@ -3211,8 +3211,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } { auto ret = vertex_to.InEdges(View::NEW); @@ -3222,8 +3222,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { ASSERT_EQ(*vertex_to.InDegree(View::NEW), 1); auto e = edges[0]; ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to.OutEdges(View::NEW)->size(), 0); ASSERT_EQ(*vertex_to.OutDegree(View::NEW), 0); @@ -3267,8 +3267,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_from->OutEdges(View::NEW).GetError(), Error::DELETED_OBJECT); ASSERT_EQ(vertex_from->OutDegree(View::NEW).GetError(), Error::DELETED_OBJECT); @@ -3281,8 +3281,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { auto e = edges[0]; ASSERT_EQ(e.EdgeType(), et); ASSERT_EQ(e.Gid(), edge_id); - ASSERT_EQ(e.FromVertex(), from_id); - ASSERT_EQ(e.ToVertex(), to_id); + ASSERT_EQ(e.From(), from_id); + ASSERT_EQ(e.To(), to_id); } ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -3338,29 +3338,29 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_TRUE(res1.HasValue()); // auto edge1 = res1.GetValue(); // ASSERT_EQ(edge1.EdgeType(), et1); -// ASSERT_EQ(edge1.FromVertex(), vertex1); -// ASSERT_EQ(edge1.ToVertex(), vertex2); +// ASSERT_EQ(edge1.From(), vertex1); +// ASSERT_EQ(edge1.To(), vertex2); // auto res2 = acc.CreateEdge(&vertex2, &vertex1, et2); // ASSERT_TRUE(res2.HasValue()); // auto edge2 = res2.GetValue(); // ASSERT_EQ(edge2.EdgeType(), et2); -// ASSERT_EQ(edge2.FromVertex(), vertex2); -// ASSERT_EQ(edge2.ToVertex(), vertex1); +// ASSERT_EQ(edge2.From(), vertex2); +// ASSERT_EQ(edge2.To(), vertex1); // auto res3 = acc.CreateEdge(&vertex1, &vertex1, et3); // ASSERT_TRUE(res3.HasValue()); // auto edge3 = res3.GetValue(); // ASSERT_EQ(edge3.EdgeType(), et3); -// ASSERT_EQ(edge3.FromVertex(), vertex1); -// ASSERT_EQ(edge3.ToVertex(), vertex1); +// ASSERT_EQ(edge3.From(), vertex1); +// ASSERT_EQ(edge3.To(), vertex1); // auto res4 = acc.CreateEdge(&vertex2, &vertex2, et4); // ASSERT_TRUE(res4.HasValue()); // auto edge4 = res4.GetValue(); // ASSERT_EQ(edge4.EdgeType(), et4); -// ASSERT_EQ(edge4.FromVertex(), vertex2); -// ASSERT_EQ(edge4.ToVertex(), vertex2); +// ASSERT_EQ(edge4.From(), vertex2); +// ASSERT_EQ(edge4.To(), vertex2); // // Check edges // { @@ -3372,14 +3372,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex1); // } // } // { @@ -3391,14 +3391,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex1); // } // } // { @@ -3410,14 +3410,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex2); // } // } // { @@ -3429,14 +3429,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex2); // } // } @@ -3480,14 +3480,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // ASSERT_EQ(vertex1->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -3501,14 +3501,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // ASSERT_EQ(vertex1->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -3522,14 +3522,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -3540,8 +3540,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->OutEdges(View::OLD); @@ -3552,14 +3552,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -3570,8 +3570,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // acc.Commit(GetNextHlc()); @@ -3596,8 +3596,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->InEdges(View::NEW); @@ -3607,8 +3607,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->OutEdges(View::OLD); @@ -3618,8 +3618,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->OutEdges(View::NEW); @@ -3629,8 +3629,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // } @@ -3653,8 +3653,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_TRUE(res.HasValue()); // auto edge = res.GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), vertex_from); -// ASSERT_EQ(edge.ToVertex(), vertex_to); +// ASSERT_EQ(edge.From(), vertex_from); +// ASSERT_EQ(edge.To(), vertex_to); // gid_from = vertex_from.Gid(); // gid_to = vertex_to.Gid(); @@ -3670,8 +3670,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_from.OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), vertex_from); -// ASSERT_EQ(e.ToVertex(), vertex_to); +// ASSERT_EQ(e.From(), vertex_from); +// ASSERT_EQ(e.To(), vertex_to); // } // { // auto ret = vertex_to.InEdges(View::NEW); @@ -3681,8 +3681,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_to.InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), vertex_from); -// ASSERT_EQ(e.ToVertex(), vertex_to); +// ASSERT_EQ(e.From(), vertex_from); +// ASSERT_EQ(e.To(), vertex_to); // } // ASSERT_EQ(vertex_to.OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_to.OutDegree(View::NEW), 0); @@ -3727,8 +3727,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_from->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // ASSERT_EQ(vertex_from->OutDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -3740,8 +3740,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -3774,8 +3774,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // { // auto ret = vertex_to->InEdges(View::NEW); @@ -3785,8 +3785,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); @@ -3831,8 +3831,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_from->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // ASSERT_EQ(vertex_from->OutDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -3844,8 +3844,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.FromVertex(), *vertex_from); -// ASSERT_EQ(e.ToVertex(), *vertex_to); +// ASSERT_EQ(e.From(), *vertex_from); +// ASSERT_EQ(e.To(), *vertex_to); // } // ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); // ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); @@ -3901,29 +3901,29 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_TRUE(res1.HasValue()); // auto edge1 = res1.GetValue(); // ASSERT_EQ(edge1.EdgeType(), et1); -// ASSERT_EQ(edge1.FromVertex(), vertex1); -// ASSERT_EQ(edge1.ToVertex(), vertex2); +// ASSERT_EQ(edge1.From(), vertex1); +// ASSERT_EQ(edge1.To(), vertex2); // auto res2 = acc.CreateEdge(&vertex2, &vertex1, et2); // ASSERT_TRUE(res2.HasValue()); // auto edge2 = res2.GetValue(); // ASSERT_EQ(edge2.EdgeType(), et2); -// ASSERT_EQ(edge2.FromVertex(), vertex2); -// ASSERT_EQ(edge2.ToVertex(), vertex1); +// ASSERT_EQ(edge2.From(), vertex2); +// ASSERT_EQ(edge2.To(), vertex1); // auto res3 = acc.CreateEdge(&vertex1, &vertex1, et3); // ASSERT_TRUE(res3.HasValue()); // auto edge3 = res3.GetValue(); // ASSERT_EQ(edge3.EdgeType(), et3); -// ASSERT_EQ(edge3.FromVertex(), vertex1); -// ASSERT_EQ(edge3.ToVertex(), vertex1); +// ASSERT_EQ(edge3.From(), vertex1); +// ASSERT_EQ(edge3.To(), vertex1); // auto res4 = acc.CreateEdge(&vertex2, &vertex2, et4); // ASSERT_TRUE(res4.HasValue()); // auto edge4 = res4.GetValue(); // ASSERT_EQ(edge4.EdgeType(), et4); -// ASSERT_EQ(edge4.FromVertex(), vertex2); -// ASSERT_EQ(edge4.ToVertex(), vertex2); +// ASSERT_EQ(edge4.From(), vertex2); +// ASSERT_EQ(edge4.To(), vertex2); // // Check edges // { @@ -3935,14 +3935,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex1); // } // } // { @@ -3954,14 +3954,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex1); // } // } // { @@ -3973,14 +3973,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), vertex1); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex1); +// ASSERT_EQ(e.To(), vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex2); // } // } // { @@ -3992,14 +3992,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex1); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), vertex2); -// ASSERT_EQ(e.ToVertex(), vertex2); +// ASSERT_EQ(e.From(), vertex2); +// ASSERT_EQ(e.To(), vertex2); // } // } @@ -4043,14 +4043,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // ASSERT_EQ(vertex1->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -4064,14 +4064,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // ASSERT_EQ(vertex1->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -4085,14 +4085,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -4103,8 +4103,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->OutEdges(View::OLD); @@ -4115,14 +4115,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -4133,8 +4133,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // acc.Abort(); @@ -4163,14 +4163,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // { @@ -4182,14 +4182,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // { @@ -4201,14 +4201,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // { @@ -4220,14 +4220,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // { @@ -4239,14 +4239,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -4258,14 +4258,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -4277,14 +4277,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -4296,14 +4296,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } @@ -4347,14 +4347,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // ASSERT_EQ(vertex1->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -4368,14 +4368,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex1); // } // } // ASSERT_EQ(vertex1->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); @@ -4389,14 +4389,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.FromVertex(), *vertex1); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex1); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -4407,8 +4407,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->OutEdges(View::OLD); @@ -4419,14 +4419,14 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // { // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex1); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex1); // } // { // auto e = edges[1]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // { @@ -4437,8 +4437,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // acc.Commit(GetNextHlc()); @@ -4463,8 +4463,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->InDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->InEdges(View::NEW); @@ -4474,8 +4474,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->OutEdges(View::OLD); @@ -4485,8 +4485,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->OutDegree(View::OLD), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // { // auto ret = vertex2->OutEdges(View::NEW); @@ -4496,8 +4496,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); // auto e = edges[0]; // ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.FromVertex(), *vertex2); -// ASSERT_EQ(e.ToVertex(), *vertex2); +// ASSERT_EQ(e.From(), *vertex2); +// ASSERT_EQ(e.To(), *vertex2); // } // } // } @@ -4513,8 +4513,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // auto et = acc.NameToEdgeType("et5"); // auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), vertex); -// ASSERT_EQ(edge.ToVertex(), vertex); +// ASSERT_EQ(edge.From(), vertex); +// ASSERT_EQ(edge.To(), vertex); // auto property = acc.NameToProperty("property5"); @@ -4645,8 +4645,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // auto et = acc.NameToEdgeType("et5"); // auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), vertex); -// ASSERT_EQ(edge.ToVertex(), vertex); +// ASSERT_EQ(edge.From(), vertex); +// ASSERT_EQ(edge.To(), vertex); // acc.Commit(GetNextHlc()); // } @@ -4934,8 +4934,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // auto et = acc.NameToEdgeType("et5"); // auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), vertex); -// ASSERT_EQ(edge.ToVertex(), vertex); +// ASSERT_EQ(edge.From(), vertex); +// ASSERT_EQ(edge.To(), vertex); // acc.Commit(GetNextHlc()); // } @@ -5045,8 +5045,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // auto et = acc.NameToEdgeType("et5"); // auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), vertex); -// ASSERT_EQ(edge.ToVertex(), vertex); +// ASSERT_EQ(edge.From(), vertex); +// ASSERT_EQ(edge.To(), vertex); // auto old_value = edge.SetProperty(property1, memgraph::storage::PropertyValue("value")); // ASSERT_TRUE(old_value.HasValue()); @@ -5158,8 +5158,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // auto et = acc.NameToEdgeType("et5"); // auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), vertex); -// ASSERT_EQ(edge.ToVertex(), vertex); +// ASSERT_EQ(edge.From(), vertex); +// ASSERT_EQ(edge.To(), vertex); // acc.Commit(GetNextHlc()); // } // { @@ -5226,8 +5226,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // auto et = acc.NameToEdgeType("et5"); // auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); // ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.FromVertex(), vertex); -// ASSERT_EQ(edge.ToVertex(), vertex); +// ASSERT_EQ(edge.From(), vertex); +// ASSERT_EQ(edge.To(), vertex); // acc.Commit(GetNextHlc()); // } // { From 94bc671551281a426e5c3ea94e0c3ca3d22fdba3 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Wed, 9 Nov 2022 18:15:30 +0200 Subject: [PATCH 02/26] Add awesome memgraph functions e2e tests --- tests/e2e/distributed_queries/CMakeLists.txt | 1 + .../awesome_memgraph_functions.py | 90 +++++++++++++++++++ tests/e2e/distributed_queries/workloads.yaml | 5 ++ 3 files changed, 96 insertions(+) create mode 100644 tests/e2e/distributed_queries/awesome_memgraph_functions.py diff --git a/tests/e2e/distributed_queries/CMakeLists.txt b/tests/e2e/distributed_queries/CMakeLists.txt index 455e6ad45..5a7a8d81b 100644 --- a/tests/e2e/distributed_queries/CMakeLists.txt +++ b/tests/e2e/distributed_queries/CMakeLists.txt @@ -9,3 +9,4 @@ distributed_queries_e2e_python_files(order_by_and_limit.py) distributed_queries_e2e_python_files(distinct.py) distributed_queries_e2e_python_files(optional_match.py) distributed_queries_e2e_python_files(common.py) +distributed_queries_e2e_python_files(awesome_memgraph_functions.py) diff --git a/tests/e2e/distributed_queries/awesome_memgraph_functions.py b/tests/e2e/distributed_queries/awesome_memgraph_functions.py new file mode 100644 index 000000000..469979733 --- /dev/null +++ b/tests/e2e/distributed_queries/awesome_memgraph_functions.py @@ -0,0 +1,90 @@ +# Copyright 2022 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 sys +import time +import typing + +import mgclient +import pytest + +from common import * + + +def test_vertex_creation_and_scanall(connection): + wait_for_shard_manager_to_initialize() + cursor = connection.cursor() + + assert has_n_result_row(cursor, "CREATE (n :label {property:1})", 0) + assert has_n_result_row(cursor, "CREATE (n :label {property:2})", 0) + assert has_n_result_row(cursor, "CREATE (n :label {property:3})", 0) + assert has_n_result_row(cursor, "CREATE (n :label {property:4})", 0) + assert has_n_result_row(cursor, "CREATE (n :label {property:10})", 0) + + results = execute_and_fetch_all(cursor, "MATCH (n) WITH COLLECT(n) as nn RETURN SIZE(nn)") + assert len(results) == 1 + assert results[0][0] == 5 + + results = execute_and_fetch_all(cursor, "MATCH (n) WITH COLLECT(n.property) as nn RETURN ALL(i IN nn WHERE i > 0)") + assert len(results) == 1 + assert results[0][0] == True + + results = execute_and_fetch_all(cursor, """RETURN CONTAINS("Pineapple", "P")""") + assert len(results) == 1 + assert results[0][0] == True + + results = execute_and_fetch_all(cursor, """RETURN ENDSWITH("Pineapple", "e")""") + assert len(results) == 1 + assert results[0][0] == True + + results = execute_and_fetch_all(cursor, """RETURN LEFT("Pineapple", 1)""") + assert len(results) == 1 + assert results[0][0] == "P" + + results = execute_and_fetch_all(cursor, """RETURN RIGHT("Pineapple", 1)""") + assert len(results) == 1 + assert results[0][0] == "e" + + results = execute_and_fetch_all(cursor, """RETURN REVERSE("Apple")""") + assert len(results) == 1 + assert results[0][0] == "elppA" + + results = execute_and_fetch_all(cursor, """RETURN REPLACE("Apple", "A", "a")""") + assert len(results) == 1 + assert results[0][0] == "apple" + + results = execute_and_fetch_all(cursor, """RETURN TOLOWER("Apple")""") + assert len(results) == 1 + assert results[0][0] == "apple" + + results = execute_and_fetch_all(cursor, """RETURN TOUPPER("Apple")""") + assert len(results) == 1 + assert results[0][0] == "APPLE" + + results = execute_and_fetch_all(cursor, """RETURN TRIM(" Apple")""") + assert len(results) == 1 + assert results[0][0] == "Apple" + + results = execute_and_fetch_all(cursor, """RETURN SPLIT("Apple.Apple", ".")""") + assert len(results) == 1 + assert results[0][0] == ["Apple", "Apple"] + + results = execute_and_fetch_all(cursor, """RETURN LOG10(100)""") + assert len(results) == 1 + assert results[0][0] == 2 + + results = execute_and_fetch_all(cursor, """RETURN SQRT(4)""") + assert len(results) == 1 + assert results[0][0] == 2 + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__, "-rA"])) diff --git a/tests/e2e/distributed_queries/workloads.yaml b/tests/e2e/distributed_queries/workloads.yaml index 741d6d939..eacc3e713 100644 --- a/tests/e2e/distributed_queries/workloads.yaml +++ b/tests/e2e/distributed_queries/workloads.yaml @@ -36,3 +36,8 @@ workloads: binary: "tests/e2e/pytest_runner.sh" args: ["distributed_queries/optional_match.py"] <<: *template_cluster + + - name: "Awesome memgraph functions" + binary: "tests/e2e/pytest_runner.sh" + args: ["distributed_queries/awesome_memgraph_functions.py"] + <<: *template_cluster From 213583f91649621dc796b54958b50ff6eb08bc62 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Mon, 14 Nov 2022 20:44:32 +0200 Subject: [PATCH 03/26] Add expression evaluator && awesome_memgraph_functions unit tests --- tests/unit/CMakeLists.txt | 4 + tests/unit/query_v2_expression_evaluator.cpp | 2192 ++++++++++++++++++ 2 files changed, 2196 insertions(+) create mode 100644 tests/unit/query_v2_expression_evaluator.cpp diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 0e5824318..2f16ab8c2 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -403,3 +403,7 @@ target_link_libraries(${test_prefix}coordinator_shard_map mg-coordinator) # Tests for many shards, many creates, scan add_unit_test(high_density_shard_create_scan.cpp) target_link_libraries(${test_prefix}high_density_shard_create_scan mg-io mg-coordinator mg-storage-v3 mg-query-v2) + +# Tests for awesome_memgraph_functions +add_unit_test(query_v2_expression_evaluator.cpp) +target_link_libraries(${test_prefix}query_v2_expression_evaluator mg-query-v2) diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp new file mode 100644 index 000000000..6bc6e1c8b --- /dev/null +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -0,0 +1,2192 @@ +// Copyright 2022 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 <cmath> +#include <iterator> +#include <memory> +#include <unordered_map> +#include <vector> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "coordinator/shard_map.hpp" +#include "exceptions.hpp" +#include "functions/awesome_memgraph_functions.hpp" +#include "parser/opencypher/parser.hpp" +#include "query/v2/accessors.hpp" +#include "query/v2/bindings/eval.hpp" +#include "query/v2/bindings/frame.hpp" +#include "query/v2/context.hpp" +#include "query/v2/frontend/ast/ast.hpp" +#include "query/v2/requests.hpp" +#include "query/v2/shard_request_manager.hpp" +#include "storage/v3/storage.hpp" +#include "utils/exceptions.hpp" +#include "utils/string.hpp" + +#include "query_v2_query_common.hpp" +//#include "utils/temporal.hpp" + +using namespace memgraph::query::v2; +using memgraph::query::v2::test_common::ToIntList; +using testing::ElementsAre; +using testing::UnorderedElementsAre; + +using memgraph::io::Time; +using memgraph::io::TimedOut; +using memgraph::io::simulator::Simulator; +using memgraph::io::simulator::SimulatorConfig; +using memgraph::io::simulator::SimulatorTransport; +using memgraph::msgs::CreateExpandRequest; +using memgraph::msgs::CreateExpandResponse; +using memgraph::msgs::CreateVerticesRequest; +using memgraph::msgs::CreateVerticesResponse; +using memgraph::msgs::ExpandOneRequest; +using memgraph::msgs::ExpandOneResponse; +using memgraph::msgs::ExpandOneResultRow; +using memgraph::msgs::NewExpand; +using memgraph::msgs::NewVertex; +using memgraph::msgs::ScanVerticesRequest; +using memgraph::msgs::ScanVerticesResponse; +using ShardMap = memgraph::coordinator::ShardMap; +using LabelId = memgraph::storage::v3::LabelId; +using PropertyId = memgraph::storage::v3::PropertyId; +using memgraph::coordinator::Shards; +using CompoundKey = memgraph::coordinator::PrimaryKey; +using memgraph::expr::ExpressionRuntimeException; +using memgraph::functions::FunctionRuntimeException; + +namespace { + +class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInterface { + public: + using VertexAccessor = memgraph::query::v2::accessors::VertexAccessor; + explicit MockedShardRequestManager(ShardMap shard_map) : shards_map_(std::move(shard_map)) { SetUpNameIdMappers(); } + memgraph::storage::v3::EdgeTypeId NameToEdgeType(const std::string &name) const override { + return shards_map_.GetEdgeTypeId(name).value(); + } + + memgraph::storage::v3::PropertyId NameToProperty(const std::string &name) const override { + return shards_map_.GetPropertyId(name).value(); + } + + memgraph::storage::v3::LabelId NameToLabel(const std::string &name) const override { + return shards_map_.GetLabelId(name).value(); + } + void StartTransaction() override {} + void Commit() override {} + std::vector<VertexAccessor> Request( + memgraph::msgs::ExecutionState<memgraph::msgs::ScanVerticesRequest> &state) override { + return {}; + } + + std::vector<CreateVerticesResponse> Request(memgraph::msgs::ExecutionState<CreateVerticesRequest> &state, + std::vector<memgraph::msgs::NewVertex> new_vertices) override { + return {}; + } + + std::vector<ExpandOneResultRow> Request(memgraph::msgs::ExecutionState<ExpandOneRequest> &state, + ExpandOneRequest request) override { + return {}; + } + + std::vector<CreateExpandResponse> Request(memgraph::msgs::ExecutionState<CreateExpandRequest> &state, + std::vector<NewExpand> new_edges) override { + return {}; + } + + const std::string &PropertyToName(memgraph::storage::v3::PropertyId id) const override { + return properties_.IdToName(id.AsUint()); + } + + const std::string &LabelToName(memgraph::storage::v3::LabelId id) const override { + return labels_.IdToName(id.AsUint()); + } + + const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId id) const override { + return edge_types_.IdToName(id.AsUint()); + } + + bool IsPrimaryLabel(LabelId label) const override { return true; } + + bool IsPrimaryKey(LabelId primary_label, PropertyId property) const override { return true; } + + private: + void SetUpNameIdMappers() { + std::unordered_map<uint64_t, std::string> id_to_name; + for (const auto &[name, id] : shards_map_.labels) { + id_to_name.emplace(id.AsUint(), name); + } + labels_.StoreMapping(std::move(id_to_name)); + id_to_name.clear(); + for (const auto &[name, id] : shards_map_.properties) { + id_to_name.emplace(id.AsUint(), name); + } + properties_.StoreMapping(std::move(id_to_name)); + id_to_name.clear(); + for (const auto &[name, id] : shards_map_.edge_types) { + id_to_name.emplace(id.AsUint(), name); + } + edge_types_.StoreMapping(std::move(id_to_name)); + } + + ShardMap shards_map_; + memgraph::storage::v3::NameIdMapper properties_; + memgraph::storage::v3::NameIdMapper edge_types_; + memgraph::storage::v3::NameIdMapper labels_; +}; + +ShardMap CreateDummyShardmap() { + static const std::string label_name = std::string("label1"); + ShardMap sm; + + // register new properties + const std::vector<std::string> property_names = {"prop", "property_2", "age", "height", "a", "b", "c"}; + const auto properties = sm.AllocatePropertyIds(property_names); + const auto property_id_1 = properties.at("prop"); + const auto property_id_2 = properties.at("property_2"); + const auto property_id_3 = properties.at("age"); + const auto property_id_4 = properties.at("height"); + const auto property_id_5 = properties.at("a"); + const auto property_id_6 = properties.at("b"); + const auto property_id_7 = properties.at("c"); + const auto type_1 = memgraph::common::SchemaType::INT; + + using SchemaProperty = memgraph::coordinator::SchemaProperty; + // register new label space + std::vector<SchemaProperty> schema = { + SchemaProperty{.property_id = property_id_1, .type = type_1}, + SchemaProperty{.property_id = property_id_2, .type = type_1}, + SchemaProperty{.property_id = property_id_3, .type = type_1}, + SchemaProperty{.property_id = property_id_4, .type = type_1}, + SchemaProperty{.property_id = property_id_5, .type = type_1}, + SchemaProperty{.property_id = property_id_6, .type = type_1}, + SchemaProperty{.property_id = property_id_7, .type = type_1}, + }; + + auto label_success = sm.InitializeNewLabel(label_name, schema, 1, sm.shard_map_version); + MG_ASSERT(label_success); + + const LabelId label_id = sm.labels.at(label_name); + auto &label_space = sm.label_spaces.at(label_id); + Shards &shards_for_label = label_space.shards; + shards_for_label.clear(); + + auto key1 = memgraph::storage::v3::PropertyValue(0); + auto key2 = memgraph::storage::v3::PropertyValue(0); + CompoundKey compound_key_1 = {key1, key2}; + shards_for_label[compound_key_1] = {}; + + auto key3 = memgraph::storage::v3::PropertyValue(12); + auto key4 = memgraph::storage::v3::PropertyValue(13); + CompoundKey compound_key_2 = {key3, key4}; + shards_for_label[compound_key_2] = {}; + + sm.AllocateEdgeTypeIds(std::vector<memgraph::coordinator::EdgeTypeName>{"edge_type"}); + + return sm; +} + +class ExpressionEvaluatorTest : public ::testing::Test { + public: + ExpressionEvaluatorTest() {} + + protected: + // memgraph::storage::Storage db; + // memgraph::storage::Storage::Accessor storage_dba{db.Access()}; + // memgraph::query::DbAccessor dba{&storage_dba}; + // + AstStorage storage; + memgraph::utils::MonotonicBufferResource mem{1024}; + EvaluationContext ctx{.memory = &mem, .timestamp = memgraph::query::v2::QueryTimestamp()}; + SymbolTable symbol_table; + + Frame frame{128}; + std::unique_ptr<memgraph::msgs::ShardRequestManagerInterface> shard_manager = + std::make_unique<MockedShardRequestManager>(CreateDummyShardmap()); + ExpressionEvaluator eval{&frame, symbol_table, ctx, shard_manager.get(), memgraph::storage::v3::View::OLD}; + + Identifier *CreateIdentifierWithValue(std::string name, const TypedValue &value) { + auto id = storage.Create<Identifier>(name, true); + auto symbol = symbol_table.CreateSymbol(name, true); + id->MapTo(symbol); + frame[symbol] = value; + return id; + } + + template <class TExpression> + auto Eval(TExpression *expr) { + ctx.properties = NamesToProperties(storage.properties_, shard_manager.get()); + ctx.labels = NamesToLabels(storage.labels_, shard_manager.get()); + auto value = expr->Accept(eval); + EXPECT_EQ(value.GetMemoryResource(), &mem) << "ExpressionEvaluator must use the MemoryResource from " + "EvaluationContext for allocations!"; + return value; + } +}; + +TEST_F(ExpressionEvaluatorTest, OrOperator) { + auto *op = + storage.Create<OrOperator>(storage.Create<PrimitiveLiteral>(true), storage.Create<PrimitiveLiteral>(false)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create<OrOperator>(storage.Create<PrimitiveLiteral>(true), storage.Create<PrimitiveLiteral>(true)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, XorOperator) { + auto *op = + storage.Create<XorOperator>(storage.Create<PrimitiveLiteral>(true), storage.Create<PrimitiveLiteral>(false)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create<XorOperator>(storage.Create<PrimitiveLiteral>(true), storage.Create<PrimitiveLiteral>(true)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, AndOperator) { + auto *op = + storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(true), storage.Create<PrimitiveLiteral>(true)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(false), storage.Create<PrimitiveLiteral>(true)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, AndOperatorShortCircuit) { + { + auto *op = + storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(false), storage.Create<PrimitiveLiteral>(5)); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), false); + } + { + auto *op = + storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(5), storage.Create<PrimitiveLiteral>(false)); + // We are evaluating left to right, so we don't short circuit here and + // raise due to `5`. This differs from neo4j, where they evaluate both + // sides and return `false` without checking for type of the first + // expression. + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } +} + +TEST_F(ExpressionEvaluatorTest, AndOperatorNull) { + { + // Null doesn't short circuit + auto *op = storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(TypedValue()), + storage.Create<PrimitiveLiteral>(5)); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + auto *op = storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(TypedValue()), + storage.Create<PrimitiveLiteral>(true)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + auto *op = storage.Create<AndOperator>(storage.Create<PrimitiveLiteral>(TypedValue()), + storage.Create<PrimitiveLiteral>(false)); + auto value = Eval(op); + ASSERT_TRUE(value.IsBool()); + EXPECT_EQ(value.ValueBool(), false); + } +} + +TEST_F(ExpressionEvaluatorTest, AdditionOperator) { + auto *op = storage.Create<AdditionOperator>(storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, SubtractionOperator) { + auto *op = + storage.Create<SubtractionOperator>(storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), -1); +} + +TEST_F(ExpressionEvaluatorTest, MultiplicationOperator) { + auto *op = + storage.Create<MultiplicationOperator>(storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 6); +} + +TEST_F(ExpressionEvaluatorTest, DivisionOperator) { + auto *op = + storage.Create<DivisionOperator>(storage.Create<PrimitiveLiteral>(50), storage.Create<PrimitiveLiteral>(10)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, ModOperator) { + auto *op = storage.Create<ModOperator>(storage.Create<PrimitiveLiteral>(65), storage.Create<PrimitiveLiteral>(10)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, EqualOperator) { + auto *op = storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(10), storage.Create<PrimitiveLiteral>(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(15), storage.Create<PrimitiveLiteral>(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); + op = storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(20), storage.Create<PrimitiveLiteral>(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, NotEqualOperator) { + auto *op = + storage.Create<NotEqualOperator>(storage.Create<PrimitiveLiteral>(10), storage.Create<PrimitiveLiteral>(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create<NotEqualOperator>(storage.Create<PrimitiveLiteral>(15), storage.Create<PrimitiveLiteral>(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); + op = storage.Create<NotEqualOperator>(storage.Create<PrimitiveLiteral>(20), storage.Create<PrimitiveLiteral>(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, LessOperator) { + auto *op = storage.Create<LessOperator>(storage.Create<PrimitiveLiteral>(10), storage.Create<PrimitiveLiteral>(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create<LessOperator>(storage.Create<PrimitiveLiteral>(15), storage.Create<PrimitiveLiteral>(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); + op = storage.Create<LessOperator>(storage.Create<PrimitiveLiteral>(20), storage.Create<PrimitiveLiteral>(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, GreaterOperator) { + auto *op = + storage.Create<GreaterOperator>(storage.Create<PrimitiveLiteral>(10), storage.Create<PrimitiveLiteral>(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create<GreaterOperator>(storage.Create<PrimitiveLiteral>(15), storage.Create<PrimitiveLiteral>(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); + op = storage.Create<GreaterOperator>(storage.Create<PrimitiveLiteral>(20), storage.Create<PrimitiveLiteral>(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, LessEqualOperator) { + auto *op = + storage.Create<LessEqualOperator>(storage.Create<PrimitiveLiteral>(10), storage.Create<PrimitiveLiteral>(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create<LessEqualOperator>(storage.Create<PrimitiveLiteral>(15), storage.Create<PrimitiveLiteral>(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); + op = storage.Create<LessEqualOperator>(storage.Create<PrimitiveLiteral>(20), storage.Create<PrimitiveLiteral>(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, GreaterEqualOperator) { + auto *op = + storage.Create<GreaterEqualOperator>(storage.Create<PrimitiveLiteral>(10), storage.Create<PrimitiveLiteral>(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create<GreaterEqualOperator>(storage.Create<PrimitiveLiteral>(15), storage.Create<PrimitiveLiteral>(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); + op = storage.Create<GreaterEqualOperator>(storage.Create<PrimitiveLiteral>(20), storage.Create<PrimitiveLiteral>(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, InListOperator) { + auto *list_literal = storage.Create<ListLiteral>(std::vector<Expression *>{ + storage.Create<PrimitiveLiteral>(1), storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>("a")}); + { + // Element exists in list. + auto *op = storage.Create<InListOperator>(storage.Create<PrimitiveLiteral>(2), list_literal); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), true); + } + { + // Element doesn't exist in list. + auto *op = storage.Create<InListOperator>(storage.Create<PrimitiveLiteral>("x"), list_literal); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), false); + } + { + auto *list_literal = storage.Create<ListLiteral>( + std::vector<Expression *>{storage.Create<PrimitiveLiteral>(TypedValue()), storage.Create<PrimitiveLiteral>(2), + storage.Create<PrimitiveLiteral>("a")}); + // Element doesn't exist in list with null element. + auto *op = storage.Create<InListOperator>(storage.Create<PrimitiveLiteral>("x"), list_literal); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Null list. + auto *op = storage.Create<InListOperator>(storage.Create<PrimitiveLiteral>("x"), + storage.Create<PrimitiveLiteral>(TypedValue())); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Null literal. + auto *op = storage.Create<InListOperator>(storage.Create<PrimitiveLiteral>(TypedValue()), list_literal); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Null literal, empty list. + auto *op = storage.Create<InListOperator>(storage.Create<PrimitiveLiteral>(TypedValue()), + storage.Create<ListLiteral>(std::vector<Expression *>())); + auto value = Eval(op); + EXPECT_FALSE(value.ValueBool()); + } +} + +TEST_F(ExpressionEvaluatorTest, ListIndexing) { + auto *list_literal = storage.Create<ListLiteral>( + std::vector<Expression *>{storage.Create<PrimitiveLiteral>(1), storage.Create<PrimitiveLiteral>(2), + storage.Create<PrimitiveLiteral>(3), storage.Create<PrimitiveLiteral>(4)}); + { + // Legal indexing. + auto *op = storage.Create<SubscriptOperator>(list_literal, storage.Create<PrimitiveLiteral>(2)); + auto value = Eval(op); + EXPECT_EQ(value.ValueInt(), 3); + } + { + // Out of bounds indexing. + auto *op = storage.Create<SubscriptOperator>(list_literal, storage.Create<PrimitiveLiteral>(4)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Out of bounds indexing with negative bound. + auto *op = storage.Create<SubscriptOperator>(list_literal, storage.Create<PrimitiveLiteral>(-100)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Legal indexing with negative index. + auto *op = storage.Create<SubscriptOperator>(list_literal, storage.Create<PrimitiveLiteral>(-2)); + auto value = Eval(op); + EXPECT_EQ(value.ValueInt(), 3); + } + { + // Indexing with one operator being null. + auto *op = storage.Create<SubscriptOperator>(storage.Create<PrimitiveLiteral>(TypedValue()), + storage.Create<PrimitiveLiteral>(-2)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Indexing with incompatible type. + auto *op = storage.Create<SubscriptOperator>(list_literal, storage.Create<PrimitiveLiteral>("bla")); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } +} + +TEST_F(ExpressionEvaluatorTest, MapIndexing) { + auto *map_literal = storage.Create<MapLiteral>( + std::unordered_map<PropertyIx, Expression *>{{storage.GetPropertyIx("a"), storage.Create<PrimitiveLiteral>(1)}, + {storage.GetPropertyIx("b"), storage.Create<PrimitiveLiteral>(2)}, + {storage.GetPropertyIx("c"), storage.Create<PrimitiveLiteral>(3)}}); + { + // Legal indexing. + auto *op = storage.Create<SubscriptOperator>(map_literal, storage.Create<PrimitiveLiteral>("b")); + auto value = Eval(op); + EXPECT_EQ(value.ValueInt(), 2); + } + { + // Legal indexing, non-existing key. + auto *op = storage.Create<SubscriptOperator>(map_literal, storage.Create<PrimitiveLiteral>("z")); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Wrong key type. + auto *op = storage.Create<SubscriptOperator>(map_literal, storage.Create<PrimitiveLiteral>(42)); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + // Indexing with Null. + auto *op = storage.Create<SubscriptOperator>(map_literal, storage.Create<PrimitiveLiteral>(TypedValue())); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } +} + +using Vertex = memgraph::msgs::Vertex; +using Edge = memgraph::msgs::Edge; +using EdgeType = memgraph::msgs::EdgeType; +using Value = memgraph::msgs::Value; +using VertexId = memgraph::msgs::VertexId; +using Label = memgraph::msgs::Label; + +memgraph::query::v2::accessors::VertexAccessor CreateVertex(std::vector<std::pair<PropertyId, Value>> props, + const memgraph::msgs::ShardRequestManagerInterface *manager, + Label label = {}) { + static size_t id = 0; + return {Vertex{VertexId{label, id++}, {label}}, std::move(props), manager}; +} + +memgraph::query::v2::accessors::EdgeAccessor CreateEdge(std::vector<std::pair<PropertyId, Value>> props, + const memgraph::msgs::ShardRequestManagerInterface *manager) { + auto edge = Edge{.src = VertexId{{}, 0}, + .dst = VertexId{{}, 0}, + .properties = std::move(props), + .type = EdgeType{manager->NameToEdgeType("edge_type")}}; + return memgraph::query::v2::accessors::EdgeAccessor{std::move(edge), manager}; +} + +TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) { + auto prop = shard_manager->NameToProperty("prop"); + auto vertex = CreateVertex({{prop, Value(static_cast<int64_t>(42))}}, shard_manager.get()); + auto edge = CreateEdge({{prop, Value(static_cast<int64_t>(43))}}, shard_manager.get()); + + auto *vertex_id = CreateIdentifierWithValue("v1", TypedValue(vertex)); + auto *edge_id = CreateIdentifierWithValue("e11", TypedValue(edge)); + { + // Legal indexing. + auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>("prop")); + auto value1 = Eval(op1); + EXPECT_EQ(value1.ValueInt(), 42); + + auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>("prop")); + auto value2 = Eval(op2); + EXPECT_EQ(value2.ValueInt(), 43); + } + // TODO(kostasrim) Investigate + // Shall we return null on missing properties? Or shall we throw bad optional access as we do now? + + // { + // // Legal indexing, non-existing key. + // auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>("blah")); + // auto value1 = Eval(op1); + // EXPECT_TRUE(value1.IsNull()); + // + // auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>("blah")); + // auto value2 = Eval(op2); + // EXPECT_TRUE(value2.IsNull()); + // } + // { + // // Wrong key type. + // auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>(1)); + // EXPECT_THROW(Eval(op1), ExpressionRuntimeException); + // + // auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>(1)); + // EXPECT_THROW(Eval(op2), ExpressionRuntimeException); + // } + // { + // // Indexing with Null. + // auto *op1 = storage.Create<SubscriptOperator>(vertex_id, + // storage.Create<PrimitiveLiteral>(memgraph::storage::PropertyValue())); + // auto value1 = Eval(op1); + // EXPECT_TRUE(value1.IsNull()); + // + // auto *op2 = storage.Create<SubscriptOperator>(edge_id, + // storage.Create<PrimitiveLiteral>(memgraph::storage::PropertyValue())); + // auto value2 = Eval(op2); + // EXPECT_TRUE(value2.IsNull()); + // } +} + +TEST_F(ExpressionEvaluatorTest, ListSlicingOperator) { + auto *list_literal = storage.Create<ListLiteral>( + std::vector<Expression *>{storage.Create<PrimitiveLiteral>(1), storage.Create<PrimitiveLiteral>(2), + storage.Create<PrimitiveLiteral>(3), storage.Create<PrimitiveLiteral>(4)}); + + auto extract_ints = [](TypedValue list) { + std::vector<int64_t> int_list; + for (auto x : list.ValueList()) { + int_list.push_back(x.ValueInt()); + } + return int_list; + }; + { + // Legal slicing with both bounds defined. + auto *op = storage.Create<ListSlicingOperator>(list_literal, storage.Create<PrimitiveLiteral>(2), + storage.Create<PrimitiveLiteral>(4)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(3, 4)); + } + { + // Legal slicing with negative bound. + auto *op = storage.Create<ListSlicingOperator>(list_literal, storage.Create<PrimitiveLiteral>(2), + storage.Create<PrimitiveLiteral>(-1)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(3)); + } + { + // Lower bound larger than upper bound. + auto *op = storage.Create<ListSlicingOperator>(list_literal, storage.Create<PrimitiveLiteral>(2), + storage.Create<PrimitiveLiteral>(-4)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre()); + } + { + // Bounds ouf or range. + auto *op = storage.Create<ListSlicingOperator>(list_literal, storage.Create<PrimitiveLiteral>(-100), + storage.Create<PrimitiveLiteral>(10)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(1, 2, 3, 4)); + } + { + // Lower bound undefined. + auto *op = storage.Create<ListSlicingOperator>(list_literal, nullptr, storage.Create<PrimitiveLiteral>(3)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(1, 2, 3)); + } + { + // Upper bound undefined. + auto *op = storage.Create<ListSlicingOperator>(list_literal, storage.Create<PrimitiveLiteral>(-2), nullptr); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(3, 4)); + } + { + // Bound of illegal type and null value bound. + auto *op = storage.Create<ListSlicingOperator>(list_literal, storage.Create<PrimitiveLiteral>(TypedValue()), + storage.Create<PrimitiveLiteral>("mirko")); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + // List of illegal type. + auto *op = storage.Create<ListSlicingOperator>(storage.Create<PrimitiveLiteral>("a"), + storage.Create<PrimitiveLiteral>(-2), nullptr); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + // Null value list with undefined upper bound. + auto *op = storage.Create<ListSlicingOperator>(storage.Create<PrimitiveLiteral>(TypedValue()), + storage.Create<PrimitiveLiteral>(-2), nullptr); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + ; + } + { + // Null value index. + auto *op = storage.Create<ListSlicingOperator>(list_literal, storage.Create<PrimitiveLiteral>(-2), + storage.Create<PrimitiveLiteral>(TypedValue())); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + ; + } +} + +TEST_F(ExpressionEvaluatorTest, IfOperator) { + auto *then_expression = storage.Create<PrimitiveLiteral>(10); + auto *else_expression = storage.Create<PrimitiveLiteral>(20); + { + auto *condition_true = + storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(2)); + auto *op = storage.Create<IfOperator>(condition_true, then_expression, else_expression); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 10); + } + { + auto *condition_false = + storage.Create<EqualOperator>(storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3)); + auto *op = storage.Create<IfOperator>(condition_false, then_expression, else_expression); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 20); + } + { + auto *condition_exception = + storage.Create<AdditionOperator>(storage.Create<PrimitiveLiteral>(2), storage.Create<PrimitiveLiteral>(3)); + auto *op = storage.Create<IfOperator>(condition_exception, then_expression, else_expression); + ASSERT_THROW(Eval(op), ExpressionRuntimeException); + } +} + +TEST_F(ExpressionEvaluatorTest, NotOperator) { + auto *op = storage.Create<NotOperator>(storage.Create<PrimitiveLiteral>(false)); + auto value = Eval(op); + ASSERT_EQ(value.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, UnaryPlusOperator) { + auto *op = storage.Create<UnaryPlusOperator>(storage.Create<PrimitiveLiteral>(5)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, UnaryMinusOperator) { + auto *op = storage.Create<UnaryMinusOperator>(storage.Create<PrimitiveLiteral>(5)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), -5); +} + +TEST_F(ExpressionEvaluatorTest, IsNullOperator) { + auto *op = storage.Create<IsNullOperator>(storage.Create<PrimitiveLiteral>(1)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create<IsNullOperator>(storage.Create<PrimitiveLiteral>(TypedValue())); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); +} + +// TEST_F(ExpressionEvaluatorTest, LabelsTest) { +// auto v1 = dba.InsertVertex(); +// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("ANIMAL")).HasValue()); +// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("DOG")).HasValue()); +// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("NICE_DOG")).HasValue()); +// dba.AdvanceCommand(); +// auto *identifier = storage.Create<Identifier>("n"); +// auto node_symbol = symbol_table.CreateSymbol("n", true); +// identifier->MapTo(node_symbol); +// frame[node_symbol] = TypedValue(v1); +// { +// auto *op = storage.Create<LabelsTest>( +// identifier, std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("ANIMAL")}); +// auto value = Eval(op); +// EXPECT_EQ(value.ValueBool(), true); +// } +// { +// auto *op = storage.Create<LabelsTest>( +// identifier, +// std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("BAD_DOG"), +// storage.GetLabelIx("ANIMAL")}); +// auto value = Eval(op); +// EXPECT_EQ(value.ValueBool(), false); +// } +// { +// frame[node_symbol] = TypedValue(); +// auto *op = storage.Create<LabelsTest>( +// identifier, +// std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("BAD_DOG"), +// storage.GetLabelIx("ANIMAL")}); +// auto value = Eval(op); +// EXPECT_TRUE(value.IsNull()); +// } +// } +// +TEST_F(ExpressionEvaluatorTest, Aggregation) { + auto aggr = storage.Create<Aggregation>(storage.Create<PrimitiveLiteral>(42), nullptr, Aggregation::Op::COUNT); + auto aggr_sym = symbol_table.CreateSymbol("aggr", true); + aggr->MapTo(aggr_sym); + frame[aggr_sym] = TypedValue(1); + auto value = Eval(aggr); + EXPECT_EQ(value.ValueInt(), 1); +} + +TEST_F(ExpressionEvaluatorTest, ListLiteral) { + auto *list_literal = storage.Create<ListLiteral>(std::vector<Expression *>{storage.Create<PrimitiveLiteral>(1), + storage.Create<PrimitiveLiteral>("bla"), + storage.Create<PrimitiveLiteral>(true)}); + TypedValue result = Eval(list_literal); + ASSERT_TRUE(result.IsList()); + auto &result_elems = result.ValueList(); + ASSERT_EQ(3, result_elems.size()); + EXPECT_TRUE(result_elems[0].IsInt()); + ; + EXPECT_TRUE(result_elems[1].IsString()); + ; + EXPECT_TRUE(result_elems[2].IsBool()); + ; +} + +TEST_F(ExpressionEvaluatorTest, ParameterLookup) { + ctx.parameters.Add(0, memgraph::storage::v3::PropertyValue(42)); + auto *param_lookup = storage.Create<ParameterLookup>(0); + auto value = Eval(param_lookup); + ASSERT_TRUE(value.IsInt()); + EXPECT_EQ(value.ValueInt(), 42); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAll1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *all = ALL("x", LIST(LITERAL(1), LITERAL(1)), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + all->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(all); + ASSERT_TRUE(value.IsBool()); + EXPECT_TRUE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAll2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *all = ALL("x", LIST(LITERAL(1), LITERAL(2)), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + all->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(all); + ASSERT_TRUE(value.IsBool()); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAllNullList) { + AstStorage storage; + auto *all = ALL("x", LITERAL(TypedValue()), WHERE(LITERAL(true))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + all->identifier_->MapTo(x_sym); + auto value = Eval(all); + EXPECT_TRUE(value.IsNull()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAllNullElementInList1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *all = ALL("x", LIST(LITERAL(1), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + all->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(all); + ASSERT_TRUE(value.IsBool()); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAllNullElementInList2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *all = ALL("x", LIST(LITERAL(2), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + all->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(all); + ASSERT_TRUE(value.IsBool()); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAllWhereWrongType) { + AstStorage storage; + auto *all = ALL("x", LIST(LITERAL(1)), WHERE(LITERAL(2))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + all->identifier_->MapTo(x_sym); + EXPECT_THROW(Eval(all), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, FunctionSingle1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *single = SINGLE("x", LIST(LITERAL(1), LITERAL(2)), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + single->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(single); + ASSERT_TRUE(value.IsBool()); + EXPECT_TRUE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionSingle2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *single = SINGLE("x", LIST(LITERAL(1), LITERAL(2)), WHERE(GREATER(ident_x, LITERAL(0)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + single->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(single); + ASSERT_TRUE(value.IsBool()); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionSingleNullList) { + AstStorage storage; + auto *single = SINGLE("x", LITERAL(TypedValue()), WHERE(LITERAL(true))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + single->identifier_->MapTo(x_sym); + auto value = Eval(single); + EXPECT_TRUE(value.IsNull()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionSingleNullElementInList1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *single = SINGLE("x", LIST(LITERAL(1), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + single->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(single); + ASSERT_TRUE(value.IsBool()); + EXPECT_TRUE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionSingleNullElementInList2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *single = SINGLE("x", LIST(LITERAL(2), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + single->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(single); + ASSERT_TRUE(value.IsBool()); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAny1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *any = ANY("x", LIST(LITERAL(1), LITERAL(2)), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + any->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(any); + ASSERT_TRUE(value.IsBool()); + EXPECT_TRUE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAny2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *any = ANY("x", LIST(LITERAL(1), LITERAL(2)), WHERE(EQ(ident_x, LITERAL(0)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + any->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(any); + ASSERT_TRUE(value.IsBool()); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAnyNullList) { + AstStorage storage; + auto *any = ANY("x", LITERAL(TypedValue()), WHERE(LITERAL(true))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + any->identifier_->MapTo(x_sym); + auto value = Eval(any); + EXPECT_TRUE(value.IsNull()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAnyNullElementInList1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *any = ANY("x", LIST(LITERAL(0), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(0)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + any->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(any); + EXPECT_TRUE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAnyNullElementInList2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *any = ANY("x", LIST(LITERAL(1), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(0)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + any->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(any); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionAnyWhereWrongType) { + AstStorage storage; + auto *any = ANY("x", LIST(LITERAL(1)), WHERE(LITERAL(2))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + any->identifier_->MapTo(x_sym); + EXPECT_THROW(Eval(any), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, FunctionNone1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *none = NONE("x", LIST(LITERAL(1), LITERAL(2)), WHERE(EQ(ident_x, LITERAL(0)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + none->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(none); + ASSERT_TRUE(value.IsBool()); + EXPECT_TRUE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionNone2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *none = NONE("x", LIST(LITERAL(1), LITERAL(2)), WHERE(EQ(ident_x, LITERAL(1)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + none->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(none); + ASSERT_TRUE(value.IsBool()); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionNoneNullList) { + AstStorage storage; + auto *none = NONE("x", LITERAL(TypedValue()), WHERE(LITERAL(true))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + none->identifier_->MapTo(x_sym); + auto value = Eval(none); + EXPECT_TRUE(value.IsNull()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionNoneNullElementInList1) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *any = NONE("x", LIST(LITERAL(1), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(0)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + any->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(any); + EXPECT_TRUE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionNoneNullElementInList2) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *none = NONE("x", LIST(LITERAL(0), LITERAL(TypedValue())), WHERE(EQ(ident_x, LITERAL(0)))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + none->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(none); + EXPECT_FALSE(value.ValueBool()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionNoneWhereWrongType) { + AstStorage storage; + auto *none = NONE("x", LIST(LITERAL(1)), WHERE(LITERAL(2))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + none->identifier_->MapTo(x_sym); + EXPECT_THROW(Eval(none), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, FunctionReduce) { + AstStorage storage; + auto *ident_sum = IDENT("sum"); + auto *ident_x = IDENT("x"); + auto *reduce = REDUCE("sum", LITERAL(0), "x", LIST(LITERAL(1), LITERAL(2)), ADD(ident_sum, ident_x)); + const auto sum_sym = symbol_table.CreateSymbol("sum", true); + reduce->accumulator_->MapTo(sum_sym); + ident_sum->MapTo(sum_sym); + const auto x_sym = symbol_table.CreateSymbol("x", true); + reduce->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(reduce); + ASSERT_TRUE(value.IsInt()); + EXPECT_EQ(value.ValueInt(), 3); +} + +TEST_F(ExpressionEvaluatorTest, FunctionExtract) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *extract = EXTRACT("x", LIST(LITERAL(1), LITERAL(2), LITERAL(TypedValue())), ADD(ident_x, LITERAL(1))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + extract->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(extract); + EXPECT_TRUE(value.IsList()); + ; + auto result = value.ValueList(); + EXPECT_EQ(result[0].ValueInt(), 2); + EXPECT_EQ(result[1].ValueInt(), 3); + EXPECT_TRUE(result[2].IsNull()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionExtractNull) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *extract = EXTRACT("x", LITERAL(TypedValue()), ADD(ident_x, LITERAL(1))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + extract->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + auto value = Eval(extract); + EXPECT_TRUE(value.IsNull()); +} + +TEST_F(ExpressionEvaluatorTest, FunctionExtractExceptions) { + AstStorage storage; + auto *ident_x = IDENT("x"); + auto *extract = EXTRACT("x", LITERAL("bla"), ADD(ident_x, LITERAL(1))); + const auto x_sym = symbol_table.CreateSymbol("x", true); + extract->identifier_->MapTo(x_sym); + ident_x->MapTo(x_sym); + EXPECT_THROW(Eval(extract), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, RegexMatchInvalidArguments) { + EXPECT_TRUE(Eval(storage.Create<RegexMatch>(LITERAL(TypedValue()), LITERAL("regex"))).IsNull()); + EXPECT_TRUE(Eval(storage.Create<RegexMatch>(LITERAL(3), LITERAL("regex"))).IsNull()); + EXPECT_TRUE(Eval(storage.Create<RegexMatch>(LIST(LITERAL("string")), LITERAL("regex"))).IsNull()); + EXPECT_TRUE(Eval(storage.Create<RegexMatch>(LITERAL("string"), LITERAL(TypedValue()))).IsNull()); + EXPECT_THROW(Eval(storage.Create<RegexMatch>(LITERAL("string"), LITERAL(42))), ExpressionRuntimeException); + EXPECT_THROW(Eval(storage.Create<RegexMatch>(LITERAL("string"), LIST(LITERAL("regex")))), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, RegexMatchInvalidRegex) { + EXPECT_THROW(Eval(storage.Create<RegexMatch>(LITERAL("text"), LITERAL("*ext"))), ExpressionRuntimeException); + EXPECT_THROW(Eval(storage.Create<RegexMatch>(LITERAL("text"), LITERAL("[ext"))), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, RegexMatch) { + EXPECT_FALSE(Eval(storage.Create<RegexMatch>(LITERAL("text"), LITERAL(".*ex"))).ValueBool()); + EXPECT_TRUE(Eval(storage.Create<RegexMatch>(LITERAL("text"), LITERAL(".*ext"))).ValueBool()); + EXPECT_FALSE(Eval(storage.Create<RegexMatch>(LITERAL("text"), LITERAL("[ext]"))).ValueBool()); + EXPECT_TRUE(Eval(storage.Create<RegexMatch>(LITERAL("text"), LITERAL(".+[ext]"))).ValueBool()); +} + +class ExpressionEvaluatorPropertyLookup : public ExpressionEvaluatorTest { + protected: + std::pair<std::string, memgraph::storage::v3::PropertyId> prop_age = + std::make_pair("age", shard_manager->NameToProperty("age")); + std::pair<std::string, memgraph::storage::v3::PropertyId> prop_height = + std::make_pair("height", shard_manager->NameToProperty("height")); + Identifier *identifier = storage.Create<Identifier>("element"); + Symbol symbol = symbol_table.CreateSymbol("element", true); + + void SetUp() { identifier->MapTo(symbol); } + + auto Value(std::pair<std::string, memgraph::storage::v3::PropertyId> property) { + auto *op = storage.Create<PropertyLookup>(identifier, storage.GetPropertyIx(property.first)); + return Eval(op); + } +}; + +// TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) { +// auto v1 = dba.InsertVertex(); +// ASSERT_TRUE(v1.SetProperty(prop_age.second, memgraph::storage::PropertyValue(10)).HasValue()); +// dba.AdvanceCommand(); +// frame[symbol] = TypedValue(v1); +// EXPECT_EQ(Value(prop_age).ValueInt(), 10); +// EXPECT_TRUE(Value(prop_height).IsNull()); +// } +// +// TEST_F(ExpressionEvaluatorPropertyLookup, Duration) { +// const memgraph::utils::Duration dur({10, 1, 30, 2, 22, 45}); +// frame[symbol] = TypedValue(dur); +// +// const std::pair day = std::make_pair("day", dba.NameToProperty("day")); +// const auto total_days = Value(day); +// EXPECT_TRUE(total_days.IsInt()); +// EXPECT_EQ(total_days.ValueInt(), 10); +// +// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour")); +// const auto total_hours = Value(hour); +// EXPECT_TRUE(total_hours.IsInt()); +// EXPECT_EQ(total_hours.ValueInt(), 1); +// +// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute")); +// const auto total_mins = Value(minute); +// EXPECT_TRUE(total_mins.IsInt()); +// +// EXPECT_EQ(total_mins.ValueInt(), 1 * 60 + 30); +// +// const std::pair sec = std::make_pair("second", dba.NameToProperty("second")); +// const auto total_secs = Value(sec); +// EXPECT_TRUE(total_secs.IsInt()); +// const auto expected_secs = total_mins.ValueInt() * 60 + 2; +// EXPECT_EQ(total_secs.ValueInt(), expected_secs); +// +// const std::pair milli = std::make_pair("millisecond", dba.NameToProperty("millisecond")); +// const auto total_milli = Value(milli); +// EXPECT_TRUE(total_milli.IsInt()); +// const auto expected_milli = total_secs.ValueInt() * 1000 + 22; +// EXPECT_EQ(total_milli.ValueInt(), expected_milli); +// +// const std::pair micro = std::make_pair("microsecond", dba.NameToProperty("microsecond")); +// const auto total_micros = Value(micro); +// EXPECT_TRUE(total_micros.IsInt()); +// const auto expected_micros = expected_milli * 1000 + 45; +// EXPECT_EQ(total_micros.ValueInt(), expected_micros); +// +// const std::pair nano = std::make_pair("nanosecond", dba.NameToProperty("nanosecond")); +// const auto total_nano = Value(nano); +// EXPECT_TRUE(total_nano.IsInt()); +// const auto expected_nano = expected_micros * 1000; +// EXPECT_EQ(total_nano.ValueInt(), expected_nano); +// } +// +// TEST_F(ExpressionEvaluatorPropertyLookup, Date) { +// const memgraph::utils::Date date({1996, 11, 22}); +// frame[symbol] = TypedValue(date); +// +// const std::pair year = std::make_pair("year", dba.NameToProperty("year")); +// const auto y = Value(year); +// EXPECT_TRUE(y.IsInt()); +// EXPECT_EQ(y.ValueInt(), 1996); +// +// const std::pair month = std::make_pair("month", dba.NameToProperty("month")); +// const auto m = Value(month); +// EXPECT_TRUE(m.IsInt()); +// EXPECT_EQ(m.ValueInt(), 11); +// +// const std::pair day = std::make_pair("day", dba.NameToProperty("day")); +// const auto d = Value(day); +// EXPECT_TRUE(d.IsInt()); +// EXPECT_EQ(d.ValueInt(), 22); +// } +// +// TEST_F(ExpressionEvaluatorPropertyLookup, LocalTime) { +// const memgraph::utils::LocalTime lt({1, 2, 3, 11, 22}); +// frame[symbol] = TypedValue(lt); +// +// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour")); +// const auto h = Value(hour); +// EXPECT_TRUE(h.IsInt()); +// EXPECT_EQ(h.ValueInt(), 1); +// +// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute")); +// const auto min = Value(minute); +// EXPECT_TRUE(min.IsInt()); +// EXPECT_EQ(min.ValueInt(), 2); +// +// const std::pair second = std::make_pair("second", dba.NameToProperty("second")); +// const auto sec = Value(second); +// EXPECT_TRUE(sec.IsInt()); +// EXPECT_EQ(sec.ValueInt(), 3); +// +// const std::pair millis = std::make_pair("millisecond", dba.NameToProperty("millisecond")); +// const auto mil = Value(millis); +// EXPECT_TRUE(mil.IsInt()); +// EXPECT_EQ(mil.ValueInt(), 11); +// +// const std::pair micros = std::make_pair("microsecond", dba.NameToProperty("microsecond")); +// const auto mic = Value(micros); +// EXPECT_TRUE(mic.IsInt()); +// EXPECT_EQ(mic.ValueInt(), 22); +// } +// +// TEST_F(ExpressionEvaluatorPropertyLookup, LocalDateTime) { +// const memgraph::utils::LocalDateTime ldt({1993, 8, 6}, {2, 3, 4, 55, 40}); +// frame[symbol] = TypedValue(ldt); +// +// const std::pair year = std::make_pair("year", dba.NameToProperty("year")); +// const auto y = Value(year); +// EXPECT_TRUE(y.IsInt()); +// EXPECT_EQ(y.ValueInt(), 1993); +// +// const std::pair month = std::make_pair("month", dba.NameToProperty("month")); +// const auto m = Value(month); +// EXPECT_TRUE(m.IsInt()); +// EXPECT_EQ(m.ValueInt(), 8); +// +// const std::pair day = std::make_pair("day", dba.NameToProperty("day")); +// const auto d = Value(day); +// EXPECT_TRUE(d.IsInt()); +// EXPECT_EQ(d.ValueInt(), 6); +// +// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour")); +// const auto h = Value(hour); +// EXPECT_TRUE(h.IsInt()); +// EXPECT_EQ(h.ValueInt(), 2); +// +// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute")); +// const auto min = Value(minute); +// EXPECT_TRUE(min.IsInt()); +// EXPECT_EQ(min.ValueInt(), 3); +// +// const std::pair second = std::make_pair("second", dba.NameToProperty("second")); +// const auto sec = Value(second); +// EXPECT_TRUE(sec.IsInt()); +// EXPECT_EQ(sec.ValueInt(), 4); +// +// const std::pair millis = std::make_pair("millisecond", dba.NameToProperty("millisecond")); +// const auto mil = Value(millis); +// EXPECT_TRUE(mil.IsInt()); +// EXPECT_EQ(mil.ValueInt(), 55); +// +// const std::pair micros = std::make_pair("microsecond", dba.NameToProperty("microsecond")); +// const auto mic = Value(micros); +// EXPECT_TRUE(mic.IsInt()); +// EXPECT_EQ(mic.ValueInt(), 40); +// } +// +// TEST_F(ExpressionEvaluatorPropertyLookup, Edge) { +// auto v1 = dba.InsertVertex(); +// auto v2 = dba.InsertVertex(); +// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("edge_type")); +// ASSERT_TRUE(e12.HasValue()); +// ASSERT_TRUE(e12->SetProperty(prop_age.second, memgraph::storage::PropertyValue(10)).HasValue()); +// dba.AdvanceCommand(); +// frame[symbol] = TypedValue(*e12); +// EXPECT_EQ(Value(prop_age).ValueInt(), 10); +// EXPECT_TRUE(Value(prop_height).IsNull()); +// } +// +TEST_F(ExpressionEvaluatorPropertyLookup, Null) { + frame[symbol] = TypedValue(); + EXPECT_TRUE(Value(prop_age).IsNull()); +} + +TEST_F(ExpressionEvaluatorPropertyLookup, MapLiteral) { + frame[symbol] = TypedValue(std::map<std::string, TypedValue>{{prop_age.first, TypedValue(10)}}); + EXPECT_EQ(Value(prop_age).ValueInt(), 10); + EXPECT_TRUE(Value(prop_height).IsNull()); +} + +class FunctionTest : public ExpressionEvaluatorTest { + protected: + std::vector<Expression *> ExpressionsFromTypedValues(const std::vector<TypedValue> &tvs) { + std::vector<Expression *> expressions; + expressions.reserve(tvs.size()); + + for (size_t i = 0; i < tvs.size(); ++i) { + auto *ident = storage.Create<Identifier>("arg_" + std::to_string(i), true); + auto sym = symbol_table.CreateSymbol("arg_" + std::to_string(i), true); + ident->MapTo(sym); + frame[sym] = tvs[i]; + expressions.push_back(ident); + } + + return expressions; + } + + TypedValue EvaluateFunctionWithExprs(const std::string &function_name, const std::vector<Expression *> &expressions) { + auto *op = storage.Create<Function>(function_name, expressions); + return Eval(op); + } + + template <class... TArgs> + TypedValue EvaluateFunction(const std::string &function_name, std::tuple<TArgs...> args) { + std::vector<TypedValue> tv_args; + tv_args.reserve(args.size()); + for (auto &arg : args) tv_args.emplace_back(std::move(arg)); + return EvaluateFunctionWithExprs(function_name, ExpressionsFromTypedValues(tv_args)); + } + + template <class... TArgs> + TypedValue EvaluateFunction(const std::string &function_name, TArgs &&...args) { + return EvaluateFunctionWithExprs(function_name, + ExpressionsFromTypedValues(std::vector<TypedValue>{TypedValue(args)...})); + } +}; + +template <class... TArgs> +static TypedValue MakeTypedValueList(TArgs &&...args) { + return TypedValue(std::vector<TypedValue>{TypedValue(args)...}); +} + +TEST_F(FunctionTest, EndNode) { + ASSERT_THROW(EvaluateFunction("ENDNODE"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("ENDNODE", TypedValue()).IsNull()); + auto v1 = CreateVertex({}, shard_manager.get()); + auto e = CreateEdge({}, shard_manager.get()); + const auto expected = VertexId{{}, 0}; + const auto res = EvaluateFunction("ENDNODE", e).ValueVertex().Id(); + ASSERT_EQ(res, expected); + ASSERT_THROW(EvaluateFunction("ENDNODE", 2), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Head) { + ASSERT_THROW(EvaluateFunction("HEAD"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("HEAD", TypedValue()).IsNull()); + auto argument = MakeTypedValueList(3, 4, 5); + ASSERT_EQ(EvaluateFunction("HEAD", argument).ValueInt(), 3); + argument.ValueList().clear(); + ASSERT_TRUE(EvaluateFunction("HEAD", argument).IsNull()); + ASSERT_THROW(EvaluateFunction("HEAD", 2), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Properties) { + ASSERT_THROW(EvaluateFunction("PROPERTIES"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("PROPERTIES", TypedValue()).IsNull()); + const auto height = shard_manager->NameToProperty("height"); + const auto age = shard_manager->NameToProperty("age"); + auto v1 = CreateVertex({{height, Value(static_cast<int64_t>(5))}, {age, Value(static_cast<int64_t>(10))}}, + shard_manager.get()); + auto e = CreateEdge({{height, Value(static_cast<int64_t>(3))}, {age, Value(static_cast<int64_t>(15))}}, + shard_manager.get()); + + auto prop_values_to_int = [](TypedValue t) { + std::unordered_map<std::string, int> properties; + for (auto property : t.ValueMap()) { + properties[std::string(property.first)] = property.second.ValueInt(); + } + return properties; + }; + + ASSERT_THAT(prop_values_to_int(EvaluateFunction("PROPERTIES", v1)), + UnorderedElementsAre(testing::Pair("height", 5), testing::Pair("age", 10))); + ASSERT_THAT(prop_values_to_int(EvaluateFunction("PROPERTIES", e)), + UnorderedElementsAre(testing::Pair("height", 3), testing::Pair("age", 15))); + ASSERT_THROW(EvaluateFunction("PROPERTIES", 2), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Last) { + ASSERT_THROW(EvaluateFunction("LAST"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("LAST", TypedValue()).IsNull()); + auto argument = MakeTypedValueList(3, 4, 5); + ASSERT_EQ(EvaluateFunction("LAST", argument).ValueInt(), 5); + argument.ValueList().clear(); + ASSERT_TRUE(EvaluateFunction("LAST", argument).IsNull()); + ASSERT_THROW(EvaluateFunction("LAST", 5), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Size) { + ASSERT_THROW(EvaluateFunction("SIZE"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("SIZE", TypedValue()).IsNull()); + auto argument = MakeTypedValueList(3, 4, 5); + ASSERT_EQ(EvaluateFunction("SIZE", argument).ValueInt(), 3); + ASSERT_EQ(EvaluateFunction("SIZE", "john").ValueInt(), 4); + ASSERT_EQ(EvaluateFunction("SIZE", + std::map<std::string, TypedValue>{ + {"a", TypedValue(5)}, {"b", TypedValue(true)}, {"c", TypedValue("123")}}) + .ValueInt(), + 3); + ASSERT_THROW(EvaluateFunction("SIZE", 5), FunctionRuntimeException); + + // TODO(kostasrim) Add this when we enable paths on the accessors + // auto v0 = dba.InsertVertex(); + // memgraph::query::Path path(v0); + // EXPECT_EQ(EvaluateFunction("SIZE", path).ValueInt(), 0); + // auto v1 = dba.InsertVertex(); + // auto edge = dba.InsertEdge(&v0, &v1, dba.NameToEdgeType("type")); + // ASSERT_TRUE(edge.HasValue()); + // path.Expand(*edge); + // path.Expand(v1); + // EXPECT_EQ(EvaluateFunction("SIZE", path).ValueInt(), 1); +} + +TEST_F(FunctionTest, StartNode) { + ASSERT_THROW(EvaluateFunction("STARTNODE"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("STARTNODE", TypedValue()).IsNull()); + auto v1 = CreateVertex({}, shard_manager.get()); + auto e = CreateEdge({}, shard_manager.get()); + const auto expected = VertexId{{}, 0}; + const auto res = EvaluateFunction("STARTNODE", e).ValueVertex().Id(); + ASSERT_EQ(res, expected); + ASSERT_THROW(EvaluateFunction("STARTNODE", 2), FunctionRuntimeException); +} + +// TODO(kostasrim) Enable this test once we add degree to the accessors +// TEST_F(FunctionTest, Degree) { +// ASSERT_THROW(EvaluateFunction("DEGREE"), ExpressionRuntimeException); +// ASSERT_TRUE(EvaluateFunction("DEGREE", TypedValue()).IsNull()); +// auto v1 = dba.InsertVertex(); +// auto v2 = dba.InsertVertex(); +// auto v3 = dba.InsertVertex(); +// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t")); +// ASSERT_TRUE(e12.HasValue()); +// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue()); +// dba.AdvanceCommand(); +// ASSERT_EQ(EvaluateFunction("DEGREE", v1).ValueInt(), 1); +// ASSERT_EQ(EvaluateFunction("DEGREE", v2).ValueInt(), 2); +// ASSERT_EQ(EvaluateFunction("DEGREE", v3).ValueInt(), 1); +// ASSERT_THROW(EvaluateFunction("DEGREE", 2), ExpressionRuntimeException); +// ASSERT_THROW(EvaluateFunction("DEGREE", *e12), ExpressionRuntimeException); +// } +// +// TODO(kostasrim) Enable this test once we add InDegree to the accessors +// TEST_F(FunctionTest, InDegree) { +// ASSERT_THROW(EvaluateFunction("INDEGREE"), ExpressionRuntimeException); +// ASSERT_TRUE(EvaluateFunction("INDEGREE", TypedValue()).IsNull()); +// auto v1 = dba.InsertVertex(); +// auto v2 = dba.InsertVertex(); +// auto v3 = dba.InsertVertex(); +// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t")); +// ASSERT_TRUE(e12.HasValue()); +// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue()); +// dba.AdvanceCommand(); +// ASSERT_EQ(EvaluateFunction("INDEGREE", v1).ValueInt(), 0); +// ASSERT_EQ(EvaluateFunction("INDEGREE", v2).ValueInt(), 2); +// ASSERT_EQ(EvaluateFunction("INDEGREE", v3).ValueInt(), 0); +// ASSERT_THROW(EvaluateFunction("INDEGREE", 2), ExpressionRuntimeException); +// ASSERT_THROW(EvaluateFunction("INDEGREE", *e12), ExpressionRuntimeException); +// } +// +// TODO(kostasrim) Enable this test once we add OutDegree to the accessors +// TEST_F(FunctionTest, OutDegree) { +// ASSERT_THROW(EvaluateFunction("OUTDEGREE"), ExpressionRuntimeException); +// ASSERT_TRUE(EvaluateFunction("OUTDEGREE", TypedValue()).IsNull()); +// auto v1 = dba.InsertVertex(); +// auto v2 = dba.InsertVertex(); +// auto v3 = dba.InsertVertex(); +// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t")); +// ASSERT_TRUE(e12.HasValue()); +// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue()); +// dba.AdvanceCommand(); +// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v1).ValueInt(), 1); +// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v2).ValueInt(), 0); +// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v3).ValueInt(), 1); +// ASSERT_THROW(EvaluateFunction("OUTDEGREE", 2), ExpressionRuntimeException); +// ASSERT_THROW(EvaluateFunction("OUTDEGREE", *e12), ExpressionRuntimeException); +// } +// +TEST_F(FunctionTest, ToBoolean) { + ASSERT_THROW(EvaluateFunction("TOBOOLEAN"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("TOBOOLEAN", TypedValue()).IsNull()); + ASSERT_EQ(EvaluateFunction("TOBOOLEAN", 123).ValueBool(), true); + ASSERT_EQ(EvaluateFunction("TOBOOLEAN", -213).ValueBool(), true); + ASSERT_EQ(EvaluateFunction("TOBOOLEAN", 0).ValueBool(), false); + ASSERT_EQ(EvaluateFunction("TOBOOLEAN", " trUE \n\t").ValueBool(), true); + ASSERT_EQ(EvaluateFunction("TOBOOLEAN", "\n\tFalsE").ValueBool(), false); + ASSERT_TRUE(EvaluateFunction("TOBOOLEAN", "\n\tFALSEA ").IsNull()); + ASSERT_EQ(EvaluateFunction("TOBOOLEAN", true).ValueBool(), true); + ASSERT_EQ(EvaluateFunction("TOBOOLEAN", false).ValueBool(), false); +} + +TEST_F(FunctionTest, ToFloat) { + ASSERT_THROW(EvaluateFunction("TOFLOAT"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("TOFLOAT", TypedValue()).IsNull()); + ASSERT_EQ(EvaluateFunction("TOFLOAT", " -3.5 \n\t").ValueDouble(), -3.5); + ASSERT_EQ(EvaluateFunction("TOFLOAT", "\n\t0.5e-1").ValueDouble(), 0.05); + ASSERT_TRUE(EvaluateFunction("TOFLOAT", "\n\t3.4e-3X ").IsNull()); + ASSERT_EQ(EvaluateFunction("TOFLOAT", -3.5).ValueDouble(), -3.5); + ASSERT_EQ(EvaluateFunction("TOFLOAT", -3).ValueDouble(), -3.0); + ASSERT_THROW(EvaluateFunction("TOFLOAT", true), FunctionRuntimeException); +} + +TEST_F(FunctionTest, ToInteger) { + ASSERT_THROW(EvaluateFunction("TOINTEGER"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("TOINTEGER", TypedValue()).IsNull()); + ASSERT_EQ(EvaluateFunction("TOINTEGER", false).ValueInt(), 0); + ASSERT_EQ(EvaluateFunction("TOINTEGER", true).ValueInt(), 1); + ASSERT_EQ(EvaluateFunction("TOINTEGER", "\n\t3").ValueInt(), 3); + ASSERT_EQ(EvaluateFunction("TOINTEGER", " -3.5 \n\t").ValueInt(), -3); + ASSERT_TRUE(EvaluateFunction("TOINTEGER", "\n\t3X ").IsNull()); + ASSERT_EQ(EvaluateFunction("TOINTEGER", -3.5).ValueInt(), -3); + ASSERT_EQ(EvaluateFunction("TOINTEGER", 3.5).ValueInt(), 3); +} + +TEST_F(FunctionTest, Type) { + ASSERT_THROW(EvaluateFunction("TYPE"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("TYPE", TypedValue()).IsNull()); + auto e = CreateEdge({}, shard_manager.get()); + ASSERT_EQ(EvaluateFunction("TYPE", e).ValueString(), "edge_type"); + ASSERT_THROW(EvaluateFunction("TYPE", 2), FunctionRuntimeException); +} + +TEST_F(FunctionTest, ValueType) { + ASSERT_THROW(EvaluateFunction("VALUETYPE"), FunctionRuntimeException); + ASSERT_THROW(EvaluateFunction("VALUETYPE", TypedValue(), TypedValue()), FunctionRuntimeException); + ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue()).ValueString(), "NULL"); + ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(true)).ValueString(), "BOOLEAN"); + ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(1)).ValueString(), "INTEGER"); + ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(1.1)).ValueString(), "FLOAT"); + ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue("test")).ValueString(), "STRING"); + ASSERT_EQ( + EvaluateFunction("VALUETYPE", TypedValue(std::vector<TypedValue>{TypedValue(1), TypedValue(2)})).ValueString(), + "LIST"); + ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(std::map<std::string, TypedValue>{{"test", TypedValue(1)}})) + .ValueString(), + "MAP"); + auto v1 = CreateVertex({}, shard_manager.get()); + ASSERT_EQ(EvaluateFunction("VALUETYPE", v1).ValueString(), "NODE"); + auto e = CreateEdge({}, shard_manager.get()); + ASSERT_EQ(EvaluateFunction("VALUETYPE", e).ValueString(), "RELATIONSHIP"); + // TODO(kostasrim) Fix this when we add Path to accessors + // Path p(v1, *e, v2); + // ASSERT_EQ(EvaluateFunction("VALUETYPE", p).ValueString(), "PATH"); +} + +TEST_F(FunctionTest, Labels) { + ASSERT_THROW(EvaluateFunction("LABELS"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("LABELS", TypedValue()).IsNull()); + Label label{shard_manager->NameToLabel("label1")}; + auto v = CreateVertex({}, shard_manager.get(), std::move(label)); + std::vector<std::string> labels; + auto _labels = EvaluateFunction("LABELS", v).ValueList(); + labels.reserve(_labels.size()); + for (auto label : _labels) { + labels.emplace_back(label.ValueString()); + } + ASSERT_THAT(labels, UnorderedElementsAre("label1")); + ASSERT_THROW(EvaluateFunction("LABELS", 2), FunctionRuntimeException); +} + +// TODO(kostasrim) Enable this once we fix accessors Path +// TEST_F(FunctionTest, NodesRelationships) { +// EXPECT_THROW(EvaluateFunction("NODES"), ExpressionRuntimeException); +// EXPECT_THROW(EvaluateFunction("RELATIONSHIPS"), ExpressionRuntimeException); +// EXPECT_TRUE(EvaluateFunction("NODES", TypedValue()).IsNull()); +// EXPECT_TRUE(EvaluateFunction("RELATIONSHIPS", TypedValue()).IsNull()); +// +// { +// auto v1 = dba.InsertVertex(); +// auto v2 = dba.InsertVertex(); +// auto v3 = dba.InsertVertex(); +// auto e1 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("Type")); +// ASSERT_TRUE(e1.HasValue()); +// auto e2 = dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("Type")); +// ASSERT_TRUE(e2.HasValue()); +// memgraph::query::Path path{v1, *e1, v2, *e2, v3}; +// dba.AdvanceCommand(); +// +// auto _nodes = EvaluateFunction("NODES", path).ValueList(); +// std::vector<memgraph::query::VertexAccessor> nodes; +// for (const auto &node : _nodes) { +// nodes.push_back(node.ValueVertex()); +// } +// EXPECT_THAT(nodes, ElementsAre(v1, v2, v3)); +// +// auto _edges = EvaluateFunction("RELATIONSHIPS", path).ValueList(); +// std::vector<memgraph::query::EdgeAccessor> edges; +// for (const auto &edge : _edges) { +// edges.push_back(edge.ValueEdge()); +// } +// EXPECT_THAT(edges, ElementsAre(*e1, *e2)); +// } +// +// EXPECT_THROW(EvaluateFunction("NODES", 2), ExpressionRuntimeException); +// EXPECT_THROW(EvaluateFunction("RELATIONSHIPS", 2), ExpressionRuntimeException); +// } +// +TEST_F(FunctionTest, Range) { + EXPECT_THROW(EvaluateFunction("RANGE"), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction("RANGE", 1, 2, TypedValue()).IsNull()); + EXPECT_THROW(EvaluateFunction("RANGE", 1, TypedValue(), 1.3), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("RANGE", 1, 2, 0), FunctionRuntimeException); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", 1, 3)), ElementsAre(1, 2, 3)); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", -1, 5, 2)), ElementsAre(-1, 1, 3, 5)); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", 2, 10, 3)), ElementsAre(2, 5, 8)); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", 2, 2, 2)), ElementsAre(2)); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", 3, 0, 5)), ElementsAre()); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", 5, 1, -2)), ElementsAre(5, 3, 1)); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", 6, 1, -2)), ElementsAre(6, 4, 2)); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", 2, 2, -3)), ElementsAre(2)); + EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", -2, 4, -1)), ElementsAre()); +} + +TEST_F(FunctionTest, Keys) { + ASSERT_THROW(EvaluateFunction("KEYS"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("KEYS", TypedValue()).IsNull()); + const auto height = shard_manager->NameToProperty("height"); + const auto age = shard_manager->NameToProperty("age"); + auto v1 = CreateVertex({{height, Value(static_cast<int64_t>(5))}, {age, Value(static_cast<int64_t>(10))}}, + shard_manager.get()); + auto edge = CreateEdge({{height, Value(static_cast<int64_t>(3))}, {age, Value(static_cast<int64_t>(15))}}, + shard_manager.get()); + auto prop_keys_to_string = [](TypedValue t) { + std::vector<std::string> keys; + for (auto property : t.ValueList()) { + keys.emplace_back(property.ValueString()); + } + return keys; + }; + ASSERT_THAT(prop_keys_to_string(EvaluateFunction("KEYS", v1)), UnorderedElementsAre("height", "age")); + ASSERT_THAT(prop_keys_to_string(EvaluateFunction("KEYS", edge)), UnorderedElementsAre("height", "age")); + ASSERT_THROW(EvaluateFunction("KEYS", 2), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Tail) { + ASSERT_THROW(EvaluateFunction("TAIL"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("TAIL", TypedValue()).IsNull()); + auto argument = MakeTypedValueList(); + ASSERT_EQ(EvaluateFunction("TAIL", argument).ValueList().size(), 0U); + argument = MakeTypedValueList(3, 4, true, "john"); + auto list = EvaluateFunction("TAIL", argument).ValueList(); + ASSERT_EQ(list.size(), 3U); + ASSERT_EQ(list[0].ValueInt(), 4); + ASSERT_EQ(list[1].ValueBool(), true); + ASSERT_EQ(list[2].ValueString(), "john"); + ASSERT_THROW(EvaluateFunction("TAIL", 2), FunctionRuntimeException); +} + +TEST_F(FunctionTest, UniformSample) { + ASSERT_THROW(EvaluateFunction("UNIFORMSAMPLE"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("UNIFORMSAMPLE", TypedValue(), TypedValue()).IsNull()); + ASSERT_TRUE(EvaluateFunction("UNIFORMSAMPLE", TypedValue(), 1).IsNull()); + ASSERT_TRUE(EvaluateFunction("UNIFORMSAMPLE", MakeTypedValueList(), TypedValue()).IsNull()); + ASSERT_TRUE(EvaluateFunction("UNIFORMSAMPLE", MakeTypedValueList(), 1).IsNull()); + ASSERT_THROW(EvaluateFunction("UNIFORMSAMPLE", MakeTypedValueList(1, 2, 3), -1), FunctionRuntimeException); + ASSERT_EQ(EvaluateFunction("UNIFORMSAMPLE", MakeTypedValueList(1, 2, 3), 0).ValueList().size(), 0); + ASSERT_EQ(EvaluateFunction("UNIFORMSAMPLE", MakeTypedValueList(1, 2, 3), 2).ValueList().size(), 2); + ASSERT_EQ(EvaluateFunction("UNIFORMSAMPLE", MakeTypedValueList(1, 2, 3), 3).ValueList().size(), 3); + ASSERT_EQ(EvaluateFunction("UNIFORMSAMPLE", MakeTypedValueList(1, 2, 3), 5).ValueList().size(), 5); +} + +TEST_F(FunctionTest, Abs) { + ASSERT_THROW(EvaluateFunction("ABS"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("ABS", TypedValue()).IsNull()); + ASSERT_EQ(EvaluateFunction("ABS", -2).ValueInt(), 2); + ASSERT_EQ(EvaluateFunction("ABS", -2.5).ValueDouble(), 2.5); + ASSERT_THROW(EvaluateFunction("ABS", true), FunctionRuntimeException); +} + +//// Test if log works. If it does then all functions wrapped with +//// WRAP_CMATH_FLOAT_FUNCTION macro should work and are not gonna be tested for +//// correctnes.. +TEST_F(FunctionTest, Log) { + ASSERT_THROW(EvaluateFunction("LOG"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("LOG", TypedValue()).IsNull()); + ASSERT_DOUBLE_EQ(EvaluateFunction("LOG", 2).ValueDouble(), log(2)); + ASSERT_DOUBLE_EQ(EvaluateFunction("LOG", 1.5).ValueDouble(), log(1.5)); + // Not portable, but should work on most platforms. + ASSERT_TRUE(std::isnan(EvaluateFunction("LOG", -1.5).ValueDouble())); + ASSERT_THROW(EvaluateFunction("LOG", true), FunctionRuntimeException); +} + +//// Function Round wraps round from cmath and will work if FunctionTest.Log test +//// passes. This test is used to show behavior of round since it differs from +//// neo4j's round. +TEST_F(FunctionTest, Round) { + ASSERT_THROW(EvaluateFunction("ROUND"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("ROUND", TypedValue()).IsNull()); + ASSERT_EQ(EvaluateFunction("ROUND", -2).ValueDouble(), -2); + ASSERT_EQ(EvaluateFunction("ROUND", -2.4).ValueDouble(), -2); + ASSERT_EQ(EvaluateFunction("ROUND", -2.5).ValueDouble(), -3); + ASSERT_EQ(EvaluateFunction("ROUND", -2.6).ValueDouble(), -3); + ASSERT_EQ(EvaluateFunction("ROUND", 2.4).ValueDouble(), 2); + ASSERT_EQ(EvaluateFunction("ROUND", 2.5).ValueDouble(), 3); + ASSERT_EQ(EvaluateFunction("ROUND", 2.6).ValueDouble(), 3); + ASSERT_THROW(EvaluateFunction("ROUND", true), FunctionRuntimeException); +} + +// Check if wrapped functions are callable (check if everything was spelled +// correctly...). Wrapper correctnes is checked in FunctionTest.Log function +// test. +TEST_F(FunctionTest, WrappedMathFunctions) { + for (auto function_name : + {"FLOOR", "CEIL", "ROUND", "EXP", "LOG", "LOG10", "SQRT", "ACOS", "ASIN", "ATAN", "COS", "SIN", "TAN"}) { + EvaluateFunction(function_name, 0.5); + } +} + +TEST_F(FunctionTest, Atan2) { + ASSERT_THROW(EvaluateFunction("ATAN2"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("ATAN2", TypedValue(), 1).IsNull()); + ASSERT_TRUE(EvaluateFunction("ATAN2", 1, TypedValue()).IsNull()); + ASSERT_DOUBLE_EQ(EvaluateFunction("ATAN2", 2, -1.0).ValueDouble(), atan2(2, -1)); + ASSERT_THROW(EvaluateFunction("ATAN2", 3.0, true), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Sign) { + ASSERT_THROW(EvaluateFunction("SIGN"), FunctionRuntimeException); + ASSERT_TRUE(EvaluateFunction("SIGN", TypedValue()).IsNull()); + ASSERT_EQ(EvaluateFunction("SIGN", -2).ValueInt(), -1); + ASSERT_EQ(EvaluateFunction("SIGN", -0.2).ValueInt(), -1); + ASSERT_EQ(EvaluateFunction("SIGN", 0.0).ValueInt(), 0); + ASSERT_EQ(EvaluateFunction("SIGN", 2.5).ValueInt(), 1); + ASSERT_THROW(EvaluateFunction("SIGN", true), FunctionRuntimeException); +} + +TEST_F(FunctionTest, E) { + ASSERT_THROW(EvaluateFunction("E", 1), FunctionRuntimeException); + ASSERT_DOUBLE_EQ(EvaluateFunction("E").ValueDouble(), M_E); +} + +TEST_F(FunctionTest, Pi) { + ASSERT_THROW(EvaluateFunction("PI", 1), FunctionRuntimeException); + ASSERT_DOUBLE_EQ(EvaluateFunction("PI").ValueDouble(), M_PI); +} + +TEST_F(FunctionTest, Rand) { + ASSERT_THROW(EvaluateFunction("RAND", 1), FunctionRuntimeException); + ASSERT_GE(EvaluateFunction("RAND").ValueDouble(), 0.0); + ASSERT_LT(EvaluateFunction("RAND").ValueDouble(), 1.0); +} + +using memgraph::functions::kStartsWith; +TEST_F(FunctionTest, StartsWith) { + EXPECT_THROW(EvaluateFunction(kStartsWith), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction(kStartsWith, "a", TypedValue()).IsNull()); + EXPECT_THROW(EvaluateFunction(kStartsWith, TypedValue(), 1.3), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction(kStartsWith, "abc", "abc").ValueBool()); + EXPECT_TRUE(EvaluateFunction(kStartsWith, "abcdef", "abc").ValueBool()); + EXPECT_FALSE(EvaluateFunction(kStartsWith, "abcdef", "aBc").ValueBool()); + EXPECT_FALSE(EvaluateFunction(kStartsWith, "abc", "abcd").ValueBool()); +} + +using memgraph::functions::kEndsWith; +TEST_F(FunctionTest, EndsWith) { + EXPECT_THROW(EvaluateFunction(kEndsWith), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction(kEndsWith, "a", TypedValue()).IsNull()); + EXPECT_THROW(EvaluateFunction(kEndsWith, TypedValue(), 1.3), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction(kEndsWith, "abc", "abc").ValueBool()); + EXPECT_TRUE(EvaluateFunction(kEndsWith, "abcdef", "def").ValueBool()); + EXPECT_FALSE(EvaluateFunction(kEndsWith, "abcdef", "dEf").ValueBool()); + EXPECT_FALSE(EvaluateFunction(kEndsWith, "bcd", "abcd").ValueBool()); +} + +using memgraph::functions::kContains; +TEST_F(FunctionTest, Contains) { + EXPECT_THROW(EvaluateFunction(kContains), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction(kContains, "a", TypedValue()).IsNull()); + EXPECT_THROW(EvaluateFunction(kContains, TypedValue(), 1.3), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction(kContains, "abc", "abc").ValueBool()); + EXPECT_TRUE(EvaluateFunction(kContains, "abcde", "bcd").ValueBool()); + EXPECT_FALSE(EvaluateFunction(kContains, "cde", "abcdef").ValueBool()); + EXPECT_FALSE(EvaluateFunction(kContains, "abcdef", "dEf").ValueBool()); +} + +TEST_F(FunctionTest, Assert) { + // Invalid calls. + ASSERT_THROW(EvaluateFunction("ASSERT"), FunctionRuntimeException); + ASSERT_THROW(EvaluateFunction("ASSERT", false, false), FunctionRuntimeException); + ASSERT_THROW(EvaluateFunction("ASSERT", "string", false), FunctionRuntimeException); + ASSERT_THROW(EvaluateFunction("ASSERT", false, "reason", true), FunctionRuntimeException); + + // Valid calls, assertion fails. + ASSERT_THROW(EvaluateFunction("ASSERT", false), FunctionRuntimeException); + ASSERT_THROW(EvaluateFunction("ASSERT", false, "message"), FunctionRuntimeException); + try { + EvaluateFunction("ASSERT", false, "bbgba"); + } catch (FunctionRuntimeException &e) { + ASSERT_TRUE(std::string(e.what()).find("bbgba") != std::string::npos); + } + + // Valid calls, assertion passes. + ASSERT_TRUE(EvaluateFunction("ASSERT", true).ValueBool()); + ASSERT_TRUE(EvaluateFunction("ASSERT", true, "message").ValueBool()); +} + +TEST_F(FunctionTest, Counter) { + EXPECT_THROW(EvaluateFunction("COUNTER"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("COUNTER", "a"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("COUNTER", "a", "b"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("COUNTER", "a", "b", "c"), FunctionRuntimeException); + + EXPECT_EQ(EvaluateFunction("COUNTER", "c1", 0).ValueInt(), 0); + EXPECT_EQ(EvaluateFunction("COUNTER", "c1", 0).ValueInt(), 1); + EXPECT_EQ(EvaluateFunction("COUNTER", "c2", 0).ValueInt(), 0); + EXPECT_EQ(EvaluateFunction("COUNTER", "c1", 0).ValueInt(), 2); + EXPECT_EQ(EvaluateFunction("COUNTER", "c2", 0).ValueInt(), 1); + + EXPECT_EQ(EvaluateFunction("COUNTER", "c3", -1).ValueInt(), -1); + EXPECT_EQ(EvaluateFunction("COUNTER", "c3", -1).ValueInt(), 0); + EXPECT_EQ(EvaluateFunction("COUNTER", "c3", -1).ValueInt(), 1); + + EXPECT_EQ(EvaluateFunction("COUNTER", "c4", 0, 5).ValueInt(), 0); + EXPECT_EQ(EvaluateFunction("COUNTER", "c4", 0, 5).ValueInt(), 5); + EXPECT_EQ(EvaluateFunction("COUNTER", "c4", 0, 5).ValueInt(), 10); + + EXPECT_EQ(EvaluateFunction("COUNTER", "c5", 0, -5).ValueInt(), 0); + EXPECT_EQ(EvaluateFunction("COUNTER", "c5", 0, -5).ValueInt(), -5); + EXPECT_EQ(EvaluateFunction("COUNTER", "c5", 0, -5).ValueInt(), -10); + + EXPECT_THROW(EvaluateFunction("COUNTER", "c6", 0, 0), FunctionRuntimeException); +} + +// TODO(kostasrim) Add this once we fix accessors CypherId() functions +// TEST_F(FunctionTest, Id) { +// auto v = CreateVertex({}, shard_manager.get()); +// auto e = CreateEdge({}, shard_manager.get()); +// EXPECT_TRUE(EvaluateFunction("ID", TypedValue()).IsNull()); +// EXPECT_EQ(EvaluateFunction("ID", v).ValueInt(), 0); +// EXPECT_EQ(EvaluateFunction("ID", e).ValueInt(), 0); +// EXPECT_THROW(EvaluateFunction("ID"), FunctionRuntimeException); +// EXPECT_THROW(EvaluateFunction("ID", 0), FunctionRuntimeException); +// EXPECT_THROW(EvaluateFunction("ID", v, e), FunctionRuntimeException); +//} + +TEST_F(FunctionTest, ToStringNull) { EXPECT_TRUE(EvaluateFunction("TOSTRING", TypedValue()).IsNull()); } + +TEST_F(FunctionTest, ToStringString) { + EXPECT_EQ(EvaluateFunction("TOSTRING", "").ValueString(), ""); + EXPECT_EQ(EvaluateFunction("TOSTRING", "this is a string").ValueString(), "this is a string"); +} + +TEST_F(FunctionTest, ToStringInteger) { + EXPECT_EQ(EvaluateFunction("TOSTRING", -23321312).ValueString(), "-23321312"); + EXPECT_EQ(EvaluateFunction("TOSTRING", 0).ValueString(), "0"); + EXPECT_EQ(EvaluateFunction("TOSTRING", 42).ValueString(), "42"); +} + +TEST_F(FunctionTest, ToStringDouble) { + EXPECT_EQ(EvaluateFunction("TOSTRING", -42.42).ValueString(), "-42.420000"); + EXPECT_EQ(EvaluateFunction("TOSTRING", 0.0).ValueString(), "0.000000"); + EXPECT_EQ(EvaluateFunction("TOSTRING", 238910.2313217).ValueString(), "238910.231322"); +} + +TEST_F(FunctionTest, ToStringBool) { + EXPECT_EQ(EvaluateFunction("TOSTRING", true).ValueString(), "true"); + EXPECT_EQ(EvaluateFunction("TOSTRING", false).ValueString(), "false"); +} + +// TEST_F(FunctionTest, ToStringDate) { +// const auto date = memgraph::utils::Date({1970, 1, 2}); +// EXPECT_EQ(EvaluateFunction("TOSTRING", date).ValueString(), "1970-01-02"); +// } +// +// TEST_F(FunctionTest, ToStringLocalTime) { +// const auto lt = memgraph::utils::LocalTime({13, 2, 40, 100, 50}); +// EXPECT_EQ(EvaluateFunction("TOSTRING", lt).ValueString(), "13:02:40.100050"); +// } +// +// TEST_F(FunctionTest, ToStringLocalDateTime) { +// const auto ldt = memgraph::utils::LocalDateTime({1970, 1, 2}, {23, 02, 59}); +// EXPECT_EQ(EvaluateFunction("TOSTRING", ldt).ValueString(), "1970-01-02T23:02:59.000000"); +// } +// +// TEST_F(FunctionTest, ToStringDuration) { +// memgraph::utils::Duration duration{{.minute = 2, .second = 2, .microsecond = 33}}; +// EXPECT_EQ(EvaluateFunction("TOSTRING", duration).ValueString(), "P0DT0H2M2.000033S"); +// } +// +TEST_F(FunctionTest, ToStringExceptions) { + EXPECT_THROW(EvaluateFunction("TOSTRING", 1, 2, 3), FunctionRuntimeException); +} +// +// TEST_F(FunctionTest, TimestampVoid) { +// ctx.timestamp = 42; +// EXPECT_EQ(EvaluateFunction("TIMESTAMP").ValueInt(), 42); +// } +// +// TEST_F(FunctionTest, TimestampDate) { +// ctx.timestamp = 42; +// EXPECT_EQ(EvaluateFunction("TIMESTAMP", memgraph::utils::Date({1970, 1, 1})).ValueInt(), 0); +// EXPECT_EQ(EvaluateFunction("TIMESTAMP", memgraph::utils::Date({1971, 1, 1})).ValueInt(), 31536000000000); +// } +// +// TEST_F(FunctionTest, TimestampLocalTime) { +// ctx.timestamp = 42; +// const memgraph::utils::LocalTime time(10000); +// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 10000); +// } +// +// TEST_F(FunctionTest, TimestampLocalDateTime) { +// ctx.timestamp = 42; +// const memgraph::utils::LocalDateTime time(20000); +// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 20000); +// } +// +// TEST_F(FunctionTest, TimestampDuration) { +// ctx.timestamp = 42; +// const memgraph::utils::Duration time(20000); +// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 20000); +// } +// +// TEST_F(FunctionTest, TimestampExceptions) { +// ctx.timestamp = 42; +// EXPECT_THROW(EvaluateFunction("TIMESTAMP", 1).ValueInt(), ExpressionRuntimeException); +// } +// +TEST_F(FunctionTest, Left) { + EXPECT_THROW(EvaluateFunction("LEFT"), FunctionRuntimeException); + + EXPECT_TRUE(EvaluateFunction("LEFT", TypedValue(), TypedValue()).IsNull()); + EXPECT_TRUE(EvaluateFunction("LEFT", TypedValue(), 10).IsNull()); + EXPECT_THROW(EvaluateFunction("LEFT", TypedValue(), -10), FunctionRuntimeException); + + EXPECT_EQ(EvaluateFunction("LEFT", "memgraph", 0).ValueString(), ""); + EXPECT_EQ(EvaluateFunction("LEFT", "memgraph", 3).ValueString(), "mem"); + EXPECT_EQ(EvaluateFunction("LEFT", "memgraph", 1000).ValueString(), "memgraph"); + EXPECT_THROW(EvaluateFunction("LEFT", "memgraph", -10), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("LEFT", "memgraph", "graph"), FunctionRuntimeException); + + EXPECT_THROW(EvaluateFunction("LEFT", 132, 10), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Right) { + EXPECT_THROW(EvaluateFunction("RIGHT"), FunctionRuntimeException); + + EXPECT_TRUE(EvaluateFunction("RIGHT", TypedValue(), TypedValue()).IsNull()); + EXPECT_TRUE(EvaluateFunction("RIGHT", TypedValue(), 10).IsNull()); + EXPECT_THROW(EvaluateFunction("RIGHT", TypedValue(), -10), FunctionRuntimeException); + + EXPECT_EQ(EvaluateFunction("RIGHT", "memgraph", 0).ValueString(), ""); + EXPECT_EQ(EvaluateFunction("RIGHT", "memgraph", 3).ValueString(), "aph"); + EXPECT_EQ(EvaluateFunction("RIGHT", "memgraph", 1000).ValueString(), "memgraph"); + EXPECT_THROW(EvaluateFunction("RIGHT", "memgraph", -10), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("RIGHT", "memgraph", "graph"), FunctionRuntimeException); + + EXPECT_THROW(EvaluateFunction("RIGHT", 132, 10), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Trimming) { + EXPECT_TRUE(EvaluateFunction("LTRIM", TypedValue()).IsNull()); + EXPECT_TRUE(EvaluateFunction("RTRIM", TypedValue()).IsNull()); + EXPECT_TRUE(EvaluateFunction("TRIM", TypedValue()).IsNull()); + + EXPECT_EQ(EvaluateFunction("LTRIM", " abc ").ValueString(), "abc "); + EXPECT_EQ(EvaluateFunction("RTRIM", " abc ").ValueString(), " abc"); + EXPECT_EQ(EvaluateFunction("TRIM", "abc").ValueString(), "abc"); + + EXPECT_THROW(EvaluateFunction("LTRIM", "x", "y"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("RTRIM", "x", "y"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("TRIM", "x", "y"), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Reverse) { + EXPECT_TRUE(EvaluateFunction("REVERSE", TypedValue()).IsNull()); + EXPECT_EQ(EvaluateFunction("REVERSE", "abc").ValueString(), "cba"); + EXPECT_THROW(EvaluateFunction("REVERSE", "x", "y"), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Replace) { + EXPECT_THROW(EvaluateFunction("REPLACE"), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction("REPLACE", TypedValue(), "l", "w").IsNull()); + EXPECT_TRUE(EvaluateFunction("REPLACE", "hello", TypedValue(), "w").IsNull()); + EXPECT_TRUE(EvaluateFunction("REPLACE", "hello", "l", TypedValue()).IsNull()); + EXPECT_EQ(EvaluateFunction("REPLACE", "hello", "l", "w").ValueString(), "hewwo"); + + EXPECT_THROW(EvaluateFunction("REPLACE", 1, "l", "w"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("REPLACE", "hello", 1, "w"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("REPLACE", "hello", "l", 1), FunctionRuntimeException); +} + +TEST_F(FunctionTest, Split) { + EXPECT_THROW(EvaluateFunction("SPLIT"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("SPLIT", "one,two", 1), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("SPLIT", 1, "one,two"), FunctionRuntimeException); + + EXPECT_TRUE(EvaluateFunction("SPLIT", TypedValue(), TypedValue()).IsNull()); + EXPECT_TRUE(EvaluateFunction("SPLIT", "one,two", TypedValue()).IsNull()); + EXPECT_TRUE(EvaluateFunction("SPLIT", TypedValue(), ",").IsNull()); + + auto result = EvaluateFunction("SPLIT", "one,two", ","); + EXPECT_TRUE(result.IsList()); + EXPECT_EQ(result.ValueList()[0].ValueString(), "one"); + EXPECT_EQ(result.ValueList()[1].ValueString(), "two"); +} + +TEST_F(FunctionTest, Substring) { + EXPECT_THROW(EvaluateFunction("SUBSTRING"), FunctionRuntimeException); + + EXPECT_TRUE(EvaluateFunction("SUBSTRING", TypedValue(), 0, 10).IsNull()); + EXPECT_THROW(EvaluateFunction("SUBSTRING", TypedValue(), TypedValue()), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("SUBSTRING", TypedValue(), -10), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("SUBSTRING", TypedValue(), 0, TypedValue()), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("SUBSTRING", TypedValue(), 0, -10), FunctionRuntimeException); + + EXPECT_EQ(EvaluateFunction("SUBSTRING", "hello", 2).ValueString(), "llo"); + EXPECT_EQ(EvaluateFunction("SUBSTRING", "hello", 10).ValueString(), ""); + EXPECT_EQ(EvaluateFunction("SUBSTRING", "hello", 2, 0).ValueString(), ""); + EXPECT_EQ(EvaluateFunction("SUBSTRING", "hello", 1, 3).ValueString(), "ell"); + EXPECT_EQ(EvaluateFunction("SUBSTRING", "hello", 1, 4).ValueString(), "ello"); + EXPECT_EQ(EvaluateFunction("SUBSTRING", "hello", 1, 10).ValueString(), "ello"); +} + +TEST_F(FunctionTest, ToLower) { + EXPECT_THROW(EvaluateFunction("TOLOWER"), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction("TOLOWER", TypedValue()).IsNull()); + EXPECT_EQ(EvaluateFunction("TOLOWER", "Ab__C").ValueString(), "ab__c"); +} + +TEST_F(FunctionTest, ToUpper) { + EXPECT_THROW(EvaluateFunction("TOUPPER"), FunctionRuntimeException); + EXPECT_TRUE(EvaluateFunction("TOUPPER", TypedValue()).IsNull()); + EXPECT_EQ(EvaluateFunction("TOUPPER", "Ab__C").ValueString(), "AB__C"); +} + +TEST_F(FunctionTest, ToByteString) { + EXPECT_THROW(EvaluateFunction("TOBYTESTRING"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("TOBYTESTRING", 42), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("TOBYTESTRING", TypedValue()), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("TOBYTESTRING", "", 42), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("TOBYTESTRING", "ff"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("TOBYTESTRING", "00"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("TOBYTESTRING", "0xG"), FunctionRuntimeException); + EXPECT_EQ(EvaluateFunction("TOBYTESTRING", "").ValueString(), ""); + EXPECT_EQ(EvaluateFunction("TOBYTESTRING", "0x").ValueString(), ""); + EXPECT_EQ(EvaluateFunction("TOBYTESTRING", "0X").ValueString(), ""); + EXPECT_EQ(EvaluateFunction("TOBYTESTRING", "0x0123456789aAbBcCdDeEfF").ValueString(), + "\x01\x23\x45\x67\x89\xAA\xBB\xCC\xDD\xEE\xFF"); + EXPECT_EQ(EvaluateFunction("TOBYTESTRING", "0x042").ValueString().size(), 2); + EXPECT_EQ(EvaluateFunction("TOBYTESTRING", "0x042").ValueString(), + memgraph::utils::pmr::string("\x00\x42", 2, memgraph::utils::NewDeleteResource())); +} + +TEST_F(FunctionTest, FromByteString) { + EXPECT_THROW(EvaluateFunction("FROMBYTESTRING"), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("FROMBYTESTRING", 42), FunctionRuntimeException); + EXPECT_THROW(EvaluateFunction("FROMBYTESTRING", TypedValue()), FunctionRuntimeException); + EXPECT_EQ(EvaluateFunction("FROMBYTESTRING", "").ValueString(), ""); + auto bytestring = EvaluateFunction("TOBYTESTRING", "0x123456789aAbBcCdDeEfF"); + EXPECT_EQ(EvaluateFunction("FROMBYTESTRING", bytestring).ValueString(), "0x0123456789aabbccddeeff"); + EXPECT_EQ(EvaluateFunction("FROMBYTESTRING", std::string("\x00\x42", 2)).ValueString(), "0x0042"); +} + +// TEST_F(FunctionTest, Date) { +// const auto unix_epoch = memgraph::utils::Date({1970, 1, 1}); +// EXPECT_EQ(EvaluateFunction("DATE", "1970-01-01").ValueDate(), unix_epoch); +// const auto map_param = TypedValue( +// std::map<std::string, TypedValue>{{"year", TypedValue(1970)}, {"month", TypedValue(1)}, {"day", +// TypedValue(1)}}); +// EXPECT_EQ(EvaluateFunction("DATE", map_param).ValueDate(), unix_epoch); +// const auto today = memgraph::utils::CurrentDate(); +// EXPECT_EQ(EvaluateFunction("DATE").ValueDate(), today); +// +// EXPECT_THROW(EvaluateFunction("DATE", "{}"), memgraph::utils::BasicException); +// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"years", TypedValue(1970)}}), +// ExpressionRuntimeException); +// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"mnths", TypedValue(1970)}}), +// ExpressionRuntimeException); +// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"dayz", TypedValue(1970)}}), +// ExpressionRuntimeException); +// } +// +// TEST_F(FunctionTest, LocalTime) { +// const auto local_time = memgraph::utils::LocalTime({13, 3, 2, 0, 0}); +// EXPECT_EQ(EvaluateFunction("LOCALTIME", "130302").ValueLocalTime(), local_time); +// const auto one_sec_in_microseconds = 1000000; +// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"hour", TypedValue(1)}, +// {"minute", TypedValue(2)}, +// {"second", TypedValue(3)}, +// {"millisecond", TypedValue(4)}, +// {"microsecond", TypedValue(5)}}); +// EXPECT_EQ(EvaluateFunction("LOCALTIME", map_param).ValueLocalTime(), memgraph::utils::LocalTime({1, 2, 3, 4, 5})); +// const auto today = memgraph::utils::CurrentLocalTime(); +// EXPECT_NEAR(EvaluateFunction("LOCALTIME").ValueLocalTime().MicrosecondsSinceEpoch(), +// today.MicrosecondsSinceEpoch(), +// one_sec_in_microseconds); +// +// EXPECT_THROW(EvaluateFunction("LOCALTIME", "{}"), memgraph::utils::BasicException); +// EXPECT_THROW(EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"hous", +// TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"minut", TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"seconds", TypedValue(1970)}})), +// ExpressionRuntimeException); +// } +// +// TEST_F(FunctionTest, LocalDateTime) { +// const auto local_date_time = memgraph::utils::LocalDateTime({1970, 1, 1}, {13, 3, 2, 0, 0}); +// EXPECT_EQ(EvaluateFunction("LOCALDATETIME", "1970-01-01T13:03:02").ValueLocalDateTime(), local_date_time); +// const auto today = memgraph::utils::CurrentLocalDateTime(); +// const auto one_sec_in_microseconds = 1000000; +// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"year", TypedValue(1972)}, +// {"month", TypedValue(2)}, +// {"day", TypedValue(3)}, +// {"hour", TypedValue(4)}, +// {"minute", TypedValue(5)}, +// {"second", TypedValue(6)}, +// {"millisecond", TypedValue(7)}, +// {"microsecond", TypedValue(8)}}); +// +// EXPECT_EQ(EvaluateFunction("LOCALDATETIME", map_param).ValueLocalDateTime(), +// memgraph::utils::LocalDateTime({1972, 2, 3}, {4, 5, 6, 7, 8})); +// EXPECT_NEAR(EvaluateFunction("LOCALDATETIME").ValueLocalDateTime().MicrosecondsSinceEpoch(), +// today.MicrosecondsSinceEpoch(), one_sec_in_microseconds); +// EXPECT_THROW(EvaluateFunction("LOCALDATETIME", "{}"), memgraph::utils::BasicException); +// EXPECT_THROW( +// EvaluateFunction("LOCALDATETIME", TypedValue(std::map<std::string, TypedValue>{{"hours", TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("LOCALDATETIME", TypedValue(std::map<std::string, TypedValue>{{"seconds", +// TypedValue(1970)}})), ExpressionRuntimeException); +// } +// +// TEST_F(FunctionTest, Duration) { +// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"day", TypedValue(3)}, +// {"hour", TypedValue(4)}, +// {"minute", TypedValue(5)}, +// {"second", TypedValue(6)}, +// {"millisecond", TypedValue(7)}, +// {"microsecond", TypedValue(8)}}); +// +// EXPECT_EQ(EvaluateFunction("DURATION", map_param).ValueDuration(), memgraph::utils::Duration({3, 4, 5, 6, 7, 8})); +// EXPECT_THROW(EvaluateFunction("DURATION", "{}"), memgraph::utils::BasicException); +// EXPECT_THROW(EvaluateFunction("DURATION", TypedValue(std::map<std::string, TypedValue>{{"hours", +// TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("DURATION", TypedValue(std::map<std::string, TypedValue>{{"seconds", TypedValue(1970)}})), +// ExpressionRuntimeException); +// +// const auto map_param_negative = TypedValue(std::map<std::string, TypedValue>{{"day", TypedValue(-3)}, +// {"hour", TypedValue(-4)}, +// {"minute", TypedValue(-5)}, +// {"second", TypedValue(-6)}, +// {"millisecond", TypedValue(-7)}, +// {"microsecond", TypedValue(-8)}}); +// EXPECT_EQ(EvaluateFunction("DURATION", map_param_negative).ValueDuration(), +// memgraph::utils::Duration({-3, -4, -5, -6, -7, -8})); +// +// EXPECT_EQ(EvaluateFunction("DURATION", "P4DT4H5M6.2S").ValueDuration(), +// memgraph::utils::Duration({4, 4, 5, 6, 0, 200000})); +// EXPECT_EQ(EvaluateFunction("DURATION", "P3DT4H5M6.100S").ValueDuration(), +// memgraph::utils::Duration({3, 4, 5, 6, 0, 100000})); +// EXPECT_EQ(EvaluateFunction("DURATION", "P3DT4H5M6.100110S").ValueDuration(), +// memgraph::utils::Duration({3, 4, 5, 6, 100, 110})); +// } +} // namespace From 9e81fe791cfaf5bfbf7ab321f5f7325518f6b7dd Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Mon, 14 Nov 2022 21:22:28 +0200 Subject: [PATCH 04/26] Fix clang-tidy warnings, remove commented out code and add HasLabel functions in ShardRequestManager to avoid throwing bad optional on expression evaluator --- src/expr/interpret/eval.hpp | 2 +- src/functions/awesome_memgraph_functions.hpp | 152 ++--- src/query/v2/accessors.cpp | 9 +- src/query/v2/shard_request_manager.hpp | 9 + tests/unit/query_v2_expression_evaluator.cpp | 550 +++---------------- 5 files changed, 165 insertions(+), 557 deletions(-) diff --git a/src/expr/interpret/eval.hpp b/src/expr/interpret/eval.hpp index 139e37514..8b8b5a7c7 100644 --- a/src/expr/interpret/eval.hpp +++ b/src/expr/interpret/eval.hpp @@ -417,7 +417,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { TReturnType HasLabelImpl(const VertexAccessor &vertex, const LabelIx &label_ix, QueryEngineTag /*tag*/) { auto label = typename VertexAccessor::Label{LabelId::FromUint(label_ix.ix)}; auto has_label = vertex.HasLabel(label); - return !has_label; + return has_label; } TypedValue Visit(LabelsTest &labels_test) override { diff --git a/src/functions/awesome_memgraph_functions.hpp b/src/functions/awesome_memgraph_functions.hpp index ca415c69b..0a2b873c2 100644 --- a/src/functions/awesome_memgraph_functions.hpp +++ b/src/functions/awesome_memgraph_functions.hpp @@ -61,12 +61,10 @@ template <typename TypedValueT, typename FunctionContextT, typename Tag, typenam std::function<TypedValueT(const TypedValueT *arguments, int64_t num_arguments, const FunctionContextT &context)> NameToFunction(const std::string &function_name); -namespace { -const char kStartsWith[] = "STARTSWITH"; -const char kEndsWith[] = "ENDSWITH"; -const char kContains[] = "CONTAINS"; -const char kId[] = "ID"; -} // namespace +inline const char kStartsWith[] = "STARTSWITH"; +inline const char kEndsWith[] = "ENDSWITH"; +inline const char kContains[] = "CONTAINS"; +inline const char kId[] = "ID"; } // namespace memgraph::functions @@ -484,11 +482,11 @@ TypedValueT Properties(const TypedValueT *args, int64_t nargs, const FunctionCon const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsVertex()) { - return get_properties(value.ValueVertex()); - } else { - return get_properties(value.ValueEdge()); } + if (value.IsVertex()) { + return get_properties(value.ValueVertex()); + } + return get_properties(value.ValueEdge()); } template <typename TypedValueT, typename FunctionContextT> @@ -497,17 +495,19 @@ TypedValueT Size(const TypedValueT *args, int64_t nargs, const FunctionContextT const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsList()) { + } + if (value.IsList()) { return TypedValueT(static_cast<int64_t>(value.ValueList().size()), ctx.memory); - } else if (value.IsString()) { + } + if (value.IsString()) { return TypedValueT(static_cast<int64_t>(value.ValueString().size()), ctx.memory); - } else if (value.IsMap()) { + } + if (value.IsMap()) { // neo4j doesn't implement size for map, but I don't see a good reason not // to do it. return TypedValueT(static_cast<int64_t>(value.ValueMap().size()), ctx.memory); - } else { - return TypedValueT(static_cast<int64_t>(value.ValuePath().edges().size()), ctx.memory); } + return TypedValueT(static_cast<int64_t>(value.ValuePath().edges().size()), ctx.memory); } template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv> @@ -527,9 +527,9 @@ TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionCont } } -namespace { - -size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) { +// This is needed because clang-tidy fails to identify the use of this function in the if-constexpr branch +// NOLINTNEXTLINE(clang-diagnostic-unused-function) +inline size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) { if (maybe_degree.HasError()) { switch (maybe_degree.GetError()) { case storage::v3::Error::DELETED_OBJECT: @@ -546,8 +546,6 @@ size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) { return *maybe_degree; } -} // namespace - template <typename TypedValueT, typename FunctionContextT, typename Tag> TypedValueT Degree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType<TypedValueT, Or<Null, Vertex>>("degree", args, nargs); @@ -599,18 +597,19 @@ TypedValueT ToBoolean(const TypedValueT *args, int64_t nargs, const FunctionCont const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsBool()) { - return TypedValueT(value.ValueBool(), ctx.memory); - } else if (value.IsInt()) { - return TypedValueT(value.ValueInt() != 0L, ctx.memory); - } else { - auto s = utils::ToUpperCase(utils::Trim(value.ValueString())); - if (s == "TRUE") return TypedValueT(true, ctx.memory); - if (s == "FALSE") return TypedValueT(false, ctx.memory); - // I think this is just stupid and that exception should be thrown, but - // neo4j does it this way... - return TypedValueT(ctx.memory); } + if (value.IsBool()) { + return TypedValueT(value.ValueBool(), ctx.memory); + } + if (value.IsInt()) { + return TypedValueT(value.ValueInt() != 0L, ctx.memory); + } + auto s = utils::ToUpperCase(utils::Trim(value.ValueString())); + if (s == "TRUE") return TypedValueT(true, ctx.memory); + if (s == "FALSE") return TypedValueT(false, ctx.memory); + // I think this is just stupid and that exception should be thrown, but + // neo4j does it this way... + return TypedValueT(ctx.memory); } template <typename TypedValueT, typename FunctionContextT> @@ -619,16 +618,17 @@ TypedValueT ToFloat(const TypedValueT *args, int64_t nargs, const FunctionContex const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsInt()) { + } + if (value.IsInt()) { return TypedValueT(static_cast<double>(value.ValueInt()), ctx.memory); - } else if (value.IsDouble()) { + } + if (value.IsDouble()) { return TypedValueT(value, ctx.memory); - } else { - try { - return TypedValueT(utils::ParseDouble(utils::Trim(value.ValueString())), ctx.memory); - } catch (const utils::BasicException &) { - return TypedValueT(ctx.memory); - } + } + try { + return TypedValueT(utils::ParseDouble(utils::Trim(value.ValueString())), ctx.memory); + } catch (const utils::BasicException &) { + return TypedValueT(ctx.memory); } } @@ -638,20 +638,22 @@ TypedValueT ToInteger(const TypedValueT *args, int64_t nargs, const FunctionCont const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsBool()) { + } + if (value.IsBool()) { return TypedValueT(value.ValueBool() ? 1L : 0L, ctx.memory); - } else if (value.IsInt()) { + } + if (value.IsInt()) { return TypedValueT(value, ctx.memory); - } else if (value.IsDouble()) { + } + if (value.IsDouble()) { return TypedValueT(static_cast<int64_t>(value.ValueDouble()), ctx.memory); - } else { - try { - // Yup, this is correct. String is valid if it has floating point - // number, then it is parsed and converted to int. - return TypedValueT(static_cast<int64_t>(utils::ParseDouble(utils::Trim(value.ValueString()))), ctx.memory); - } catch (const utils::BasicException &) { - return TypedValueT(ctx.memory); - } + } + try { + // Yup, this is correct. String is valid if it has floating point + // number, then it is parsed and converted to int. + return TypedValueT(static_cast<int64_t>(utils::ParseDouble(utils::Trim(value.ValueString()))), ctx.memory); + } catch (const utils::BasicException &) { + return TypedValueT(ctx.memory); } } @@ -736,11 +738,11 @@ TypedValueT Keys(const TypedValueT *args, int64_t nargs, const FunctionContextT const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsVertex()) { - return get_keys(value.ValueVertex()); - } else { - return get_keys(value.ValueEdge()); } + if (value.IsVertex()) { + return get_keys(value.ValueVertex()); + } + return get_keys(value.ValueEdge()); } template <typename TypedValueT, typename FunctionContextT, typename Tag> @@ -853,13 +855,14 @@ TypedValueT Abs(const TypedValueT *args, int64_t nargs, const FunctionContextT & const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsInt()) { - return TypedValueT(std::abs(value.ValueInt()), ctx.memory); - } else { - return TypedValueT(std::abs(value.ValueDouble()), ctx.memory); } + if (value.IsInt()) { + return TypedValueT(std::abs(value.ValueInt()), ctx.memory); + } + return TypedValueT(std::abs(value.ValueDouble()), ctx.memory); } +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \ template <typename TypedValueT, typename FunctionContextT> \ TypedValueT name(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { \ @@ -867,11 +870,11 @@ TypedValueT Abs(const TypedValueT *args, int64_t nargs, const FunctionContextT & const auto &value = args[0]; \ if (value.IsNull()) { \ return TypedValueT(ctx.memory); \ - } else if (value.IsInt()) { \ - return TypedValueT(lowercased_name(value.ValueInt()), ctx.memory); \ - } else { \ - return TypedValueT(lowercased_name(value.ValueDouble()), ctx.memory); \ } \ + if (value.IsInt()) { \ + return TypedValueT(lowercased_name(value.ValueInt()), ctx.memory); \ + } \ + return TypedValueT(lowercased_name(value.ValueDouble()), ctx.memory); \ } WRAP_CMATH_FLOAT_FUNCTION(Ceil, ceil) @@ -899,9 +902,8 @@ TypedValueT Atan2(const TypedValueT *args, int64_t nargs, const FunctionContextT auto to_double = [](const TypedValueT &t) -> double { if (t.IsInt()) { return t.ValueInt(); - } else { - return t.ValueDouble(); } + return t.ValueDouble(); }; double y = to_double(args[0]); double x = to_double(args[1]); @@ -915,11 +917,11 @@ TypedValueT Sign(const TypedValueT *args, int64_t nargs, const FunctionContextT const auto &value = args[0]; if (value.IsNull()) { return TypedValueT(ctx.memory); - } else if (value.IsInt()) { - return sign(value.ValueInt()); - } else { - return sign(value.ValueDouble()); } + if (value.IsInt()) { + return sign(value.ValueInt()); + } + return sign(value.ValueDouble()); } template <typename TypedValueT, typename FunctionContextT> @@ -962,7 +964,7 @@ struct StartsWithPredicate { }; template <typename TypedValueT, typename FunctionContextT> -inline auto StartsWith = StringMatchOperator<StartsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>; +inline const auto StartsWith = StringMatchOperator<StartsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>; // Check if s1 ends with s2. template <typename TypedValueT> @@ -975,7 +977,7 @@ struct EndsWithPredicate { }; template <typename TypedValueT, typename FunctionContextT> -inline auto EndsWith = StringMatchOperator<EndsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>; +inline const auto EndsWith = StringMatchOperator<EndsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>; // Check if s1 contains s2. template <typename TypedValueT> @@ -988,7 +990,7 @@ struct ContainsPredicate { }; template <typename TypedValueT, typename FunctionContextT> -inline auto Contains = StringMatchOperator<ContainsPredicate<TypedValueT>, TypedValueT, FunctionContextT>; +inline const auto Contains = StringMatchOperator<ContainsPredicate<TypedValueT>, TypedValueT, FunctionContextT>; template <typename TypedValueT, typename FunctionContextT> TypedValueT Assert(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { @@ -1026,11 +1028,11 @@ TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &c const auto &arg = args[0]; if (arg.IsNull()) { return TypedValueT(ctx.memory); - } else if (arg.IsVertex()) { - return TypedValueT(static_cast<int64_t>(arg.ValueVertex().CypherId()), ctx.memory); - } else { - return TypedValueT(static_cast<int64_t>(arg.ValueEdge().CypherId()), ctx.memory); } + if (arg.IsVertex()) { + return TypedValueT(static_cast<int64_t>(arg.ValueVertex().CypherId()), ctx.memory); + } + return TypedValueT(static_cast<int64_t>(arg.ValueEdge().CypherId()), ctx.memory); } template <typename TypedValueT, typename FunctionContextT> diff --git a/src/query/v2/accessors.cpp b/src/query/v2/accessors.cpp index cbdce89e0..63915327f 100644 --- a/src/query/v2/accessors.cpp +++ b/src/query/v2/accessors.cpp @@ -23,11 +23,11 @@ EdgeTypeId EdgeAccessor::EdgeType() const { return edge.type.id; } const std::vector<std::pair<PropertyId, Value>> &EdgeAccessor::Properties() const { return edge.properties; } Value EdgeAccessor::GetProperty(const std::string &prop_name) const { - auto prop_id = manager_->NameToProperty(prop_name); - auto it = std::find_if(edge.properties.begin(), edge.properties.end(), [&](auto &pr) { return prop_id == pr.first; }); - if (it == edge.properties.end()) { + if (!manager_->HasProperty(prop_name)) { return {}; } + auto prop_id = manager_->NameToProperty(prop_name); + auto it = std::find_if(edge.properties.begin(), edge.properties.end(), [&](auto &pr) { return prop_id == pr.first; }); return it->second; } @@ -88,6 +88,9 @@ Value VertexAccessor::GetProperty(PropertyId prop_id) const { // NOLINTNEXTLINE(readability-convert-member-functions-to-static) Value VertexAccessor::GetProperty(const std::string &prop_name) const { + if (!manager_->HasProperty(prop_name)) { + return {}; + } return GetProperty(manager_->NameToProperty(prop_name)); } diff --git a/src/query/v2/shard_request_manager.hpp b/src/query/v2/shard_request_manager.hpp index a73201046..003cafaf8 100644 --- a/src/query/v2/shard_request_manager.hpp +++ b/src/query/v2/shard_request_manager.hpp @@ -129,6 +129,9 @@ class ShardRequestManagerInterface { virtual const std::string &PropertyToName(memgraph::storage::v3::PropertyId prop) const = 0; virtual const std::string &LabelToName(memgraph::storage::v3::LabelId label) const = 0; virtual const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId type) const = 0; + virtual bool HasProperty(const std::string &name) const = 0; + virtual bool HasEdgeType(const std::string &name) const = 0; + virtual bool HasLabel(const std::string &name) const = 0; virtual bool IsPrimaryLabel(LabelId label) const = 0; virtual bool IsPrimaryKey(LabelId primary_label, PropertyId property) const = 0; }; @@ -353,6 +356,12 @@ class ShardRequestManager : public ShardRequestManagerInterface { return result_rows; } + bool HasProperty(const std::string &name) const override { return shards_map_.GetPropertyId(name).has_value(); } + + bool HasEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name).has_value(); } + + bool HasLabel(const std::string &name) const override { return shards_map_.GetLabelId(name).has_value(); } + private: enum class PaginatedResponseState { Pending, PartiallyFinished }; diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp index 6bc6e1c8b..97122ff0f 100644 --- a/tests/unit/query_v2_expression_evaluator.cpp +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -30,6 +30,7 @@ #include "query/v2/frontend/ast/ast.hpp" #include "query/v2/requests.hpp" #include "query/v2/shard_request_manager.hpp" +#include "storage/v3/property_value.hpp" #include "storage/v3/storage.hpp" #include "utils/exceptions.hpp" #include "utils/string.hpp" @@ -117,6 +118,12 @@ class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInte return edge_types_.IdToName(id.AsUint()); } + bool HasProperty(const std::string &name) const override { return shards_map_.GetPropertyId(name).has_value(); } + + bool HasEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name).has_value(); } + + bool HasLabel(const std::string &name) const override { return shards_map_.GetLabelId(name).has_value(); } + bool IsPrimaryLabel(LabelId label) const override { return true; } bool IsPrimaryKey(LabelId primary_label, PropertyId property) const override { return true; } @@ -202,10 +209,6 @@ class ExpressionEvaluatorTest : public ::testing::Test { ExpressionEvaluatorTest() {} protected: - // memgraph::storage::Storage db; - // memgraph::storage::Storage::Accessor storage_dba{db.Access()}; - // memgraph::query::DbAccessor dba{&storage_dba}; - // AstStorage storage; memgraph::utils::MonotonicBufferResource mem{1024}; EvaluationContext ctx{.memory = &mem, .timestamp = memgraph::query::v2::QueryTimestamp()}; @@ -575,36 +578,33 @@ TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) { // TODO(kostasrim) Investigate // Shall we return null on missing properties? Or shall we throw bad optional access as we do now? - // { - // // Legal indexing, non-existing key. - // auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>("blah")); - // auto value1 = Eval(op1); - // EXPECT_TRUE(value1.IsNull()); - // - // auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>("blah")); - // auto value2 = Eval(op2); - // EXPECT_TRUE(value2.IsNull()); - // } - // { - // // Wrong key type. - // auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>(1)); - // EXPECT_THROW(Eval(op1), ExpressionRuntimeException); - // - // auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>(1)); - // EXPECT_THROW(Eval(op2), ExpressionRuntimeException); - // } - // { - // // Indexing with Null. - // auto *op1 = storage.Create<SubscriptOperator>(vertex_id, - // storage.Create<PrimitiveLiteral>(memgraph::storage::PropertyValue())); - // auto value1 = Eval(op1); - // EXPECT_TRUE(value1.IsNull()); - // - // auto *op2 = storage.Create<SubscriptOperator>(edge_id, - // storage.Create<PrimitiveLiteral>(memgraph::storage::PropertyValue())); - // auto value2 = Eval(op2); - // EXPECT_TRUE(value2.IsNull()); - // } + { + // Legal indexing, non-existing key. + auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>("blah")); + auto value1 = Eval(op1); + EXPECT_TRUE(value1.IsNull()); + auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>("blah")); + auto value2 = Eval(op2); + EXPECT_TRUE(value2.IsNull()); + } + { + // Wrong key type. + auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>(1)); + EXPECT_THROW(Eval(op1), ExpressionRuntimeException); + + auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>(1)); + EXPECT_THROW(Eval(op2), ExpressionRuntimeException); + } + { + // Indexing with Null. + auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>(TypedValue{})); + auto value1 = Eval(op1); + EXPECT_TRUE(value1.IsNull()); + + auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>(TypedValue{})); + auto value2 = Eval(op2); + EXPECT_TRUE(value2.IsNull()); + } } TEST_F(ExpressionEvaluatorTest, ListSlicingOperator) { @@ -741,41 +741,31 @@ TEST_F(ExpressionEvaluatorTest, IsNullOperator) { ASSERT_EQ(val2.ValueBool(), true); } -// TEST_F(ExpressionEvaluatorTest, LabelsTest) { -// auto v1 = dba.InsertVertex(); -// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("ANIMAL")).HasValue()); -// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("DOG")).HasValue()); -// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("NICE_DOG")).HasValue()); -// dba.AdvanceCommand(); -// auto *identifier = storage.Create<Identifier>("n"); -// auto node_symbol = symbol_table.CreateSymbol("n", true); -// identifier->MapTo(node_symbol); -// frame[node_symbol] = TypedValue(v1); -// { -// auto *op = storage.Create<LabelsTest>( -// identifier, std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("ANIMAL")}); -// auto value = Eval(op); -// EXPECT_EQ(value.ValueBool(), true); -// } -// { -// auto *op = storage.Create<LabelsTest>( -// identifier, -// std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("BAD_DOG"), -// storage.GetLabelIx("ANIMAL")}); -// auto value = Eval(op); -// EXPECT_EQ(value.ValueBool(), false); -// } -// { -// frame[node_symbol] = TypedValue(); -// auto *op = storage.Create<LabelsTest>( -// identifier, -// std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("BAD_DOG"), -// storage.GetLabelIx("ANIMAL")}); -// auto value = Eval(op); -// EXPECT_TRUE(value.IsNull()); -// } -// } -// +TEST_F(ExpressionEvaluatorTest, LabelsTest) { + Label label{shard_manager->NameToLabel("label1")}; + auto v1 = CreateVertex({}, shard_manager.get(), label); + auto *identifier = storage.Create<Identifier>("n"); + auto node_symbol = symbol_table.CreateSymbol("n", true); + identifier->MapTo(node_symbol); + frame[node_symbol] = TypedValue(v1); + { + auto *op = storage.Create<LabelsTest>(identifier, std::vector<LabelIx>{LabelIx{"label1", label.id.AsInt()}}); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), true); + } + { + auto *op = storage.Create<LabelsTest>(identifier, std::vector<LabelIx>{LabelIx{"label2", 10}}); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), false); + } + { + auto *op = storage.Create<LabelsTest>(identifier, std::vector<LabelIx>{LabelIx{"label2", 10}}); + frame[node_symbol] = TypedValue(); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } +} + TEST_F(ExpressionEvaluatorTest, Aggregation) { auto aggr = storage.Create<Aggregation>(storage.Create<PrimitiveLiteral>(42), nullptr, Aggregation::Op::COUNT); auto aggr_sym = symbol_table.CreateSymbol("aggr", true); @@ -794,11 +784,8 @@ TEST_F(ExpressionEvaluatorTest, ListLiteral) { auto &result_elems = result.ValueList(); ASSERT_EQ(3, result_elems.size()); EXPECT_TRUE(result_elems[0].IsInt()); - ; EXPECT_TRUE(result_elems[1].IsString()); - ; EXPECT_TRUE(result_elems[2].IsBool()); - ; } TEST_F(ExpressionEvaluatorTest, ParameterLookup) { @@ -1148,167 +1135,16 @@ class ExpressionEvaluatorPropertyLookup : public ExpressionEvaluatorTest { } }; +// TODO(kostasrim) These will fail because of memory resource not propagating correctly. This should be done as part of +// polishing the allocators. // TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) { -// auto v1 = dba.InsertVertex(); -// ASSERT_TRUE(v1.SetProperty(prop_age.second, memgraph::storage::PropertyValue(10)).HasValue()); -// dba.AdvanceCommand(); +// auto v1 = CreateVertex({{prop_age.second, memgraph::msgs::Value(static_cast<int64_t>(32))}}, shard_manager.get()); // frame[symbol] = TypedValue(v1); // EXPECT_EQ(Value(prop_age).ValueInt(), 10); // EXPECT_TRUE(Value(prop_height).IsNull()); // } -// -// TEST_F(ExpressionEvaluatorPropertyLookup, Duration) { -// const memgraph::utils::Duration dur({10, 1, 30, 2, 22, 45}); -// frame[symbol] = TypedValue(dur); -// -// const std::pair day = std::make_pair("day", dba.NameToProperty("day")); -// const auto total_days = Value(day); -// EXPECT_TRUE(total_days.IsInt()); -// EXPECT_EQ(total_days.ValueInt(), 10); -// -// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour")); -// const auto total_hours = Value(hour); -// EXPECT_TRUE(total_hours.IsInt()); -// EXPECT_EQ(total_hours.ValueInt(), 1); -// -// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute")); -// const auto total_mins = Value(minute); -// EXPECT_TRUE(total_mins.IsInt()); -// -// EXPECT_EQ(total_mins.ValueInt(), 1 * 60 + 30); -// -// const std::pair sec = std::make_pair("second", dba.NameToProperty("second")); -// const auto total_secs = Value(sec); -// EXPECT_TRUE(total_secs.IsInt()); -// const auto expected_secs = total_mins.ValueInt() * 60 + 2; -// EXPECT_EQ(total_secs.ValueInt(), expected_secs); -// -// const std::pair milli = std::make_pair("millisecond", dba.NameToProperty("millisecond")); -// const auto total_milli = Value(milli); -// EXPECT_TRUE(total_milli.IsInt()); -// const auto expected_milli = total_secs.ValueInt() * 1000 + 22; -// EXPECT_EQ(total_milli.ValueInt(), expected_milli); -// -// const std::pair micro = std::make_pair("microsecond", dba.NameToProperty("microsecond")); -// const auto total_micros = Value(micro); -// EXPECT_TRUE(total_micros.IsInt()); -// const auto expected_micros = expected_milli * 1000 + 45; -// EXPECT_EQ(total_micros.ValueInt(), expected_micros); -// -// const std::pair nano = std::make_pair("nanosecond", dba.NameToProperty("nanosecond")); -// const auto total_nano = Value(nano); -// EXPECT_TRUE(total_nano.IsInt()); -// const auto expected_nano = expected_micros * 1000; -// EXPECT_EQ(total_nano.ValueInt(), expected_nano); -// } -// -// TEST_F(ExpressionEvaluatorPropertyLookup, Date) { -// const memgraph::utils::Date date({1996, 11, 22}); -// frame[symbol] = TypedValue(date); -// -// const std::pair year = std::make_pair("year", dba.NameToProperty("year")); -// const auto y = Value(year); -// EXPECT_TRUE(y.IsInt()); -// EXPECT_EQ(y.ValueInt(), 1996); -// -// const std::pair month = std::make_pair("month", dba.NameToProperty("month")); -// const auto m = Value(month); -// EXPECT_TRUE(m.IsInt()); -// EXPECT_EQ(m.ValueInt(), 11); -// -// const std::pair day = std::make_pair("day", dba.NameToProperty("day")); -// const auto d = Value(day); -// EXPECT_TRUE(d.IsInt()); -// EXPECT_EQ(d.ValueInt(), 22); -// } -// -// TEST_F(ExpressionEvaluatorPropertyLookup, LocalTime) { -// const memgraph::utils::LocalTime lt({1, 2, 3, 11, 22}); -// frame[symbol] = TypedValue(lt); -// -// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour")); -// const auto h = Value(hour); -// EXPECT_TRUE(h.IsInt()); -// EXPECT_EQ(h.ValueInt(), 1); -// -// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute")); -// const auto min = Value(minute); -// EXPECT_TRUE(min.IsInt()); -// EXPECT_EQ(min.ValueInt(), 2); -// -// const std::pair second = std::make_pair("second", dba.NameToProperty("second")); -// const auto sec = Value(second); -// EXPECT_TRUE(sec.IsInt()); -// EXPECT_EQ(sec.ValueInt(), 3); -// -// const std::pair millis = std::make_pair("millisecond", dba.NameToProperty("millisecond")); -// const auto mil = Value(millis); -// EXPECT_TRUE(mil.IsInt()); -// EXPECT_EQ(mil.ValueInt(), 11); -// -// const std::pair micros = std::make_pair("microsecond", dba.NameToProperty("microsecond")); -// const auto mic = Value(micros); -// EXPECT_TRUE(mic.IsInt()); -// EXPECT_EQ(mic.ValueInt(), 22); -// } -// -// TEST_F(ExpressionEvaluatorPropertyLookup, LocalDateTime) { -// const memgraph::utils::LocalDateTime ldt({1993, 8, 6}, {2, 3, 4, 55, 40}); -// frame[symbol] = TypedValue(ldt); -// -// const std::pair year = std::make_pair("year", dba.NameToProperty("year")); -// const auto y = Value(year); -// EXPECT_TRUE(y.IsInt()); -// EXPECT_EQ(y.ValueInt(), 1993); -// -// const std::pair month = std::make_pair("month", dba.NameToProperty("month")); -// const auto m = Value(month); -// EXPECT_TRUE(m.IsInt()); -// EXPECT_EQ(m.ValueInt(), 8); -// -// const std::pair day = std::make_pair("day", dba.NameToProperty("day")); -// const auto d = Value(day); -// EXPECT_TRUE(d.IsInt()); -// EXPECT_EQ(d.ValueInt(), 6); -// -// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour")); -// const auto h = Value(hour); -// EXPECT_TRUE(h.IsInt()); -// EXPECT_EQ(h.ValueInt(), 2); -// -// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute")); -// const auto min = Value(minute); -// EXPECT_TRUE(min.IsInt()); -// EXPECT_EQ(min.ValueInt(), 3); -// -// const std::pair second = std::make_pair("second", dba.NameToProperty("second")); -// const auto sec = Value(second); -// EXPECT_TRUE(sec.IsInt()); -// EXPECT_EQ(sec.ValueInt(), 4); -// -// const std::pair millis = std::make_pair("millisecond", dba.NameToProperty("millisecond")); -// const auto mil = Value(millis); -// EXPECT_TRUE(mil.IsInt()); -// EXPECT_EQ(mil.ValueInt(), 55); -// -// const std::pair micros = std::make_pair("microsecond", dba.NameToProperty("microsecond")); -// const auto mic = Value(micros); -// EXPECT_TRUE(mic.IsInt()); -// EXPECT_EQ(mic.ValueInt(), 40); -// } -// -// TEST_F(ExpressionEvaluatorPropertyLookup, Edge) { -// auto v1 = dba.InsertVertex(); -// auto v2 = dba.InsertVertex(); -// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("edge_type")); -// ASSERT_TRUE(e12.HasValue()); -// ASSERT_TRUE(e12->SetProperty(prop_age.second, memgraph::storage::PropertyValue(10)).HasValue()); -// dba.AdvanceCommand(); -// frame[symbol] = TypedValue(*e12); -// EXPECT_EQ(Value(prop_age).ValueInt(), 10); -// EXPECT_TRUE(Value(prop_height).IsNull()); -// } -// +// TEST_F(ExpressionEvaluatorPropertyLookup, Edge) {} + TEST_F(ExpressionEvaluatorPropertyLookup, Null) { frame[symbol] = TypedValue(); EXPECT_TRUE(Value(prop_age).IsNull()); @@ -1455,59 +1291,10 @@ TEST_F(FunctionTest, StartNode) { } // TODO(kostasrim) Enable this test once we add degree to the accessors -// TEST_F(FunctionTest, Degree) { -// ASSERT_THROW(EvaluateFunction("DEGREE"), ExpressionRuntimeException); -// ASSERT_TRUE(EvaluateFunction("DEGREE", TypedValue()).IsNull()); -// auto v1 = dba.InsertVertex(); -// auto v2 = dba.InsertVertex(); -// auto v3 = dba.InsertVertex(); -// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t")); -// ASSERT_TRUE(e12.HasValue()); -// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue()); -// dba.AdvanceCommand(); -// ASSERT_EQ(EvaluateFunction("DEGREE", v1).ValueInt(), 1); -// ASSERT_EQ(EvaluateFunction("DEGREE", v2).ValueInt(), 2); -// ASSERT_EQ(EvaluateFunction("DEGREE", v3).ValueInt(), 1); -// ASSERT_THROW(EvaluateFunction("DEGREE", 2), ExpressionRuntimeException); -// ASSERT_THROW(EvaluateFunction("DEGREE", *e12), ExpressionRuntimeException); -// } -// -// TODO(kostasrim) Enable this test once we add InDegree to the accessors -// TEST_F(FunctionTest, InDegree) { -// ASSERT_THROW(EvaluateFunction("INDEGREE"), ExpressionRuntimeException); -// ASSERT_TRUE(EvaluateFunction("INDEGREE", TypedValue()).IsNull()); -// auto v1 = dba.InsertVertex(); -// auto v2 = dba.InsertVertex(); -// auto v3 = dba.InsertVertex(); -// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t")); -// ASSERT_TRUE(e12.HasValue()); -// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue()); -// dba.AdvanceCommand(); -// ASSERT_EQ(EvaluateFunction("INDEGREE", v1).ValueInt(), 0); -// ASSERT_EQ(EvaluateFunction("INDEGREE", v2).ValueInt(), 2); -// ASSERT_EQ(EvaluateFunction("INDEGREE", v3).ValueInt(), 0); -// ASSERT_THROW(EvaluateFunction("INDEGREE", 2), ExpressionRuntimeException); -// ASSERT_THROW(EvaluateFunction("INDEGREE", *e12), ExpressionRuntimeException); -// } -// -// TODO(kostasrim) Enable this test once we add OutDegree to the accessors -// TEST_F(FunctionTest, OutDegree) { -// ASSERT_THROW(EvaluateFunction("OUTDEGREE"), ExpressionRuntimeException); -// ASSERT_TRUE(EvaluateFunction("OUTDEGREE", TypedValue()).IsNull()); -// auto v1 = dba.InsertVertex(); -// auto v2 = dba.InsertVertex(); -// auto v3 = dba.InsertVertex(); -// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t")); -// ASSERT_TRUE(e12.HasValue()); -// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue()); -// dba.AdvanceCommand(); -// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v1).ValueInt(), 1); -// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v2).ValueInt(), 0); -// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v3).ValueInt(), 1); -// ASSERT_THROW(EvaluateFunction("OUTDEGREE", 2), ExpressionRuntimeException); -// ASSERT_THROW(EvaluateFunction("OUTDEGREE", *e12), ExpressionRuntimeException); -// } -// +// TEST_F(FunctionTest, Degree) {} +// TEST_F(FunctionTest, InDegree) {} +// TEST_F(FunctionTest, OutDegree) {} + TEST_F(FunctionTest, ToBoolean) { ASSERT_THROW(EvaluateFunction("TOBOOLEAN"), FunctionRuntimeException); ASSERT_TRUE(EvaluateFunction("TOBOOLEAN", TypedValue()).IsNull()); @@ -1591,42 +1378,8 @@ TEST_F(FunctionTest, Labels) { } // TODO(kostasrim) Enable this once we fix accessors Path -// TEST_F(FunctionTest, NodesRelationships) { -// EXPECT_THROW(EvaluateFunction("NODES"), ExpressionRuntimeException); -// EXPECT_THROW(EvaluateFunction("RELATIONSHIPS"), ExpressionRuntimeException); -// EXPECT_TRUE(EvaluateFunction("NODES", TypedValue()).IsNull()); -// EXPECT_TRUE(EvaluateFunction("RELATIONSHIPS", TypedValue()).IsNull()); -// -// { -// auto v1 = dba.InsertVertex(); -// auto v2 = dba.InsertVertex(); -// auto v3 = dba.InsertVertex(); -// auto e1 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("Type")); -// ASSERT_TRUE(e1.HasValue()); -// auto e2 = dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("Type")); -// ASSERT_TRUE(e2.HasValue()); -// memgraph::query::Path path{v1, *e1, v2, *e2, v3}; -// dba.AdvanceCommand(); -// -// auto _nodes = EvaluateFunction("NODES", path).ValueList(); -// std::vector<memgraph::query::VertexAccessor> nodes; -// for (const auto &node : _nodes) { -// nodes.push_back(node.ValueVertex()); -// } -// EXPECT_THAT(nodes, ElementsAre(v1, v2, v3)); -// -// auto _edges = EvaluateFunction("RELATIONSHIPS", path).ValueList(); -// std::vector<memgraph::query::EdgeAccessor> edges; -// for (const auto &edge : _edges) { -// edges.push_back(edge.ValueEdge()); -// } -// EXPECT_THAT(edges, ElementsAre(*e1, *e2)); -// } -// -// EXPECT_THROW(EvaluateFunction("NODES", 2), ExpressionRuntimeException); -// EXPECT_THROW(EvaluateFunction("RELATIONSHIPS", 2), ExpressionRuntimeException); -// } -// +// TEST_F(FunctionTest, NodesRelationships) {} + TEST_F(FunctionTest, Range) { EXPECT_THROW(EvaluateFunction("RANGE"), FunctionRuntimeException); EXPECT_TRUE(EvaluateFunction("RANGE", 1, 2, TypedValue()).IsNull()); @@ -1889,64 +1642,10 @@ TEST_F(FunctionTest, ToStringBool) { EXPECT_EQ(EvaluateFunction("TOSTRING", false).ValueString(), "false"); } -// TEST_F(FunctionTest, ToStringDate) { -// const auto date = memgraph::utils::Date({1970, 1, 2}); -// EXPECT_EQ(EvaluateFunction("TOSTRING", date).ValueString(), "1970-01-02"); -// } -// -// TEST_F(FunctionTest, ToStringLocalTime) { -// const auto lt = memgraph::utils::LocalTime({13, 2, 40, 100, 50}); -// EXPECT_EQ(EvaluateFunction("TOSTRING", lt).ValueString(), "13:02:40.100050"); -// } -// -// TEST_F(FunctionTest, ToStringLocalDateTime) { -// const auto ldt = memgraph::utils::LocalDateTime({1970, 1, 2}, {23, 02, 59}); -// EXPECT_EQ(EvaluateFunction("TOSTRING", ldt).ValueString(), "1970-01-02T23:02:59.000000"); -// } -// -// TEST_F(FunctionTest, ToStringDuration) { -// memgraph::utils::Duration duration{{.minute = 2, .second = 2, .microsecond = 33}}; -// EXPECT_EQ(EvaluateFunction("TOSTRING", duration).ValueString(), "P0DT0H2M2.000033S"); -// } -// TEST_F(FunctionTest, ToStringExceptions) { EXPECT_THROW(EvaluateFunction("TOSTRING", 1, 2, 3), FunctionRuntimeException); } -// -// TEST_F(FunctionTest, TimestampVoid) { -// ctx.timestamp = 42; -// EXPECT_EQ(EvaluateFunction("TIMESTAMP").ValueInt(), 42); -// } -// -// TEST_F(FunctionTest, TimestampDate) { -// ctx.timestamp = 42; -// EXPECT_EQ(EvaluateFunction("TIMESTAMP", memgraph::utils::Date({1970, 1, 1})).ValueInt(), 0); -// EXPECT_EQ(EvaluateFunction("TIMESTAMP", memgraph::utils::Date({1971, 1, 1})).ValueInt(), 31536000000000); -// } -// -// TEST_F(FunctionTest, TimestampLocalTime) { -// ctx.timestamp = 42; -// const memgraph::utils::LocalTime time(10000); -// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 10000); -// } -// -// TEST_F(FunctionTest, TimestampLocalDateTime) { -// ctx.timestamp = 42; -// const memgraph::utils::LocalDateTime time(20000); -// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 20000); -// } -// -// TEST_F(FunctionTest, TimestampDuration) { -// ctx.timestamp = 42; -// const memgraph::utils::Duration time(20000); -// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 20000); -// } -// -// TEST_F(FunctionTest, TimestampExceptions) { -// ctx.timestamp = 42; -// EXPECT_THROW(EvaluateFunction("TIMESTAMP", 1).ValueInt(), ExpressionRuntimeException); -// } -// + TEST_F(FunctionTest, Left) { EXPECT_THROW(EvaluateFunction("LEFT"), FunctionRuntimeException); @@ -2083,110 +1782,5 @@ TEST_F(FunctionTest, FromByteString) { EXPECT_EQ(EvaluateFunction("FROMBYTESTRING", std::string("\x00\x42", 2)).ValueString(), "0x0042"); } -// TEST_F(FunctionTest, Date) { -// const auto unix_epoch = memgraph::utils::Date({1970, 1, 1}); -// EXPECT_EQ(EvaluateFunction("DATE", "1970-01-01").ValueDate(), unix_epoch); -// const auto map_param = TypedValue( -// std::map<std::string, TypedValue>{{"year", TypedValue(1970)}, {"month", TypedValue(1)}, {"day", -// TypedValue(1)}}); -// EXPECT_EQ(EvaluateFunction("DATE", map_param).ValueDate(), unix_epoch); -// const auto today = memgraph::utils::CurrentDate(); -// EXPECT_EQ(EvaluateFunction("DATE").ValueDate(), today); -// -// EXPECT_THROW(EvaluateFunction("DATE", "{}"), memgraph::utils::BasicException); -// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"years", TypedValue(1970)}}), -// ExpressionRuntimeException); -// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"mnths", TypedValue(1970)}}), -// ExpressionRuntimeException); -// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"dayz", TypedValue(1970)}}), -// ExpressionRuntimeException); -// } -// -// TEST_F(FunctionTest, LocalTime) { -// const auto local_time = memgraph::utils::LocalTime({13, 3, 2, 0, 0}); -// EXPECT_EQ(EvaluateFunction("LOCALTIME", "130302").ValueLocalTime(), local_time); -// const auto one_sec_in_microseconds = 1000000; -// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"hour", TypedValue(1)}, -// {"minute", TypedValue(2)}, -// {"second", TypedValue(3)}, -// {"millisecond", TypedValue(4)}, -// {"microsecond", TypedValue(5)}}); -// EXPECT_EQ(EvaluateFunction("LOCALTIME", map_param).ValueLocalTime(), memgraph::utils::LocalTime({1, 2, 3, 4, 5})); -// const auto today = memgraph::utils::CurrentLocalTime(); -// EXPECT_NEAR(EvaluateFunction("LOCALTIME").ValueLocalTime().MicrosecondsSinceEpoch(), -// today.MicrosecondsSinceEpoch(), -// one_sec_in_microseconds); -// -// EXPECT_THROW(EvaluateFunction("LOCALTIME", "{}"), memgraph::utils::BasicException); -// EXPECT_THROW(EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"hous", -// TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"minut", TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"seconds", TypedValue(1970)}})), -// ExpressionRuntimeException); -// } -// -// TEST_F(FunctionTest, LocalDateTime) { -// const auto local_date_time = memgraph::utils::LocalDateTime({1970, 1, 1}, {13, 3, 2, 0, 0}); -// EXPECT_EQ(EvaluateFunction("LOCALDATETIME", "1970-01-01T13:03:02").ValueLocalDateTime(), local_date_time); -// const auto today = memgraph::utils::CurrentLocalDateTime(); -// const auto one_sec_in_microseconds = 1000000; -// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"year", TypedValue(1972)}, -// {"month", TypedValue(2)}, -// {"day", TypedValue(3)}, -// {"hour", TypedValue(4)}, -// {"minute", TypedValue(5)}, -// {"second", TypedValue(6)}, -// {"millisecond", TypedValue(7)}, -// {"microsecond", TypedValue(8)}}); -// -// EXPECT_EQ(EvaluateFunction("LOCALDATETIME", map_param).ValueLocalDateTime(), -// memgraph::utils::LocalDateTime({1972, 2, 3}, {4, 5, 6, 7, 8})); -// EXPECT_NEAR(EvaluateFunction("LOCALDATETIME").ValueLocalDateTime().MicrosecondsSinceEpoch(), -// today.MicrosecondsSinceEpoch(), one_sec_in_microseconds); -// EXPECT_THROW(EvaluateFunction("LOCALDATETIME", "{}"), memgraph::utils::BasicException); -// EXPECT_THROW( -// EvaluateFunction("LOCALDATETIME", TypedValue(std::map<std::string, TypedValue>{{"hours", TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("LOCALDATETIME", TypedValue(std::map<std::string, TypedValue>{{"seconds", -// TypedValue(1970)}})), ExpressionRuntimeException); -// } -// -// TEST_F(FunctionTest, Duration) { -// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"day", TypedValue(3)}, -// {"hour", TypedValue(4)}, -// {"minute", TypedValue(5)}, -// {"second", TypedValue(6)}, -// {"millisecond", TypedValue(7)}, -// {"microsecond", TypedValue(8)}}); -// -// EXPECT_EQ(EvaluateFunction("DURATION", map_param).ValueDuration(), memgraph::utils::Duration({3, 4, 5, 6, 7, 8})); -// EXPECT_THROW(EvaluateFunction("DURATION", "{}"), memgraph::utils::BasicException); -// EXPECT_THROW(EvaluateFunction("DURATION", TypedValue(std::map<std::string, TypedValue>{{"hours", -// TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("DURATION", TypedValue(std::map<std::string, TypedValue>{{"seconds", TypedValue(1970)}})), -// ExpressionRuntimeException); -// -// const auto map_param_negative = TypedValue(std::map<std::string, TypedValue>{{"day", TypedValue(-3)}, -// {"hour", TypedValue(-4)}, -// {"minute", TypedValue(-5)}, -// {"second", TypedValue(-6)}, -// {"millisecond", TypedValue(-7)}, -// {"microsecond", TypedValue(-8)}}); -// EXPECT_EQ(EvaluateFunction("DURATION", map_param_negative).ValueDuration(), -// memgraph::utils::Duration({-3, -4, -5, -6, -7, -8})); -// -// EXPECT_EQ(EvaluateFunction("DURATION", "P4DT4H5M6.2S").ValueDuration(), -// memgraph::utils::Duration({4, 4, 5, 6, 0, 200000})); -// EXPECT_EQ(EvaluateFunction("DURATION", "P3DT4H5M6.100S").ValueDuration(), -// memgraph::utils::Duration({3, 4, 5, 6, 0, 100000})); -// EXPECT_EQ(EvaluateFunction("DURATION", "P3DT4H5M6.100110S").ValueDuration(), -// memgraph::utils::Duration({3, 4, 5, 6, 100, 110})); -// } +// TODO(kostasrim) Add temporal type tests. } // namespace From 631d18465b5fc8b89fa6c872da2e57a87645944e Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 15 Nov 2022 17:52:38 +0000 Subject: [PATCH 05/26] Allow the RsmClient to store multiple in-flight requests. Update the ShardRequestManager to use the new request tokens and refactor some bug-prone aspects of it --- src/io/rsm/rsm_client.hpp | 131 +++++++++------ src/query/v2/shard_request_manager.hpp | 211 ++++++++++++------------- 2 files changed, 188 insertions(+), 154 deletions(-) diff --git a/src/io/rsm/rsm_client.hpp b/src/io/rsm/rsm_client.hpp index b60380b08..ce6781956 100644 --- a/src/io/rsm/rsm_client.hpp +++ b/src/io/rsm/rsm_client.hpp @@ -14,6 +14,7 @@ #include <iostream> #include <optional> #include <type_traits> +#include <unordered_map> #include <vector> #include "io/address.hpp" @@ -36,6 +37,21 @@ using memgraph::io::rsm::WriteRequest; using memgraph::io::rsm::WriteResponse; using memgraph::utils::BasicResult; +class AsyncRequestToken { + size_t id_; + + public: + AsyncRequestToken(size_t id) : id_(id) {} + size_t GetId() const { return id_; } +}; + +template <typename RequestT, typename ResponseT> +struct AsyncRequest { + Time start_time; + RequestT request; + ResponseFuture<ResponseT> future; +}; + template <typename IoImpl, typename WriteRequestT, typename WriteResponseT, typename ReadRequestT, typename ReadResponseT> class RsmClient { @@ -47,13 +63,10 @@ class RsmClient { /// State for single async read/write operations. In the future this could become a map /// of async operations that can be accessed via an ID etc... - std::optional<Time> async_read_before_; - std::optional<ResponseFuture<ReadResponse<ReadResponseT>>> async_read_; - ReadRequestT current_read_request_; + std::unordered_map<size_t, AsyncRequest<ReadRequestT, ReadResponse<ReadResponseT>>> async_reads_; + std::unordered_map<size_t, AsyncRequest<WriteRequestT, WriteResponse<WriteResponseT>>> async_writes_; - std::optional<Time> async_write_before_; - std::optional<ResponseFuture<WriteResponse<WriteResponseT>>> async_write_; - WriteRequestT current_write_request_; + size_t async_token_generator_ = 0; void SelectRandomLeader() { std::uniform_int_distribution<size_t> addr_distrib(0, (server_addrs_.size() - 1)); @@ -156,42 +169,56 @@ class RsmClient { } /// AsyncRead methods - void SendAsyncReadRequest(const ReadRequestT &req) { - MG_ASSERT(!async_read_); + AsyncRequestToken SendAsyncReadRequest(const ReadRequestT &req) { + size_t token = async_token_generator_++; ReadRequest<ReadRequestT> read_req = {.operation = req}; - if (!async_read_before_) { - async_read_before_ = io_.Now(); - } - current_read_request_ = std::move(req); - async_read_ = io_.template Request<ReadRequest<ReadRequestT>, ReadResponse<ReadResponseT>>(leader_, read_req); + AsyncRequest<ReadRequestT, ReadResponse<ReadResponseT>> async_request{ + .start_time = io_.Now(), + .request = std::move(req), + .future = io_.template Request<ReadRequest<ReadRequestT>, ReadResponse<ReadResponseT>>(leader_, read_req), + }; + + async_reads_.emplace(token, std::move(async_request)); + + return AsyncRequestToken(token); } - std::optional<BasicResult<TimedOut, ReadResponseT>> PollAsyncReadRequest() { - MG_ASSERT(async_read_); + void ResendAsyncReadRequest(AsyncRequestToken &token) { + auto &async_request = async_reads_.at(token.GetId()); - if (!async_read_->IsReady()) { + ReadRequest<ReadRequestT> read_req = {.operation = async_request.request}; + + async_request.future = + io_.template Request<ReadRequest<ReadRequestT>, ReadResponse<ReadResponseT>>(leader_, read_req); + } + + std::optional<BasicResult<TimedOut, ReadResponseT>> PollAsyncReadRequest(AsyncRequestToken &token) { + auto &async_request = async_reads_.at(token.GetId()); + + if (!async_request.future.IsReady()) { return std::nullopt; } return AwaitAsyncReadRequest(); } - std::optional<BasicResult<TimedOut, ReadResponseT>> AwaitAsyncReadRequest() { - ResponseResult<ReadResponse<ReadResponseT>> get_response_result = std::move(*async_read_).Wait(); - async_read_.reset(); + std::optional<BasicResult<TimedOut, ReadResponseT>> AwaitAsyncReadRequest(AsyncRequestToken &token) { + auto &async_request = async_reads_.at(token.GetId()); + ResponseResult<ReadResponse<ReadResponseT>> get_response_result = std::move(async_request.future).Wait(); const Duration overall_timeout = io_.GetDefaultTimeout(); - const bool past_time_out = io_.Now() < *async_read_before_ + overall_timeout; + const bool past_time_out = io_.Now() > async_request.start_time + overall_timeout; const bool result_has_error = get_response_result.HasError(); if (result_has_error && past_time_out) { // TODO static assert the exact type of error. spdlog::debug("client timed out while trying to communicate with leader server {}", leader_.ToString()); - async_read_before_ = std::nullopt; + async_reads_.erase(token.GetId()); return TimedOut{}; } + if (!result_has_error) { ResponseEnvelope<ReadResponse<ReadResponseT>> &&get_response_envelope = std::move(get_response_result.GetValue()); ReadResponse<ReadResponseT> &&read_get_response = std::move(get_response_envelope.message); @@ -199,54 +226,69 @@ class RsmClient { PossiblyRedirectLeader(read_get_response); if (read_get_response.success) { - async_read_before_ = std::nullopt; + async_reads_.erase(token.GetId()); return std::move(read_get_response.read_return); } - SendAsyncReadRequest(current_read_request_); - } else if (result_has_error) { + } else { SelectRandomLeader(); - SendAsyncReadRequest(current_read_request_); } + + ResendAsyncReadRequest(token); + return std::nullopt; } /// AsyncWrite methods - void SendAsyncWriteRequest(const WriteRequestT &req) { - MG_ASSERT(!async_write_); + AsyncRequestToken SendAsyncWriteRequest(const WriteRequestT &req) { + size_t token = async_token_generator_++; WriteRequest<WriteRequestT> write_req = {.operation = req}; - if (!async_write_before_) { - async_write_before_ = io_.Now(); - } - current_write_request_ = std::move(req); - async_write_ = io_.template Request<WriteRequest<WriteRequestT>, WriteResponse<WriteResponseT>>(leader_, write_req); + AsyncRequest<WriteRequestT, WriteResponse<WriteResponseT>> async_request{ + .start_time = io_.Now(), + .request = std::move(req), + .future = io_.template Request<WriteRequest<WriteRequestT>, WriteResponse<WriteResponseT>>(leader_, write_req), + }; + + async_writes_.emplace(token, std::move(async_request)); + + return AsyncRequestToken(token); } - std::optional<BasicResult<TimedOut, WriteResponseT>> PollAsyncWriteRequest() { - MG_ASSERT(async_write_); + void ResendAsyncWriteRequest(AsyncRequestToken &token) { + auto &async_request = async_writes_.at(token.GetId()); - if (!async_write_->IsReady()) { + WriteRequest<WriteRequestT> write_req = {.operation = async_request.request}; + + async_request.future = + io_.template Request<WriteRequest<WriteRequestT>, WriteResponse<WriteResponseT>>(leader_, write_req); + } + + std::optional<BasicResult<TimedOut, WriteResponseT>> PollAsyncWriteRequest(AsyncRequestToken &token) { + auto &async_request = async_writes_.at(token.GetId()); + + if (!async_request.future.IsReady()) { return std::nullopt; } return AwaitAsyncWriteRequest(); } - std::optional<BasicResult<TimedOut, WriteResponseT>> AwaitAsyncWriteRequest() { - ResponseResult<WriteResponse<WriteResponseT>> get_response_result = std::move(*async_write_).Wait(); - async_write_.reset(); + std::optional<BasicResult<TimedOut, WriteResponseT>> AwaitAsyncWriteRequest(AsyncRequestToken &token) { + auto &async_request = async_writes_.at(token.GetId()); + ResponseResult<WriteResponse<WriteResponseT>> get_response_result = std::move(async_request.future).Wait(); const Duration overall_timeout = io_.GetDefaultTimeout(); - const bool past_time_out = io_.Now() < *async_write_before_ + overall_timeout; + const bool past_time_out = io_.Now() > async_request.start_time + overall_timeout; const bool result_has_error = get_response_result.HasError(); if (result_has_error && past_time_out) { // TODO static assert the exact type of error. spdlog::debug("client timed out while trying to communicate with leader server {}", leader_.ToString()); - async_write_before_ = std::nullopt; + async_writes_.erase(token.GetId()); return TimedOut{}; } + if (!result_has_error) { ResponseEnvelope<WriteResponse<WriteResponseT>> &&get_response_envelope = std::move(get_response_result.GetValue()); @@ -255,14 +297,15 @@ class RsmClient { PossiblyRedirectLeader(write_get_response); if (write_get_response.success) { - async_write_before_ = std::nullopt; + async_writes_.erase(token.GetId()); return std::move(write_get_response.write_return); } - SendAsyncWriteRequest(current_write_request_); - } else if (result_has_error) { + } else { SelectRandomLeader(); - SendAsyncWriteRequest(current_write_request_); } + + ResendAsyncWriteRequest(token); + return std::nullopt; } }; diff --git a/src/query/v2/shard_request_manager.hpp b/src/query/v2/shard_request_manager.hpp index a73201046..386fb0930 100644 --- a/src/query/v2/shard_request_manager.hpp +++ b/src/query/v2/shard_request_manager.hpp @@ -72,6 +72,13 @@ class RsmStorageClientManager { std::map<Shard, TStorageClient> cli_cache_; }; +template <typename TRequest> +struct ShardRequestState { + memgraph::coordinator::Shard shard; + TRequest request; + std::optional<io::rsm::AsyncRequestToken> async_request_token; +}; + template <typename TRequest> struct ExecutionState { using CompoundKey = memgraph::io::rsm::ShardRsmKey; @@ -91,14 +98,13 @@ struct ExecutionState { // it pulled all the requested data from the given Shard, it will be removed from the Vector. When the Vector becomes // empty, it means that all of the requests have completed succefully. // TODO(gvolfing) - // Maybe make this into a more complex object to be able to keep track of paginated resutls. E.g. instead of a vector + // Maybe make this into a more complex object to be able to keep track of paginated results. E.g. instead of a vector // of Shards make it into a std::vector<std::pair<Shard, PaginatedResultType>> (probably a struct instead of a pair) // where PaginatedResultType is an enum signaling the progress on the given request. This way we can easily check if // a partial response on a shard(if there is one) is finished and we can send off the request for the next batch. - std::vector<Shard> shard_cache; // 1-1 mapping with `shard_cache`. // A vector that tracks request metadata for each shard (For example, next_id for a ScanAll on Shard A) - std::vector<TRequest> requests; + std::vector<ShardRequestState<TRequest>> requests; State state = INITIALIZING; }; @@ -259,8 +265,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { }; std::map<Shard, PaginatedResponseState> paginated_response_tracker; - for (const auto &shard : state.shard_cache) { - paginated_response_tracker.insert(std::make_pair(shard, PaginatedResponseState::Pending)); + for (const auto &request : state.requests) { + paginated_response_tracker.insert(std::make_pair(request.shard, PaginatedResponseState::Pending)); } do { @@ -278,15 +284,14 @@ class ShardRequestManager : public ShardRequestManagerInterface { MG_ASSERT(!new_vertices.empty()); MaybeInitializeExecutionState(state, new_vertices); std::vector<CreateVerticesResponse> responses; - auto &shard_cache_ref = state.shard_cache; // 1. Send the requests. - SendAllRequests(state, shard_cache_ref); + SendAllRequests(state); // 2. Block untill all the futures are exhausted do { AwaitOnResponses(state, responses); - } while (!state.shard_cache.empty()); + } while (!state.requests.empty()); MaybeCompleteState(state); // TODO(kostasrim) Before returning start prefetching the batch (this shall be done once we get MgFuture as return @@ -299,11 +304,9 @@ class ShardRequestManager : public ShardRequestManagerInterface { MG_ASSERT(!new_edges.empty()); MaybeInitializeExecutionState(state, new_edges); std::vector<CreateExpandResponse> responses; - auto &shard_cache_ref = state.shard_cache; - size_t id{0}; - for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end(); ++id) { - auto &storage_client = GetStorageClientForShard(*shard_it); - WriteRequests req = state.requests[id]; + for (auto &request : state.requests) { + auto &storage_client = GetStorageClientForShard(request.shard); + WriteRequests req = request.request; auto write_response_result = storage_client.SendWriteRequest(std::move(req)); if (write_response_result.HasError()) { throw std::runtime_error("CreateVertices request timedout"); @@ -315,9 +318,9 @@ class ShardRequestManager : public ShardRequestManagerInterface { throw std::runtime_error("CreateExpand request did not succeed"); } responses.push_back(mapped_response); - shard_it = shard_cache_ref.erase(shard_it); } // We are done with this state + state.requests.clear(); MaybeCompleteState(state); return responses; } @@ -330,15 +333,14 @@ class ShardRequestManager : public ShardRequestManagerInterface { // must be fetched again with an ExpandOne(Edges.dst) MaybeInitializeExecutionState(state, std::move(request)); std::vector<ExpandOneResponse> responses; - auto &shard_cache_ref = state.shard_cache; // 1. Send the requests. - SendAllRequests(state, shard_cache_ref); + SendAllRequests(state); // 2. Block untill all the futures are exhausted do { AwaitOnResponses(state, responses); - } while (!state.shard_cache.empty()); + } while (!state.requests.empty()); std::vector<ExpandOneResultRow> result_rows; const auto total_row_count = std::accumulate( responses.begin(), responses.end(), 0, @@ -402,13 +404,17 @@ class ShardRequestManager : public ShardRequestManagerInterface { if (!per_shard_request_table.contains(shard)) { CreateVerticesRequest create_v_rqst{.transaction_id = transaction_id_}; per_shard_request_table.insert(std::pair(shard, std::move(create_v_rqst))); - state.shard_cache.push_back(shard); } per_shard_request_table[shard].new_vertices.push_back(std::move(new_vertex)); } - for (auto &[shard, rqst] : per_shard_request_table) { - state.requests.push_back(std::move(rqst)); + for (auto &[shard, request] : per_shard_request_table) { + ShardRequestState<CreateVerticesRequest> shard_request_state{ + .shard = shard, + .request = request, + .async_request_token = std::nullopt, + }; + state.requests.emplace_back(std::move(shard_request_state)); } state.state = ExecutionState<CreateVerticesRequest>::EXECUTING; } @@ -445,8 +451,12 @@ class ShardRequestManager : public ShardRequestManagerInterface { } for (auto &[shard, request] : per_shard_request_table) { - state.shard_cache.push_back(shard); - state.requests.push_back(std::move(request)); + ShardRequestState<CreateExpandRequest> shard_request_state{ + .shard = shard, + .request = request, + .async_request_token = std::nullopt, + }; + state.requests.emplace_back(std::move(shard_request_state)); } state.state = ExecutionState<CreateExpandRequest>::EXECUTING; } @@ -470,11 +480,18 @@ class ShardRequestManager : public ShardRequestManagerInterface { for (auto &shards : multi_shards) { for (auto &[key, shard] : shards) { MG_ASSERT(!shard.empty()); - state.shard_cache.push_back(std::move(shard)); - ScanVerticesRequest rqst; - rqst.transaction_id = transaction_id_; - rqst.start_id.second = storage::conversions::ConvertValueVector(key); - state.requests.push_back(std::move(rqst)); + + ScanVerticesRequest request; + request.transaction_id = transaction_id_; + request.start_id.second = storage::conversions::ConvertValueVector(key); + + ShardRequestState<ScanVerticesRequest> shard_request_state{ + .shard = shard, + .request = std::move(request), + .async_request_token = std::nullopt, + }; + + state.requests.emplace_back(std::move(shard_request_state)); } } state.state = ExecutionState<ScanVerticesRequest>::EXECUTING; @@ -497,13 +514,18 @@ class ShardRequestManager : public ShardRequestManagerInterface { shards_map_.GetShardForKey(vertex.first.id, storage::conversions::ConvertPropertyVector(vertex.second)); if (!per_shard_request_table.contains(shard)) { per_shard_request_table.insert(std::pair(shard, top_level_rqst_template)); - state.shard_cache.push_back(shard); } per_shard_request_table[shard].src_vertices.push_back(vertex); } - for (auto &[shard, rqst] : per_shard_request_table) { - state.requests.push_back(std::move(rqst)); + for (auto &[shard, request] : per_shard_request_table) { + ShardRequestState<ExpandOneRequest> shard_request_state{ + .shard = shard, + .request = request, + .async_request_token = std::nullopt, + }; + + state.requests.emplace_back(std::move(shard_request_state)); } state.state = ExecutionState<ExpandOneRequest>::EXECUTING; } @@ -533,65 +555,46 @@ class ShardRequestManager : public ShardRequestManagerInterface { } void SendAllRequests(ExecutionState<ScanVerticesRequest> &state) { - int64_t shard_idx = 0; - for (const auto &request : state.requests) { - const auto ¤t_shard = state.shard_cache[shard_idx]; + for (auto &request : state.requests) { + const auto ¤t_shard = request.shard; auto &storage_client = GetStorageClientForShard(current_shard); - ReadRequests req = request; - storage_client.SendAsyncReadRequest(request); + ReadRequests req = request.request; - ++shard_idx; + request.async_request_token = storage_client.SendAsyncReadRequest(request.request); } } - void SendAllRequests(ExecutionState<CreateVerticesRequest> &state, - std::vector<memgraph::coordinator::Shard> &shard_cache_ref) { - size_t id = 0; - for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end(); ++shard_it) { - // This is fine because all new_vertices of each request end up on the same shard - const auto labels = state.requests[id].new_vertices[0].label_ids; - auto req_deep_copy = state.requests[id]; + void SendAllRequests(ExecutionState<CreateVerticesRequest> &state) { + for (auto &request : state.requests) { + auto req_deep_copy = request.request; for (auto &new_vertex : req_deep_copy.new_vertices) { new_vertex.label_ids.erase(new_vertex.label_ids.begin()); } - auto &storage_client = GetStorageClientForShard(*shard_it); + auto &storage_client = GetStorageClientForShard(request.shard); WriteRequests req = req_deep_copy; - storage_client.SendAsyncWriteRequest(req); - ++id; + request.async_request_token = storage_client.SendAsyncWriteRequest(req); } } - void SendAllRequests(ExecutionState<ExpandOneRequest> &state, - std::vector<memgraph::coordinator::Shard> &shard_cache_ref) { - size_t id = 0; - for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end(); ++shard_it) { - auto &storage_client = GetStorageClientForShard(*shard_it); - ReadRequests req = state.requests[id]; - storage_client.SendAsyncReadRequest(req); - ++id; + void SendAllRequests(ExecutionState<ExpandOneRequest> &state) { + for (auto &request : state.requests) { + auto &storage_client = GetStorageClientForShard(request.shard); + ReadRequests req = request.request; + request.async_request_token = storage_client.SendAsyncReadRequest(req); } } void AwaitOnResponses(ExecutionState<CreateVerticesRequest> &state, std::vector<CreateVerticesResponse> &responses) { - auto &shard_cache_ref = state.shard_cache; - int64_t request_idx = 0; + for (auto &request : state.requests) { + auto &storage_client = GetStorageClientForShard(request.shard); - for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end();) { - // This is fine because all new_vertices of each request end up on the same shard - const auto labels = state.requests[request_idx].new_vertices[0].label_ids; - - auto &storage_client = GetStorageClientForShard(*shard_it); - - auto poll_result = storage_client.AwaitAsyncWriteRequest(); - if (!poll_result) { - ++shard_it; - ++request_idx; - - continue; + auto poll_result = storage_client.AwaitAsyncWriteRequest(request.async_request_token.value()); + while (!poll_result) { + poll_result = storage_client.AwaitAsyncWriteRequest(request.async_request_token.value()); } if (poll_result->HasError()) { @@ -605,26 +608,17 @@ class ShardRequestManager : public ShardRequestManagerInterface { throw std::runtime_error("CreateVertices request did not succeed"); } responses.push_back(response); - - shard_it = shard_cache_ref.erase(shard_it); - // Needed to maintain the 1-1 mapping between the ShardCache and the requests. - auto it = state.requests.begin() + request_idx; - state.requests.erase(it); } + state.requests.clear(); } void AwaitOnResponses(ExecutionState<ExpandOneRequest> &state, std::vector<ExpandOneResponse> &responses) { - auto &shard_cache_ref = state.shard_cache; - int64_t request_idx = 0; + for (auto &request : state.requests) { + auto &storage_client = GetStorageClientForShard(request.shard); - for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end();) { - auto &storage_client = GetStorageClientForShard(*shard_it); - - auto poll_result = storage_client.PollAsyncReadRequest(); - if (!poll_result) { - ++shard_it; - ++request_idx; - continue; + auto poll_result = storage_client.AwaitAsyncReadRequest(request.async_request_token.value()); + while (!poll_result) { + poll_result = storage_client.AwaitAsyncReadRequest(request.async_request_token.value()); } if (poll_result->HasError()) { @@ -642,36 +636,28 @@ class ShardRequestManager : public ShardRequestManagerInterface { } responses.push_back(std::move(response)); - shard_it = shard_cache_ref.erase(shard_it); - // Needed to maintain the 1-1 mapping between the ShardCache and the requests. - auto it = state.requests.begin() + request_idx; - state.requests.erase(it); } + state.requests.clear(); } void AwaitOnPaginatedRequests(ExecutionState<ScanVerticesRequest> &state, std::vector<ScanVerticesResponse> &responses, std::map<Shard, PaginatedResponseState> &paginated_response_tracker) { - auto &shard_cache_ref = state.shard_cache; + std::vector<int> to_erase{}; - // Find the first request that is not holding a paginated response. - int64_t request_idx = 0; - for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end();) { - if (paginated_response_tracker.at(*shard_it) != PaginatedResponseState::Pending) { - ++shard_it; - ++request_idx; + for (int i = 0; i < state.requests.size(); i++) { + auto &request = state.requests[i]; + // only operate on paginated requests + if (paginated_response_tracker.at(request.shard) != PaginatedResponseState::Pending) { continue; } - auto &storage_client = GetStorageClientForShard(*shard_it); + auto &storage_client = GetStorageClientForShard(request.shard); - auto await_result = storage_client.AwaitAsyncReadRequest(); - - if (!await_result) { - // Redirection has occured. - ++shard_it; - ++request_idx; - continue; + // drive it to completion + auto await_result = storage_client.AwaitAsyncReadRequest(request.async_request_token.value()); + while (!await_result) { + await_result = storage_client.AwaitAsyncReadRequest(request.async_request_token.value()); } if (await_result->HasError()) { @@ -685,17 +671,22 @@ class ShardRequestManager : public ShardRequestManagerInterface { } if (!response.next_start_id) { - paginated_response_tracker.erase((*shard_it)); - shard_cache_ref.erase(shard_it); - // Needed to maintain the 1-1 mapping between the ShardCache and the requests. - auto it = state.requests.begin() + request_idx; - state.requests.erase(it); - + paginated_response_tracker.erase(request.shard); + to_erase.push_back(i); } else { - state.requests[request_idx].start_id.second = response.next_start_id->second; - paginated_response_tracker[*shard_it] = PaginatedResponseState::PartiallyFinished; + request.request.start_id.second = response.next_start_id->second; + paginated_response_tracker[request.shard] = PaginatedResponseState::PartiallyFinished; } + responses.push_back(std::move(response)); + + // reverse sort to_erase to remove requests in reverse order for correctness + std::sort(to_erase.begin(), to_erase.end(), std::greater<>()); + + auto requests_begin = state.requests.begin(); + for (int i : to_erase) { + state.requests.erase(requests_begin + i); + } } } From 6d544e4fc0e92490b657c1523ae5a71022f04bb4 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Wed, 23 Nov 2022 14:51:38 +0200 Subject: [PATCH 06/26] Address GH comments --- src/expr/interpret/eval.hpp | 3 +- src/functions/CMakeLists.txt | 1 - src/functions/awesome_memgraph_functions.hpp | 103 +- src/query/v2/accessors.cpp | 12 +- src/query/v2/accessors.hpp | 45 +- src/query/v2/bindings/eval.hpp | 3 +- src/query/v2/shard_request_manager.hpp | 18 +- .../awesome_memgraph_functions.py | 2 +- tests/unit/query_v2_expression_evaluator.cpp | 112 +- tests/unit/storage_v3_edge.cpp | 4046 ----------------- 10 files changed, 76 insertions(+), 4269 deletions(-) diff --git a/src/expr/interpret/eval.hpp b/src/expr/interpret/eval.hpp index 8b8b5a7c7..4ad17437b 100644 --- a/src/expr/interpret/eval.hpp +++ b/src/expr/interpret/eval.hpp @@ -416,8 +416,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> { typename TReturnType = std::enable_if_t<std::is_same_v<TTag, QueryEngineTag>, bool>> TReturnType HasLabelImpl(const VertexAccessor &vertex, const LabelIx &label_ix, QueryEngineTag /*tag*/) { auto label = typename VertexAccessor::Label{LabelId::FromUint(label_ix.ix)}; - auto has_label = vertex.HasLabel(label); - return has_label; + return vertex.HasLabel(label); } TypedValue Visit(LabelsTest &labels_test) override { diff --git a/src/functions/CMakeLists.txt b/src/functions/CMakeLists.txt index 09720c862..3a3d430cd 100644 --- a/src/functions/CMakeLists.txt +++ b/src/functions/CMakeLists.txt @@ -1,2 +1 @@ add_library(mg-functions INTERFACE) -target_include_directories(mg-functions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/functions/awesome_memgraph_functions.hpp b/src/functions/awesome_memgraph_functions.hpp index 0a2b873c2..33cc954f5 100644 --- a/src/functions/awesome_memgraph_functions.hpp +++ b/src/functions/awesome_memgraph_functions.hpp @@ -409,21 +409,13 @@ void FType(const char *name, const TypedValueT *args, int64_t nargs, int64_t pos // TODO: Implement degrees, haversin, radians // TODO: Implement spatial functions -template <typename TypedValueT, typename FunctionContextT, typename Tag> +template <typename TypedValueT, typename FunctionContextT> TypedValueT EndNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType<TypedValueT, Or<Null, Edge>>("endNode", args, nargs); - if (args[0].IsNull()) return TypedValueT(ctx.memory); - if constexpr (std::is_same_v<Tag, StorageEngineTag>) { - const auto to = args[0].ValueEdge().To(); - auto pk = to.primary_key; - auto maybe_vertex_accessor = ctx.db_accessor->FindVertex(pk, ctx.view); - if (!maybe_vertex_accessor) { - throw functions::FunctionRuntimeException("Trying to get properties from a deleted object."); - } - return TypedValueT(*maybe_vertex_accessor, ctx.memory); - } else { - return TypedValueT(args[0].ValueEdge().To(), ctx.memory); + if (args[0].IsNull()) { + return TypedValueT(ctx.memory); } + return TypedValueT(args[0].ValueEdge().To(), ctx.memory); } template <typename TypedValueT, typename FunctionContextT> @@ -450,6 +442,7 @@ TypedValueT Properties(const TypedValueT *args, int64_t nargs, const FunctionCon auto *dba = ctx.db_accessor; auto get_properties = [&](const auto &record_accessor) { typename TypedValueT::TMap properties(ctx.memory); + Conv conv; if constexpr (std::is_same_v<Tag, StorageEngineTag>) { auto maybe_props = record_accessor.Properties(ctx.view); if (maybe_props.HasError()) { @@ -466,11 +459,9 @@ TypedValueT Properties(const TypedValueT *args, int64_t nargs, const FunctionCon } } for (const auto &property : *maybe_props) { - Conv conv; properties.emplace(dba->PropertyToName(property.first), conv(property.second)); } } else { - Conv conv; for (const auto &property : record_accessor.Properties()) { properties.emplace(utils::pmr::string(dba->PropertyToName(property.first), ctx.memory), conv(property.second, dba)); @@ -510,21 +501,13 @@ TypedValueT Size(const TypedValueT *args, int64_t nargs, const FunctionContextT return TypedValueT(static_cast<int64_t>(value.ValuePath().edges().size()), ctx.memory); } -template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv> +template <typename TypedValueT, typename FunctionContextT, typename Conv> TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType<TypedValueT, Or<Null, Edge>>("startNode", args, nargs); - if (args[0].IsNull()) return TypedValueT(ctx.memory); - if constexpr (std::is_same_v<Tag, StorageEngineTag>) { - const auto to = args[0].ValueEdge().From(); - auto pk = to.primary_key; - auto maybe_vertex_accessor = ctx.db_accessor->FindVertex(pk, ctx.view); - if (!maybe_vertex_accessor) { - throw functions::FunctionRuntimeException("Trying to get properties from a deleted object."); - } - return TypedValueT(*maybe_vertex_accessor, ctx.memory); - } else { - return TypedValueT(args[0].ValueEdge().From(), ctx.memory); + if (args[0].IsNull()) { + return TypedValueT(ctx.memory); } + return TypedValueT(args[0].ValueEdge().From(), ctx.memory); } // This is needed because clang-tidy fails to identify the use of this function in the if-constexpr branch @@ -702,49 +685,6 @@ TypedValueT ValueType(const TypedValueT *args, int64_t nargs, const FunctionCont } } -// TODO: How is Keys different from Properties function? -template <typename TypedValueT, typename FunctionContextT, typename Tag> -TypedValueT Keys(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { - FType<TypedValueT, Or<Null, Vertex, Edge>>("keys", args, nargs); - auto *dba = ctx.db_accessor; - auto get_keys = [&](const auto &record_accessor) { - typename TypedValueT::TVector keys(ctx.memory); - if constexpr (std::same_as<Tag, StorageEngineTag>) { - auto maybe_props = record_accessor.Properties(ctx.view); - if (maybe_props.HasError()) { - switch (maybe_props.GetError()) { - case storage::v3::Error::DELETED_OBJECT: - throw functions::FunctionRuntimeException("Trying to get keys from a deleted object."); - case storage::v3::Error::NONEXISTENT_OBJECT: - throw functions::FunctionRuntimeException("Trying to get keys from an object that doesn't exist."); - case storage::v3::Error::SERIALIZATION_ERROR: - case storage::v3::Error::VERTEX_HAS_EDGES: - case storage::v3::Error::PROPERTIES_DISABLED: - case storage::v3::Error::VERTEX_ALREADY_INSERTED: - throw functions::FunctionRuntimeException("Unexpected error when getting keys."); - } - } - for (const auto &property : *maybe_props) { - keys.emplace_back(dba->PropertyToName(property.first)); - } - } else { - for (const auto &property : record_accessor.Properties()) { - keys.emplace_back(dba->PropertyToName(property.first)); - } - } - return TypedValueT(std::move(keys)); - }; - - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValueT(ctx.memory); - } - if (value.IsVertex()) { - return get_keys(value.ValueVertex()); - } - return get_keys(value.ValueEdge()); -} - template <typename TypedValueT, typename FunctionContextT, typename Tag> TypedValueT Labels(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType<TypedValueT, Or<Null, Vertex>>("labels", args, nargs); @@ -1026,12 +966,9 @@ template <typename TypedValueT, typename FunctionContextT> TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType<TypedValueT, Or<Null, Vertex, Edge>>("id", args, nargs); const auto &arg = args[0]; - if (arg.IsNull()) { + if (arg.IsNull() || arg.IsVertex()) { return TypedValueT(ctx.memory); } - if (arg.IsVertex()) { - return TypedValueT(static_cast<int64_t>(arg.ValueVertex().CypherId()), ctx.memory); - } return TypedValueT(static_cast<int64_t>(arg.ValueEdge().CypherId()), ctx.memory); } @@ -1382,22 +1319,24 @@ NameToFunction(const std::string &function_name) { if (function_name == "DEGREE") return functions::impl::Degree<TypedValueT, FunctionContextT, Tag>; if (function_name == "INDEGREE") return functions::impl::InDegree<TypedValueT, FunctionContextT, Tag>; if (function_name == "OUTDEGREE") return functions::impl::OutDegree<TypedValueT, FunctionContextT, Tag>; - if (function_name == "ENDNODE") return functions::impl::EndNode<TypedValueT, FunctionContextT, Tag>; if (function_name == "HEAD") return functions::impl::Head<TypedValueT, FunctionContextT>; if (function_name == kId) return functions::impl::Id<TypedValueT, FunctionContextT>; if (function_name == "LAST") return functions::impl::Last<TypedValueT, FunctionContextT>; if (function_name == "PROPERTIES") return functions::impl::Properties<TypedValueT, FunctionContextT, Tag, Conv>; if (function_name == "SIZE") return functions::impl::Size<TypedValueT, FunctionContextT>; - if (function_name == "STARTNODE") return functions::impl::StartNode<TypedValueT, FunctionContextT, Tag, Conv>; if (function_name == "TIMESTAMP") return functions::impl::Timestamp<TypedValueT, FunctionContextT>; if (function_name == "TOBOOLEAN") return functions::impl::ToBoolean<TypedValueT, FunctionContextT>; if (function_name == "TOFLOAT") return functions::impl::ToFloat<TypedValueT, FunctionContextT>; if (function_name == "TOINTEGER") return functions::impl::ToInteger<TypedValueT, FunctionContextT>; if (function_name == "TYPE") return functions::impl::Type<TypedValueT, FunctionContextT>; if (function_name == "VALUETYPE") return functions::impl::ValueType<TypedValueT, FunctionContextT>; + // Only on QE + if constexpr (std::is_same_v<Tag, QueryEngineTag>) { + if (function_name == "STARTNODE") return functions::impl::StartNode<TypedValueT, FunctionContextT, Conv>; + if (function_name == "ENDNODE") return functions::impl::EndNode<TypedValueT, FunctionContextT>; + } // List functions - if (function_name == "KEYS") return functions::impl::Keys<TypedValueT, FunctionContextT, Tag>; if (function_name == "LABELS") return functions::impl::Labels<TypedValueT, FunctionContextT, Tag>; if (function_name == "NODES") return functions::impl::Nodes<TypedValueT, FunctionContextT>; if (function_name == "RANGE") return functions::impl::Range<TypedValueT, FunctionContextT>; @@ -1449,9 +1388,12 @@ NameToFunction(const std::string &function_name) { // Memgraph specific functions if (function_name == "ASSERT") return functions::impl::Assert<TypedValueT, FunctionContextT>; - if (function_name == "COUNTER") return functions::impl::Counter<TypedValueT, FunctionContextT>; if (function_name == "TOBYTESTRING") return functions::impl::ToByteString<TypedValueT, FunctionContextT>; if (function_name == "FROMBYTESTRING") return functions::impl::FromByteString<TypedValueT, FunctionContextT>; + // Only on QE + if constexpr (std::is_same_v<Tag, QueryEngineTag>) { + if (function_name == "COUNTER") return functions::impl::Counter<TypedValueT, FunctionContextT>; + } // Functions for temporal types if (function_name == "DATE") return functions::impl::Date<TypedValueT, FunctionContextT>; @@ -1459,6 +1401,13 @@ NameToFunction(const std::string &function_name) { if (function_name == "LOCALDATETIME") return functions::impl::LocalDateTime<TypedValueT, FunctionContextT>; if (function_name == "DURATION") return functions::impl::Duration<TypedValueT, FunctionContextT>; + // Only on QE + if constexpr (std::is_same_v<Tag, QueryEngineTag>) { + if (function_name == "COUNTER") return functions::impl::Counter<TypedValueT, FunctionContextT>; + if (function_name == "STARTNODE") return functions::impl::StartNode<TypedValueT, FunctionContextT, Conv>; + if (function_name == "ENDNODE") return functions::impl::EndNode<TypedValueT, FunctionContextT>; + } + return nullptr; } diff --git a/src/query/v2/accessors.cpp b/src/query/v2/accessors.cpp index 63915327f..6d8abeb41 100644 --- a/src/query/v2/accessors.cpp +++ b/src/query/v2/accessors.cpp @@ -23,10 +23,11 @@ EdgeTypeId EdgeAccessor::EdgeType() const { return edge.type.id; } const std::vector<std::pair<PropertyId, Value>> &EdgeAccessor::Properties() const { return edge.properties; } Value EdgeAccessor::GetProperty(const std::string &prop_name) const { - if (!manager_->HasProperty(prop_name)) { + auto maybe_prop = manager_->MaybeNameToProperty(prop_name); + if (!maybe_prop) { return {}; } - auto prop_id = manager_->NameToProperty(prop_name); + const auto prop_id = *maybe_prop; auto it = std::find_if(edge.properties.begin(), edge.properties.end(), [&](auto &pr) { return prop_id == pr.first; }); return it->second; } @@ -35,6 +36,8 @@ const Edge &EdgeAccessor::GetEdge() const { return edge; } bool EdgeAccessor::IsCycle() const { return edge.src == edge.dst; }; +size_t EdgeAccessor::CypherId() const { return edge.id.gid; } + VertexAccessor EdgeAccessor::To() const { return VertexAccessor(Vertex{edge.dst}, std::vector<std::pair<PropertyId, msgs::Value>>{}, manager_); } @@ -88,10 +91,11 @@ Value VertexAccessor::GetProperty(PropertyId prop_id) const { // NOLINTNEXTLINE(readability-convert-member-functions-to-static) Value VertexAccessor::GetProperty(const std::string &prop_name) const { - if (!manager_->HasProperty(prop_name)) { + auto maybe_prop = manager_->MaybeNameToProperty(prop_name); + if (!maybe_prop) { return {}; } - return GetProperty(manager_->NameToProperty(prop_name)); + return GetProperty(*maybe_prop); } msgs::Vertex VertexAccessor::GetVertex() const { return vertex; } diff --git a/src/query/v2/accessors.hpp b/src/query/v2/accessors.hpp index 73cc24ba2..ba3937bb8 100644 --- a/src/query/v2/accessors.hpp +++ b/src/query/v2/accessors.hpp @@ -53,12 +53,7 @@ class EdgeAccessor final { [[nodiscard]] bool IsCycle() const; - // Dummy function - // NOLINTNEXTLINE(readability-convert-member-functions-to-static) - [[nodiscard]] size_t CypherId() const { return 10; } - - // bool HasSrcAccessor const { return src == nullptr; } - // bool HasDstAccessor const { return dst == nullptr; } + [[nodiscard]] size_t CypherId() const; [[nodiscard]] VertexAccessor To() const; [[nodiscard]] VertexAccessor From() const; @@ -98,44 +93,6 @@ class VertexAccessor final { [[nodiscard]] msgs::Vertex GetVertex() const; - // Dummy function - // NOLINTNEXTLINE(readability-convert-member-functions-to-static) - [[nodiscard]] size_t CypherId() const { return 10; } - - // auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types) const - // -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> { - // auto maybe_edges = impl_.InEdges(view, edge_types); - // if (maybe_edges.HasError()) return maybe_edges.GetError(); - // return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges)); - // } - // - // auto InEdges(storage::View view) const { return InEdges(view, {}); } - // - // auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types, const VertexAccessor &dest) - // const - // -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> { - // auto maybe_edges = impl_.InEdges(view, edge_types, &dest.impl_); - // if (maybe_edges.HasError()) return maybe_edges.GetError(); - // return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges)); - // } - // - // auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types) const - // -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> { - // auto maybe_edges = impl_.OutEdges(view, edge_types); - // if (maybe_edges.HasError()) return maybe_edges.GetError(); - // return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges)); - // } - // - // auto OutEdges(storage::View view) const { return OutEdges(view, {}); } - // - // auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types, - // const VertexAccessor &dest) const - // -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> { - // auto maybe_edges = impl_.OutEdges(view, edge_types, &dest.impl_); - // if (maybe_edges.HasError()) return maybe_edges.GetError(); - // return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges)); - // } - // NOLINTNEXTLINE(readability-convert-member-functions-to-static) [[nodiscard]] size_t InDegree() const { return 0; } diff --git a/src/query/v2/bindings/eval.hpp b/src/query/v2/bindings/eval.hpp index 52455bdb2..380eb879a 100644 --- a/src/query/v2/bindings/eval.hpp +++ b/src/query/v2/bindings/eval.hpp @@ -25,11 +25,10 @@ namespace memgraph::msgs { class ShardRequestManagerInterface; -} // namespace memgraph::msgs +} // namespace memgraph::msgs namespace memgraph::query::v2 { -inline const auto lam = [](const auto &val) { return ValueToTypedValue(val); }; namespace detail { class Callable { public: diff --git a/src/query/v2/shard_request_manager.hpp b/src/query/v2/shard_request_manager.hpp index 003cafaf8..ef2d3dc43 100644 --- a/src/query/v2/shard_request_manager.hpp +++ b/src/query/v2/shard_request_manager.hpp @@ -129,9 +129,9 @@ class ShardRequestManagerInterface { virtual const std::string &PropertyToName(memgraph::storage::v3::PropertyId prop) const = 0; virtual const std::string &LabelToName(memgraph::storage::v3::LabelId label) const = 0; virtual const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId type) const = 0; - virtual bool HasProperty(const std::string &name) const = 0; - virtual bool HasEdgeType(const std::string &name) const = 0; - virtual bool HasLabel(const std::string &name) const = 0; + virtual std::optional<storage::v3::PropertyId> MaybeNameToProperty(const std::string &name) const = 0; + virtual std::optional<storage::v3::EdgeTypeId> MaybeNameToEdge(const std::string &name) const = 0; + virtual std::optional<storage::v3::LabelId> MaybeNameToLabel(const std::string &name) const = 0; virtual bool IsPrimaryLabel(LabelId label) const = 0; virtual bool IsPrimaryKey(LabelId primary_label, PropertyId property) const = 0; }; @@ -356,11 +356,17 @@ class ShardRequestManager : public ShardRequestManagerInterface { return result_rows; } - bool HasProperty(const std::string &name) const override { return shards_map_.GetPropertyId(name).has_value(); } + std::optional<storage::v3::PropertyId> MaybeNameToProperty(const std::string &name) const override { + return shards_map_.GetPropertyId(name); + } - bool HasEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name).has_value(); } + std::optional<storage::v3::EdgeTypeId> MaybeNameToEdge(const std::string &name) const override { + return shards_map_.GetEdgeTypeId(name); + } - bool HasLabel(const std::string &name) const override { return shards_map_.GetLabelId(name).has_value(); } + std::optional<storage::v3::LabelId> MaybeNameToLabel(const std::string &name) const override { + return shards_map_.GetLabelId(name); + } private: enum class PaginatedResponseState { Pending, PartiallyFinished }; diff --git a/tests/e2e/distributed_queries/awesome_memgraph_functions.py b/tests/e2e/distributed_queries/awesome_memgraph_functions.py index 469979733..1c4bc87a4 100644 --- a/tests/e2e/distributed_queries/awesome_memgraph_functions.py +++ b/tests/e2e/distributed_queries/awesome_memgraph_functions.py @@ -19,7 +19,7 @@ import pytest from common import * -def test_vertex_creation_and_scanall(connection): +def test_awesome_memgraph_functions(connection): wait_for_shard_manager_to_initialize() cursor = connection.cursor() diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp index 97122ff0f..1c0130571 100644 --- a/tests/unit/query_v2_expression_evaluator.cpp +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -30,15 +30,12 @@ #include "query/v2/frontend/ast/ast.hpp" #include "query/v2/requests.hpp" #include "query/v2/shard_request_manager.hpp" +#include "query_v2_query_common.hpp" #include "storage/v3/property_value.hpp" #include "storage/v3/storage.hpp" #include "utils/exceptions.hpp" #include "utils/string.hpp" -#include "query_v2_query_common.hpp" -//#include "utils/temporal.hpp" - -using namespace memgraph::query::v2; using memgraph::query::v2::test_common::ToIntList; using testing::ElementsAre; using testing::UnorderedElementsAre; @@ -67,11 +64,11 @@ using CompoundKey = memgraph::coordinator::PrimaryKey; using memgraph::expr::ExpressionRuntimeException; using memgraph::functions::FunctionRuntimeException; -namespace { +namespace memgraph::query::v2::tests { class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInterface { public: - using VertexAccessor = memgraph::query::v2::accessors::VertexAccessor; + using VertexAccessor = accessors::VertexAccessor; explicit MockedShardRequestManager(ShardMap shard_map) : shards_map_(std::move(shard_map)) { SetUpNameIdMappers(); } memgraph::storage::v3::EdgeTypeId NameToEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name).value(); @@ -118,11 +115,17 @@ class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInte return edge_types_.IdToName(id.AsUint()); } - bool HasProperty(const std::string &name) const override { return shards_map_.GetPropertyId(name).has_value(); } + std::optional<storage::v3::PropertyId> MaybeNameToProperty(const std::string &name) const override { + return shards_map_.GetPropertyId(name); + } - bool HasEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name).has_value(); } + std::optional<storage::v3::EdgeTypeId> MaybeNameToEdge(const std::string &name) const override { + return shards_map_.GetEdgeTypeId(name); + } - bool HasLabel(const std::string &name) const override { return shards_map_.GetLabelId(name).has_value(); } + std::optional<storage::v3::LabelId> MaybeNameToLabel(const std::string &name) const override { + return shards_map_.GetLabelId(name); + } bool IsPrimaryLabel(LabelId label) const override { return true; } @@ -211,7 +214,7 @@ class ExpressionEvaluatorTest : public ::testing::Test { protected: AstStorage storage; memgraph::utils::MonotonicBufferResource mem{1024}; - EvaluationContext ctx{.memory = &mem, .timestamp = memgraph::query::v2::QueryTimestamp()}; + EvaluationContext ctx{.memory = &mem, .timestamp = QueryTimestamp()}; SymbolTable symbol_table; Frame frame{128}; @@ -542,20 +545,19 @@ using Value = memgraph::msgs::Value; using VertexId = memgraph::msgs::VertexId; using Label = memgraph::msgs::Label; -memgraph::query::v2::accessors::VertexAccessor CreateVertex(std::vector<std::pair<PropertyId, Value>> props, - const memgraph::msgs::ShardRequestManagerInterface *manager, - Label label = {}) { - static size_t id = 0; - return {Vertex{VertexId{label, id++}, {label}}, std::move(props), manager}; +accessors::VertexAccessor CreateVertex(std::vector<std::pair<PropertyId, Value>> props, + const memgraph::msgs::ShardRequestManagerInterface *manager, Label label = {}) { + static int64_t id = 0; + return {Vertex{VertexId{label, {memgraph::msgs::Value(id++)}}, {label}}, std::move(props), manager}; } -memgraph::query::v2::accessors::EdgeAccessor CreateEdge(std::vector<std::pair<PropertyId, Value>> props, - const memgraph::msgs::ShardRequestManagerInterface *manager) { - auto edge = Edge{.src = VertexId{{}, 0}, - .dst = VertexId{{}, 0}, +accessors::EdgeAccessor CreateEdge(std::vector<std::pair<PropertyId, Value>> props, + const memgraph::msgs::ShardRequestManagerInterface *manager) { + auto edge = Edge{.src = VertexId{{}, {}}, + .dst = VertexId{{}, {}}, .properties = std::move(props), .type = EdgeType{manager->NameToEdgeType("edge_type")}}; - return memgraph::query::v2::accessors::EdgeAccessor{std::move(edge), manager}; + return accessors::EdgeAccessor{std::move(edge), manager}; } TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) { @@ -575,8 +577,6 @@ TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) { auto value2 = Eval(op2); EXPECT_EQ(value2.ValueInt(), 43); } - // TODO(kostasrim) Investigate - // Shall we return null on missing properties? Or shall we throw bad optional access as we do now? { // Legal indexing, non-existing key. @@ -1135,16 +1135,6 @@ class ExpressionEvaluatorPropertyLookup : public ExpressionEvaluatorTest { } }; -// TODO(kostasrim) These will fail because of memory resource not propagating correctly. This should be done as part of -// polishing the allocators. -// TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) { -// auto v1 = CreateVertex({{prop_age.second, memgraph::msgs::Value(static_cast<int64_t>(32))}}, shard_manager.get()); -// frame[symbol] = TypedValue(v1); -// EXPECT_EQ(Value(prop_age).ValueInt(), 10); -// EXPECT_TRUE(Value(prop_height).IsNull()); -// } -// TEST_F(ExpressionEvaluatorPropertyLookup, Edge) {} - TEST_F(ExpressionEvaluatorPropertyLookup, Null) { frame[symbol] = TypedValue(); EXPECT_TRUE(Value(prop_age).IsNull()); @@ -1266,17 +1256,6 @@ TEST_F(FunctionTest, Size) { .ValueInt(), 3); ASSERT_THROW(EvaluateFunction("SIZE", 5), FunctionRuntimeException); - - // TODO(kostasrim) Add this when we enable paths on the accessors - // auto v0 = dba.InsertVertex(); - // memgraph::query::Path path(v0); - // EXPECT_EQ(EvaluateFunction("SIZE", path).ValueInt(), 0); - // auto v1 = dba.InsertVertex(); - // auto edge = dba.InsertEdge(&v0, &v1, dba.NameToEdgeType("type")); - // ASSERT_TRUE(edge.HasValue()); - // path.Expand(*edge); - // path.Expand(v1); - // EXPECT_EQ(EvaluateFunction("SIZE", path).ValueInt(), 1); } TEST_F(FunctionTest, StartNode) { @@ -1290,11 +1269,6 @@ TEST_F(FunctionTest, StartNode) { ASSERT_THROW(EvaluateFunction("STARTNODE", 2), FunctionRuntimeException); } -// TODO(kostasrim) Enable this test once we add degree to the accessors -// TEST_F(FunctionTest, Degree) {} -// TEST_F(FunctionTest, InDegree) {} -// TEST_F(FunctionTest, OutDegree) {} - TEST_F(FunctionTest, ToBoolean) { ASSERT_THROW(EvaluateFunction("TOBOOLEAN"), FunctionRuntimeException); ASSERT_TRUE(EvaluateFunction("TOBOOLEAN", TypedValue()).IsNull()); @@ -1368,9 +1342,9 @@ TEST_F(FunctionTest, Labels) { Label label{shard_manager->NameToLabel("label1")}; auto v = CreateVertex({}, shard_manager.get(), std::move(label)); std::vector<std::string> labels; - auto _labels = EvaluateFunction("LABELS", v).ValueList(); - labels.reserve(_labels.size()); - for (auto label : _labels) { + auto evaluated_labels = EvaluateFunction("LABELS", v).ValueList(); + labels.reserve(evaluated_labels.size()); + for (auto label : evaluated_labels) { labels.emplace_back(label.ValueString()); } ASSERT_THAT(labels, UnorderedElementsAre("label1")); @@ -1396,27 +1370,6 @@ TEST_F(FunctionTest, Range) { EXPECT_THAT(ToIntList(EvaluateFunction("RANGE", -2, 4, -1)), ElementsAre()); } -TEST_F(FunctionTest, Keys) { - ASSERT_THROW(EvaluateFunction("KEYS"), FunctionRuntimeException); - ASSERT_TRUE(EvaluateFunction("KEYS", TypedValue()).IsNull()); - const auto height = shard_manager->NameToProperty("height"); - const auto age = shard_manager->NameToProperty("age"); - auto v1 = CreateVertex({{height, Value(static_cast<int64_t>(5))}, {age, Value(static_cast<int64_t>(10))}}, - shard_manager.get()); - auto edge = CreateEdge({{height, Value(static_cast<int64_t>(3))}, {age, Value(static_cast<int64_t>(15))}}, - shard_manager.get()); - auto prop_keys_to_string = [](TypedValue t) { - std::vector<std::string> keys; - for (auto property : t.ValueList()) { - keys.emplace_back(property.ValueString()); - } - return keys; - }; - ASSERT_THAT(prop_keys_to_string(EvaluateFunction("KEYS", v1)), UnorderedElementsAre("height", "age")); - ASSERT_THAT(prop_keys_to_string(EvaluateFunction("KEYS", edge)), UnorderedElementsAre("height", "age")); - ASSERT_THROW(EvaluateFunction("KEYS", 2), FunctionRuntimeException); -} - TEST_F(FunctionTest, Tail) { ASSERT_THROW(EvaluateFunction("TAIL"), FunctionRuntimeException); ASSERT_TRUE(EvaluateFunction("TAIL", TypedValue()).IsNull()); @@ -1606,18 +1559,6 @@ TEST_F(FunctionTest, Counter) { EXPECT_THROW(EvaluateFunction("COUNTER", "c6", 0, 0), FunctionRuntimeException); } -// TODO(kostasrim) Add this once we fix accessors CypherId() functions -// TEST_F(FunctionTest, Id) { -// auto v = CreateVertex({}, shard_manager.get()); -// auto e = CreateEdge({}, shard_manager.get()); -// EXPECT_TRUE(EvaluateFunction("ID", TypedValue()).IsNull()); -// EXPECT_EQ(EvaluateFunction("ID", v).ValueInt(), 0); -// EXPECT_EQ(EvaluateFunction("ID", e).ValueInt(), 0); -// EXPECT_THROW(EvaluateFunction("ID"), FunctionRuntimeException); -// EXPECT_THROW(EvaluateFunction("ID", 0), FunctionRuntimeException); -// EXPECT_THROW(EvaluateFunction("ID", v, e), FunctionRuntimeException); -//} - TEST_F(FunctionTest, ToStringNull) { EXPECT_TRUE(EvaluateFunction("TOSTRING", TypedValue()).IsNull()); } TEST_F(FunctionTest, ToStringString) { @@ -1782,5 +1723,4 @@ TEST_F(FunctionTest, FromByteString) { EXPECT_EQ(EvaluateFunction("FROMBYTESTRING", std::string("\x00\x42", 2)).ValueString(), "0x0042"); } -// TODO(kostasrim) Add temporal type tests. -} // namespace +} // namespace memgraph::query::v2::tests diff --git a/tests/unit/storage_v3_edge.cpp b/tests/unit/storage_v3_edge.cpp index 5c0759e98..99b981b7b 100644 --- a/tests/unit/storage_v3_edge.cpp +++ b/tests/unit/storage_v3_edge.cpp @@ -279,592 +279,6 @@ TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) { } } -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeCreateFromLargerCommit) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_from = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertices -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_to = acc.CreateVertex(); -// auto vertex_from = acc.CreateVertex(); -// gid_to = vertex_to.Gid(); -// gid_from = vertex_from.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&from_id, &to_id, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex_from); -// ASSERT_EQ(edge.To(), *vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeCreateFromSameCommit) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_vertex = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertex -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid_vertex = vertex.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&*vertex, &*vertex, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex); -// ASSERT_EQ(edge.To(), *vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeCreateFromSmallerAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_from = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertices -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.CreateVertex(); -// auto vertex_to = acc.CreateVertex(); -// gid_from = vertex_from.Gid(); -// gid_to = vertex_to.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge, but abort the transaction -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&from_id, &to_id, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex_from); -// ASSERT_EQ(edge.To(), *vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Abort(); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&from_id, &to_id, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex_from); -// ASSERT_EQ(edge.To(), *vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - // NOLINTNEXTLINE(hicpp-special-member-functions) TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { // Create vertices @@ -1174,232 +588,6 @@ TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) { } } -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeCreateFromSameAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_vertex = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertex -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid_vertex = vertex.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge, but abort the transaction -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&*vertex, &*vertex, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex); -// ASSERT_EQ(edge.To(), *vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Abort(); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&*vertex, &*vertex, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex); -// ASSERT_EQ(edge.To(), *vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - // NOLINTNEXTLINE(hicpp-special-member-functions) TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { // Create vertex @@ -1590,921 +778,6 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) { } } -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeDeleteFromLargerCommit) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_from = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertices -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_to = acc.CreateVertex(); -// auto vertex_from = acc.CreateVertex(); -// gid_from = vertex_from.Gid(); -// gid_to = vertex_to.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&from_id, &to_id, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex_from); -// ASSERT_EQ(edge.To(), *vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Delete edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto edge = vertex_from->OutEdges(View::NEW).GetValue()[0]; - -// auto res = acc.DeleteEdge(&edge); -// ASSERT_TRUE(res.HasValue()); -// ASSERT_TRUE(res.GetValue()); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeDeleteFromSameCommit) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_vertex = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertex -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid_vertex = vertex.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&*vertex, &*vertex, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex); -// ASSERT_EQ(edge.To(), *vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Delete edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto res = acc.DeleteEdge(&edge); -// ASSERT_TRUE(res.HasValue()); -// ASSERT_TRUE(res.GetValue()); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 0); -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_from = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertices -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.CreateVertex(); -// auto vertex_to = acc.CreateVertex(); -// gid_from = vertex_from.Gid(); -// gid_to = vertex_to.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&from_id, &to_id, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex_from); -// ASSERT_EQ(edge.To(), *vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Delete the edge, but abort the transaction -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto edge = vertex_from->OutEdges(View::NEW).GetValue()[0]; - -// auto res = acc.DeleteEdge(&edge); -// ASSERT_TRUE(res.HasValue()); -// ASSERT_TRUE(res.GetValue()); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); - -// acc.Abort(); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Delete the edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// auto edge = vertex_from->OutEdges(View::NEW).GetValue()[0]; - -// auto res = acc.DeleteEdge(&edge); -// ASSERT_TRUE(res.HasValue()); -// ASSERT_TRUE(res.GetValue()); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &to_id)->size(), 1); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD, {}, &from_id)->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &from_id)->size(), 1); -// ASSERT_EQ(vertex_to->InEdges(View::OLD, {}, &to_id)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// // Check edges without filters -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - // NOLINTNEXTLINE(hicpp-special-member-functions) TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { // Create vertex @@ -2814,365 +1087,6 @@ TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) { } } -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, EdgeDeleteFromSameAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_vertex = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create vertex -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid_vertex = vertex.Gid(); -// acc.Commit(GetNextHlc()); -// } - -// // Create edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&*vertex, &*vertex, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), *vertex); -// ASSERT_EQ(edge.To(), *vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Delete the edge, but abort the transaction -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto res = acc.DeleteEdge(&edge); -// ASSERT_TRUE(res.HasValue()); -// ASSERT_TRUE(res.GetValue()); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 0); -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et}, &*vertex)->size(), 0); - -// acc.Abort(); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// { -// auto ret = vertex->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Delete the edge -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// auto et = acc.NameToEdgeType("et5"); - -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto res = acc.DeleteEdge(&edge); -// ASSERT_TRUE(res.HasValue()); -// ASSERT_TRUE(res.GetValue()); - -// // Check edges without filters -// { -// auto ret = vertex->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 0); -// { -// auto ret = vertex->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex); -// ASSERT_EQ(e.To(), *vertex); -// } -// ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); - -// auto other_et = acc.NameToEdgeType("other"); - -// // Check edges with filters -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->InEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->InEdges(View::OLD, {other_et}, &*vertex)->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et})->size(), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {et, other_et})->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {}, &*vertex)->size(), 1); -// ASSERT_EQ(vertex->OutEdges(View::OLD, {other_et}, &*vertex)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check whether the edge exists -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid_vertex, View::NEW); -// ASSERT_TRUE(vertex); - -// // Check edges without filters -// ASSERT_EQ(vertex->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } -// } - // NOLINTNEXTLINE(hicpp-special-member-functions) TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { // Create vertices @@ -3313,1964 +1227,4 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) { ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); } } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, VertexDetachDeleteMultipleCommit) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_vertex1 = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// memgraph::storage::Gid gid_vertex2 = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.CreateVertex(); -// auto vertex2 = acc.CreateVertex(); - -// gid_vertex1 = vertex1.Gid(); -// gid_vertex2 = vertex2.Gid(); - -// auto et1 = acc.NameToEdgeType("et1"); -// auto et2 = acc.NameToEdgeType("et2"); -// auto et3 = acc.NameToEdgeType("et3"); -// auto et4 = acc.NameToEdgeType("et4"); - -// auto res1 = acc.CreateEdge(&vertex1, &vertex2, et1); -// ASSERT_TRUE(res1.HasValue()); -// auto edge1 = res1.GetValue(); -// ASSERT_EQ(edge1.EdgeType(), et1); -// ASSERT_EQ(edge1.From(), vertex1); -// ASSERT_EQ(edge1.To(), vertex2); - -// auto res2 = acc.CreateEdge(&vertex2, &vertex1, et2); -// ASSERT_TRUE(res2.HasValue()); -// auto edge2 = res2.GetValue(); -// ASSERT_EQ(edge2.EdgeType(), et2); -// ASSERT_EQ(edge2.From(), vertex2); -// ASSERT_EQ(edge2.To(), vertex1); - -// auto res3 = acc.CreateEdge(&vertex1, &vertex1, et3); -// ASSERT_TRUE(res3.HasValue()); -// auto edge3 = res3.GetValue(); -// ASSERT_EQ(edge3.EdgeType(), et3); -// ASSERT_EQ(edge3.From(), vertex1); -// ASSERT_EQ(edge3.To(), vertex1); - -// auto res4 = acc.CreateEdge(&vertex2, &vertex2, et4); -// ASSERT_TRUE(res4.HasValue()); -// auto edge4 = res4.GetValue(); -// ASSERT_EQ(edge4.EdgeType(), et4); -// ASSERT_EQ(edge4.From(), vertex2); -// ASSERT_EQ(edge4.To(), vertex2); - -// // Check edges -// { -// auto ret = vertex1.InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1.InDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex1); -// } -// } -// { -// auto ret = vertex1.OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1.OutDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex1); -// } -// } -// { -// auto ret = vertex2.InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2.InDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex2); -// } -// } -// { -// auto ret = vertex2.OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2.OutDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex2); -// } -// } - -// acc.Commit(GetNextHlc()); -// } - -// // Detach delete vertex -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.FindVertex(gid_vertex1, View::NEW); -// auto vertex2 = acc.FindVertex(gid_vertex2, View::NEW); -// ASSERT_TRUE(vertex1); -// ASSERT_TRUE(vertex2); - -// auto et1 = acc.NameToEdgeType("et1"); -// auto et2 = acc.NameToEdgeType("et2"); -// auto et3 = acc.NameToEdgeType("et3"); -// auto et4 = acc.NameToEdgeType("et4"); - -// // Delete must fail -// { -// auto ret = acc.DeleteVertex(&*vertex1); -// ASSERT_TRUE(ret.HasError()); -// ASSERT_EQ(ret.GetError(), memgraph::storage::Error::VERTEX_HAS_EDGES); -// } - -// // Detach delete vertex -// { -// auto ret = acc.DetachDeleteVertex(&*vertex1); -// ASSERT_TRUE(ret.HasValue()); -// ASSERT_TRUE(*ret); -// } - -// // Check edges -// { -// auto ret = vertex1->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// ASSERT_EQ(vertex1->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex1->InDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex1->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// ASSERT_EQ(vertex1->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex1->OutDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex2->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } - -// acc.Commit(GetNextHlc()); -// } - -// // Check dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.FindVertex(gid_vertex1, View::NEW); -// auto vertex2 = acc.FindVertex(gid_vertex2, View::NEW); -// ASSERT_FALSE(vertex1); -// ASSERT_TRUE(vertex2); - -// auto et4 = acc.NameToEdgeType("et4"); - -// // Check edges -// { -// auto ret = vertex2->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, VertexDetachDeleteSingleAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_from = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.CreateVertex(); -// auto vertex_to = acc.CreateVertex(); - -// auto et = acc.NameToEdgeType("et5"); - -// auto res = acc.CreateEdge(&vertex_from, &vertex_to, et); -// ASSERT_TRUE(res.HasValue()); -// auto edge = res.GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), vertex_from); -// ASSERT_EQ(edge.To(), vertex_to); - -// gid_from = vertex_from.Gid(); -// gid_to = vertex_to.Gid(); - -// // Check edges -// ASSERT_EQ(vertex_from.InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from.InDegree(View::NEW), 0); -// { -// auto ret = vertex_from.OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from.OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), vertex_from); -// ASSERT_EQ(e.To(), vertex_to); -// } -// { -// auto ret = vertex_to.InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to.InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), vertex_from); -// ASSERT_EQ(e.To(), vertex_to); -// } -// ASSERT_EQ(vertex_to.OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to.OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Detach delete vertex, but abort the transaction -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Delete must fail -// { -// auto ret = acc.DeleteVertex(&from_id); -// ASSERT_TRUE(ret.HasError()); -// ASSERT_EQ(ret.GetError(), memgraph::storage::Error::VERTEX_HAS_EDGES); -// } - -// // Detach delete vertex -// { -// auto ret = acc.DetachDeleteVertex(&from_id); -// ASSERT_TRUE(ret.HasValue()); -// ASSERT_TRUE(*ret); -// } - -// // Check edges -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex_from->InDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_from->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex_from->OutDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// acc.Abort(); -// } - -// // Check dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Check edges -// ASSERT_EQ(vertex_from->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::NEW), 0); -// { -// auto ret = vertex_from->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// { -// auto ret = vertex_to->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Detach delete vertex -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_TRUE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// auto et = acc.NameToEdgeType("et5"); - -// // Delete must fail -// { -// auto ret = acc.DeleteVertex(&from_id); -// ASSERT_TRUE(ret.HasError()); -// ASSERT_EQ(ret.GetError(), memgraph::storage::Error::VERTEX_HAS_EDGES); -// } - -// // Detach delete vertex -// { -// auto ret = acc.DetachDeleteVertex(&from_id); -// ASSERT_TRUE(ret.HasValue()); -// ASSERT_TRUE(*ret); -// } - -// // Check edges -// ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_from->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex_from->InDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex_from->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_from->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_from->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex_from->OutDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex_to->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et); -// ASSERT_EQ(e.From(), *vertex_from); -// ASSERT_EQ(e.To(), *vertex_to); -// } -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex_from = acc.FindVertex(gid_from, View::NEW); -// auto vertex_to = acc.FindVertex(gid_to, View::NEW); -// ASSERT_FALSE(vertex_from); -// ASSERT_TRUE(vertex_to); - -// // Check edges -// ASSERT_EQ(vertex_to->InEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->InEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->InDegree(View::NEW), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::OLD)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::OLD), 0); -// ASSERT_EQ(vertex_to->OutEdges(View::NEW)->size(), 0); -// ASSERT_EQ(*vertex_to->OutDegree(View::NEW), 0); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST_P(StorageEdgeTest, VertexDetachDeleteMultipleAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = GetParam()}}); -// memgraph::storage::Gid gid_vertex1 = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// memgraph::storage::Gid gid_vertex2 = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.CreateVertex(); -// auto vertex2 = acc.CreateVertex(); - -// gid_vertex1 = vertex1.Gid(); -// gid_vertex2 = vertex2.Gid(); - -// auto et1 = acc.NameToEdgeType("et1"); -// auto et2 = acc.NameToEdgeType("et2"); -// auto et3 = acc.NameToEdgeType("et3"); -// auto et4 = acc.NameToEdgeType("et4"); - -// auto res1 = acc.CreateEdge(&vertex1, &vertex2, et1); -// ASSERT_TRUE(res1.HasValue()); -// auto edge1 = res1.GetValue(); -// ASSERT_EQ(edge1.EdgeType(), et1); -// ASSERT_EQ(edge1.From(), vertex1); -// ASSERT_EQ(edge1.To(), vertex2); - -// auto res2 = acc.CreateEdge(&vertex2, &vertex1, et2); -// ASSERT_TRUE(res2.HasValue()); -// auto edge2 = res2.GetValue(); -// ASSERT_EQ(edge2.EdgeType(), et2); -// ASSERT_EQ(edge2.From(), vertex2); -// ASSERT_EQ(edge2.To(), vertex1); - -// auto res3 = acc.CreateEdge(&vertex1, &vertex1, et3); -// ASSERT_TRUE(res3.HasValue()); -// auto edge3 = res3.GetValue(); -// ASSERT_EQ(edge3.EdgeType(), et3); -// ASSERT_EQ(edge3.From(), vertex1); -// ASSERT_EQ(edge3.To(), vertex1); - -// auto res4 = acc.CreateEdge(&vertex2, &vertex2, et4); -// ASSERT_TRUE(res4.HasValue()); -// auto edge4 = res4.GetValue(); -// ASSERT_EQ(edge4.EdgeType(), et4); -// ASSERT_EQ(edge4.From(), vertex2); -// ASSERT_EQ(edge4.To(), vertex2); - -// // Check edges -// { -// auto ret = vertex1.InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1.InDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex1); -// } -// } -// { -// auto ret = vertex1.OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1.OutDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex1); -// } -// } -// { -// auto ret = vertex2.InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2.InDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), vertex1); -// ASSERT_EQ(e.To(), vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex2); -// } -// } -// { -// auto ret = vertex2.OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2.OutDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), vertex2); -// ASSERT_EQ(e.To(), vertex2); -// } -// } - -// acc.Commit(GetNextHlc()); -// } - -// // Detach delete vertex, but abort the transaction -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.FindVertex(gid_vertex1, View::NEW); -// auto vertex2 = acc.FindVertex(gid_vertex2, View::NEW); -// ASSERT_TRUE(vertex1); -// ASSERT_TRUE(vertex2); - -// auto et1 = acc.NameToEdgeType("et1"); -// auto et2 = acc.NameToEdgeType("et2"); -// auto et3 = acc.NameToEdgeType("et3"); -// auto et4 = acc.NameToEdgeType("et4"); - -// // Delete must fail -// { -// auto ret = acc.DeleteVertex(&*vertex1); -// ASSERT_TRUE(ret.HasError()); -// ASSERT_EQ(ret.GetError(), memgraph::storage::Error::VERTEX_HAS_EDGES); -// } - -// // Detach delete vertex -// { -// auto ret = acc.DetachDeleteVertex(&*vertex1); -// ASSERT_TRUE(ret.HasValue()); -// ASSERT_TRUE(*ret); -// } - -// // Check edges -// { -// auto ret = vertex1->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// ASSERT_EQ(vertex1->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex1->InDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex1->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// ASSERT_EQ(vertex1->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex1->OutDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex2->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } - -// acc.Abort(); -// } - -// // Check dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.FindVertex(gid_vertex1, View::NEW); -// auto vertex2 = acc.FindVertex(gid_vertex2, View::NEW); -// ASSERT_TRUE(vertex1); -// ASSERT_TRUE(vertex2); - -// auto et1 = acc.NameToEdgeType("et1"); -// auto et2 = acc.NameToEdgeType("et2"); -// auto et3 = acc.NameToEdgeType("et3"); -// auto et4 = acc.NameToEdgeType("et4"); - -// // Check edges -// { -// auto ret = vertex1->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// { -// auto ret = vertex1->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->InDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// { -// auto ret = vertex1->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// { -// auto ret = vertex1->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->OutDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// { -// auto ret = vertex2->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->InDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->OutDegree(View::NEW), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } - -// acc.Commit(GetNextHlc()); -// } - -// // Detach delete vertex -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.FindVertex(gid_vertex1, View::NEW); -// auto vertex2 = acc.FindVertex(gid_vertex2, View::NEW); -// ASSERT_TRUE(vertex1); -// ASSERT_TRUE(vertex2); - -// auto et1 = acc.NameToEdgeType("et1"); -// auto et2 = acc.NameToEdgeType("et2"); -// auto et3 = acc.NameToEdgeType("et3"); -// auto et4 = acc.NameToEdgeType("et4"); - -// // Delete must fail -// { -// auto ret = acc.DeleteVertex(&*vertex1); -// ASSERT_TRUE(ret.HasError()); -// ASSERT_EQ(ret.GetError(), memgraph::storage::Error::VERTEX_HAS_EDGES); -// } - -// // Detach delete vertex -// { -// auto ret = acc.DetachDeleteVertex(&*vertex1); -// ASSERT_TRUE(ret.HasValue()); -// ASSERT_TRUE(*ret); -// } - -// // Check edges -// { -// auto ret = vertex1->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// ASSERT_EQ(vertex1->InEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex1->InDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex1->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex1->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et3); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex1); -// } -// } -// ASSERT_EQ(vertex1->OutEdges(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// ASSERT_EQ(vertex1->OutDegree(View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); -// { -// auto ret = vertex2->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->InDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et1); -// ASSERT_EQ(e.From(), *vertex1); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// std::sort(edges.begin(), edges.end(), [](const auto &a, const auto &b) { return a.EdgeType() < b.EdgeType(); -// }); ASSERT_EQ(edges.size(), 2); ASSERT_EQ(*vertex2->OutDegree(View::OLD), 2); -// { -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et2); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex1); -// } -// { -// auto e = edges[1]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// { -// auto ret = vertex2->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } - -// acc.Commit(GetNextHlc()); -// } - -// // Check dataset -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex1 = acc.FindVertex(gid_vertex1, View::NEW); -// auto vertex2 = acc.FindVertex(gid_vertex2, View::NEW); -// ASSERT_FALSE(vertex1); -// ASSERT_TRUE(vertex2); - -// auto et4 = acc.NameToEdgeType("et4"); - -// // Check edges -// { -// auto ret = vertex2->InEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->InDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->InEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->InDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->OutEdges(View::OLD); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->OutDegree(View::OLD), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// { -// auto ret = vertex2->OutEdges(View::NEW); -// ASSERT_TRUE(ret.HasValue()); -// auto edges = ret.GetValue(); -// ASSERT_EQ(edges.size(), 1); -// ASSERT_EQ(*vertex2->OutDegree(View::NEW), 1); -// auto e = edges[0]; -// ASSERT_EQ(e.EdgeType(), et4); -// ASSERT_EQ(e.From(), *vertex2); -// ASSERT_EQ(e.To(), *vertex2); -// } -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST(StorageWithProperties, EdgePropertyCommit) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = true}}); -// memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid = vertex.Gid(); -// auto et = acc.NameToEdgeType("et5"); -// auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), vertex); -// ASSERT_EQ(edge.To(), vertex); - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue("temporary")); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_TRUE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "temporary"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "temporary"); -// } - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue("nandare")); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_FALSE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// acc.Commit(GetNextHlc()); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// auto other_property = acc.NameToProperty("other"); - -// ASSERT_TRUE(edge.GetProperty(other_property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(other_property, View::NEW)->IsNull()); - -// acc.Abort(); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue()); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_FALSE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue()); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_TRUE(old_value->IsNull()); -// } - -// acc.Commit(GetNextHlc()); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::OLD)->size(), 0); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// auto other_property = acc.NameToProperty("other"); - -// ASSERT_TRUE(edge.GetProperty(other_property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(other_property, View::NEW)->IsNull()); - -// acc.Abort(); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST(StorageWithProperties, EdgePropertyAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = true}}); -// memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); - -// // Create the vertex. -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid = vertex.Gid(); -// auto et = acc.NameToEdgeType("et5"); -// auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), vertex); -// ASSERT_EQ(edge.To(), vertex); -// acc.Commit(GetNextHlc()); -// } - -// // Set property 5 to "nandare", but abort the transaction. -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue("temporary")); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_TRUE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "temporary"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "temporary"); -// } - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue("nandare")); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_FALSE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// acc.Abort(); -// } - -// // Check that property 5 is null. -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::OLD)->size(), 0); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// auto other_property = acc.NameToProperty("other"); - -// ASSERT_TRUE(edge.GetProperty(other_property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(other_property, View::NEW)->IsNull()); - -// acc.Abort(); -// } - -// // Set property 5 to "nandare". -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue("temporary")); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_TRUE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "temporary"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "temporary"); -// } - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue("nandare")); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_FALSE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// acc.Commit(GetNextHlc()); -// } - -// // Check that property 5 is "nandare". -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// auto other_property = acc.NameToProperty("other"); - -// ASSERT_TRUE(edge.GetProperty(other_property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(other_property, View::NEW)->IsNull()); - -// acc.Abort(); -// } - -// // Set property 5 to null, but abort the transaction. -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue()); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_FALSE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// acc.Abort(); -// } - -// // Check that property 5 is "nandare". -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// auto other_property = acc.NameToProperty("other"); - -// ASSERT_TRUE(edge.GetProperty(other_property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(other_property, View::NEW)->IsNull()); - -// acc.Abort(); -// } - -// // Set property 5 to null. -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::NEW)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// { -// auto old_value = edge.SetProperty(property, memgraph::storage::PropertyValue()); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_FALSE(old_value->IsNull()); -// } - -// ASSERT_EQ(edge.GetProperty(property, View::OLD)->ValueString(), "nandare"); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property].ValueString(), "nandare"); -// } - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// acc.Commit(GetNextHlc()); -// } - -// // Check that property 5 is null. -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::OLD)->size(), 0); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// auto other_property = acc.NameToProperty("other"); - -// ASSERT_TRUE(edge.GetProperty(other_property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(other_property, View::NEW)->IsNull()); - -// acc.Abort(); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST(StorageWithProperties, EdgePropertySerializationError) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = true}}); -// memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid = vertex.Gid(); -// auto et = acc.NameToEdgeType("et5"); -// auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), vertex); -// ASSERT_EQ(edge.To(), vertex); -// acc.Commit(GetNextHlc()); -// } - -// auto acc1 = store.Access(GetNextHlc()); -// auto acc2 = store.Access(GetNextHlc()); - -// // Set property 1 to 123 in accessor 1. -// { -// auto vertex = acc1.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property1 = acc1.NameToProperty("property1"); -// auto property2 = acc1.NameToProperty("property2"); - -// ASSERT_TRUE(edge.GetProperty(property1, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property1, View::NEW)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::OLD)->size(), 0); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto old_value = edge.SetProperty(property1, memgraph::storage::PropertyValue(123)); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_TRUE(old_value->IsNull()); -// } - -// ASSERT_TRUE(edge.GetProperty(property1, View::OLD)->IsNull()); -// ASSERT_EQ(edge.GetProperty(property1, View::NEW)->ValueInt(), 123); -// ASSERT_TRUE(edge.GetProperty(property2, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::OLD)->size(), 0); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property1].ValueInt(), 123); -// } -// } - -// // Set property 2 to "nandare" in accessor 2. -// { -// auto vertex = acc2.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property1 = acc2.NameToProperty("property1"); -// auto property2 = acc2.NameToProperty("property2"); - -// ASSERT_TRUE(edge.GetProperty(property1, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property1, View::NEW)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::OLD)->size(), 0); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto res = edge.SetProperty(property2, memgraph::storage::PropertyValue("nandare")); -// ASSERT_TRUE(res.HasError()); -// ASSERT_EQ(res.GetError(), memgraph::storage::Error::SERIALIZATION_ERROR); -// } -// } - -// // Finalize both accessors. -// ASSERT_FALSE(acc1.Commit(GetNextHlc()); -// acc2.Abort(); - -// // Check which properties exist. -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property1 = acc.NameToProperty("property1"); -// auto property2 = acc.NameToProperty("property2"); - -// ASSERT_EQ(edge.GetProperty(property1, View::OLD)->ValueInt(), 123); -// ASSERT_TRUE(edge.GetProperty(property2, View::OLD)->IsNull()); -// { -// auto properties = edge.Properties(View::OLD).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property1].ValueInt(), 123); -// } - -// ASSERT_EQ(edge.GetProperty(property1, View::NEW)->ValueInt(), 123); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// { -// auto properties = edge.Properties(View::NEW).GetValue(); -// ASSERT_EQ(properties.size(), 1); -// ASSERT_EQ(properties[property1].ValueInt(), 123); -// } - -// acc.Abort(); -// } -// } - -// TEST(StorageWithProperties, EdgePropertyClear) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = true}}); -// memgraph::storage::Gid gid; -// auto property1 = store.NameToProperty("property1"); -// auto property2 = store.NameToProperty("property2"); -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid = vertex.Gid(); -// auto et = acc.NameToEdgeType("et5"); -// auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), vertex); -// ASSERT_EQ(edge.To(), vertex); - -// auto old_value = edge.SetProperty(property1, memgraph::storage::PropertyValue("value")); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_TRUE(old_value->IsNull()); - -// acc.Commit(GetNextHlc()); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// ASSERT_EQ(edge.GetProperty(property1, View::OLD)->ValueString(), "value"); -// ASSERT_TRUE(edge.GetProperty(property2, View::OLD)->IsNull()); -// ASSERT_THAT(edge.Properties(View::OLD).GetValue(), -// UnorderedElementsAre(std::pair(property1, memgraph::storage::PropertyValue("value")))); - -// { -// auto old_values = edge.ClearProperties(); -// ASSERT_TRUE(old_values.HasValue()); -// ASSERT_FALSE(old_values->empty()); -// } - -// ASSERT_TRUE(edge.GetProperty(property1, View::NEW)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW).GetValue().size(), 0); - -// { -// auto old_values = edge.ClearProperties(); -// ASSERT_TRUE(old_values.HasValue()); -// ASSERT_TRUE(old_values->empty()); -// } - -// ASSERT_TRUE(edge.GetProperty(property1, View::NEW)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW).GetValue().size(), 0); - -// acc.Abort(); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto old_value = edge.SetProperty(property2, memgraph::storage::PropertyValue(42)); -// ASSERT_TRUE(old_value.HasValue()); -// ASSERT_TRUE(old_value->IsNull()); - -// acc.Commit(GetNextHlc()); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// ASSERT_EQ(edge.GetProperty(property1, View::OLD)->ValueString(), "value"); -// ASSERT_EQ(edge.GetProperty(property2, View::OLD)->ValueInt(), 42); -// ASSERT_THAT(edge.Properties(View::OLD).GetValue(), -// UnorderedElementsAre(std::pair(property1, memgraph::storage::PropertyValue("value")), -// std::pair(property2, memgraph::storage::PropertyValue(42)))); - -// { -// auto old_values = edge.ClearProperties(); -// ASSERT_TRUE(old_values.HasValue()); -// ASSERT_FALSE(old_values->empty()); -// } - -// ASSERT_TRUE(edge.GetProperty(property1, View::NEW)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW).GetValue().size(), 0); - -// { -// auto old_values = edge.ClearProperties(); -// ASSERT_TRUE(old_values.HasValue()); -// ASSERT_TRUE(old_values->empty()); -// } - -// ASSERT_TRUE(edge.GetProperty(property1, View::NEW)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW).GetValue().size(), 0); - -// acc.Commit(GetNextHlc()); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// ASSERT_TRUE(edge.GetProperty(property1, View::NEW)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(property2, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW).GetValue().size(), 0); - -// acc.Abort(); -// } -// } - -// // NOLINTNEXTLINE(hicpp-special-member-functions) -// TEST(StorageWithoutProperties, EdgePropertyAbort) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = false}}); -// memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits<uint64_t>::max()); -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid = vertex.Gid(); -// auto et = acc.NameToEdgeType("et5"); -// auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), vertex); -// ASSERT_EQ(edge.To(), vertex); -// acc.Commit(GetNextHlc()); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto res = edge.SetProperty(property, memgraph::storage::PropertyValue("temporary")); -// ASSERT_TRUE(res.HasError()); -// ASSERT_EQ(res.GetError(), memgraph::storage::Error::PROPERTIES_DISABLED); -// } - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// { -// auto res = edge.SetProperty(property, memgraph::storage::PropertyValue("nandare")); -// ASSERT_TRUE(res.HasError()); -// ASSERT_EQ(res.GetError(), memgraph::storage::Error::PROPERTIES_DISABLED); -// } - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// acc.Abort(); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// auto property = acc.NameToProperty("property5"); - -// ASSERT_TRUE(edge.GetProperty(property, View::OLD)->IsNull()); -// ASSERT_EQ(edge.Properties(View::OLD)->size(), 0); - -// ASSERT_TRUE(edge.GetProperty(property, View::NEW)->IsNull()); -// ASSERT_EQ(edge.Properties(View::NEW)->size(), 0); - -// auto other_property = acc.NameToProperty("other"); - -// ASSERT_TRUE(edge.GetProperty(other_property, View::OLD)->IsNull()); -// ASSERT_TRUE(edge.GetProperty(other_property, View::NEW)->IsNull()); - -// acc.Abort(); -// } -// } - -// TEST(StorageWithoutProperties, EdgePropertyClear) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = false}}); -// memgraph::storage::Gid gid; -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// gid = vertex.Gid(); -// auto et = acc.NameToEdgeType("et5"); -// auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue(); -// ASSERT_EQ(edge.EdgeType(), et); -// ASSERT_EQ(edge.From(), vertex); -// ASSERT_EQ(edge.To(), vertex); -// acc.Commit(GetNextHlc()); -// } -// { -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.FindVertex(gid, View::OLD); -// ASSERT_TRUE(vertex); -// auto edge = vertex->OutEdges(View::NEW).GetValue()[0]; - -// ASSERT_EQ(edge.ClearProperties().GetError(), memgraph::storage::Error::PROPERTIES_DISABLED); - -// acc.Abort(); -// } -// } - -// TEST(StorageWithProperties, EdgeNonexistentPropertyAPI) { -// memgraph::storage::Storage store({.items = {.properties_on_edges = true}}); - -// auto property = store.NameToProperty("property"); - -// auto acc = store.Access(GetNextHlc()); -// auto vertex = acc.CreateVertex(); -// auto edge = acc.CreateEdge(&vertex, &vertex, acc.NameToEdgeType("edge")); -// ASSERT_TRUE(edge.HasValue()); - -// // Check state before (OLD view). -// ASSERT_EQ(edge->Properties(View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); -// ASSERT_EQ(edge->GetProperty(property, View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); - -// // Check state before (NEW view). -// ASSERT_EQ(edge->Properties(View::NEW)->size(), 0); -// ASSERT_EQ(*edge->GetProperty(property, View::NEW), memgraph::storage::PropertyValue()); - -// // Modify edge. -// ASSERT_TRUE(edge->SetProperty(property, memgraph::storage::PropertyValue("value"))->IsNull()); - -// // Check state after (OLD view). -// ASSERT_EQ(edge->Properties(View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); -// ASSERT_EQ(edge->GetProperty(property, View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); - -// // Check state after (NEW view). -// ASSERT_EQ(edge->Properties(View::NEW)->size(), 1); -// ASSERT_EQ(*edge->GetProperty(property, View::NEW), memgraph::storage::PropertyValue("value")); - -// acc.Commit(GetNextHlc()); -// } } // namespace memgraph::storage::v3::tests From 2ff81ebf047eba12ff4a3d254e1c0e2ddcee7e6b Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Wed, 23 Nov 2022 15:16:14 +0200 Subject: [PATCH 07/26] Address missed GH comments && fix broken merge --- src/functions/awesome_memgraph_functions.hpp | 8 +------- src/storage/v3/edge_accessor.cpp | 2 +- src/storage/v3/vertex_accessor.cpp | 3 --- src/storage/v3/vertex_accessor.hpp | 3 --- tests/unit/query_v2_expression_evaluator.cpp | 2 +- 5 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/functions/awesome_memgraph_functions.hpp b/src/functions/awesome_memgraph_functions.hpp index 33cc954f5..475380217 100644 --- a/src/functions/awesome_memgraph_functions.hpp +++ b/src/functions/awesome_memgraph_functions.hpp @@ -45,19 +45,13 @@ struct FunctionContext { struct StorageEngineTag {}; struct QueryEngineTag {}; -namespace impl { -struct SinkCallable { - void operator()() {} -}; -} // namespace impl - /// Return the function implementation with the given name. /// /// Note, returned function signature uses C-style access to an array to allow /// having an array stored anywhere the caller likes, as long as it is /// contiguous in memory. Since most functions don't take many arguments, it's /// convenient to have them stored in the calling stack frame. -template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv = impl::SinkCallable> +template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv> std::function<TypedValueT(const TypedValueT *arguments, int64_t num_arguments, const FunctionContextT &context)> NameToFunction(const std::string &function_name); diff --git a/src/storage/v3/edge_accessor.cpp b/src/storage/v3/edge_accessor.cpp index d60cdeebc..312a9c2d7 100644 --- a/src/storage/v3/edge_accessor.cpp +++ b/src/storage/v3/edge_accessor.cpp @@ -180,6 +180,6 @@ Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View view) } // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -size_t EdgeAccessor::CypherId() const { return 10; } +size_t EdgeAccessor::CypherId() const { return Gid().AsUint(); } } // namespace memgraph::storage::v3 diff --git a/src/storage/v3/vertex_accessor.cpp b/src/storage/v3/vertex_accessor.cpp index 10c39dba6..543caa88a 100644 --- a/src/storage/v3/vertex_accessor.cpp +++ b/src/storage/v3/vertex_accessor.cpp @@ -733,7 +733,4 @@ Result<size_t> VertexAccessor::OutDegree(View view) const { return degree; } -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) -size_t VertexAccessor::CypherId() const { return 10; } - } // namespace memgraph::storage::v3 diff --git a/src/storage/v3/vertex_accessor.hpp b/src/storage/v3/vertex_accessor.hpp index d708f723e..682a04e39 100644 --- a/src/storage/v3/vertex_accessor.hpp +++ b/src/storage/v3/vertex_accessor.hpp @@ -118,9 +118,6 @@ class VertexAccessor final { } bool operator!=(const VertexAccessor &other) const noexcept { return !(*this == other); } - // Dummy function - size_t CypherId() const; - private: /// Add a label and return `true` if insertion took place. /// `false` is returned if the label already existed. diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp index 1c0130571..396d03eb6 100644 --- a/tests/unit/query_v2_expression_evaluator.cpp +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -32,7 +32,7 @@ #include "query/v2/shard_request_manager.hpp" #include "query_v2_query_common.hpp" #include "storage/v3/property_value.hpp" -#include "storage/v3/storage.hpp" +#include "storage/v3/shard.hpp" #include "utils/exceptions.hpp" #include "utils/string.hpp" From c4327cfb001bfd6674083d38bad07d365a095142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1nos=20Benjamin=20Antal?= <benjamin.antal@memgraph.io> Date: Thu, 24 Nov 2022 11:13:55 +0100 Subject: [PATCH 08/26] Make implicit-fallthrough a compilation error --- CMakeLists.txt | 3 ++- src/communication/bolt/v1/states/executing.hpp | 2 +- src/storage/v2/constraints.cpp | 4 ++-- src/storage/v3/request_helper.cpp | 3 +++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 916389424..36e648e8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -182,7 +182,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # c99-designator is disabled because of required mixture of designated and # non-designated initializers in Python Query Module code (`py_module.cpp`). set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \ - -Werror=switch -Werror=switch-bool -Werror=return-type \ + -Werror=switch -Werror=switch-bool -Werror=implicit-fallthrough \ + -Werror=return-type \ -Werror=return-stack-address \ -Wno-c99-designator \ -DBOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT") diff --git a/src/communication/bolt/v1/states/executing.hpp b/src/communication/bolt/v1/states/executing.hpp index 54504985b..de4b2a00e 100644 --- a/src/communication/bolt/v1/states/executing.hpp +++ b/src/communication/bolt/v1/states/executing.hpp @@ -74,7 +74,7 @@ State RunHandlerV4(Signature signature, TSession &session, State state, Marker m } case Signature::Route: { if constexpr (bolt_minor >= 3) { - if (signature == Signature::Route) return HandleRoute<TSession>(session); + return HandleRoute<TSession>(session); } else { spdlog::trace("Supported only in bolt v4.3"); return State::Close; diff --git a/src/storage/v2/constraints.cpp b/src/storage/v2/constraints.cpp index fab6ee4c4..2a71ee2b0 100644 --- a/src/storage/v2/constraints.cpp +++ b/src/storage/v2/constraints.cpp @@ -97,15 +97,15 @@ bool LastCommittedVersionHasLabelProperty(const Vertex &vertex, LabelId label, c if (delta->label == label) { MG_ASSERT(!has_label, "Invalid database state!"); has_label = true; - break; } + break; } case Delta::Action::REMOVE_LABEL: { if (delta->label == label) { MG_ASSERT(has_label, "Invalid database state!"); has_label = false; - break; } + break; } case Delta::Action::ADD_IN_EDGE: case Delta::Action::ADD_OUT_EDGE: diff --git a/src/storage/v3/request_helper.cpp b/src/storage/v3/request_helper.cpp index 8288a6154..0f6132a1a 100644 --- a/src/storage/v3/request_helper.cpp +++ b/src/storage/v3/request_helper.cpp @@ -471,12 +471,14 @@ std::array<std::vector<EdgeAccessor>, 2> GetEdgesFromVertex(const VertexAccessor if (edges.HasValue()) { in_edges = edges.GetValue(); } + break; } case memgraph::msgs::EdgeDirection::OUT: { auto edges = vertex_accessor.OutEdges(View::OLD); if (edges.HasValue()) { out_edges = edges.GetValue(); } + break; } case memgraph::msgs::EdgeDirection::BOTH: { auto maybe_in_edges = vertex_accessor.InEdges(View::OLD); @@ -488,6 +490,7 @@ std::array<std::vector<EdgeAccessor>, 2> GetEdgesFromVertex(const VertexAccessor if (maybe_out_edges.HasValue()) { out_edges = maybe_out_edges.GetValue(); } + break; } } From 6f4996de0e5b34fcaced77be2fbbdd9235b7ad37 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Fri, 25 Nov 2022 16:20:38 +0200 Subject: [PATCH 09/26] Fix broken merge and address GH comments --- src/functions/awesome_memgraph_functions.hpp | 77 ++++++++++++-------- src/query/v2/accessors.hpp | 5 +- src/query/v2/shard_request_manager.hpp | 4 +- src/storage/v3/bindings/db_accessor.hpp | 2 +- src/storage/v3/request_helper.cpp | 10 +-- tests/unit/query_v2_expression_evaluator.cpp | 2 +- 6 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/functions/awesome_memgraph_functions.hpp b/src/functions/awesome_memgraph_functions.hpp index 475380217..7acfa6943 100644 --- a/src/functions/awesome_memgraph_functions.hpp +++ b/src/functions/awesome_memgraph_functions.hpp @@ -17,6 +17,7 @@ #include <unordered_map> #include "storage/v3/result.hpp" +#include "storage/v3/shard.hpp" #include "storage/v3/view.hpp" #include "utils/algorithm.hpp" #include "utils/cast.hpp" @@ -440,15 +441,22 @@ TypedValueT Properties(const TypedValueT *args, int64_t nargs, const FunctionCon if constexpr (std::is_same_v<Tag, StorageEngineTag>) { auto maybe_props = record_accessor.Properties(ctx.view); if (maybe_props.HasError()) { - switch (maybe_props.GetError()) { - case storage::v3::Error::DELETED_OBJECT: + switch (maybe_props.GetError().code) { + case common::ErrorCode::DELETED_OBJECT: throw functions::FunctionRuntimeException("Trying to get properties from a deleted object."); - case storage::v3::Error::NONEXISTENT_OBJECT: + case common::ErrorCode::NONEXISTENT_OBJECT: throw functions::FunctionRuntimeException("Trying to get properties from an object that doesn't exist."); - case storage::v3::Error::SERIALIZATION_ERROR: - case storage::v3::Error::VERTEX_HAS_EDGES: - case storage::v3::Error::PROPERTIES_DISABLED: - case storage::v3::Error::VERTEX_ALREADY_INSERTED: + case common::ErrorCode::SERIALIZATION_ERROR: + case common::ErrorCode::VERTEX_HAS_EDGES: + case common::ErrorCode::PROPERTIES_DISABLED: + case common::ErrorCode::VERTEX_ALREADY_INSERTED: + case common::ErrorCode::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL: + case common::ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE: + case common::ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY: + case common::ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL: + case common::ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY: + case common::ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED: + case common::ErrorCode::OBJECT_NOT_FOUND: throw functions::FunctionRuntimeException("Unexpected error when getting properties."); } } @@ -506,17 +514,24 @@ TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionCont // This is needed because clang-tidy fails to identify the use of this function in the if-constexpr branch // NOLINTNEXTLINE(clang-diagnostic-unused-function) -inline size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) { +inline size_t UnwrapDegreeResult(storage::v3::ShardResult<size_t> maybe_degree) { if (maybe_degree.HasError()) { - switch (maybe_degree.GetError()) { - case storage::v3::Error::DELETED_OBJECT: + switch (maybe_degree.GetError().code) { + case common::ErrorCode::DELETED_OBJECT: throw functions::FunctionRuntimeException("Trying to get degree of a deleted node."); - case storage::v3::Error::NONEXISTENT_OBJECT: + case common::ErrorCode::NONEXISTENT_OBJECT: throw functions::FunctionRuntimeException("Trying to get degree of a node that doesn't exist."); - case storage::v3::Error::SERIALIZATION_ERROR: - case storage::v3::Error::VERTEX_HAS_EDGES: - case storage::v3::Error::PROPERTIES_DISABLED: - case storage::v3::Error::VERTEX_ALREADY_INSERTED: + case common::ErrorCode::SERIALIZATION_ERROR: + case common::ErrorCode::VERTEX_HAS_EDGES: + case common::ErrorCode::PROPERTIES_DISABLED: + case common::ErrorCode::VERTEX_ALREADY_INSERTED: + case common::ErrorCode::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL: + case common::ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE: + case common::ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY: + case common::ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL: + case common::ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY: + case common::ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED: + case common::ErrorCode::OBJECT_NOT_FOUND: throw functions::FunctionRuntimeException("Unexpected error when getting node degree."); } } @@ -688,15 +703,22 @@ TypedValueT Labels(const TypedValueT *args, int64_t nargs, const FunctionContext if constexpr (std::is_same_v<Tag, StorageEngineTag>) { auto maybe_labels = args[0].ValueVertex().Labels(ctx.view); if (maybe_labels.HasError()) { - switch (maybe_labels.GetError()) { - case storage::v3::Error::DELETED_OBJECT: + switch (maybe_labels.GetError().code) { + case common::ErrorCode::DELETED_OBJECT: throw functions::FunctionRuntimeException("Trying to get labels from a deleted node."); - case storage::v3::Error::NONEXISTENT_OBJECT: + case common::ErrorCode::NONEXISTENT_OBJECT: throw functions::FunctionRuntimeException("Trying to get labels from a node that doesn't exist."); - case storage::v3::Error::SERIALIZATION_ERROR: - case storage::v3::Error::VERTEX_HAS_EDGES: - case storage::v3::Error::PROPERTIES_DISABLED: - case storage::v3::Error::VERTEX_ALREADY_INSERTED: + case common::ErrorCode::SERIALIZATION_ERROR: + case common::ErrorCode::VERTEX_HAS_EDGES: + case common::ErrorCode::PROPERTIES_DISABLED: + case common::ErrorCode::VERTEX_ALREADY_INSERTED: + case common::ErrorCode::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL: + case common::ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE: + case common::ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY: + case common::ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL: + case common::ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY: + case common::ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED: + case common::ErrorCode::OBJECT_NOT_FOUND: throw functions::FunctionRuntimeException("Unexpected error when getting labels."); } } @@ -958,9 +980,9 @@ TypedValueT Counter(const TypedValueT *args, int64_t nargs, const FunctionContex template <typename TypedValueT, typename FunctionContextT> TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { - FType<TypedValueT, Or<Null, Vertex, Edge>>("id", args, nargs); + FType<TypedValueT, Or<Null, Edge>>("id", args, nargs); const auto &arg = args[0]; - if (arg.IsNull() || arg.IsVertex()) { + if (arg.IsNull()) { return TypedValueT(ctx.memory); } return TypedValueT(static_cast<int64_t>(arg.ValueEdge().CypherId()), ctx.memory); @@ -1395,13 +1417,6 @@ NameToFunction(const std::string &function_name) { if (function_name == "LOCALDATETIME") return functions::impl::LocalDateTime<TypedValueT, FunctionContextT>; if (function_name == "DURATION") return functions::impl::Duration<TypedValueT, FunctionContextT>; - // Only on QE - if constexpr (std::is_same_v<Tag, QueryEngineTag>) { - if (function_name == "COUNTER") return functions::impl::Counter<TypedValueT, FunctionContextT>; - if (function_name == "STARTNODE") return functions::impl::StartNode<TypedValueT, FunctionContextT, Conv>; - if (function_name == "ENDNODE") return functions::impl::EndNode<TypedValueT, FunctionContextT>; - } - return nullptr; } diff --git a/src/query/v2/accessors.hpp b/src/query/v2/accessors.hpp index ba3937bb8..bb40fcef8 100644 --- a/src/query/v2/accessors.hpp +++ b/src/query/v2/accessors.hpp @@ -94,11 +94,10 @@ class VertexAccessor final { [[nodiscard]] msgs::Vertex GetVertex() const; // NOLINTNEXTLINE(readability-convert-member-functions-to-static) - [[nodiscard]] size_t InDegree() const { return 0; } + [[nodiscard]] size_t InDegree() const { throw utils::NotYetImplemented("InDegree() not yet implemented"); } // NOLINTNEXTLINE(readability-convert-member-functions-to-static) - [[nodiscard]] size_t OutDegree() const { return 0; } - // + [[nodiscard]] size_t OutDegree() const { throw utils::NotYetImplemented("OutDegree() not yet implemented"); } friend bool operator==(const VertexAccessor &lhs, const VertexAccessor &rhs) { return lhs.vertex == rhs.vertex && lhs.properties == rhs.properties; diff --git a/src/query/v2/shard_request_manager.hpp b/src/query/v2/shard_request_manager.hpp index 9c9c1d89e..dbf3a6bd8 100644 --- a/src/query/v2/shard_request_manager.hpp +++ b/src/query/v2/shard_request_manager.hpp @@ -130,7 +130,7 @@ class ShardRequestManagerInterface { virtual const std::string &LabelToName(memgraph::storage::v3::LabelId label) const = 0; virtual const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId type) const = 0; virtual std::optional<storage::v3::PropertyId> MaybeNameToProperty(const std::string &name) const = 0; - virtual std::optional<storage::v3::EdgeTypeId> MaybeNameToEdge(const std::string &name) const = 0; + virtual std::optional<storage::v3::EdgeTypeId> MaybeNameToEdgeType(const std::string &name) const = 0; virtual std::optional<storage::v3::LabelId> MaybeNameToLabel(const std::string &name) const = 0; virtual bool IsPrimaryLabel(LabelId label) const = 0; virtual bool IsPrimaryKey(LabelId primary_label, PropertyId property) const = 0; @@ -360,7 +360,7 @@ class ShardRequestManager : public ShardRequestManagerInterface { return shards_map_.GetPropertyId(name); } - std::optional<storage::v3::EdgeTypeId> MaybeNameToEdge(const std::string &name) const override { + std::optional<storage::v3::EdgeTypeId> MaybeNameToEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name); } diff --git a/src/storage/v3/bindings/db_accessor.hpp b/src/storage/v3/bindings/db_accessor.hpp index 1a5e846fa..6392ed18f 100644 --- a/src/storage/v3/bindings/db_accessor.hpp +++ b/src/storage/v3/bindings/db_accessor.hpp @@ -88,7 +88,7 @@ class DbAccessor final { } storage::v3::ShardResult<std::optional<EdgeAccessor>> RemoveEdge(EdgeAccessor *edge) { - auto res = accessor_->DeleteEdge(edge->FromVertex(), edge->ToVertex(), edge->Gid()); + auto res = accessor_->DeleteEdge(edge->From(), edge->To(), edge->Gid()); if (res.HasError()) { return res.GetError(); } diff --git a/src/storage/v3/request_helper.cpp b/src/storage/v3/request_helper.cpp index 481741f60..3b0c18326 100644 --- a/src/storage/v3/request_helper.cpp +++ b/src/storage/v3/request_helper.cpp @@ -257,7 +257,7 @@ EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbo case msgs::EdgeDirection::OUT: { is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set, const storage::v3::EdgeAccessor &edge_acc) { - auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.ToVertex()); + auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.To()); return insertion_happened; }; break; @@ -265,7 +265,7 @@ EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbo case msgs::EdgeDirection::IN: { is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set, const storage::v3::EdgeAccessor &edge_acc) { - auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.FromVertex()); + auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.From()); return insertion_happened; }; break; @@ -311,8 +311,8 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) { value_properties.insert(std::make_pair(prop_key, FromPropertyValueToValue(std::move(prop_val)))); } using EdgeWithAllProperties = msgs::ExpandOneResultRow::EdgeWithAllProperties; - EdgeWithAllProperties edges{ToMsgsVertexId(edge.FromVertex()), msgs::EdgeType{edge.EdgeType()}, - edge.Gid().AsUint(), std::move(value_properties)}; + EdgeWithAllProperties edges{ToMsgsVertexId(edge.From()), msgs::EdgeType{edge.EdgeType()}, edge.Gid().AsUint(), + std::move(value_properties)}; if (is_in_edge) { result_row.in_edges_with_all_properties.push_back(std::move(edges)); } else { @@ -336,7 +336,7 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) { value_properties.emplace_back(FromPropertyValueToValue(std::move(property_result.GetValue()))); } using EdgeWithSpecificProperties = msgs::ExpandOneResultRow::EdgeWithSpecificProperties; - EdgeWithSpecificProperties edges{ToMsgsVertexId(edge.FromVertex()), msgs::EdgeType{edge.EdgeType()}, + EdgeWithSpecificProperties edges{ToMsgsVertexId(edge.From()), msgs::EdgeType{edge.EdgeType()}, edge.Gid().AsUint(), std::move(value_properties)}; if (is_in_edge) { result_row.in_edges_with_specific_properties.push_back(std::move(edges)); diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp index 396d03eb6..de324ea2b 100644 --- a/tests/unit/query_v2_expression_evaluator.cpp +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -119,7 +119,7 @@ class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInte return shards_map_.GetPropertyId(name); } - std::optional<storage::v3::EdgeTypeId> MaybeNameToEdge(const std::string &name) const override { + std::optional<storage::v3::EdgeTypeId> MaybeNameToEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name); } From a8dc6fd41e6480e546f0efca30df8bc7926b72f5 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Mon, 28 Nov 2022 09:43:56 +0000 Subject: [PATCH 10/26] Change the namespace of ShardRequestManager to query::v2 instead of msgs --- src/glue/v2/communication.cpp | 10 +- src/glue/v2/communication.hpp | 18 +- src/memgraph.cpp | 5 +- src/query/v2/accessors.cpp | 8 +- src/query/v2/accessors.hpp | 28 +-- src/query/v2/bindings/eval.hpp | 19 +- src/query/v2/context.hpp | 8 +- src/query/v2/conversions.hpp | 2 +- src/query/v2/cypher_query_interpreter.cpp | 4 +- src/query/v2/cypher_query_interpreter.hpp | 4 +- .../interpret/awesome_memgraph_functions.hpp | 8 +- src/query/v2/interpreter.cpp | 24 +-- src/query/v2/interpreter.hpp | 4 +- src/query/v2/plan/operator.cpp | 18 +- src/query/v2/plan/pretty_print.cpp | 18 +- src/query/v2/plan/pretty_print.hpp | 27 ++- src/query/v2/plan/vertex_count_cache.hpp | 2 +- src/query/v2/shard_request_manager.hpp | 192 +++++++++--------- tests/simulation/shard_request_manager.cpp | 10 +- tests/simulation/test_cluster.hpp | 11 +- tests/unit/high_density_shard_create_scan.cpp | 11 +- tests/unit/machine_manager.cpp | 17 +- 22 files changed, 225 insertions(+), 223 deletions(-) diff --git a/src/glue/v2/communication.cpp b/src/glue/v2/communication.cpp index eedf699bb..3406105b0 100644 --- a/src/glue/v2/communication.cpp +++ b/src/glue/v2/communication.cpp @@ -72,7 +72,7 @@ query::v2::TypedValue ToTypedValue(const Value &value) { } communication::bolt::Vertex ToBoltVertex(const query::v2::accessors::VertexAccessor &vertex, - const msgs::ShardRequestManagerInterface *shard_request_manager, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View /*view*/) { auto id = communication::bolt::Id::FromUint(0); @@ -92,7 +92,7 @@ communication::bolt::Vertex ToBoltVertex(const query::v2::accessors::VertexAcces } communication::bolt::Edge ToBoltEdge(const query::v2::accessors::EdgeAccessor &edge, - const msgs::ShardRequestManagerInterface *shard_request_manager, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View /*view*/) { // TODO(jbajic) Fix bolt communication auto id = communication::bolt::Id::FromUint(0); @@ -109,15 +109,15 @@ communication::bolt::Edge ToBoltEdge(const query::v2::accessors::EdgeAccessor &e } communication::bolt::Path ToBoltPath(const query::v2::accessors::Path & /*edge*/, - const msgs::ShardRequestManagerInterface * /*shard_request_manager*/, + const query::v2::ShardRequestManagerInterface * /*shard_request_manager*/, storage::v3::View /*view*/) { // TODO(jbajic) Fix bolt communication MG_ASSERT(false, "Path is unimplemented!"); return {}; } -Value ToBoltValue(const query::v2::TypedValue &value, const msgs::ShardRequestManagerInterface *shard_request_manager, - storage::v3::View view) { +Value ToBoltValue(const query::v2::TypedValue &value, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View view) { switch (value.type()) { case query::v2::TypedValue::Type::Null: return {}; diff --git a/src/glue/v2/communication.hpp b/src/glue/v2/communication.hpp index a20162176..817ff02bd 100644 --- a/src/glue/v2/communication.hpp +++ b/src/glue/v2/communication.hpp @@ -32,39 +32,39 @@ namespace memgraph::glue::v2 { /// @param storage::v3::VertexAccessor for converting to /// communication::bolt::Vertex. -/// @param msgs::ShardRequestManagerInterface *shard_request_manager getting label and property names. +/// @param query::v2::ShardRequestManagerInterface *shard_request_manager getting label and property names. /// @param storage::v3::View for deciding which vertex attributes are visible. /// /// @throw std::bad_alloc communication::bolt::Vertex ToBoltVertex(const storage::v3::VertexAccessor &vertex, - const msgs::ShardRequestManagerInterface *shard_request_manager, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View view); /// @param storage::v3::EdgeAccessor for converting to communication::bolt::Edge. -/// @param msgs::ShardRequestManagerInterface *shard_request_manager getting edge type and property names. +/// @param query::v2::ShardRequestManagerInterface *shard_request_manager getting edge type and property names. /// @param storage::v3::View for deciding which edge attributes are visible. /// /// @throw std::bad_alloc communication::bolt::Edge ToBoltEdge(const storage::v3::EdgeAccessor &edge, - const msgs::ShardRequestManagerInterface *shard_request_manager, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View view); /// @param query::v2::Path for converting to communication::bolt::Path. -/// @param msgs::ShardRequestManagerInterface *shard_request_manager ToBoltVertex and ToBoltEdge. +/// @param query::v2::ShardRequestManagerInterface *shard_request_manager ToBoltVertex and ToBoltEdge. /// @param storage::v3::View for ToBoltVertex and ToBoltEdge. /// /// @throw std::bad_alloc communication::bolt::Path ToBoltPath(const query::v2::accessors::Path &path, - const msgs::ShardRequestManagerInterface *shard_request_manager, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View view); /// @param query::v2::TypedValue for converting to communication::bolt::Value. -/// @param msgs::ShardRequestManagerInterface *shard_request_manager ToBoltVertex and ToBoltEdge. +/// @param query::v2::ShardRequestManagerInterface *shard_request_manager ToBoltVertex and ToBoltEdge. /// @param storage::v3::View for ToBoltVertex and ToBoltEdge. /// /// @throw std::bad_alloc communication::bolt::Value ToBoltValue(const query::v2::TypedValue &value, - const msgs::ShardRequestManagerInterface *shard_request_manager, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View view); query::v2::TypedValue ToTypedValue(const communication::bolt::Value &value); @@ -76,7 +76,7 @@ storage::v3::PropertyValue ToPropertyValue(const communication::bolt::Value &val communication::bolt::Value ToBoltValue(msgs::Value value); communication::bolt::Value ToBoltValue(msgs::Value value, - const msgs::ShardRequestManagerInterface *shard_request_manager, + const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View view); } // namespace memgraph::glue::v2 diff --git a/src/memgraph.cpp b/src/memgraph.cpp index 5903e65ad..565f9940c 100644 --- a/src/memgraph.cpp +++ b/src/memgraph.cpp @@ -497,7 +497,8 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph /// before forwarding the calls to original TEncoder. class TypedValueResultStream { public: - TypedValueResultStream(TEncoder *encoder, const memgraph::msgs::ShardRequestManagerInterface *shard_request_manager) + TypedValueResultStream(TEncoder *encoder, + const memgraph::query::v2::ShardRequestManagerInterface *shard_request_manager) : encoder_(encoder), shard_request_manager_(shard_request_manager) {} void Result(const std::vector<memgraph::query::v2::TypedValue> &values) { @@ -512,7 +513,7 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph private: TEncoder *encoder_; - const memgraph::msgs::ShardRequestManagerInterface *shard_request_manager_{nullptr}; + const memgraph::query::v2::ShardRequestManagerInterface *shard_request_manager_{nullptr}; }; memgraph::query::v2::Interpreter interpreter_; memgraph::communication::v2::ServerEndpoint endpoint_; diff --git a/src/query/v2/accessors.cpp b/src/query/v2/accessors.cpp index cbdce89e0..4f6e0d0d7 100644 --- a/src/query/v2/accessors.cpp +++ b/src/query/v2/accessors.cpp @@ -15,7 +15,7 @@ #include "storage/v3/id_types.hpp" namespace memgraph::query::v2::accessors { -EdgeAccessor::EdgeAccessor(Edge edge, const msgs::ShardRequestManagerInterface *manager) +EdgeAccessor::EdgeAccessor(Edge edge, const ShardRequestManagerInterface *manager) : edge(std::move(edge)), manager_(manager) {} EdgeTypeId EdgeAccessor::EdgeType() const { return edge.type.id; } @@ -44,11 +44,11 @@ VertexAccessor EdgeAccessor::From() const { } VertexAccessor::VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, - const msgs::ShardRequestManagerInterface *manager) + const ShardRequestManagerInterface *manager) : vertex(std::move(v)), properties(std::move(props)), manager_(manager) {} VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, - const msgs::ShardRequestManagerInterface *manager) + const ShardRequestManagerInterface *manager) : vertex(std::move(v)), manager_(manager) { properties.reserve(props.size()); for (auto &[id, value] : props) { @@ -57,7 +57,7 @@ VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, } VertexAccessor::VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, - const msgs::ShardRequestManagerInterface *manager) + const ShardRequestManagerInterface *manager) : vertex(std::move(v)), manager_(manager) { properties.reserve(props.size()); for (const auto &[id, value] : props) { diff --git a/src/query/v2/accessors.hpp b/src/query/v2/accessors.hpp index 8e10c865d..df4180818 100644 --- a/src/query/v2/accessors.hpp +++ b/src/query/v2/accessors.hpp @@ -24,24 +24,24 @@ #include "utils/memory.hpp" #include "utils/memory_tracker.hpp" -namespace memgraph::msgs { +namespace memgraph::query::v2 { class ShardRequestManagerInterface; -} // namespace memgraph::msgs +} namespace memgraph::query::v2::accessors { -using Value = memgraph::msgs::Value; -using Edge = memgraph::msgs::Edge; -using Vertex = memgraph::msgs::Vertex; -using Label = memgraph::msgs::Label; -using PropertyId = memgraph::msgs::PropertyId; -using EdgeTypeId = memgraph::msgs::EdgeTypeId; +using Value = msgs::Value; +using Edge = msgs::Edge; +using Vertex = msgs::Vertex; +using Label = msgs::Label; +using PropertyId = msgs::PropertyId; +using EdgeTypeId = msgs::EdgeTypeId; class VertexAccessor; class EdgeAccessor final { public: - explicit EdgeAccessor(Edge edge, const msgs::ShardRequestManagerInterface *manager); + explicit EdgeAccessor(Edge edge, const ShardRequestManagerInterface *manager); [[nodiscard]] EdgeTypeId EdgeType() const; @@ -69,7 +69,7 @@ class EdgeAccessor final { private: Edge edge; - const msgs::ShardRequestManagerInterface *manager_; + const ShardRequestManagerInterface *manager_; }; class VertexAccessor final { @@ -78,10 +78,10 @@ class VertexAccessor final { using Label = msgs::Label; using VertexId = msgs::VertexId; VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, - const msgs::ShardRequestManagerInterface *manager); + const ShardRequestManagerInterface *manager); - VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const msgs::ShardRequestManagerInterface *manager); - VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, const msgs::ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, const ShardRequestManagerInterface *manager); [[nodiscard]] Label PrimaryLabel() const; @@ -150,7 +150,7 @@ class VertexAccessor final { private: Vertex vertex; std::vector<std::pair<PropertyId, Value>> properties; - const msgs::ShardRequestManagerInterface *manager_; + const ShardRequestManagerInterface *manager_; }; // inline VertexAccessor EdgeAccessor::To() const { return VertexAccessor(impl_.ToVertex()); } diff --git a/src/query/v2/bindings/eval.hpp b/src/query/v2/bindings/eval.hpp index 8f1b19384..584e88922 100644 --- a/src/query/v2/bindings/eval.hpp +++ b/src/query/v2/bindings/eval.hpp @@ -24,27 +24,26 @@ #include "storage/v3/result.hpp" #include "storage/v3/view.hpp" -namespace memgraph::msgs { -class ShardRequestManagerInterface; -} // namespace memgraph::msgs - namespace memgraph::query::v2 { +class ShardRequestManagerInterface; + inline const auto lam = [](const auto &val) { return ValueToTypedValue(val); }; namespace detail { class Callable { public: - auto operator()(const memgraph::storage::v3::PropertyValue &val) const { - return memgraph::storage::v3::PropertyToTypedValue<TypedValue>(val); + auto operator()(const storage::v3::PropertyValue &val) const { + return storage::v3::PropertyToTypedValue<TypedValue>(val); }; - auto operator()(const msgs::Value &val, memgraph::msgs::ShardRequestManagerInterface *manager) const { + auto operator()(const msgs::Value &val, ShardRequestManagerInterface *manager) const { return ValueToTypedValue(val, manager); }; }; } // namespace detail -using ExpressionEvaluator = memgraph::expr::ExpressionEvaluator< - TypedValue, memgraph::query::v2::EvaluationContext, memgraph::msgs::ShardRequestManagerInterface, storage::v3::View, - storage::v3::LabelId, msgs::Value, detail::Callable, common::ErrorCode, memgraph::expr::QueryEngineTag>; +using ExpressionEvaluator = + expr::ExpressionEvaluator<TypedValue, query::v2::EvaluationContext, ShardRequestManagerInterface, storage::v3::View, + storage::v3::LabelId, msgs::Value, detail::Callable, common::ErrorCode, + expr::QueryEngineTag>; } // namespace memgraph::query::v2 diff --git a/src/query/v2/context.hpp b/src/query/v2/context.hpp index 338546f4d..388342349 100644 --- a/src/query/v2/context.hpp +++ b/src/query/v2/context.hpp @@ -60,8 +60,8 @@ struct EvaluationContext { mutable std::unordered_map<std::string, int64_t> counters; }; -inline std::vector<storage::v3::PropertyId> NamesToProperties( - const std::vector<std::string> &property_names, msgs::ShardRequestManagerInterface *shard_request_manager) { +inline std::vector<storage::v3::PropertyId> NamesToProperties(const std::vector<std::string> &property_names, + ShardRequestManagerInterface *shard_request_manager) { std::vector<storage::v3::PropertyId> properties; // TODO Fix by using reference properties.reserve(property_names.size()); @@ -74,7 +74,7 @@ inline std::vector<storage::v3::PropertyId> NamesToProperties( } inline std::vector<storage::v3::LabelId> NamesToLabels(const std::vector<std::string> &label_names, - msgs::ShardRequestManagerInterface *shard_request_manager) { + ShardRequestManagerInterface *shard_request_manager) { std::vector<storage::v3::LabelId> labels; labels.reserve(label_names.size()); // TODO Fix by using reference @@ -97,7 +97,7 @@ struct ExecutionContext { plan::ProfilingStats *stats_root{nullptr}; ExecutionStats execution_stats; utils::AsyncTimer timer; - msgs::ShardRequestManagerInterface *shard_request_manager{nullptr}; + ShardRequestManagerInterface *shard_request_manager{nullptr}; IdAllocator *edge_ids_alloc; }; diff --git a/src/query/v2/conversions.hpp b/src/query/v2/conversions.hpp index 10299c919..c18ba8cc0 100644 --- a/src/query/v2/conversions.hpp +++ b/src/query/v2/conversions.hpp @@ -17,7 +17,7 @@ namespace memgraph::query::v2 { -inline TypedValue ValueToTypedValue(const msgs::Value &value, msgs::ShardRequestManagerInterface *manager) { +inline TypedValue ValueToTypedValue(const msgs::Value &value, ShardRequestManagerInterface *manager) { using Value = msgs::Value; switch (value.type) { case Value::Type::Null: diff --git a/src/query/v2/cypher_query_interpreter.cpp b/src/query/v2/cypher_query_interpreter.cpp index d365a53fb..908ee36cb 100644 --- a/src/query/v2/cypher_query_interpreter.cpp +++ b/src/query/v2/cypher_query_interpreter.cpp @@ -118,7 +118,7 @@ ParsedQuery ParseQuery(const std::string &query_string, const std::map<std::stri } std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers) { auto vertex_counts = plan::MakeVertexCountCache(shard_manager); auto symbol_table = expr::MakeSymbolTable(query, predefined_identifiers); @@ -130,7 +130,7 @@ std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery std::shared_ptr<CachedPlan> CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList<PlanCacheEntry> *plan_cache, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers) { std::optional<utils::SkipList<PlanCacheEntry>::Accessor> plan_cache_access; if (plan_cache) { diff --git a/src/query/v2/cypher_query_interpreter.hpp b/src/query/v2/cypher_query_interpreter.hpp index 74dbe85d5..b7f63ab8f 100644 --- a/src/query/v2/cypher_query_interpreter.hpp +++ b/src/query/v2/cypher_query_interpreter.hpp @@ -132,7 +132,7 @@ class SingleNodeLogicalPlan final : public LogicalPlan { }; std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers); /** @@ -145,7 +145,7 @@ std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery */ std::shared_ptr<CachedPlan> CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList<PlanCacheEntry> *plan_cache, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers = {}); } // namespace memgraph::query::v2 diff --git a/src/query/v2/interpret/awesome_memgraph_functions.hpp b/src/query/v2/interpret/awesome_memgraph_functions.hpp index 134f05d7d..1fd351cd8 100644 --- a/src/query/v2/interpret/awesome_memgraph_functions.hpp +++ b/src/query/v2/interpret/awesome_memgraph_functions.hpp @@ -20,12 +20,10 @@ #include "storage/v3/view.hpp" #include "utils/memory.hpp" -namespace memgraph::msgs { -class ShardRequestManagerInterface; -} // namespace memgraph::msgs - namespace memgraph::query::v2 { +class ShardRequestManagerInterface; + namespace { const char kStartsWith[] = "STARTSWITH"; const char kEndsWith[] = "ENDSWITH"; @@ -36,7 +34,7 @@ const char kId[] = "ID"; struct FunctionContext { // TODO(kostasrim) consider optional here. ShardRequestManager does not exist on the storage. // DbAccessor *db_accessor; - msgs::ShardRequestManagerInterface *manager; + ShardRequestManagerInterface *manager; utils::MemoryResource *memory; int64_t timestamp; std::unordered_map<std::string, int64_t> *counters; diff --git a/src/query/v2/interpreter.cpp b/src/query/v2/interpreter.cpp index 045d94709..f9dc37184 100644 --- a/src/query/v2/interpreter.cpp +++ b/src/query/v2/interpreter.cpp @@ -143,7 +143,7 @@ class ReplQueryHandler final : public query::v2::ReplicationQueryHandler { /// @throw QueryRuntimeException if an error ocurred. Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Parameters ¶meters, - msgs::ShardRequestManagerInterface *manager) { + ShardRequestManagerInterface *manager) { // Empty frame for evaluation of password expression. This is OK since // password should be either null or string literal and it's evaluation // should not depend on frame. @@ -312,7 +312,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa } Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters ¶meters, - InterpreterContext *interpreter_context, msgs::ShardRequestManagerInterface *manager, + InterpreterContext *interpreter_context, ShardRequestManagerInterface *manager, std::vector<Notification> *notifications) { expr::Frame<TypedValue> frame(0); SymbolTable symbol_table; @@ -448,7 +448,7 @@ Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters & } Callback HandleSettingQuery(SettingQuery *setting_query, const Parameters ¶meters, - msgs::ShardRequestManagerInterface *manager) { + ShardRequestManagerInterface *manager) { expr::Frame<TypedValue> frame(0); SymbolTable symbol_table; EvaluationContext evaluation_context; @@ -649,7 +649,7 @@ struct PullPlanVector { struct PullPlan { explicit PullPlan(std::shared_ptr<CachedPlan> plan, const Parameters ¶meters, bool is_profile_query, DbAccessor *dba, InterpreterContext *interpreter_context, utils::MemoryResource *execution_memory, - msgs::ShardRequestManagerInterface *shard_request_manager = nullptr, + ShardRequestManagerInterface *shard_request_manager = nullptr, // TriggerContextCollector *trigger_context_collector = nullptr, std::optional<size_t> memory_limit = {}); std::optional<plan::ProfilingStatsWithTotalTime> Pull(AnyStream *stream, std::optional<int> n, @@ -679,7 +679,7 @@ struct PullPlan { PullPlan::PullPlan(const std::shared_ptr<CachedPlan> plan, const Parameters ¶meters, const bool is_profile_query, DbAccessor *dba, InterpreterContext *interpreter_context, utils::MemoryResource *execution_memory, - msgs::ShardRequestManagerInterface *shard_request_manager, const std::optional<size_t> memory_limit) + ShardRequestManagerInterface *shard_request_manager, const std::optional<size_t> memory_limit) : plan_(plan), cursor_(plan->plan().MakeCursor(execution_memory)), frame_(plan->symbol_table().max_position(), execution_memory), @@ -804,7 +804,7 @@ Interpreter::Interpreter(InterpreterContext *interpreter_context) : interpreter_ auto random_uuid = boost::uuids::uuid{boost::uuids::random_generator()()}; auto query_io = interpreter_context_->io.ForkLocal(random_uuid); - shard_request_manager_ = std::make_unique<msgs::ShardRequestManager<io::local_transport::LocalTransport>>( + shard_request_manager_ = std::make_unique<ShardRequestManager<io::local_transport::LocalTransport>>( coordinator::CoordinatorClient<io::local_transport::LocalTransport>( query_io, interpreter_context_->coordinator_address, std::vector{interpreter_context_->coordinator_address}), std::move(query_io)); @@ -881,7 +881,7 @@ PreparedQuery Interpreter::PrepareTransactionQuery(std::string_view query_upper) PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, std::vector<Notification> *notifications, - msgs::ShardRequestManagerInterface *shard_request_manager) { + ShardRequestManagerInterface *shard_request_manager) { // TriggerContextCollector *trigger_context_collector = nullptr) { auto *cypher_query = utils::Downcast<CypherQuery>(parsed_query.query); @@ -942,7 +942,7 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map<std::string, PreparedQuery PrepareExplainQuery(ParsedQuery parsed_query, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, - msgs::ShardRequestManagerInterface *shard_request_manager, + ShardRequestManagerInterface *shard_request_manager, utils::MemoryResource *execution_memory) { const std::string kExplainQueryStart = "explain "; MG_ASSERT(utils::StartsWith(utils::ToLowerCase(parsed_query.stripped_query.query()), kExplainQueryStart), @@ -991,7 +991,7 @@ PreparedQuery PrepareExplainQuery(ParsedQuery parsed_query, std::map<std::string PreparedQuery PrepareProfileQuery(ParsedQuery parsed_query, bool in_explicit_transaction, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, - msgs::ShardRequestManagerInterface *shard_request_manager = nullptr) { + ShardRequestManagerInterface *shard_request_manager = nullptr) { const std::string kProfileQueryStart = "profile "; MG_ASSERT(utils::StartsWith(utils::ToLowerCase(parsed_query.stripped_query.query()), kProfileQueryStart), @@ -1185,7 +1185,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans PreparedQuery PrepareAuthQuery(ParsedQuery parsed_query, bool in_explicit_transaction, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, - msgs::ShardRequestManagerInterface *manager) { + ShardRequestManagerInterface *manager) { if (in_explicit_transaction) { throw UserModificationInMulticommandTxException(); } @@ -1221,7 +1221,7 @@ PreparedQuery PrepareAuthQuery(ParsedQuery parsed_query, bool in_explicit_transa PreparedQuery PrepareReplicationQuery(ParsedQuery parsed_query, const bool in_explicit_transaction, std::vector<Notification> *notifications, InterpreterContext *interpreter_context, - msgs::ShardRequestManagerInterface *manager) { + ShardRequestManagerInterface *manager) { if (in_explicit_transaction) { throw ReplicationModificationInMulticommandTxException(); } @@ -1317,7 +1317,7 @@ PreparedQuery PrepareCreateSnapshotQuery(ParsedQuery parsed_query, bool in_expli } PreparedQuery PrepareSettingQuery(ParsedQuery parsed_query, const bool in_explicit_transaction, - msgs::ShardRequestManagerInterface *manager) { + ShardRequestManagerInterface *manager) { if (in_explicit_transaction) { throw SettingConfigInMulticommandTxException{}; } diff --git a/src/query/v2/interpreter.hpp b/src/query/v2/interpreter.hpp index dc413ef44..afc298a0c 100644 --- a/src/query/v2/interpreter.hpp +++ b/src/query/v2/interpreter.hpp @@ -296,7 +296,7 @@ class Interpreter final { */ void Abort(); - const msgs::ShardRequestManagerInterface *GetShardRequestManager() const { return shard_request_manager_.get(); } + const ShardRequestManagerInterface *GetShardRequestManager() const { return shard_request_manager_.get(); } private: struct QueryExecution { @@ -342,7 +342,7 @@ class Interpreter final { // move this unique_ptr into a shared_ptr. std::unique_ptr<storage::v3::Shard::Accessor> db_accessor_; std::optional<DbAccessor> execution_db_accessor_; - std::unique_ptr<msgs::ShardRequestManagerInterface> shard_request_manager_; + std::unique_ptr<ShardRequestManagerInterface> shard_request_manager_; bool in_explicit_transaction_{false}; bool expect_rollback_{false}; diff --git a/src/query/v2/plan/operator.cpp b/src/query/v2/plan/operator.cpp index d82d83034..30db1012e 100644 --- a/src/query/v2/plan/operator.cpp +++ b/src/query/v2/plan/operator.cpp @@ -252,7 +252,7 @@ class DistributedCreateNodeCursor : public Cursor { std::vector<const NodeCreationInfo *> nodes_info_; std::vector<std::vector<std::pair<storage::v3::PropertyId, msgs::Value>>> src_vertex_props_; std::vector<msgs::PrimaryKey> primary_keys_; - msgs::ExecutionState<msgs::CreateVerticesRequest> state_; + ExecutionState<msgs::CreateVerticesRequest> state_; }; bool Once::OnceCursor::Pull(Frame &, ExecutionContext &context) { @@ -365,7 +365,7 @@ class ScanAllCursor : public Cursor { std::optional<decltype(vertices_.value().begin())> vertices_it_; const char *op_name_; std::vector<msgs::ScanVerticesResponse> current_batch; - msgs::ExecutionState<msgs::ScanVerticesRequest> request_state; + ExecutionState<msgs::ScanVerticesRequest> request_state; }; class DistributedScanAllAndFilterCursor : public Cursor { @@ -386,7 +386,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { using VertexAccessor = accessors::VertexAccessor; - bool MakeRequest(msgs::ShardRequestManagerInterface &shard_manager, ExecutionContext &context) { + bool MakeRequest(ShardRequestManagerInterface &shard_manager, ExecutionContext &context) { { SCOPED_REQUEST_WAIT_PROFILE; current_batch = shard_manager.Request(request_state_); @@ -403,7 +403,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { if (MustAbort(context)) { throw HintedAbortError(); } - using State = msgs::ExecutionState<msgs::ScanVerticesRequest>; + using State = ExecutionState<msgs::ScanVerticesRequest>; if (request_state_.state == State::INITIALIZING) { if (!input_cursor_->Pull(frame, context)) { @@ -430,7 +430,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { void ResetExecutionState() { current_batch.clear(); current_vertex_it = current_batch.end(); - request_state_ = msgs::ExecutionState<msgs::ScanVerticesRequest>{}; + request_state_ = ExecutionState<msgs::ScanVerticesRequest>{}; } void Reset() override { @@ -444,7 +444,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { const char *op_name_; std::vector<VertexAccessor> current_batch; std::vector<VertexAccessor>::iterator current_vertex_it; - msgs::ExecutionState<msgs::ScanVerticesRequest> request_state_; + ExecutionState<msgs::ScanVerticesRequest> request_state_; std::optional<storage::v3::LabelId> label_; std::optional<std::pair<storage::v3::PropertyId, Expression *>> property_expression_pair_; std::optional<std::vector<Expression *>> filter_expressions_; @@ -2426,7 +2426,7 @@ class DistributedCreateExpandCursor : public Cursor { const UniqueCursorPtr input_cursor_; const CreateExpand &self_; - msgs::ExecutionState<msgs::CreateExpandRequest> state_; + ExecutionState<msgs::CreateExpandRequest> state_; }; class DistributedExpandCursor : public Cursor { @@ -2473,7 +2473,7 @@ class DistributedExpandCursor : public Cursor { request.edge_properties.emplace(); request.src_vertices.push_back(get_dst_vertex(edge, direction)); request.direction = (direction == EdgeAtom::Direction::IN) ? msgs::EdgeDirection::OUT : msgs::EdgeDirection::IN; - msgs::ExecutionState<msgs::ExpandOneRequest> request_state; + ExecutionState<msgs::ExpandOneRequest> request_state; auto result_rows = context.shard_request_manager->Request(request_state, std::move(request)); MG_ASSERT(result_rows.size() == 1); auto &result_row = result_rows.front(); @@ -2499,7 +2499,7 @@ class DistributedExpandCursor : public Cursor { // to not fetch any properties of the edges request.edge_properties.emplace(); request.src_vertices.push_back(vertex.Id()); - msgs::ExecutionState<msgs::ExpandOneRequest> request_state; + ExecutionState<msgs::ExpandOneRequest> request_state; auto result_rows = std::invoke([&context, &request_state, &request]() mutable { SCOPED_REQUEST_WAIT_PROFILE; return context.shard_request_manager->Request(request_state, std::move(request)); diff --git a/src/query/v2/plan/pretty_print.cpp b/src/query/v2/plan/pretty_print.cpp index b756a6299..b7ab6da6e 100644 --- a/src/query/v2/plan/pretty_print.cpp +++ b/src/query/v2/plan/pretty_print.cpp @@ -19,7 +19,7 @@ namespace memgraph::query::v2::plan { -PlanPrinter::PlanPrinter(const msgs::ShardRequestManagerInterface *request_manager, std::ostream *out) +PlanPrinter::PlanPrinter(const ShardRequestManagerInterface *request_manager, std::ostream *out) : request_manager_(request_manager), out_(out) {} #define PRE_VISIT(TOp) \ @@ -263,14 +263,14 @@ void PlanPrinter::Branch(query::v2::plan::LogicalOperator &op, const std::string --depth_; } -void PrettyPrint(const msgs::ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root, +void PrettyPrint(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root, std::ostream *out) { PlanPrinter printer(&request_manager, out); // FIXME(mtomic): We should make visitors that take const arguments. const_cast<LogicalOperator *>(plan_root)->Accept(printer); } -nlohmann::json PlanToJson(const msgs::ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root) { +nlohmann::json PlanToJson(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root) { impl::PlanToJsonVisitor visitor(&request_manager); // FIXME(mtomic): We should make visitors that take const arguments. const_cast<LogicalOperator *>(plan_root)->Accept(visitor); @@ -349,15 +349,15 @@ json ToJson(const utils::Bound<Expression *> &bound) { json ToJson(const Symbol &symbol) { return symbol.name(); } -json ToJson(storage::v3::EdgeTypeId edge_type, const msgs::ShardRequestManagerInterface &request_manager) { +json ToJson(storage::v3::EdgeTypeId edge_type, const ShardRequestManagerInterface &request_manager) { return request_manager.EdgeTypeToName(edge_type); } -json ToJson(storage::v3::LabelId label, const msgs::ShardRequestManagerInterface &request_manager) { +json ToJson(storage::v3::LabelId label, const ShardRequestManagerInterface &request_manager) { return request_manager.LabelToName(label); } -json ToJson(storage::v3::PropertyId property, const msgs::ShardRequestManagerInterface &request_manager) { +json ToJson(storage::v3::PropertyId property, const ShardRequestManagerInterface &request_manager) { return request_manager.PropertyToName(property); } @@ -369,7 +369,7 @@ json ToJson(NamedExpression *nexpr) { } json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> &properties, - const msgs::ShardRequestManagerInterface &request_manager) { + const ShardRequestManagerInterface &request_manager) { json json; for (const auto &prop_pair : properties) { json.emplace(ToJson(prop_pair.first, request_manager), ToJson(prop_pair.second)); @@ -377,7 +377,7 @@ json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> return json; } -json ToJson(const NodeCreationInfo &node_info, const msgs::ShardRequestManagerInterface &request_manager) { +json ToJson(const NodeCreationInfo &node_info, const ShardRequestManagerInterface &request_manager) { json self; self["symbol"] = ToJson(node_info.symbol); self["labels"] = ToJson(node_info.labels, request_manager); @@ -386,7 +386,7 @@ json ToJson(const NodeCreationInfo &node_info, const msgs::ShardRequestManagerIn return self; } -json ToJson(const EdgeCreationInfo &edge_info, const msgs::ShardRequestManagerInterface &request_manager) { +json ToJson(const EdgeCreationInfo &edge_info, const ShardRequestManagerInterface &request_manager) { json self; self["symbol"] = ToJson(edge_info.symbol); const auto *props = std::get_if<PropertiesMapList>(&edge_info.properties); diff --git a/src/query/v2/plan/pretty_print.hpp b/src/query/v2/plan/pretty_print.hpp index c7442b196..8485723a3 100644 --- a/src/query/v2/plan/pretty_print.hpp +++ b/src/query/v2/plan/pretty_print.hpp @@ -30,17 +30,17 @@ class LogicalOperator; /// ShardRequestManager is needed for resolving label and property names. /// Note that `plan_root` isn't modified, but we can't take it as a const /// because we don't have support for visiting a const LogicalOperator. -void PrettyPrint(const msgs::ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root, +void PrettyPrint(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root, std::ostream *out); /// Overload of `PrettyPrint` which defaults the `std::ostream` to `std::cout`. -inline void PrettyPrint(const msgs::ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root) { +inline void PrettyPrint(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root) { PrettyPrint(request_manager, plan_root, &std::cout); } /// Convert a `LogicalOperator` plan to a JSON representation. /// DbAccessor is needed for resolving label and property names. -nlohmann::json PlanToJson(const msgs::ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root); +nlohmann::json PlanToJson(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root); class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { public: @@ -48,7 +48,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { using HierarchicalLogicalOperatorVisitor::PreVisit; using HierarchicalLogicalOperatorVisitor::Visit; - PlanPrinter(const msgs::ShardRequestManagerInterface *request_manager, std::ostream *out); + PlanPrinter(const ShardRequestManagerInterface *request_manager, std::ostream *out); bool DefaultPreVisit() override; @@ -115,7 +115,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { void Branch(LogicalOperator &op, const std::string &branch_name = ""); int64_t depth_{0}; - const msgs::ShardRequestManagerInterface *request_manager_{nullptr}; + const ShardRequestManagerInterface *request_manager_{nullptr}; std::ostream *out_{nullptr}; }; @@ -133,20 +133,20 @@ nlohmann::json ToJson(const utils::Bound<Expression *> &bound); nlohmann::json ToJson(const Symbol &symbol); -nlohmann::json ToJson(storage::v3::EdgeTypeId edge_type, const msgs::ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(storage::v3::EdgeTypeId edge_type, const ShardRequestManagerInterface &request_manager); -nlohmann::json ToJson(storage::v3::LabelId label, const msgs::ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(storage::v3::LabelId label, const ShardRequestManagerInterface &request_manager); -nlohmann::json ToJson(storage::v3::PropertyId property, const msgs::ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(storage::v3::PropertyId property, const ShardRequestManagerInterface &request_manager); nlohmann::json ToJson(NamedExpression *nexpr); nlohmann::json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> &properties, - const msgs::ShardRequestManagerInterface &request_manager); + const ShardRequestManagerInterface &request_manager); -nlohmann::json ToJson(const NodeCreationInfo &node_info, const msgs::ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(const NodeCreationInfo &node_info, const ShardRequestManagerInterface &request_manager); -nlohmann::json ToJson(const EdgeCreationInfo &edge_info, const msgs::ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(const EdgeCreationInfo &edge_info, const ShardRequestManagerInterface &request_manager); nlohmann::json ToJson(const Aggregate::Element &elem); @@ -161,8 +161,7 @@ nlohmann::json ToJson(const std::vector<T> &items, Args &&...args) { class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { public: - explicit PlanToJsonVisitor(const msgs::ShardRequestManagerInterface *request_manager) - : request_manager_(request_manager) {} + explicit PlanToJsonVisitor(const ShardRequestManagerInterface *request_manager) : request_manager_(request_manager) {} using HierarchicalLogicalOperatorVisitor::PostVisit; using HierarchicalLogicalOperatorVisitor::PreVisit; @@ -218,7 +217,7 @@ class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { protected: nlohmann::json output_; - const msgs::ShardRequestManagerInterface *request_manager_; + const ShardRequestManagerInterface *request_manager_; nlohmann::json PopOutput() { nlohmann::json tmp; diff --git a/src/query/v2/plan/vertex_count_cache.hpp b/src/query/v2/plan/vertex_count_cache.hpp index a7bfbdf85..47a10ba3e 100644 --- a/src/query/v2/plan/vertex_count_cache.hpp +++ b/src/query/v2/plan/vertex_count_cache.hpp @@ -57,7 +57,7 @@ class VertexCountCache { bool LabelPropertyIndexExists(storage::v3::LabelId /*label*/, storage::v3::PropertyId /*property*/) { return false; } - msgs::ShardRequestManagerInterface *shard_request_manager_; + ShardRequestManagerInterface *shard_request_manager_; }; template <class TDbAccessor> diff --git a/src/query/v2/shard_request_manager.hpp b/src/query/v2/shard_request_manager.hpp index 20bae7b97..68a10f384 100644 --- a/src/query/v2/shard_request_manager.hpp +++ b/src/query/v2/shard_request_manager.hpp @@ -42,13 +42,12 @@ #include "storage/v3/value_conversions.hpp" #include "utils/result.hpp" -namespace memgraph::msgs { +namespace memgraph::query::v2 { template <typename TStorageClient> class RsmStorageClientManager { public: - using CompoundKey = memgraph::io::rsm::ShardRsmKey; - using Shard = memgraph::coordinator::Shard; - using LabelId = memgraph::storage::v3::LabelId; + using CompoundKey = io::rsm::ShardRsmKey; + using Shard = coordinator::Shard; RsmStorageClientManager() = default; RsmStorageClientManager(const RsmStorageClientManager &) = delete; RsmStorageClientManager(RsmStorageClientManager &&) = delete; @@ -74,8 +73,8 @@ class RsmStorageClientManager { template <typename TRequest> struct ExecutionState { - using CompoundKey = memgraph::io::rsm::ShardRsmKey; - using Shard = memgraph::coordinator::Shard; + using CompoundKey = io::rsm::ShardRsmKey; + using Shard = coordinator::Shard; enum State : int8_t { INITIALIZING, EXECUTING, COMPLETED }; // label is optional because some operators can create/remove etc, vertices. These kind of requests contain the label @@ -85,7 +84,7 @@ struct ExecutionState { // of a shard. One example is ScanAll, where we only require the field label. std::optional<CompoundKey> key; // Transaction id to be filled by the ShardRequestManager implementation - memgraph::coordinator::Hlc transaction_id; + coordinator::Hlc transaction_id; // Initialized by ShardRequestManager implementation. This vector is filled with the shards that // the ShardRequestManager impl will send requests to. When a request to a shard exhausts it, meaning that // it pulled all the requested data from the given Shard, it will be removed from the Vector. When the Vector becomes @@ -104,7 +103,7 @@ struct ExecutionState { class ShardRequestManagerInterface { public: - using VertexAccessor = memgraph::query::v2::accessors::VertexAccessor; + using VertexAccessor = query::v2::accessors::VertexAccessor; ShardRequestManagerInterface() = default; ShardRequestManagerInterface(const ShardRequestManagerInterface &) = delete; ShardRequestManagerInterface(ShardRequestManagerInterface &&) = delete; @@ -115,38 +114,38 @@ class ShardRequestManagerInterface { virtual void StartTransaction() = 0; virtual void Commit() = 0; - virtual std::vector<VertexAccessor> Request(ExecutionState<ScanVerticesRequest> &state) = 0; - virtual std::vector<CreateVerticesResponse> Request(ExecutionState<CreateVerticesRequest> &state, - std::vector<NewVertex> new_vertices) = 0; - virtual std::vector<ExpandOneResultRow> Request(ExecutionState<ExpandOneRequest> &state, - ExpandOneRequest request) = 0; - virtual std::vector<CreateExpandResponse> Request(ExecutionState<CreateExpandRequest> &state, - std::vector<NewExpand> new_edges) = 0; + virtual std::vector<VertexAccessor> Request(ExecutionState<msgs::ScanVerticesRequest> &state) = 0; + virtual std::vector<msgs::CreateVerticesResponse> Request(ExecutionState<msgs::CreateVerticesRequest> &state, + std::vector<msgs::NewVertex> new_vertices) = 0; + virtual std::vector<msgs::ExpandOneResultRow> Request(ExecutionState<msgs::ExpandOneRequest> &state, + msgs::ExpandOneRequest request) = 0; + virtual std::vector<msgs::CreateExpandResponse> Request(ExecutionState<msgs::CreateExpandRequest> &state, + std::vector<msgs::NewExpand> new_edges) = 0; virtual storage::v3::EdgeTypeId NameToEdgeType(const std::string &name) const = 0; virtual storage::v3::PropertyId NameToProperty(const std::string &name) const = 0; virtual storage::v3::LabelId NameToLabel(const std::string &name) const = 0; - virtual const std::string &PropertyToName(memgraph::storage::v3::PropertyId prop) const = 0; - virtual const std::string &LabelToName(memgraph::storage::v3::LabelId label) const = 0; - virtual const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId type) const = 0; - virtual bool IsPrimaryLabel(LabelId label) const = 0; - virtual bool IsPrimaryKey(LabelId primary_label, PropertyId property) const = 0; + virtual const std::string &PropertyToName(storage::v3::PropertyId prop) const = 0; + virtual const std::string &LabelToName(storage::v3::LabelId label) const = 0; + virtual const std::string &EdgeTypeToName(storage::v3::EdgeTypeId type) const = 0; + virtual bool IsPrimaryLabel(storage::v3::LabelId label) const = 0; + virtual bool IsPrimaryKey(storage::v3::LabelId primary_label, storage::v3::PropertyId property) const = 0; }; // TODO(kostasrim)rename this class template template <typename TTransport> class ShardRequestManager : public ShardRequestManagerInterface { public: - using StorageClient = - memgraph::coordinator::RsmClient<TTransport, WriteRequests, WriteResponses, ReadRequests, ReadResponses>; - using CoordinatorWriteRequests = memgraph::coordinator::CoordinatorWriteRequests; - using CoordinatorClient = memgraph::coordinator::CoordinatorClient<TTransport>; - using Address = memgraph::io::Address; - using Shard = memgraph::coordinator::Shard; - using ShardMap = memgraph::coordinator::ShardMap; - using CompoundKey = memgraph::coordinator::PrimaryKey; - using VertexAccessor = memgraph::query::v2::accessors::VertexAccessor; - ShardRequestManager(CoordinatorClient coord, memgraph::io::Io<TTransport> &&io) + using StorageClient = coordinator::RsmClient<TTransport, msgs::WriteRequests, msgs::WriteResponses, + msgs::ReadRequests, msgs::ReadResponses>; + using CoordinatorWriteRequests = coordinator::CoordinatorWriteRequests; + using CoordinatorClient = coordinator::CoordinatorClient<TTransport>; + using Address = io::Address; + using Shard = coordinator::Shard; + using ShardMap = coordinator::ShardMap; + using CompoundKey = coordinator::PrimaryKey; + using VertexAccessor = query::v2::accessors::VertexAccessor; + ShardRequestManager(CoordinatorClient coord, io::Io<TTransport> &&io) : coord_cli_(std::move(coord)), io_(std::move(io)) {} ShardRequestManager(const ShardRequestManager &) = delete; @@ -157,14 +156,14 @@ class ShardRequestManager : public ShardRequestManagerInterface { ~ShardRequestManager() override {} void StartTransaction() override { - memgraph::coordinator::HlcRequest req{.last_shard_map_version = shards_map_.GetHlc()}; + coordinator::HlcRequest req{.last_shard_map_version = shards_map_.GetHlc()}; CoordinatorWriteRequests write_req = req; auto write_res = coord_cli_.SendWriteRequest(write_req); if (write_res.HasError()) { throw std::runtime_error("HLC request failed"); } auto coordinator_write_response = write_res.GetValue(); - auto hlc_response = std::get<memgraph::coordinator::HlcResponse>(coordinator_write_response); + auto hlc_response = std::get<coordinator::HlcResponse>(coordinator_write_response); // Transaction ID to be used later... transaction_id_ = hlc_response.new_hlc; @@ -176,14 +175,14 @@ class ShardRequestManager : public ShardRequestManagerInterface { } void Commit() override { - memgraph::coordinator::HlcRequest req{.last_shard_map_version = shards_map_.GetHlc()}; + coordinator::HlcRequest req{.last_shard_map_version = shards_map_.GetHlc()}; CoordinatorWriteRequests write_req = req; auto write_res = coord_cli_.SendWriteRequest(write_req); if (write_res.HasError()) { throw std::runtime_error("HLC request for commit failed"); } auto coordinator_write_response = write_res.GetValue(); - auto hlc_response = std::get<memgraph::coordinator::HlcResponse>(coordinator_write_response); + auto hlc_response = std::get<coordinator::HlcResponse>(coordinator_write_response); if (hlc_response.fresher_shard_map) { shards_map_ = hlc_response.fresher_shard_map.value(); @@ -204,8 +203,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { if (commit_response.HasError()) { throw std::runtime_error("Commit request timed out"); } - WriteResponses write_response_variant = commit_response.GetValue(); - auto &response = std::get<CommitResponse>(write_response_variant); + msgs::WriteResponses write_response_variant = commit_response.GetValue(); + auto &response = std::get<msgs::CommitResponse>(write_response_variant); if (response.error) { throw std::runtime_error("Commit request did not succeed"); } @@ -225,17 +224,15 @@ class ShardRequestManager : public ShardRequestManagerInterface { return shards_map_.GetLabelId(name).value(); } - const std::string &PropertyToName(memgraph::storage::v3::PropertyId id) const override { + const std::string &PropertyToName(storage::v3::PropertyId id) const override { return properties_.IdToName(id.AsUint()); } - const std::string &LabelToName(memgraph::storage::v3::LabelId id) const override { - return labels_.IdToName(id.AsUint()); - } - const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId id) const override { + const std::string &LabelToName(storage::v3::LabelId id) const override { return labels_.IdToName(id.AsUint()); } + const std::string &EdgeTypeToName(storage::v3::EdgeTypeId id) const override { return edge_types_.IdToName(id.AsUint()); } - bool IsPrimaryKey(LabelId primary_label, PropertyId property) const override { + bool IsPrimaryKey(storage::v3::LabelId primary_label, storage::v3::PropertyId property) const override { const auto schema_it = shards_map_.schemas.find(primary_label); MG_ASSERT(schema_it != shards_map_.schemas.end(), "Invalid primary label id: {}", primary_label.AsUint()); @@ -244,12 +241,12 @@ class ShardRequestManager : public ShardRequestManagerInterface { }) != schema_it->second.end(); } - bool IsPrimaryLabel(LabelId label) const override { return shards_map_.label_spaces.contains(label); } + bool IsPrimaryLabel(storage::v3::LabelId label) const override { return shards_map_.label_spaces.contains(label); } // TODO(kostasrim) Simplify return result - std::vector<VertexAccessor> Request(ExecutionState<ScanVerticesRequest> &state) override { + std::vector<VertexAccessor> Request(ExecutionState<msgs::ScanVerticesRequest> &state) override { MaybeInitializeExecutionState(state); - std::vector<ScanVerticesResponse> responses; + std::vector<msgs::ScanVerticesResponse> responses; SendAllRequests(state); auto all_requests_gathered = [](auto &paginated_rsp_tracker) { @@ -273,11 +270,11 @@ class ShardRequestManager : public ShardRequestManagerInterface { return PostProcess(std::move(responses)); } - std::vector<CreateVerticesResponse> Request(ExecutionState<CreateVerticesRequest> &state, - std::vector<NewVertex> new_vertices) override { + std::vector<msgs::CreateVerticesResponse> Request(ExecutionState<msgs::CreateVerticesRequest> &state, + std::vector<msgs::NewVertex> new_vertices) override { MG_ASSERT(!new_vertices.empty()); MaybeInitializeExecutionState(state, new_vertices); - std::vector<CreateVerticesResponse> responses; + std::vector<msgs::CreateVerticesResponse> responses; auto &shard_cache_ref = state.shard_cache; // 1. Send the requests. @@ -294,22 +291,22 @@ class ShardRequestManager : public ShardRequestManagerInterface { return responses; } - std::vector<CreateExpandResponse> Request(ExecutionState<CreateExpandRequest> &state, - std::vector<NewExpand> new_edges) override { + std::vector<msgs::CreateExpandResponse> Request(ExecutionState<msgs::CreateExpandRequest> &state, + std::vector<msgs::NewExpand> new_edges) override { MG_ASSERT(!new_edges.empty()); MaybeInitializeExecutionState(state, new_edges); - std::vector<CreateExpandResponse> responses; + std::vector<msgs::CreateExpandResponse> responses; auto &shard_cache_ref = state.shard_cache; size_t id{0}; for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end(); ++id) { auto &storage_client = GetStorageClientForShard(*shard_it); - WriteRequests req = state.requests[id]; + msgs::WriteRequests req = state.requests[id]; auto write_response_result = storage_client.SendWriteRequest(std::move(req)); if (write_response_result.HasError()) { throw std::runtime_error("CreateVertices request timedout"); } - WriteResponses response_variant = write_response_result.GetValue(); - CreateExpandResponse mapped_response = std::get<CreateExpandResponse>(response_variant); + msgs::WriteResponses response_variant = write_response_result.GetValue(); + msgs::CreateExpandResponse mapped_response = std::get<msgs::CreateExpandResponse>(response_variant); if (mapped_response.error) { throw std::runtime_error("CreateExpand request did not succeed"); @@ -322,14 +319,15 @@ class ShardRequestManager : public ShardRequestManagerInterface { return responses; } - std::vector<ExpandOneResultRow> Request(ExecutionState<ExpandOneRequest> &state, ExpandOneRequest request) override { + std::vector<msgs::ExpandOneResultRow> Request(ExecutionState<msgs::ExpandOneRequest> &state, + msgs::ExpandOneRequest request) override { // TODO(kostasrim)Update to limit the batch size here // Expansions of the destination must be handled by the caller. For example // match (u:L1 { prop : 1 })-[:Friend]-(v:L1) // For each vertex U, the ExpandOne will result in <U, Edges>. The destination vertex and its properties // must be fetched again with an ExpandOne(Edges.dst) MaybeInitializeExecutionState(state, std::move(request)); - std::vector<ExpandOneResponse> responses; + std::vector<msgs::ExpandOneResponse> responses; auto &shard_cache_ref = state.shard_cache; // 1. Send the requests. @@ -339,10 +337,11 @@ class ShardRequestManager : public ShardRequestManagerInterface { do { AwaitOnResponses(state, responses); } while (!state.shard_cache.empty()); - std::vector<ExpandOneResultRow> result_rows; - const auto total_row_count = std::accumulate( - responses.begin(), responses.end(), 0, - [](const int64_t partial_count, const ExpandOneResponse &resp) { return partial_count + resp.result.size(); }); + std::vector<msgs::ExpandOneResultRow> result_rows; + const auto total_row_count = std::accumulate(responses.begin(), responses.end(), 0, + [](const int64_t partial_count, const msgs::ExpandOneResponse &resp) { + return partial_count + resp.result.size(); + }); result_rows.reserve(total_row_count); for (auto &response : responses) { @@ -356,7 +355,7 @@ class ShardRequestManager : public ShardRequestManagerInterface { private: enum class PaginatedResponseState { Pending, PartiallyFinished }; - std::vector<VertexAccessor> PostProcess(std::vector<ScanVerticesResponse> &&responses) const { + std::vector<VertexAccessor> PostProcess(std::vector<msgs::ScanVerticesResponse> &&responses) const { std::vector<VertexAccessor> accessors; for (auto &response : responses) { for (auto &result_row : response.results) { @@ -385,22 +384,22 @@ class ShardRequestManager : public ShardRequestManagerInterface { return state.state != ExecutionState::INITIALIZING; } - void MaybeInitializeExecutionState(ExecutionState<CreateVerticesRequest> &state, - std::vector<NewVertex> new_vertices) { + void MaybeInitializeExecutionState(ExecutionState<msgs::CreateVerticesRequest> &state, + std::vector<msgs::NewVertex> new_vertices) { ThrowIfStateCompleted(state); if (ShallNotInitializeState(state)) { return; } state.transaction_id = transaction_id_; - std::map<Shard, CreateVerticesRequest> per_shard_request_table; + std::map<Shard, msgs::CreateVerticesRequest> per_shard_request_table; for (auto &new_vertex : new_vertices) { MG_ASSERT(!new_vertex.label_ids.empty(), "This is error!"); auto shard = shards_map_.GetShardForKey(new_vertex.label_ids[0].id, storage::conversions::ConvertPropertyVector(new_vertex.primary_key)); if (!per_shard_request_table.contains(shard)) { - CreateVerticesRequest create_v_rqst{.transaction_id = transaction_id_}; + msgs::CreateVerticesRequest create_v_rqst{.transaction_id = transaction_id_}; per_shard_request_table.insert(std::pair(shard, std::move(create_v_rqst))); state.shard_cache.push_back(shard); } @@ -410,21 +409,22 @@ class ShardRequestManager : public ShardRequestManagerInterface { for (auto &[shard, rqst] : per_shard_request_table) { state.requests.push_back(std::move(rqst)); } - state.state = ExecutionState<CreateVerticesRequest>::EXECUTING; + state.state = ExecutionState<msgs::CreateVerticesRequest>::EXECUTING; } - void MaybeInitializeExecutionState(ExecutionState<CreateExpandRequest> &state, std::vector<NewExpand> new_expands) { + void MaybeInitializeExecutionState(ExecutionState<msgs::CreateExpandRequest> &state, + std::vector<msgs::NewExpand> new_expands) { ThrowIfStateCompleted(state); if (ShallNotInitializeState(state)) { return; } state.transaction_id = transaction_id_; - std::map<Shard, CreateExpandRequest> per_shard_request_table; + std::map<Shard, msgs::CreateExpandRequest> per_shard_request_table; auto ensure_shard_exists_in_table = [&per_shard_request_table, transaction_id = transaction_id_](const Shard &shard) { if (!per_shard_request_table.contains(shard)) { - CreateExpandRequest create_expand_request{.transaction_id = transaction_id}; + msgs::CreateExpandRequest create_expand_request{.transaction_id = transaction_id}; per_shard_request_table.insert({shard, std::move(create_expand_request)}); } }; @@ -448,10 +448,10 @@ class ShardRequestManager : public ShardRequestManagerInterface { state.shard_cache.push_back(shard); state.requests.push_back(std::move(request)); } - state.state = ExecutionState<CreateExpandRequest>::EXECUTING; + state.state = ExecutionState<msgs::CreateExpandRequest>::EXECUTING; } - void MaybeInitializeExecutionState(ExecutionState<ScanVerticesRequest> &state) { + void MaybeInitializeExecutionState(ExecutionState<msgs::ScanVerticesRequest> &state) { ThrowIfStateCompleted(state); if (ShallNotInitializeState(state)) { return; @@ -471,23 +471,23 @@ class ShardRequestManager : public ShardRequestManagerInterface { for (auto &[key, shard] : shards) { MG_ASSERT(!shard.empty()); state.shard_cache.push_back(std::move(shard)); - ScanVerticesRequest rqst; + msgs::ScanVerticesRequest rqst; rqst.transaction_id = transaction_id_; rqst.start_id.second = storage::conversions::ConvertValueVector(key); state.requests.push_back(std::move(rqst)); } } - state.state = ExecutionState<ScanVerticesRequest>::EXECUTING; + state.state = ExecutionState<msgs::ScanVerticesRequest>::EXECUTING; } - void MaybeInitializeExecutionState(ExecutionState<ExpandOneRequest> &state, ExpandOneRequest request) { + void MaybeInitializeExecutionState(ExecutionState<msgs::ExpandOneRequest> &state, msgs::ExpandOneRequest request) { ThrowIfStateCompleted(state); if (ShallNotInitializeState(state)) { return; } state.transaction_id = transaction_id_; - std::map<Shard, ExpandOneRequest> per_shard_request_table; + std::map<Shard, msgs::ExpandOneRequest> per_shard_request_table; auto top_level_rqst_template = request; top_level_rqst_template.transaction_id = transaction_id_; top_level_rqst_template.src_vertices.clear(); @@ -505,7 +505,7 @@ class ShardRequestManager : public ShardRequestManagerInterface { for (auto &[shard, rqst] : per_shard_request_table) { state.requests.push_back(std::move(rqst)); } - state.state = ExecutionState<ExpandOneRequest>::EXECUTING; + state.state = ExecutionState<msgs::ExpandOneRequest>::EXECUTING; } StorageClient &GetStorageClientForShard(Shard shard) { @@ -532,20 +532,20 @@ class ShardRequestManager : public ShardRequestManagerInterface { storage_cli_manager_.AddClient(target_shard, std::move(cli)); } - void SendAllRequests(ExecutionState<ScanVerticesRequest> &state) { + void SendAllRequests(ExecutionState<msgs::ScanVerticesRequest> &state) { int64_t shard_idx = 0; for (const auto &request : state.requests) { const auto ¤t_shard = state.shard_cache[shard_idx]; auto &storage_client = GetStorageClientForShard(current_shard); - ReadRequests req = request; + msgs::ReadRequests req = request; storage_client.SendAsyncReadRequest(request); ++shard_idx; } } - void SendAllRequests(ExecutionState<CreateVerticesRequest> &state, + void SendAllRequests(ExecutionState<msgs::CreateVerticesRequest> &state, std::vector<memgraph::coordinator::Shard> &shard_cache_ref) { size_t id = 0; for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end(); ++shard_it) { @@ -559,24 +559,25 @@ class ShardRequestManager : public ShardRequestManagerInterface { auto &storage_client = GetStorageClientForShard(*shard_it); - WriteRequests req = req_deep_copy; + msgs::WriteRequests req = req_deep_copy; storage_client.SendAsyncWriteRequest(req); ++id; } } - void SendAllRequests(ExecutionState<ExpandOneRequest> &state, + void SendAllRequests(ExecutionState<msgs::ExpandOneRequest> &state, std::vector<memgraph::coordinator::Shard> &shard_cache_ref) { size_t id = 0; for (auto shard_it = shard_cache_ref.begin(); shard_it != shard_cache_ref.end(); ++shard_it) { auto &storage_client = GetStorageClientForShard(*shard_it); - ReadRequests req = state.requests[id]; + msgs::ReadRequests req = state.requests[id]; storage_client.SendAsyncReadRequest(req); ++id; } } - void AwaitOnResponses(ExecutionState<CreateVerticesRequest> &state, std::vector<CreateVerticesResponse> &responses) { + void AwaitOnResponses(ExecutionState<msgs::CreateVerticesRequest> &state, + std::vector<msgs::CreateVerticesResponse> &responses) { auto &shard_cache_ref = state.shard_cache; int64_t request_idx = 0; @@ -598,8 +599,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { throw std::runtime_error("CreateVertices request timed out"); } - WriteResponses response_variant = poll_result->GetValue(); - auto response = std::get<CreateVerticesResponse>(response_variant); + msgs::WriteResponses response_variant = poll_result->GetValue(); + auto response = std::get<msgs::CreateVerticesResponse>(response_variant); if (response.error) { throw std::runtime_error("CreateVertices request did not succeed"); @@ -613,7 +614,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { } } - void AwaitOnResponses(ExecutionState<ExpandOneRequest> &state, std::vector<ExpandOneResponse> &responses) { + void AwaitOnResponses(ExecutionState<msgs::ExpandOneRequest> &state, + std::vector<msgs::ExpandOneResponse> &responses) { auto &shard_cache_ref = state.shard_cache; int64_t request_idx = 0; @@ -631,8 +633,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { throw std::runtime_error("ExpandOne request timed out"); } - ReadResponses response_variant = poll_result->GetValue(); - auto response = std::get<ExpandOneResponse>(response_variant); + msgs::ReadResponses response_variant = poll_result->GetValue(); + auto response = std::get<msgs::ExpandOneResponse>(response_variant); // -NOTE- // Currently a boolean flag for signaling the overall success of the // ExpandOne request does not exist. But it should, so here we assume @@ -649,8 +651,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { } } - void AwaitOnPaginatedRequests(ExecutionState<ScanVerticesRequest> &state, - std::vector<ScanVerticesResponse> &responses, + void AwaitOnPaginatedRequests(ExecutionState<msgs::ScanVerticesRequest> &state, + std::vector<msgs::ScanVerticesResponse> &responses, std::map<Shard, PaginatedResponseState> &paginated_response_tracker) { auto &shard_cache_ref = state.shard_cache; @@ -678,8 +680,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { throw std::runtime_error("ScanAll request timed out"); } - ReadResponses read_response_variant = await_result->GetValue(); - auto response = std::get<ScanVerticesResponse>(read_response_variant); + msgs::ReadResponses read_response_variant = await_result->GetValue(); + auto response = std::get<msgs::ScanVerticesResponse>(read_response_variant); if (response.error) { throw std::runtime_error("ScanAll request did not succeed"); } @@ -723,8 +725,8 @@ class ShardRequestManager : public ShardRequestManagerInterface { storage::v3::NameIdMapper labels_; CoordinatorClient coord_cli_; RsmStorageClientManager<StorageClient> storage_cli_manager_; - memgraph::io::Io<TTransport> io_; - memgraph::coordinator::Hlc transaction_id_; + io::Io<TTransport> io_; + coordinator::Hlc transaction_id_; // TODO(kostasrim) Add batch prefetching }; -} // namespace memgraph::msgs +} // namespace memgraph::query::v2 diff --git a/tests/simulation/shard_request_manager.cpp b/tests/simulation/shard_request_manager.cpp index 746ab385f..9db18659e 100644 --- a/tests/simulation/shard_request_manager.cpp +++ b/tests/simulation/shard_request_manager.cpp @@ -151,7 +151,7 @@ void RunStorageRaft(Raft<IoImpl, MockedShardRsm, WriteRequests, WriteResponses, server.Run(); } -void TestScanVertices(msgs::ShardRequestManagerInterface &io) { +void TestScanVertices(query::v2::ShardRequestManagerInterface &io) { msgs::ExecutionState<ScanVerticesRequest> state{.label = "test_label"}; auto result = io.Request(state); @@ -171,7 +171,7 @@ void TestScanVertices(msgs::ShardRequestManagerInterface &io) { } } -void TestCreateVertices(msgs::ShardRequestManagerInterface &io) { +void TestCreateVertices(query::v2::ShardRequestManagerInterface &io) { using PropVal = msgs::Value; msgs::ExecutionState<CreateVerticesRequest> state; std::vector<msgs::NewVertex> new_vertices; @@ -187,7 +187,7 @@ void TestCreateVertices(msgs::ShardRequestManagerInterface &io) { MG_ASSERT(result.size() == 2); } -void TestCreateExpand(msgs::ShardRequestManagerInterface &io) { +void TestCreateExpand(query::v2::ShardRequestManagerInterface &io) { using PropVal = msgs::Value; msgs::ExecutionState<msgs::CreateExpandRequest> state; std::vector<msgs::NewExpand> new_expands; @@ -209,7 +209,7 @@ void TestCreateExpand(msgs::ShardRequestManagerInterface &io) { MG_ASSERT(responses[1].success); } -void TestExpandOne(msgs::ShardRequestManagerInterface &shard_request_manager) { +void TestExpandOne(query::v2::ShardRequestManagerInterface &shard_request_manager) { msgs::ExecutionState<msgs::ExpandOneRequest> state{}; msgs::ExpandOneRequest request; const auto edge_type_id = shard_request_manager.NameToEdgeType("edge_type"); @@ -337,7 +337,7 @@ void DoTest() { // also get the current shard map CoordinatorClient<SimulatorTransport> coordinator_client(cli_io, c_addrs[0], c_addrs); - msgs::ShardRequestManager<SimulatorTransport> io(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager<SimulatorTransport> io(std::move(coordinator_client), std::move(cli_io)); io.StartTransaction(); TestScanVertices(io); diff --git a/tests/simulation/test_cluster.hpp b/tests/simulation/test_cluster.hpp index 096009b7a..fd62b99f9 100644 --- a/tests/simulation/test_cluster.hpp +++ b/tests/simulation/test_cluster.hpp @@ -151,7 +151,7 @@ ShardMap TestShardMap(int n_splits, int replication_factor) { return sm; } -void ExecuteOp(msgs::ShardRequestManager<SimulatorTransport> &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager<SimulatorTransport> &shard_request_manager, std::set<CompoundKey> &correctness_model, CreateVertex create_vertex) { const auto key1 = memgraph::storage::v3::PropertyValue(create_vertex.first); const auto key2 = memgraph::storage::v3::PropertyValue(create_vertex.second); @@ -164,7 +164,7 @@ void ExecuteOp(msgs::ShardRequestManager<SimulatorTransport> &shard_request_mana return; } - msgs::ExecutionState<msgs::CreateVerticesRequest> state; + query::v2::ExecutionState<msgs::CreateVerticesRequest> state; auto label_id = shard_request_manager.NameToLabel("test_label"); @@ -182,9 +182,9 @@ void ExecuteOp(msgs::ShardRequestManager<SimulatorTransport> &shard_request_mana correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(msgs::ShardRequestManager<SimulatorTransport> &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager<SimulatorTransport> &shard_request_manager, std::set<CompoundKey> &correctness_model, ScanAll scan_all) { - msgs::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; + query::v2::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; auto results = shard_request_manager.Request(request); @@ -247,7 +247,8 @@ std::pair<SimulatorStats, LatencyHistogramSummaries> RunClusterSimulation(const CoordinatorClient<SimulatorTransport> coordinator_client(cli_io, coordinator_address, {coordinator_address}); WaitForShardsToInitialize(coordinator_client); - msgs::ShardRequestManager<SimulatorTransport> shard_request_manager(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager<SimulatorTransport> shard_request_manager(std::move(coordinator_client), + std::move(cli_io)); shard_request_manager.StartTransaction(); diff --git a/tests/unit/high_density_shard_create_scan.cpp b/tests/unit/high_density_shard_create_scan.cpp index a0c0a0c28..e586a3556 100644 --- a/tests/unit/high_density_shard_create_scan.cpp +++ b/tests/unit/high_density_shard_create_scan.cpp @@ -161,7 +161,7 @@ ShardMap TestShardMap(int shards, int replication_factor, int gap_between_shards return sm; } -void ExecuteOp(msgs::ShardRequestManager<LocalTransport> &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager<LocalTransport> &shard_request_manager, std::set<CompoundKey> &correctness_model, CreateVertex create_vertex) { const auto key1 = memgraph::storage::v3::PropertyValue(create_vertex.first); const auto key2 = memgraph::storage::v3::PropertyValue(create_vertex.second); @@ -174,7 +174,7 @@ void ExecuteOp(msgs::ShardRequestManager<LocalTransport> &shard_request_manager, return; } - msgs::ExecutionState<msgs::CreateVerticesRequest> state; + query::v2::ExecutionState<msgs::CreateVerticesRequest> state; auto label_id = shard_request_manager.NameToLabel("test_label"); @@ -192,9 +192,9 @@ void ExecuteOp(msgs::ShardRequestManager<LocalTransport> &shard_request_manager, correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(msgs::ShardRequestManager<LocalTransport> &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager<LocalTransport> &shard_request_manager, std::set<CompoundKey> &correctness_model, ScanAll scan_all) { - msgs::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; + query::v2::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; auto results = shard_request_manager.Request(request); @@ -245,7 +245,8 @@ void RunWorkload(int shards, int replication_factor, int create_ops, int scan_op WaitForShardsToInitialize(coordinator_client); auto time_after_shard_stabilization = cli_io_2.Now(); - msgs::ShardRequestManager<LocalTransport> shard_request_manager(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager<LocalTransport> shard_request_manager(std::move(coordinator_client), + std::move(cli_io)); shard_request_manager.StartTransaction(); diff --git a/tests/unit/machine_manager.cpp b/tests/unit/machine_manager.cpp index 110220eda..834523fee 100644 --- a/tests/unit/machine_manager.cpp +++ b/tests/unit/machine_manager.cpp @@ -111,15 +111,15 @@ ShardMap TestShardMap() { template <typename ShardRequestManager> void TestScanAll(ShardRequestManager &shard_request_manager) { - msgs::ExecutionState<msgs::ScanVerticesRequest> state{.label = kLabelName}; + query::v2::ExecutionState<msgs::ScanVerticesRequest> state{.label = kLabelName}; auto result = shard_request_manager.Request(state); EXPECT_EQ(result.size(), 2); } -void TestCreateVertices(msgs::ShardRequestManagerInterface &shard_request_manager) { +void TestCreateVertices(query::v2::ShardRequestManagerInterface &shard_request_manager) { using PropVal = msgs::Value; - msgs::ExecutionState<msgs::CreateVerticesRequest> state; + query::v2::ExecutionState<msgs::CreateVerticesRequest> state; std::vector<msgs::NewVertex> new_vertices; auto label_id = shard_request_manager.NameToLabel(kLabelName); msgs::NewVertex a1{.primary_key = {PropVal(int64_t(0)), PropVal(int64_t(0))}}; @@ -134,9 +134,9 @@ void TestCreateVertices(msgs::ShardRequestManagerInterface &shard_request_manage EXPECT_FALSE(result[0].error.has_value()) << result[0].error->message; } -void TestCreateExpand(msgs::ShardRequestManagerInterface &shard_request_manager) { +void TestCreateExpand(query::v2::ShardRequestManagerInterface &shard_request_manager) { using PropVal = msgs::Value; - msgs::ExecutionState<msgs::CreateExpandRequest> state; + query::v2::ExecutionState<msgs::CreateExpandRequest> state; std::vector<msgs::NewExpand> new_expands; const auto edge_type_id = shard_request_manager.NameToEdgeType("edge_type"); @@ -155,8 +155,8 @@ void TestCreateExpand(msgs::ShardRequestManagerInterface &shard_request_manager) MG_ASSERT(!responses[0].error.has_value()); } -void TestExpandOne(msgs::ShardRequestManagerInterface &shard_request_manager) { - msgs::ExecutionState<msgs::ExpandOneRequest> state{}; +void TestExpandOne(query::v2::ShardRequestManagerInterface &shard_request_manager) { + query::v2::ExecutionState<msgs::ExpandOneRequest> state{}; msgs::ExpandOneRequest request; const auto edge_type_id = shard_request_manager.NameToEdgeType("edge_type"); const auto label = msgs::Label{shard_request_manager.NameToLabel("test_label")}; @@ -226,7 +226,8 @@ TEST(MachineManager, BasicFunctionality) { CoordinatorClient<LocalTransport> coordinator_client(cli_io, coordinator_address, {coordinator_address}); - msgs::ShardRequestManager<LocalTransport> shard_request_manager(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager<LocalTransport> shard_request_manager(std::move(coordinator_client), + std::move(cli_io)); shard_request_manager.StartTransaction(); TestCreateVertices(shard_request_manager); From 6d3c04bd61400e6765d1fb948744b150e9fa2efa Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Mon, 28 Nov 2022 10:09:59 +0000 Subject: [PATCH 11/26] Address clang-tidy feedback --- src/query/v2/accessors.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/v2/accessors.hpp b/src/query/v2/accessors.hpp index df4180818..ca7ec999d 100644 --- a/src/query/v2/accessors.hpp +++ b/src/query/v2/accessors.hpp @@ -26,7 +26,7 @@ namespace memgraph::query::v2 { class ShardRequestManagerInterface; -} +} // namespace memgraph::query::v2 namespace memgraph::query::v2::accessors { From ed0b67dfdb6d0a6449f48089042b5c0fb565af3d Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Mon, 28 Nov 2022 13:38:12 +0200 Subject: [PATCH 12/26] Fix compilation issues of the merge --- src/query/v2/conversions.hpp | 2 +- src/query/v2/frontend/ast/ast.lcp | 6 +++--- src/query/v2/shard_request_manager.hpp | 4 ++-- tests/unit/query_v2_expression_evaluator.cpp | 18 ++++++++---------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/query/v2/conversions.hpp b/src/query/v2/conversions.hpp index baeaf90d5..a1db5ed17 100644 --- a/src/query/v2/conversions.hpp +++ b/src/query/v2/conversions.hpp @@ -56,7 +56,7 @@ inline TypedValue ValueToTypedValue(const msgs::Value &value, ShardRequestManage throw std::runtime_error("Incorrect type in conversion"); } -inline const auto ValueToTypedValueFunctor = [](const msgs::Value &value, msgs::ShardRequestManagerInterface *manager) { +inline const auto ValueToTypedValueFunctor = [](const msgs::Value &value, ShardRequestManagerInterface *manager) { return ValueToTypedValue(value, manager); }; diff --git a/src/query/v2/frontend/ast/ast.lcp b/src/query/v2/frontend/ast/ast.lcp index 209bdfd50..dadcc9fa7 100644 --- a/src/query/v2/frontend/ast/ast.lcp +++ b/src/query/v2/frontend/ast/ast.lcp @@ -838,14 +838,14 @@ cpp<# :slk-load (slk-load-ast-vector "Expression")) (function-name "std::string" :scope :public) (function "std::function<TypedValue(const TypedValue *, int64_t, - const functions::FunctionContext<msgs::ShardRequestManagerInterface> &)>" + const functions::FunctionContext<ShardRequestManagerInterface> &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp self->${member} = functions::NameToFunction<TypedValue, - functions::FunctionContext<msgs::ShardRequestManagerInterface>, + functions::FunctionContext<ShardRequestManagerInterface>, functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(self->function_name_); cpp<#))) (:public @@ -869,7 +869,7 @@ cpp<# const std::vector<Expression *> &arguments) : arguments_(arguments), function_name_(function_name), - function_(functions::NameToFunction<TypedValue, functions::FunctionContext<msgs::ShardRequestManagerInterface>, + function_(functions::NameToFunction<TypedValue, functions::FunctionContext<ShardRequestManagerInterface>, functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(function_name_)) { if (!function_) { throw SemanticException("Function '{}' doesn't exist.", function_name); diff --git a/src/query/v2/shard_request_manager.hpp b/src/query/v2/shard_request_manager.hpp index 19fb81a08..581dfbcab 100644 --- a/src/query/v2/shard_request_manager.hpp +++ b/src/query/v2/shard_request_manager.hpp @@ -131,8 +131,8 @@ class ShardRequestManagerInterface { virtual std::optional<storage::v3::PropertyId> MaybeNameToProperty(const std::string &name) const = 0; virtual std::optional<storage::v3::EdgeTypeId> MaybeNameToEdgeType(const std::string &name) const = 0; virtual std::optional<storage::v3::LabelId> MaybeNameToLabel(const std::string &name) const = 0; - virtual bool IsPrimaryLabel(LabelId label) const = 0; - virtual bool IsPrimaryKey(LabelId primary_label, PropertyId property) const = 0; + virtual bool IsPrimaryLabel(storage::v3::LabelId label) const = 0; + virtual bool IsPrimaryKey(storage::v3::LabelId primary_label, storage::v3::PropertyId property) const = 0; }; // TODO(kostasrim)rename this class template diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp index de324ea2b..c2e0beee7 100644 --- a/tests/unit/query_v2_expression_evaluator.cpp +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -66,7 +66,7 @@ using memgraph::functions::FunctionRuntimeException; namespace memgraph::query::v2::tests { -class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInterface { +class MockedShardRequestManager : public ShardRequestManagerInterface { public: using VertexAccessor = accessors::VertexAccessor; explicit MockedShardRequestManager(ShardMap shard_map) : shards_map_(std::move(shard_map)) { SetUpNameIdMappers(); } @@ -83,22 +83,20 @@ class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInte } void StartTransaction() override {} void Commit() override {} - std::vector<VertexAccessor> Request( - memgraph::msgs::ExecutionState<memgraph::msgs::ScanVerticesRequest> &state) override { + std::vector<VertexAccessor> Request(ExecutionState<memgraph::msgs::ScanVerticesRequest> &state) override { return {}; } - std::vector<CreateVerticesResponse> Request(memgraph::msgs::ExecutionState<CreateVerticesRequest> &state, + std::vector<CreateVerticesResponse> Request(ExecutionState<CreateVerticesRequest> &state, std::vector<memgraph::msgs::NewVertex> new_vertices) override { return {}; } - std::vector<ExpandOneResultRow> Request(memgraph::msgs::ExecutionState<ExpandOneRequest> &state, - ExpandOneRequest request) override { + std::vector<ExpandOneResultRow> Request(ExecutionState<ExpandOneRequest> &state, ExpandOneRequest request) override { return {}; } - std::vector<CreateExpandResponse> Request(memgraph::msgs::ExecutionState<CreateExpandRequest> &state, + std::vector<CreateExpandResponse> Request(ExecutionState<CreateExpandRequest> &state, std::vector<NewExpand> new_edges) override { return {}; } @@ -218,7 +216,7 @@ class ExpressionEvaluatorTest : public ::testing::Test { SymbolTable symbol_table; Frame frame{128}; - std::unique_ptr<memgraph::msgs::ShardRequestManagerInterface> shard_manager = + std::unique_ptr<ShardRequestManagerInterface> shard_manager = std::make_unique<MockedShardRequestManager>(CreateDummyShardmap()); ExpressionEvaluator eval{&frame, symbol_table, ctx, shard_manager.get(), memgraph::storage::v3::View::OLD}; @@ -546,13 +544,13 @@ using VertexId = memgraph::msgs::VertexId; using Label = memgraph::msgs::Label; accessors::VertexAccessor CreateVertex(std::vector<std::pair<PropertyId, Value>> props, - const memgraph::msgs::ShardRequestManagerInterface *manager, Label label = {}) { + const ShardRequestManagerInterface *manager, Label label = {}) { static int64_t id = 0; return {Vertex{VertexId{label, {memgraph::msgs::Value(id++)}}, {label}}, std::move(props), manager}; } accessors::EdgeAccessor CreateEdge(std::vector<std::pair<PropertyId, Value>> props, - const memgraph::msgs::ShardRequestManagerInterface *manager) { + const ShardRequestManagerInterface *manager) { auto edge = Edge{.src = VertexId{{}, {}}, .dst = VertexId{{}, {}}, .properties = std::move(props), From 82db1d4ad8ddfa2765ebaa021ae4f7e0253a9b61 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Mon, 28 Nov 2022 12:38:38 +0000 Subject: [PATCH 13/26] Rename ShardRequestManager to RequestRouter --- src/glue/v2/communication.cpp | 30 +++--- src/glue/v2/communication.hpp | 24 ++--- src/memgraph.cpp | 13 ++- src/query/v2/accessors.cpp | 11 +-- src/query/v2/accessors.hpp | 15 ++- src/query/v2/bindings/eval.hpp | 11 +-- src/query/v2/context.hpp | 16 ++-- src/query/v2/conversions.hpp | 4 +- src/query/v2/cypher_query_interpreter.cpp | 6 +- src/query/v2/cypher_query_interpreter.hpp | 4 +- .../interpret/awesome_memgraph_functions.cpp | 2 +- .../interpret/awesome_memgraph_functions.hpp | 6 +- src/query/v2/interpreter.cpp | 96 +++++++++---------- src/query/v2/interpreter.hpp | 4 +- src/query/v2/plan/operator.cpp | 66 ++++++------- src/query/v2/plan/pretty_print.cpp | 21 ++-- src/query/v2/plan/pretty_print.hpp | 31 +++--- src/query/v2/plan/rule_based_planner.hpp | 2 +- src/query/v2/plan/vertex_count_cache.hpp | 14 +-- ...request_manager.hpp => request_router.hpp} | 35 ++++--- ...request_manager.cpp => request_router.cpp} | 22 ++--- tests/simulation/test_cluster.hpp | 23 +++-- tests/unit/high_density_shard_create_scan.cpp | 25 +++-- tests/unit/machine_manager.cpp | 47 +++++---- 24 files changed, 255 insertions(+), 273 deletions(-) rename src/query/v2/{shard_request_manager.hpp => request_router.hpp} (96%) rename tests/simulation/{shard_request_manager.cpp => request_router.cpp} (94%) diff --git a/src/glue/v2/communication.cpp b/src/glue/v2/communication.cpp index 3406105b0..42228652f 100644 --- a/src/glue/v2/communication.cpp +++ b/src/glue/v2/communication.cpp @@ -18,8 +18,8 @@ #include "common/errors.hpp" #include "coordinator/shard_map.hpp" #include "query/v2/accessors.hpp" +#include "query/v2/request_router.hpp" #include "query/v2/requests.hpp" -#include "query/v2/shard_request_manager.hpp" #include "storage/v3/edge_accessor.hpp" #include "storage/v3/id_types.hpp" #include "storage/v3/shard.hpp" @@ -72,7 +72,7 @@ query::v2::TypedValue ToTypedValue(const Value &value) { } communication::bolt::Vertex ToBoltVertex(const query::v2::accessors::VertexAccessor &vertex, - const query::v2::ShardRequestManagerInterface *shard_request_manager, + const query::v2::RequestRouterInterface *request_router, storage::v3::View /*view*/) { auto id = communication::bolt::Id::FromUint(0); @@ -80,44 +80,44 @@ communication::bolt::Vertex ToBoltVertex(const query::v2::accessors::VertexAcces std::vector<std::string> new_labels; new_labels.reserve(labels.size()); for (const auto &label : labels) { - new_labels.push_back(shard_request_manager->LabelToName(label.id)); + new_labels.push_back(request_router->LabelToName(label.id)); } auto properties = vertex.Properties(); std::map<std::string, Value> new_properties; for (const auto &[prop, property_value] : properties) { - new_properties[shard_request_manager->PropertyToName(prop)] = ToBoltValue(property_value); + new_properties[request_router->PropertyToName(prop)] = ToBoltValue(property_value); } return communication::bolt::Vertex{id, new_labels, new_properties}; } communication::bolt::Edge ToBoltEdge(const query::v2::accessors::EdgeAccessor &edge, - const query::v2::ShardRequestManagerInterface *shard_request_manager, + const query::v2::RequestRouterInterface *request_router, storage::v3::View /*view*/) { // TODO(jbajic) Fix bolt communication auto id = communication::bolt::Id::FromUint(0); auto from = communication::bolt::Id::FromUint(0); auto to = communication::bolt::Id::FromUint(0); - const auto &type = shard_request_manager->EdgeTypeToName(edge.EdgeType()); + const auto &type = request_router->EdgeTypeToName(edge.EdgeType()); auto properties = edge.Properties(); std::map<std::string, Value> new_properties; for (const auto &[prop, property_value] : properties) { - new_properties[shard_request_manager->PropertyToName(prop)] = ToBoltValue(property_value); + new_properties[request_router->PropertyToName(prop)] = ToBoltValue(property_value); } return communication::bolt::Edge{id, from, to, type, new_properties}; } communication::bolt::Path ToBoltPath(const query::v2::accessors::Path & /*edge*/, - const query::v2::ShardRequestManagerInterface * /*shard_request_manager*/, + const query::v2::RequestRouterInterface * /*request_router*/, storage::v3::View /*view*/) { // TODO(jbajic) Fix bolt communication MG_ASSERT(false, "Path is unimplemented!"); return {}; } -Value ToBoltValue(const query::v2::TypedValue &value, - const query::v2::ShardRequestManagerInterface *shard_request_manager, storage::v3::View view) { +Value ToBoltValue(const query::v2::TypedValue &value, const query::v2::RequestRouterInterface *request_router, + storage::v3::View view) { switch (value.type()) { case query::v2::TypedValue::Type::Null: return {}; @@ -133,7 +133,7 @@ Value ToBoltValue(const query::v2::TypedValue &value, std::vector<Value> values; values.reserve(value.ValueList().size()); for (const auto &v : value.ValueList()) { - auto value = ToBoltValue(v, shard_request_manager, view); + auto value = ToBoltValue(v, request_router, view); values.emplace_back(std::move(value)); } return {std::move(values)}; @@ -141,21 +141,21 @@ Value ToBoltValue(const query::v2::TypedValue &value, case query::v2::TypedValue::Type::Map: { std::map<std::string, Value> map; for (const auto &kv : value.ValueMap()) { - auto value = ToBoltValue(kv.second, shard_request_manager, view); + auto value = ToBoltValue(kv.second, request_router, view); map.emplace(kv.first, std::move(value)); } return {std::move(map)}; } case query::v2::TypedValue::Type::Vertex: { - auto vertex = ToBoltVertex(value.ValueVertex(), shard_request_manager, view); + auto vertex = ToBoltVertex(value.ValueVertex(), request_router, view); return {std::move(vertex)}; } case query::v2::TypedValue::Type::Edge: { - auto edge = ToBoltEdge(value.ValueEdge(), shard_request_manager, view); + auto edge = ToBoltEdge(value.ValueEdge(), request_router, view); return {std::move(edge)}; } case query::v2::TypedValue::Type::Path: { - auto path = ToBoltPath(value.ValuePath(), shard_request_manager, view); + auto path = ToBoltPath(value.ValuePath(), request_router, view); return {std::move(path)}; } case query::v2::TypedValue::Type::Date: diff --git a/src/glue/v2/communication.hpp b/src/glue/v2/communication.hpp index 817ff02bd..c1661b521 100644 --- a/src/glue/v2/communication.hpp +++ b/src/glue/v2/communication.hpp @@ -15,7 +15,7 @@ #include "communication/bolt/v1/value.hpp" #include "coordinator/shard_map.hpp" #include "query/v2/bindings/typed_value.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "storage/v3/property_value.hpp" #include "storage/v3/result.hpp" #include "storage/v3/shard.hpp" @@ -32,40 +32,37 @@ namespace memgraph::glue::v2 { /// @param storage::v3::VertexAccessor for converting to /// communication::bolt::Vertex. -/// @param query::v2::ShardRequestManagerInterface *shard_request_manager getting label and property names. +/// @param query::v2::RequestRouterInterface *request_router getting label and property names. /// @param storage::v3::View for deciding which vertex attributes are visible. /// /// @throw std::bad_alloc communication::bolt::Vertex ToBoltVertex(const storage::v3::VertexAccessor &vertex, - const query::v2::ShardRequestManagerInterface *shard_request_manager, + const query::v2::RequestRouterInterface *request_router, storage::v3::View view); /// @param storage::v3::EdgeAccessor for converting to communication::bolt::Edge. -/// @param query::v2::ShardRequestManagerInterface *shard_request_manager getting edge type and property names. +/// @param query::v2::RequestRouterInterface *request_router getting edge type and property names. /// @param storage::v3::View for deciding which edge attributes are visible. /// /// @throw std::bad_alloc communication::bolt::Edge ToBoltEdge(const storage::v3::EdgeAccessor &edge, - const query::v2::ShardRequestManagerInterface *shard_request_manager, - storage::v3::View view); + const query::v2::RequestRouterInterface *request_router, storage::v3::View view); /// @param query::v2::Path for converting to communication::bolt::Path. -/// @param query::v2::ShardRequestManagerInterface *shard_request_manager ToBoltVertex and ToBoltEdge. +/// @param query::v2::RequestRouterInterface *request_router ToBoltVertex and ToBoltEdge. /// @param storage::v3::View for ToBoltVertex and ToBoltEdge. /// /// @throw std::bad_alloc communication::bolt::Path ToBoltPath(const query::v2::accessors::Path &path, - const query::v2::ShardRequestManagerInterface *shard_request_manager, - storage::v3::View view); + const query::v2::RequestRouterInterface *request_router, storage::v3::View view); /// @param query::v2::TypedValue for converting to communication::bolt::Value. -/// @param query::v2::ShardRequestManagerInterface *shard_request_manager ToBoltVertex and ToBoltEdge. +/// @param query::v2::RequestRouterInterface *request_router ToBoltVertex and ToBoltEdge. /// @param storage::v3::View for ToBoltVertex and ToBoltEdge. /// /// @throw std::bad_alloc communication::bolt::Value ToBoltValue(const query::v2::TypedValue &value, - const query::v2::ShardRequestManagerInterface *shard_request_manager, - storage::v3::View view); + const query::v2::RequestRouterInterface *request_router, storage::v3::View view); query::v2::TypedValue ToTypedValue(const communication::bolt::Value &value); @@ -75,8 +72,7 @@ storage::v3::PropertyValue ToPropertyValue(const communication::bolt::Value &val communication::bolt::Value ToBoltValue(msgs::Value value); -communication::bolt::Value ToBoltValue(msgs::Value value, - const query::v2::ShardRequestManagerInterface *shard_request_manager, +communication::bolt::Value ToBoltValue(msgs::Value value, const query::v2::RequestRouterInterface *request_router, storage::v3::View view); } // namespace memgraph::glue::v2 diff --git a/src/memgraph.cpp b/src/memgraph.cpp index 565f9940c..d825cc0e7 100644 --- a/src/memgraph.cpp +++ b/src/memgraph.cpp @@ -454,7 +454,7 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph std::map<std::string, memgraph::communication::bolt::Value> Pull(TEncoder *encoder, std::optional<int> n, std::optional<int> qid) override { - TypedValueResultStream stream(encoder, interpreter_.GetShardRequestManager()); + TypedValueResultStream stream(encoder, interpreter_.GetRequestRouter()); return PullResults(stream, n, qid); } @@ -481,7 +481,7 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph const auto &summary = interpreter_.Pull(&stream, n, qid); std::map<std::string, memgraph::communication::bolt::Value> decoded_summary; for (const auto &kv : summary) { - auto bolt_value = memgraph::glue::v2::ToBoltValue(kv.second, interpreter_.GetShardRequestManager(), + auto bolt_value = memgraph::glue::v2::ToBoltValue(kv.second, interpreter_.GetRequestRouter(), memgraph::storage::v3::View::NEW); decoded_summary.emplace(kv.first, std::move(bolt_value)); } @@ -497,15 +497,14 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph /// before forwarding the calls to original TEncoder. class TypedValueResultStream { public: - TypedValueResultStream(TEncoder *encoder, - const memgraph::query::v2::ShardRequestManagerInterface *shard_request_manager) - : encoder_(encoder), shard_request_manager_(shard_request_manager) {} + TypedValueResultStream(TEncoder *encoder, const memgraph::query::v2::RequestRouterInterface *request_router) + : encoder_(encoder), request_router_(request_router) {} void Result(const std::vector<memgraph::query::v2::TypedValue> &values) { std::vector<memgraph::communication::bolt::Value> decoded_values; decoded_values.reserve(values.size()); for (const auto &v : values) { - auto bolt_value = memgraph::glue::v2::ToBoltValue(v, shard_request_manager_, memgraph::storage::v3::View::NEW); + auto bolt_value = memgraph::glue::v2::ToBoltValue(v, request_router_, memgraph::storage::v3::View::NEW); decoded_values.emplace_back(std::move(bolt_value)); } encoder_->MessageRecord(decoded_values); @@ -513,7 +512,7 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph private: TEncoder *encoder_; - const memgraph::query::v2::ShardRequestManagerInterface *shard_request_manager_{nullptr}; + const memgraph::query::v2::RequestRouterInterface *request_router_{nullptr}; }; memgraph::query::v2::Interpreter interpreter_; memgraph::communication::v2::ServerEndpoint endpoint_; diff --git a/src/query/v2/accessors.cpp b/src/query/v2/accessors.cpp index 4f6e0d0d7..a28df0fe5 100644 --- a/src/query/v2/accessors.cpp +++ b/src/query/v2/accessors.cpp @@ -10,12 +10,12 @@ // licenses/APL.txt. #include "query/v2/accessors.hpp" +#include "query/v2/request_router.hpp" #include "query/v2/requests.hpp" -#include "query/v2/shard_request_manager.hpp" #include "storage/v3/id_types.hpp" namespace memgraph::query::v2::accessors { -EdgeAccessor::EdgeAccessor(Edge edge, const ShardRequestManagerInterface *manager) +EdgeAccessor::EdgeAccessor(Edge edge, const RequestRouterInterface *manager) : edge(std::move(edge)), manager_(manager) {} EdgeTypeId EdgeAccessor::EdgeType() const { return edge.type.id; } @@ -44,11 +44,10 @@ VertexAccessor EdgeAccessor::From() const { } VertexAccessor::VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, - const ShardRequestManagerInterface *manager) + const RequestRouterInterface *manager) : vertex(std::move(v)), properties(std::move(props)), manager_(manager) {} -VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, - const ShardRequestManagerInterface *manager) +VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const RequestRouterInterface *manager) : vertex(std::move(v)), manager_(manager) { properties.reserve(props.size()); for (auto &[id, value] : props) { @@ -57,7 +56,7 @@ VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, } VertexAccessor::VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, - const ShardRequestManagerInterface *manager) + const RequestRouterInterface *manager) : vertex(std::move(v)), manager_(manager) { properties.reserve(props.size()); for (const auto &[id, value] : props) { diff --git a/src/query/v2/accessors.hpp b/src/query/v2/accessors.hpp index ca7ec999d..b5585953f 100644 --- a/src/query/v2/accessors.hpp +++ b/src/query/v2/accessors.hpp @@ -25,7 +25,7 @@ #include "utils/memory_tracker.hpp" namespace memgraph::query::v2 { -class ShardRequestManagerInterface; +class RequestRouterInterface; } // namespace memgraph::query::v2 namespace memgraph::query::v2::accessors { @@ -41,7 +41,7 @@ class VertexAccessor; class EdgeAccessor final { public: - explicit EdgeAccessor(Edge edge, const ShardRequestManagerInterface *manager); + explicit EdgeAccessor(Edge edge, const RequestRouterInterface *manager); [[nodiscard]] EdgeTypeId EdgeType() const; @@ -69,7 +69,7 @@ class EdgeAccessor final { private: Edge edge; - const ShardRequestManagerInterface *manager_; + const RequestRouterInterface *manager_; }; class VertexAccessor final { @@ -77,11 +77,10 @@ class VertexAccessor final { using PropertyId = msgs::PropertyId; using Label = msgs::Label; using VertexId = msgs::VertexId; - VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, - const ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, const RequestRouterInterface *manager); - VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const ShardRequestManagerInterface *manager); - VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, const ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const RequestRouterInterface *manager); + VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, const RequestRouterInterface *manager); [[nodiscard]] Label PrimaryLabel() const; @@ -150,7 +149,7 @@ class VertexAccessor final { private: Vertex vertex; std::vector<std::pair<PropertyId, Value>> properties; - const ShardRequestManagerInterface *manager_; + const RequestRouterInterface *manager_; }; // inline VertexAccessor EdgeAccessor::To() const { return VertexAccessor(impl_.ToVertex()); } diff --git a/src/query/v2/bindings/eval.hpp b/src/query/v2/bindings/eval.hpp index 584e88922..912850e87 100644 --- a/src/query/v2/bindings/eval.hpp +++ b/src/query/v2/bindings/eval.hpp @@ -26,7 +26,7 @@ namespace memgraph::query::v2 { -class ShardRequestManagerInterface; +class RequestRouterInterface; inline const auto lam = [](const auto &val) { return ValueToTypedValue(val); }; namespace detail { @@ -35,15 +35,14 @@ class Callable { auto operator()(const storage::v3::PropertyValue &val) const { return storage::v3::PropertyToTypedValue<TypedValue>(val); }; - auto operator()(const msgs::Value &val, ShardRequestManagerInterface *manager) const { + auto operator()(const msgs::Value &val, RequestRouterInterface *manager) const { return ValueToTypedValue(val, manager); }; }; } // namespace detail -using ExpressionEvaluator = - expr::ExpressionEvaluator<TypedValue, query::v2::EvaluationContext, ShardRequestManagerInterface, storage::v3::View, - storage::v3::LabelId, msgs::Value, detail::Callable, common::ErrorCode, - expr::QueryEngineTag>; +using ExpressionEvaluator = expr::ExpressionEvaluator<TypedValue, query::v2::EvaluationContext, RequestRouterInterface, + storage::v3::View, storage::v3::LabelId, msgs::Value, + detail::Callable, common::ErrorCode, expr::QueryEngineTag>; } // namespace memgraph::query::v2 diff --git a/src/query/v2/context.hpp b/src/query/v2/context.hpp index 388342349..cb30a9ced 100644 --- a/src/query/v2/context.hpp +++ b/src/query/v2/context.hpp @@ -20,7 +20,7 @@ #include "query/v2/parameters.hpp" #include "query/v2/plan/profile.hpp" //#include "query/v2/trigger.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "utils/async_timer.hpp" namespace memgraph::query::v2 { @@ -61,26 +61,26 @@ struct EvaluationContext { }; inline std::vector<storage::v3::PropertyId> NamesToProperties(const std::vector<std::string> &property_names, - ShardRequestManagerInterface *shard_request_manager) { + RequestRouterInterface *request_router) { std::vector<storage::v3::PropertyId> properties; // TODO Fix by using reference properties.reserve(property_names.size()); - if (shard_request_manager != nullptr) { + if (request_router != nullptr) { for (const auto &name : property_names) { - properties.push_back(shard_request_manager->NameToProperty(name)); + properties.push_back(request_router->NameToProperty(name)); } } return properties; } inline std::vector<storage::v3::LabelId> NamesToLabels(const std::vector<std::string> &label_names, - ShardRequestManagerInterface *shard_request_manager) { + RequestRouterInterface *request_router) { std::vector<storage::v3::LabelId> labels; labels.reserve(label_names.size()); // TODO Fix by using reference - if (shard_request_manager != nullptr) { + if (request_router != nullptr) { for (const auto &name : label_names) { - labels.push_back(shard_request_manager->NameToLabel(name)); + labels.push_back(request_router->NameToLabel(name)); } } return labels; @@ -97,7 +97,7 @@ struct ExecutionContext { plan::ProfilingStats *stats_root{nullptr}; ExecutionStats execution_stats; utils::AsyncTimer timer; - ShardRequestManagerInterface *shard_request_manager{nullptr}; + RequestRouterInterface *request_router{nullptr}; IdAllocator *edge_ids_alloc; }; diff --git a/src/query/v2/conversions.hpp b/src/query/v2/conversions.hpp index c18ba8cc0..161f89979 100644 --- a/src/query/v2/conversions.hpp +++ b/src/query/v2/conversions.hpp @@ -12,12 +12,12 @@ #pragma once #include "bindings/typed_value.hpp" #include "query/v2/accessors.hpp" +#include "query/v2/request_router.hpp" #include "query/v2/requests.hpp" -#include "query/v2/shard_request_manager.hpp" namespace memgraph::query::v2 { -inline TypedValue ValueToTypedValue(const msgs::Value &value, ShardRequestManagerInterface *manager) { +inline TypedValue ValueToTypedValue(const msgs::Value &value, RequestRouterInterface *manager) { using Value = msgs::Value; switch (value.type) { case Value::Type::Null: diff --git a/src/query/v2/cypher_query_interpreter.cpp b/src/query/v2/cypher_query_interpreter.cpp index 908ee36cb..880165ad8 100644 --- a/src/query/v2/cypher_query_interpreter.cpp +++ b/src/query/v2/cypher_query_interpreter.cpp @@ -11,7 +11,7 @@ #include "query/v2/cypher_query_interpreter.hpp" #include "query/v2/bindings/symbol_generator.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" // NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables) DEFINE_HIDDEN_bool(query_cost_planner, true, "Use the cost-estimating query planner."); @@ -118,7 +118,7 @@ ParsedQuery ParseQuery(const std::string &query_string, const std::map<std::stri } std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers) { auto vertex_counts = plan::MakeVertexCountCache(shard_manager); auto symbol_table = expr::MakeSymbolTable(query, predefined_identifiers); @@ -130,7 +130,7 @@ std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery std::shared_ptr<CachedPlan> CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList<PlanCacheEntry> *plan_cache, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers) { std::optional<utils::SkipList<PlanCacheEntry>::Accessor> plan_cache_access; if (plan_cache) { diff --git a/src/query/v2/cypher_query_interpreter.hpp b/src/query/v2/cypher_query_interpreter.hpp index b7f63ab8f..c9d65047c 100644 --- a/src/query/v2/cypher_query_interpreter.hpp +++ b/src/query/v2/cypher_query_interpreter.hpp @@ -132,7 +132,7 @@ class SingleNodeLogicalPlan final : public LogicalPlan { }; std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers); /** @@ -145,7 +145,7 @@ std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery */ std::shared_ptr<CachedPlan> CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList<PlanCacheEntry> *plan_cache, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector<Identifier *> &predefined_identifiers = {}); } // namespace memgraph::query::v2 diff --git a/src/query/v2/interpret/awesome_memgraph_functions.cpp b/src/query/v2/interpret/awesome_memgraph_functions.cpp index 8768736b2..54fcd4468 100644 --- a/src/query/v2/interpret/awesome_memgraph_functions.cpp +++ b/src/query/v2/interpret/awesome_memgraph_functions.cpp @@ -23,7 +23,7 @@ #include "query/v2/bindings/typed_value.hpp" #include "query/v2/conversions.hpp" #include "query/v2/exceptions.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "storage/v3/conversions.hpp" #include "utils/string.hpp" #include "utils/temporal.hpp" diff --git a/src/query/v2/interpret/awesome_memgraph_functions.hpp b/src/query/v2/interpret/awesome_memgraph_functions.hpp index 1fd351cd8..35ed1d797 100644 --- a/src/query/v2/interpret/awesome_memgraph_functions.hpp +++ b/src/query/v2/interpret/awesome_memgraph_functions.hpp @@ -22,7 +22,7 @@ namespace memgraph::query::v2 { -class ShardRequestManagerInterface; +class RequestRouterInterface; namespace { const char kStartsWith[] = "STARTSWITH"; @@ -32,9 +32,9 @@ const char kId[] = "ID"; } // namespace struct FunctionContext { - // TODO(kostasrim) consider optional here. ShardRequestManager does not exist on the storage. + // TODO(kostasrim) consider optional here. RequestRouter does not exist on the storage. // DbAccessor *db_accessor; - ShardRequestManagerInterface *manager; + RequestRouterInterface *manager; utils::MemoryResource *memory; int64_t timestamp; std::unordered_map<std::string, int64_t> *counters; diff --git a/src/query/v2/interpreter.cpp b/src/query/v2/interpreter.cpp index f9dc37184..94ff7a8ff 100644 --- a/src/query/v2/interpreter.cpp +++ b/src/query/v2/interpreter.cpp @@ -44,7 +44,7 @@ #include "query/v2/plan/planner.hpp" #include "query/v2/plan/profile.hpp" #include "query/v2/plan/vertex_count_cache.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "storage/v3/property_value.hpp" #include "storage/v3/shard.hpp" #include "utils/algorithm.hpp" @@ -143,7 +143,7 @@ class ReplQueryHandler final : public query::v2::ReplicationQueryHandler { /// @throw QueryRuntimeException if an error ocurred. Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Parameters ¶meters, - ShardRequestManagerInterface *manager) { + RequestRouterInterface *manager) { // Empty frame for evaluation of password expression. This is OK since // password should be either null or string literal and it's evaluation // should not depend on frame. @@ -312,7 +312,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa } Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters ¶meters, - InterpreterContext *interpreter_context, ShardRequestManagerInterface *manager, + InterpreterContext *interpreter_context, RequestRouterInterface *manager, std::vector<Notification> *notifications) { expr::Frame<TypedValue> frame(0); SymbolTable symbol_table; @@ -448,7 +448,7 @@ Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters & } Callback HandleSettingQuery(SettingQuery *setting_query, const Parameters ¶meters, - ShardRequestManagerInterface *manager) { + RequestRouterInterface *manager) { expr::Frame<TypedValue> frame(0); SymbolTable symbol_table; EvaluationContext evaluation_context; @@ -649,7 +649,7 @@ struct PullPlanVector { struct PullPlan { explicit PullPlan(std::shared_ptr<CachedPlan> plan, const Parameters ¶meters, bool is_profile_query, DbAccessor *dba, InterpreterContext *interpreter_context, utils::MemoryResource *execution_memory, - ShardRequestManagerInterface *shard_request_manager = nullptr, + RequestRouterInterface *request_router = nullptr, // TriggerContextCollector *trigger_context_collector = nullptr, std::optional<size_t> memory_limit = {}); std::optional<plan::ProfilingStatsWithTotalTime> Pull(AnyStream *stream, std::optional<int> n, @@ -679,7 +679,7 @@ struct PullPlan { PullPlan::PullPlan(const std::shared_ptr<CachedPlan> plan, const Parameters ¶meters, const bool is_profile_query, DbAccessor *dba, InterpreterContext *interpreter_context, utils::MemoryResource *execution_memory, - ShardRequestManagerInterface *shard_request_manager, const std::optional<size_t> memory_limit) + RequestRouterInterface *request_router, const std::optional<size_t> memory_limit) : plan_(plan), cursor_(plan->plan().MakeCursor(execution_memory)), frame_(plan->symbol_table().max_position(), execution_memory), @@ -688,14 +688,14 @@ PullPlan::PullPlan(const std::shared_ptr<CachedPlan> plan, const Parameters &par ctx_.symbol_table = plan->symbol_table(); ctx_.evaluation_context.timestamp = QueryTimestamp(); ctx_.evaluation_context.parameters = parameters; - ctx_.evaluation_context.properties = NamesToProperties(plan->ast_storage().properties_, shard_request_manager); - ctx_.evaluation_context.labels = NamesToLabels(plan->ast_storage().labels_, shard_request_manager); + ctx_.evaluation_context.properties = NamesToProperties(plan->ast_storage().properties_, request_router); + ctx_.evaluation_context.labels = NamesToLabels(plan->ast_storage().labels_, request_router); if (interpreter_context->config.execution_timeout_sec > 0) { ctx_.timer = utils::AsyncTimer{interpreter_context->config.execution_timeout_sec}; } ctx_.is_shutting_down = &interpreter_context->is_shutting_down; ctx_.is_profile_query = is_profile_query; - ctx_.shard_request_manager = shard_request_manager; + ctx_.request_router = request_router; ctx_.edge_ids_alloc = &interpreter_context->edge_ids_alloc; } @@ -804,7 +804,7 @@ Interpreter::Interpreter(InterpreterContext *interpreter_context) : interpreter_ auto random_uuid = boost::uuids::uuid{boost::uuids::random_generator()()}; auto query_io = interpreter_context_->io.ForkLocal(random_uuid); - shard_request_manager_ = std::make_unique<ShardRequestManager<io::local_transport::LocalTransport>>( + request_router_ = std::make_unique<RequestRouter<io::local_transport::LocalTransport>>( coordinator::CoordinatorClient<io::local_transport::LocalTransport>( query_io, interpreter_context_->coordinator_address, std::vector{interpreter_context_->coordinator_address}), std::move(query_io)); @@ -881,7 +881,7 @@ PreparedQuery Interpreter::PrepareTransactionQuery(std::string_view query_upper) PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, std::vector<Notification> *notifications, - ShardRequestManagerInterface *shard_request_manager) { + RequestRouterInterface *request_router) { // TriggerContextCollector *trigger_context_collector = nullptr) { auto *cypher_query = utils::Downcast<CypherQuery>(parsed_query.query); @@ -890,8 +890,7 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map<std::string, EvaluationContext evaluation_context; evaluation_context.timestamp = QueryTimestamp(); evaluation_context.parameters = parsed_query.parameters; - ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, shard_request_manager, - storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, request_router, storage::v3::View::OLD); const auto memory_limit = expr::EvaluateMemoryLimit(&evaluator, cypher_query->memory_limit_, cypher_query->memory_scale_); if (memory_limit) { @@ -906,9 +905,9 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map<std::string, "convert the parsed row values to the appropriate type. This can be done using the built-in " "conversion functions such as ToInteger, ToFloat, ToBoolean etc."); } - auto plan = CypherQueryToPlan( - parsed_query.stripped_query.hash(), std::move(parsed_query.ast_storage), cypher_query, parsed_query.parameters, - parsed_query.is_cacheable ? &interpreter_context->plan_cache : nullptr, shard_request_manager); + auto plan = CypherQueryToPlan(parsed_query.stripped_query.hash(), std::move(parsed_query.ast_storage), cypher_query, + parsed_query.parameters, + parsed_query.is_cacheable ? &interpreter_context->plan_cache : nullptr, request_router); summary->insert_or_assign("cost_estimate", plan->cost()); auto rw_type_checker = plan::ReadWriteTypeChecker(); @@ -927,7 +926,7 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map<std::string, utils::FindOr(parsed_query.stripped_query.named_expressions(), symbol.token_position(), symbol.name()).first); } auto pull_plan = std::make_shared<PullPlan>(plan, parsed_query.parameters, false, dba, interpreter_context, - execution_memory, shard_request_manager, memory_limit); + execution_memory, request_router, memory_limit); // execution_memory, trigger_context_collector, memory_limit); return PreparedQuery{std::move(header), std::move(parsed_query.required_privileges), [pull_plan = std::move(pull_plan), output_symbols = std::move(output_symbols), summary]( @@ -941,8 +940,7 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map<std::string, } PreparedQuery PrepareExplainQuery(ParsedQuery parsed_query, std::map<std::string, TypedValue> *summary, - InterpreterContext *interpreter_context, - ShardRequestManagerInterface *shard_request_manager, + InterpreterContext *interpreter_context, RequestRouterInterface *request_router, utils::MemoryResource *execution_memory) { const std::string kExplainQueryStart = "explain "; MG_ASSERT(utils::StartsWith(utils::ToLowerCase(parsed_query.stripped_query.query()), kExplainQueryStart), @@ -961,20 +959,20 @@ PreparedQuery PrepareExplainQuery(ParsedQuery parsed_query, std::map<std::string auto *cypher_query = utils::Downcast<CypherQuery>(parsed_inner_query.query); MG_ASSERT(cypher_query, "Cypher grammar should not allow other queries in EXPLAIN"); - auto cypher_query_plan = CypherQueryToPlan( - parsed_inner_query.stripped_query.hash(), std::move(parsed_inner_query.ast_storage), cypher_query, - parsed_inner_query.parameters, parsed_inner_query.is_cacheable ? &interpreter_context->plan_cache : nullptr, - shard_request_manager); + auto cypher_query_plan = + CypherQueryToPlan(parsed_inner_query.stripped_query.hash(), std::move(parsed_inner_query.ast_storage), + cypher_query, parsed_inner_query.parameters, + parsed_inner_query.is_cacheable ? &interpreter_context->plan_cache : nullptr, request_router); std::stringstream printed_plan; - plan::PrettyPrint(*shard_request_manager, &cypher_query_plan->plan(), &printed_plan); + plan::PrettyPrint(*request_router, &cypher_query_plan->plan(), &printed_plan); std::vector<std::vector<TypedValue>> printed_plan_rows; for (const auto &row : utils::Split(utils::RTrim(printed_plan.str()), "\n")) { printed_plan_rows.push_back(std::vector<TypedValue>{TypedValue(row)}); } - summary->insert_or_assign("explain", plan::PlanToJson(*shard_request_manager, &cypher_query_plan->plan()).dump()); + summary->insert_or_assign("explain", plan::PlanToJson(*request_router, &cypher_query_plan->plan()).dump()); return PreparedQuery{{"QUERY PLAN"}, std::move(parsed_query.required_privileges), @@ -991,7 +989,7 @@ PreparedQuery PrepareExplainQuery(ParsedQuery parsed_query, std::map<std::string PreparedQuery PrepareProfileQuery(ParsedQuery parsed_query, bool in_explicit_transaction, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, - ShardRequestManagerInterface *shard_request_manager = nullptr) { + RequestRouterInterface *request_router = nullptr) { const std::string kProfileQueryStart = "profile "; MG_ASSERT(utils::StartsWith(utils::ToLowerCase(parsed_query.stripped_query.query()), kProfileQueryStart), @@ -1034,22 +1032,21 @@ PreparedQuery PrepareProfileQuery(ParsedQuery parsed_query, bool in_explicit_tra EvaluationContext evaluation_context; evaluation_context.timestamp = QueryTimestamp(); evaluation_context.parameters = parsed_inner_query.parameters; - ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, shard_request_manager, - storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, request_router, storage::v3::View::OLD); const auto memory_limit = expr::EvaluateMemoryLimit(&evaluator, cypher_query->memory_limit_, cypher_query->memory_scale_); - auto cypher_query_plan = CypherQueryToPlan( - parsed_inner_query.stripped_query.hash(), std::move(parsed_inner_query.ast_storage), cypher_query, - parsed_inner_query.parameters, parsed_inner_query.is_cacheable ? &interpreter_context->plan_cache : nullptr, - shard_request_manager); + auto cypher_query_plan = + CypherQueryToPlan(parsed_inner_query.stripped_query.hash(), std::move(parsed_inner_query.ast_storage), + cypher_query, parsed_inner_query.parameters, + parsed_inner_query.is_cacheable ? &interpreter_context->plan_cache : nullptr, request_router); auto rw_type_checker = plan::ReadWriteTypeChecker(); rw_type_checker.InferRWType(const_cast<plan::LogicalOperator &>(cypher_query_plan->plan())); return PreparedQuery{{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME", "CUSTOM DATA"}, std::move(parsed_query.required_privileges), [plan = std::move(cypher_query_plan), parameters = std::move(parsed_inner_query.parameters), - summary, dba, interpreter_context, execution_memory, memory_limit, shard_request_manager, + summary, dba, interpreter_context, execution_memory, memory_limit, request_router, // We want to execute the query we are profiling lazily, so we delay // the construction of the corresponding context. stats_and_total_time = std::optional<plan::ProfilingStatsWithTotalTime>{}, @@ -1058,7 +1055,7 @@ PreparedQuery PrepareProfileQuery(ParsedQuery parsed_query, bool in_explicit_tra // No output symbols are given so that nothing is streamed. if (!stats_and_total_time) { stats_and_total_time = PullPlan(plan, parameters, true, dba, interpreter_context, - execution_memory, shard_request_manager, memory_limit) + execution_memory, request_router, memory_limit) .Pull(stream, {}, {}, summary); pull_plan = std::make_shared<PullPlanVector>(ProfilingStatsToTable(*stats_and_total_time)); } @@ -1185,7 +1182,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans PreparedQuery PrepareAuthQuery(ParsedQuery parsed_query, bool in_explicit_transaction, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, - ShardRequestManagerInterface *manager) { + RequestRouterInterface *manager) { if (in_explicit_transaction) { throw UserModificationInMulticommandTxException(); } @@ -1221,7 +1218,7 @@ PreparedQuery PrepareAuthQuery(ParsedQuery parsed_query, bool in_explicit_transa PreparedQuery PrepareReplicationQuery(ParsedQuery parsed_query, const bool in_explicit_transaction, std::vector<Notification> *notifications, InterpreterContext *interpreter_context, - ShardRequestManagerInterface *manager) { + RequestRouterInterface *manager) { if (in_explicit_transaction) { throw ReplicationModificationInMulticommandTxException(); } @@ -1317,7 +1314,7 @@ PreparedQuery PrepareCreateSnapshotQuery(ParsedQuery parsed_query, bool in_expli } PreparedQuery PrepareSettingQuery(ParsedQuery parsed_query, const bool in_explicit_transaction, - ShardRequestManagerInterface *manager) { + RequestRouterInterface *manager) { if (in_explicit_transaction) { throw SettingConfigInMulticommandTxException{}; } @@ -1521,7 +1518,7 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string, if (!in_explicit_transaction_ && (utils::Downcast<CypherQuery>(parsed_query.query) || utils::Downcast<ExplainQuery>(parsed_query.query) || utils::Downcast<ProfileQuery>(parsed_query.query))) { - shard_request_manager_->StartTransaction(); + request_router_->StartTransaction(); } utils::Timer planning_timer; @@ -1530,14 +1527,14 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string, if (utils::Downcast<CypherQuery>(parsed_query.query)) { prepared_query = PrepareCypherQuery(std::move(parsed_query), &query_execution->summary, interpreter_context_, &*execution_db_accessor_, &query_execution->execution_memory, - &query_execution->notifications, shard_request_manager_.get()); + &query_execution->notifications, request_router_.get()); } else if (utils::Downcast<ExplainQuery>(parsed_query.query)) { prepared_query = PrepareExplainQuery(std::move(parsed_query), &query_execution->summary, interpreter_context_, - &*shard_request_manager_, &query_execution->execution_memory_with_exception); + &*request_router_, &query_execution->execution_memory_with_exception); } else if (utils::Downcast<ProfileQuery>(parsed_query.query)) { - prepared_query = PrepareProfileQuery( - std::move(parsed_query), in_explicit_transaction_, &query_execution->summary, interpreter_context_, - &*execution_db_accessor_, &query_execution->execution_memory_with_exception, shard_request_manager_.get()); + prepared_query = PrepareProfileQuery(std::move(parsed_query), in_explicit_transaction_, &query_execution->summary, + interpreter_context_, &*execution_db_accessor_, + &query_execution->execution_memory_with_exception, request_router_.get()); } else if (utils::Downcast<DumpQuery>(parsed_query.query)) { prepared_query = PrepareDumpQuery(std::move(parsed_query), &query_execution->summary, &*execution_db_accessor_, &query_execution->execution_memory); @@ -1545,9 +1542,9 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string, prepared_query = PrepareIndexQuery(std::move(parsed_query), in_explicit_transaction_, &query_execution->notifications, interpreter_context_); } else if (utils::Downcast<AuthQuery>(parsed_query.query)) { - prepared_query = PrepareAuthQuery( - std::move(parsed_query), in_explicit_transaction_, &query_execution->summary, interpreter_context_, - &*execution_db_accessor_, &query_execution->execution_memory_with_exception, shard_request_manager_.get()); + prepared_query = PrepareAuthQuery(std::move(parsed_query), in_explicit_transaction_, &query_execution->summary, + interpreter_context_, &*execution_db_accessor_, + &query_execution->execution_memory_with_exception, request_router_.get()); } else if (utils::Downcast<InfoQuery>(parsed_query.query)) { prepared_query = PrepareInfoQuery(std::move(parsed_query), in_explicit_transaction_, &query_execution->summary, interpreter_context_, interpreter_context_->db, @@ -1558,7 +1555,7 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string, } else if (utils::Downcast<ReplicationQuery>(parsed_query.query)) { prepared_query = PrepareReplicationQuery(std::move(parsed_query), in_explicit_transaction_, &query_execution->notifications, - interpreter_context_, shard_request_manager_.get()); + interpreter_context_, request_router_.get()); } else if (utils::Downcast<LockPathQuery>(parsed_query.query)) { prepared_query = PrepareLockPathQuery(std::move(parsed_query), in_explicit_transaction_, interpreter_context_, &*execution_db_accessor_); @@ -1575,8 +1572,7 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string, prepared_query = PrepareCreateSnapshotQuery(std::move(parsed_query), in_explicit_transaction_, interpreter_context_); } else if (utils::Downcast<SettingQuery>(parsed_query.query)) { - prepared_query = - PrepareSettingQuery(std::move(parsed_query), in_explicit_transaction_, shard_request_manager_.get()); + prepared_query = PrepareSettingQuery(std::move(parsed_query), in_explicit_transaction_, request_router_.get()); } else if (utils::Downcast<VersionQuery>(parsed_query.query)) { prepared_query = PrepareVersionQuery(std::move(parsed_query), in_explicit_transaction_); } else if (utils::Downcast<SchemaQuery>(parsed_query.query)) { @@ -1617,7 +1613,7 @@ void Interpreter::Commit() { // For now, we will not check if there are some unfinished queries. // We should document clearly that all results should be pulled to complete // a query. - shard_request_manager_->Commit(); + request_router_->Commit(); if (!db_accessor_) return; const auto reset_necessary_members = [this]() { diff --git a/src/query/v2/interpreter.hpp b/src/query/v2/interpreter.hpp index afc298a0c..985c9a90c 100644 --- a/src/query/v2/interpreter.hpp +++ b/src/query/v2/interpreter.hpp @@ -296,7 +296,7 @@ class Interpreter final { */ void Abort(); - const ShardRequestManagerInterface *GetShardRequestManager() const { return shard_request_manager_.get(); } + const RequestRouterInterface *GetRequestRouter() const { return request_router_.get(); } private: struct QueryExecution { @@ -342,7 +342,7 @@ class Interpreter final { // move this unique_ptr into a shared_ptr. std::unique_ptr<storage::v3::Shard::Accessor> db_accessor_; std::optional<DbAccessor> execution_db_accessor_; - std::unique_ptr<ShardRequestManagerInterface> shard_request_manager_; + std::unique_ptr<RequestRouterInterface> request_router_; bool in_explicit_transaction_{false}; bool expect_rollback_{false}; diff --git a/src/query/v2/plan/operator.cpp b/src/query/v2/plan/operator.cpp index 30db1012e..2d2849f0d 100644 --- a/src/query/v2/plan/operator.cpp +++ b/src/query/v2/plan/operator.cpp @@ -39,8 +39,8 @@ #include "query/v2/frontend/ast/ast.hpp" #include "query/v2/path.hpp" #include "query/v2/plan/scoped_profile.hpp" +#include "query/v2/request_router.hpp" #include "query/v2/requests.hpp" -#include "query/v2/shard_request_manager.hpp" #include "storage/v3/conversions.hpp" #include "storage/v3/property_value.hpp" #include "utils/algorithm.hpp" @@ -177,7 +177,7 @@ class DistributedCreateNodeCursor : public Cursor { bool Pull(Frame &frame, ExecutionContext &context) override { SCOPED_PROFILE_OP("CreateNode"); if (input_cursor_->Pull(frame, context)) { - auto &shard_manager = context.shard_request_manager; + auto &shard_manager = context.request_router; { SCOPED_REQUEST_WAIT_PROFILE; shard_manager->Request(state_, NodeCreationInfoToRequest(context, frame)); @@ -197,8 +197,8 @@ class DistributedCreateNodeCursor : public Cursor { // TODO(kostasrim) Make this work with batching const auto primary_label = msgs::Label{.id = nodes_info_[0]->labels[0]}; msgs::Vertex v{.id = std::make_pair(primary_label, primary_keys_[0])}; - frame[nodes_info_.front()->symbol] = TypedValue( - query::v2::accessors::VertexAccessor(std::move(v), src_vertex_props_[0], context.shard_request_manager)); + frame[nodes_info_.front()->symbol] = + TypedValue(query::v2::accessors::VertexAccessor(std::move(v), src_vertex_props_[0], context.request_router)); } std::vector<msgs::NewVertex> NodeCreationInfoToRequest(ExecutionContext &context, Frame &frame) { @@ -218,7 +218,7 @@ class DistributedCreateNodeCursor : public Cursor { if (const auto *node_info_properties = std::get_if<PropertiesMapList>(&node_info->properties)) { for (const auto &[key, value_expression] : *node_info_properties) { TypedValue val = value_expression->Accept(evaluator); - if (context.shard_request_manager->IsPrimaryKey(primary_label, key)) { + if (context.request_router->IsPrimaryKey(primary_label, key)) { rqst.primary_key.push_back(TypedValueToValue(val)); pk.push_back(TypedValueToValue(val)); } @@ -227,8 +227,8 @@ class DistributedCreateNodeCursor : public Cursor { auto property_map = evaluator.Visit(*std::get<ParameterLookup *>(node_info->properties)).ValueMap(); for (const auto &[key, value] : property_map) { auto key_str = std::string(key); - auto property_id = context.shard_request_manager->NameToProperty(key_str); - if (context.shard_request_manager->IsPrimaryKey(primary_label, property_id)) { + auto property_id = context.request_router->NameToProperty(key_str); + if (context.request_router->IsPrimaryKey(primary_label, property_id)) { rqst.primary_key.push_back(TypedValueToValue(value)); pk.push_back(TypedValueToValue(value)); } @@ -386,7 +386,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { using VertexAccessor = accessors::VertexAccessor; - bool MakeRequest(ShardRequestManagerInterface &shard_manager, ExecutionContext &context) { + bool MakeRequest(RequestRouterInterface &shard_manager, ExecutionContext &context) { { SCOPED_REQUEST_WAIT_PROFILE; current_batch = shard_manager.Request(request_state_); @@ -398,7 +398,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { bool Pull(Frame &frame, ExecutionContext &context) override { SCOPED_PROFILE_OP(op_name_); - auto &shard_manager = *context.shard_request_manager; + auto &shard_manager = *context.request_router; while (true) { if (MustAbort(context)) { throw HintedAbortError(); @@ -696,7 +696,7 @@ bool Filter::FilterCursor::Pull(Frame &frame, ExecutionContext &context) { // Like all filters, newly set values should not affect filtering of old // nodes and edges. - ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.shard_request_manager, + ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router, storage::v3::View::OLD); while (input_cursor_->Pull(frame, context)) { if (EvaluateFilter(evaluator, self_.expression_)) return true; @@ -737,8 +737,8 @@ bool Produce::ProduceCursor::Pull(Frame &frame, ExecutionContext &context) { if (input_cursor_->Pull(frame, context)) { // Produce should always yield the latest results. - ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, - context.shard_request_manager, storage::v3::View::NEW); + ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router, + storage::v3::View::NEW); for (auto named_expr : self_.named_expressions_) named_expr->Accept(evaluator); return true; @@ -1122,8 +1122,8 @@ class AggregateCursor : public Cursor { * aggregation results, and not on the number of inputs. */ void ProcessAll(Frame *frame, ExecutionContext *context) { - ExpressionEvaluator evaluator(frame, context->symbol_table, context->evaluation_context, - context->shard_request_manager, storage::v3::View::NEW); + ExpressionEvaluator evaluator(frame, context->symbol_table, context->evaluation_context, context->request_router, + storage::v3::View::NEW); while (input_cursor_->Pull(*frame, *context)) { ProcessOne(*frame, &evaluator); } @@ -1343,8 +1343,8 @@ bool Skip::SkipCursor::Pull(Frame &frame, ExecutionContext &context) { // First successful pull from the input, evaluate the skip expression. // The skip expression doesn't contain identifiers so graph view // parameter is not important. - ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, - context.shard_request_manager, storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router, + storage::v3::View::OLD); TypedValue to_skip = self_.expression_->Accept(evaluator); if (to_skip.type() != TypedValue::Type::Int) throw QueryRuntimeException("Number of elements to skip must be an integer."); @@ -1398,8 +1398,8 @@ bool Limit::LimitCursor::Pull(Frame &frame, ExecutionContext &context) { if (limit_ == -1) { // Limit expression doesn't contain identifiers so graph view is not // important. - ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, - context.shard_request_manager, storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router, + storage::v3::View::OLD); TypedValue limit = self_.expression_->Accept(evaluator); if (limit.type() != TypedValue::Type::Int) throw QueryRuntimeException("Limit on number of returned elements must be an integer."); @@ -1454,8 +1454,8 @@ class OrderByCursor : public Cursor { SCOPED_PROFILE_OP("OrderBy"); if (!did_pull_all_) { - ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, - context.shard_request_manager, storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router, + storage::v3::View::OLD); auto *mem = cache_.get_allocator().GetMemoryResource(); while (input_cursor_->Pull(frame, context)) { // collect the order_by elements @@ -1712,8 +1712,8 @@ class UnwindCursor : public Cursor { if (!input_cursor_->Pull(frame, context)) return false; // successful pull from input, initialize value and iterator - ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, - context.shard_request_manager, storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router, + storage::v3::View::OLD); TypedValue input_value = self_.input_expression_->Accept(evaluator); if (input_value.type() != TypedValue::Type::List) throw QueryRuntimeException("Argument of UNWIND must be a list, but '{}' was provided.", input_value.type()); @@ -2224,7 +2224,7 @@ class LoadCsvCursor : public Cursor { Frame frame(0); SymbolTable symbol_table; auto evaluator = - ExpressionEvaluator(&frame, symbol_table, eval_context, context.shard_request_manager, storage::v3::View::OLD); + ExpressionEvaluator(&frame, symbol_table, eval_context, context.request_router, storage::v3::View::OLD); auto maybe_file = ToOptionalString(&evaluator, self_->file_); auto maybe_delim = ToOptionalString(&evaluator, self_->delimiter_); @@ -2261,8 +2261,8 @@ class ForeachCursor : public Cursor { return false; } - ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, - context.shard_request_manager, storage::v3::View::NEW); + ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.request_router, + storage::v3::View::NEW); TypedValue expr_result = expression->Accept(evaluator); if (expr_result.IsNull()) { @@ -2338,7 +2338,7 @@ class DistributedCreateExpandCursor : public Cursor { if (!input_cursor_->Pull(frame, context)) { return false; } - auto &shard_manager = context.shard_request_manager; + auto &shard_manager = context.request_router; ResetExecutionState(); { SCOPED_REQUEST_WAIT_PROFILE; @@ -2379,7 +2379,7 @@ class DistributedCreateExpandCursor : public Cursor { // handle parameter auto property_map = evaluator.Visit(*std::get<ParameterLookup *>(edge_info.properties)).ValueMap(); for (const auto &[property, value] : property_map) { - const auto property_id = context.shard_request_manager->NameToProperty(std::string(property)); + const auto property_id = context.request_router->NameToProperty(std::string(property)); request.properties.emplace_back(property_id, storage::v3::TypedValueToValue(value)); } } @@ -2394,7 +2394,7 @@ class DistributedCreateExpandCursor : public Cursor { const auto set_vertex = [&context](const auto &vertex, auto &vertex_id) { vertex_id.first = vertex.PrimaryLabel(); for (const auto &[key, val] : vertex.Properties()) { - if (context.shard_request_manager->IsPrimaryKey(vertex_id.first.id, key)) { + if (context.request_router->IsPrimaryKey(vertex_id.first.id, key)) { vertex_id.second.push_back(val); } } @@ -2474,11 +2474,11 @@ class DistributedExpandCursor : public Cursor { request.src_vertices.push_back(get_dst_vertex(edge, direction)); request.direction = (direction == EdgeAtom::Direction::IN) ? msgs::EdgeDirection::OUT : msgs::EdgeDirection::IN; ExecutionState<msgs::ExpandOneRequest> request_state; - auto result_rows = context.shard_request_manager->Request(request_state, std::move(request)); + auto result_rows = context.request_router->Request(request_state, std::move(request)); MG_ASSERT(result_rows.size() == 1); auto &result_row = result_rows.front(); frame[self_.common_.node_symbol] = accessors::VertexAccessor( - msgs::Vertex{result_row.src_vertex}, result_row.src_vertex_properties, context.shard_request_manager); + msgs::Vertex{result_row.src_vertex}, result_row.src_vertex_properties, context.request_router); } bool InitEdges(Frame &frame, ExecutionContext &context) { @@ -2502,7 +2502,7 @@ class DistributedExpandCursor : public Cursor { ExecutionState<msgs::ExpandOneRequest> request_state; auto result_rows = std::invoke([&context, &request_state, &request]() mutable { SCOPED_REQUEST_WAIT_PROFILE; - return context.shard_request_manager->Request(request_state, std::move(request)); + return context.request_router->Request(request_state, std::move(request)); }); MG_ASSERT(result_rows.size() == 1); auto &result_row = result_rows.front(); @@ -2525,14 +2525,14 @@ class DistributedExpandCursor : public Cursor { case EdgeAtom::Direction::IN: { for (auto &edge : edge_messages) { edge_accessors.emplace_back(msgs::Edge{std::move(edge.other_end), vertex.Id(), {}, {edge.gid}, edge.type}, - context.shard_request_manager); + context.request_router); } break; } case EdgeAtom::Direction::OUT: { for (auto &edge : edge_messages) { edge_accessors.emplace_back(msgs::Edge{vertex.Id(), std::move(edge.other_end), {}, {edge.gid}, edge.type}, - context.shard_request_manager); + context.request_router); } break; } diff --git a/src/query/v2/plan/pretty_print.cpp b/src/query/v2/plan/pretty_print.cpp index b7ab6da6e..0e8d09e2b 100644 --- a/src/query/v2/plan/pretty_print.cpp +++ b/src/query/v2/plan/pretty_print.cpp @@ -14,12 +14,12 @@ #include "query/v2/bindings/pretty_print.hpp" #include "query/v2/db_accessor.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "utils/string.hpp" namespace memgraph::query::v2::plan { -PlanPrinter::PlanPrinter(const ShardRequestManagerInterface *request_manager, std::ostream *out) +PlanPrinter::PlanPrinter(const RequestRouterInterface *request_manager, std::ostream *out) : request_manager_(request_manager), out_(out) {} #define PRE_VISIT(TOp) \ @@ -263,14 +263,13 @@ void PlanPrinter::Branch(query::v2::plan::LogicalOperator &op, const std::string --depth_; } -void PrettyPrint(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root, - std::ostream *out) { +void PrettyPrint(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root, std::ostream *out) { PlanPrinter printer(&request_manager, out); // FIXME(mtomic): We should make visitors that take const arguments. const_cast<LogicalOperator *>(plan_root)->Accept(printer); } -nlohmann::json PlanToJson(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root) { +nlohmann::json PlanToJson(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root) { impl::PlanToJsonVisitor visitor(&request_manager); // FIXME(mtomic): We should make visitors that take const arguments. const_cast<LogicalOperator *>(plan_root)->Accept(visitor); @@ -349,15 +348,15 @@ json ToJson(const utils::Bound<Expression *> &bound) { json ToJson(const Symbol &symbol) { return symbol.name(); } -json ToJson(storage::v3::EdgeTypeId edge_type, const ShardRequestManagerInterface &request_manager) { +json ToJson(storage::v3::EdgeTypeId edge_type, const RequestRouterInterface &request_manager) { return request_manager.EdgeTypeToName(edge_type); } -json ToJson(storage::v3::LabelId label, const ShardRequestManagerInterface &request_manager) { +json ToJson(storage::v3::LabelId label, const RequestRouterInterface &request_manager) { return request_manager.LabelToName(label); } -json ToJson(storage::v3::PropertyId property, const ShardRequestManagerInterface &request_manager) { +json ToJson(storage::v3::PropertyId property, const RequestRouterInterface &request_manager) { return request_manager.PropertyToName(property); } @@ -369,7 +368,7 @@ json ToJson(NamedExpression *nexpr) { } json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> &properties, - const ShardRequestManagerInterface &request_manager) { + const RequestRouterInterface &request_manager) { json json; for (const auto &prop_pair : properties) { json.emplace(ToJson(prop_pair.first, request_manager), ToJson(prop_pair.second)); @@ -377,7 +376,7 @@ json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> return json; } -json ToJson(const NodeCreationInfo &node_info, const ShardRequestManagerInterface &request_manager) { +json ToJson(const NodeCreationInfo &node_info, const RequestRouterInterface &request_manager) { json self; self["symbol"] = ToJson(node_info.symbol); self["labels"] = ToJson(node_info.labels, request_manager); @@ -386,7 +385,7 @@ json ToJson(const NodeCreationInfo &node_info, const ShardRequestManagerInterfac return self; } -json ToJson(const EdgeCreationInfo &edge_info, const ShardRequestManagerInterface &request_manager) { +json ToJson(const EdgeCreationInfo &edge_info, const RequestRouterInterface &request_manager) { json self; self["symbol"] = ToJson(edge_info.symbol); const auto *props = std::get_if<PropertiesMapList>(&edge_info.properties); diff --git a/src/query/v2/plan/pretty_print.hpp b/src/query/v2/plan/pretty_print.hpp index 8485723a3..7e97de3ff 100644 --- a/src/query/v2/plan/pretty_print.hpp +++ b/src/query/v2/plan/pretty_print.hpp @@ -18,7 +18,7 @@ #include "query/v2/frontend/ast/ast.hpp" #include "query/v2/plan/operator.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" namespace memgraph::query::v2 { @@ -27,20 +27,19 @@ namespace plan { class LogicalOperator; /// Pretty print a `LogicalOperator` plan to a `std::ostream`. -/// ShardRequestManager is needed for resolving label and property names. +/// RequestRouter is needed for resolving label and property names. /// Note that `plan_root` isn't modified, but we can't take it as a const /// because we don't have support for visiting a const LogicalOperator. -void PrettyPrint(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root, - std::ostream *out); +void PrettyPrint(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root, std::ostream *out); /// Overload of `PrettyPrint` which defaults the `std::ostream` to `std::cout`. -inline void PrettyPrint(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root) { +inline void PrettyPrint(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root) { PrettyPrint(request_manager, plan_root, &std::cout); } /// Convert a `LogicalOperator` plan to a JSON representation. /// DbAccessor is needed for resolving label and property names. -nlohmann::json PlanToJson(const ShardRequestManagerInterface &request_manager, const LogicalOperator *plan_root); +nlohmann::json PlanToJson(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root); class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { public: @@ -48,7 +47,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { using HierarchicalLogicalOperatorVisitor::PreVisit; using HierarchicalLogicalOperatorVisitor::Visit; - PlanPrinter(const ShardRequestManagerInterface *request_manager, std::ostream *out); + PlanPrinter(const RequestRouterInterface *request_manager, std::ostream *out); bool DefaultPreVisit() override; @@ -115,7 +114,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { void Branch(LogicalOperator &op, const std::string &branch_name = ""); int64_t depth_{0}; - const ShardRequestManagerInterface *request_manager_{nullptr}; + const RequestRouterInterface *request_manager_{nullptr}; std::ostream *out_{nullptr}; }; @@ -133,20 +132,20 @@ nlohmann::json ToJson(const utils::Bound<Expression *> &bound); nlohmann::json ToJson(const Symbol &symbol); -nlohmann::json ToJson(storage::v3::EdgeTypeId edge_type, const ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(storage::v3::EdgeTypeId edge_type, const RequestRouterInterface &request_manager); -nlohmann::json ToJson(storage::v3::LabelId label, const ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(storage::v3::LabelId label, const RequestRouterInterface &request_manager); -nlohmann::json ToJson(storage::v3::PropertyId property, const ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(storage::v3::PropertyId property, const RequestRouterInterface &request_manager); nlohmann::json ToJson(NamedExpression *nexpr); nlohmann::json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> &properties, - const ShardRequestManagerInterface &request_manager); + const RequestRouterInterface &request_manager); -nlohmann::json ToJson(const NodeCreationInfo &node_info, const ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(const NodeCreationInfo &node_info, const RequestRouterInterface &request_manager); -nlohmann::json ToJson(const EdgeCreationInfo &edge_info, const ShardRequestManagerInterface &request_manager); +nlohmann::json ToJson(const EdgeCreationInfo &edge_info, const RequestRouterInterface &request_manager); nlohmann::json ToJson(const Aggregate::Element &elem); @@ -161,7 +160,7 @@ nlohmann::json ToJson(const std::vector<T> &items, Args &&...args) { class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { public: - explicit PlanToJsonVisitor(const ShardRequestManagerInterface *request_manager) : request_manager_(request_manager) {} + explicit PlanToJsonVisitor(const RequestRouterInterface *request_manager) : request_manager_(request_manager) {} using HierarchicalLogicalOperatorVisitor::PostVisit; using HierarchicalLogicalOperatorVisitor::PreVisit; @@ -217,7 +216,7 @@ class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { protected: nlohmann::json output_; - const ShardRequestManagerInterface *request_manager_; + const RequestRouterInterface *request_manager_; nlohmann::json PopOutput() { nlohmann::json tmp; diff --git a/src/query/v2/plan/rule_based_planner.hpp b/src/query/v2/plan/rule_based_planner.hpp index 884693c2f..2b6857aea 100644 --- a/src/query/v2/plan/rule_based_planner.hpp +++ b/src/query/v2/plan/rule_based_planner.hpp @@ -272,7 +272,7 @@ class RuleBasedPlanner { PropertiesMapList vector_props; vector_props.reserve(node_properties->size()); for (const auto &kv : *node_properties) { - // TODO(kostasrim) GetProperty should be implemented in terms of ShardRequestManager NameToProperty + // TODO(kostasrim) GetProperty should be implemented in terms of RequestRouter NameToProperty vector_props.push_back({GetProperty(kv.first), kv.second}); } return std::move(vector_props); diff --git a/src/query/v2/plan/vertex_count_cache.hpp b/src/query/v2/plan/vertex_count_cache.hpp index 47a10ba3e..e68ce1220 100644 --- a/src/query/v2/plan/vertex_count_cache.hpp +++ b/src/query/v2/plan/vertex_count_cache.hpp @@ -15,7 +15,7 @@ #include <optional> #include "query/v2/bindings/typed_value.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "storage/v3/conversions.hpp" #include "storage/v3/id_types.hpp" #include "storage/v3/property_value.hpp" @@ -29,11 +29,11 @@ namespace memgraph::query::v2::plan { template <class TDbAccessor> class VertexCountCache { public: - explicit VertexCountCache(TDbAccessor *shard_request_manager) : shard_request_manager_{shard_request_manager} {} + explicit VertexCountCache(TDbAccessor *request_router) : request_router_{request_router} {} - auto NameToLabel(const std::string &name) { return shard_request_manager_->NameToLabel(name); } - auto NameToProperty(const std::string &name) { return shard_request_manager_->NameToProperty(name); } - auto NameToEdgeType(const std::string &name) { return shard_request_manager_->NameToEdgeType(name); } + auto NameToLabel(const std::string &name) { return request_router_->NameToLabel(name); } + auto NameToProperty(const std::string &name) { return request_router_->NameToProperty(name); } + auto NameToEdgeType(const std::string &name) { return request_router_->NameToEdgeType(name); } int64_t VerticesCount() { return 1; } @@ -53,11 +53,11 @@ class VertexCountCache { } // For now return true if label is primary label - bool LabelIndexExists(storage::v3::LabelId label) { return shard_request_manager_->IsPrimaryLabel(label); } + bool LabelIndexExists(storage::v3::LabelId label) { return request_router_->IsPrimaryLabel(label); } bool LabelPropertyIndexExists(storage::v3::LabelId /*label*/, storage::v3::PropertyId /*property*/) { return false; } - ShardRequestManagerInterface *shard_request_manager_; + RequestRouterInterface *request_router_; }; template <class TDbAccessor> diff --git a/src/query/v2/shard_request_manager.hpp b/src/query/v2/request_router.hpp similarity index 96% rename from src/query/v2/shard_request_manager.hpp rename to src/query/v2/request_router.hpp index 68a10f384..86aae6bcc 100644 --- a/src/query/v2/shard_request_manager.hpp +++ b/src/query/v2/request_router.hpp @@ -83,10 +83,10 @@ struct ExecutionState { // CompoundKey is optional because some operators require to iterate over all the available keys // of a shard. One example is ScanAll, where we only require the field label. std::optional<CompoundKey> key; - // Transaction id to be filled by the ShardRequestManager implementation + // Transaction id to be filled by the RequestRouter implementation coordinator::Hlc transaction_id; - // Initialized by ShardRequestManager implementation. This vector is filled with the shards that - // the ShardRequestManager impl will send requests to. When a request to a shard exhausts it, meaning that + // Initialized by RequestRouter implementation. This vector is filled with the shards that + // the RequestRouter impl will send requests to. When a request to a shard exhausts it, meaning that // it pulled all the requested data from the given Shard, it will be removed from the Vector. When the Vector becomes // empty, it means that all of the requests have completed succefully. // TODO(gvolfing) @@ -101,16 +101,16 @@ struct ExecutionState { State state = INITIALIZING; }; -class ShardRequestManagerInterface { +class RequestRouterInterface { public: using VertexAccessor = query::v2::accessors::VertexAccessor; - ShardRequestManagerInterface() = default; - ShardRequestManagerInterface(const ShardRequestManagerInterface &) = delete; - ShardRequestManagerInterface(ShardRequestManagerInterface &&) = delete; - ShardRequestManagerInterface &operator=(const ShardRequestManagerInterface &) = delete; - ShardRequestManagerInterface &&operator=(ShardRequestManagerInterface &&) = delete; + RequestRouterInterface() = default; + RequestRouterInterface(const RequestRouterInterface &) = delete; + RequestRouterInterface(RequestRouterInterface &&) = delete; + RequestRouterInterface &operator=(const RequestRouterInterface &) = delete; + RequestRouterInterface &&operator=(RequestRouterInterface &&) = delete; - virtual ~ShardRequestManagerInterface() = default; + virtual ~RequestRouterInterface() = default; virtual void StartTransaction() = 0; virtual void Commit() = 0; @@ -134,7 +134,7 @@ class ShardRequestManagerInterface { // TODO(kostasrim)rename this class template template <typename TTransport> -class ShardRequestManager : public ShardRequestManagerInterface { +class RequestRouter : public RequestRouterInterface { public: using StorageClient = coordinator::RsmClient<TTransport, msgs::WriteRequests, msgs::WriteResponses, msgs::ReadRequests, msgs::ReadResponses>; @@ -145,15 +145,14 @@ class ShardRequestManager : public ShardRequestManagerInterface { using ShardMap = coordinator::ShardMap; using CompoundKey = coordinator::PrimaryKey; using VertexAccessor = query::v2::accessors::VertexAccessor; - ShardRequestManager(CoordinatorClient coord, io::Io<TTransport> &&io) - : coord_cli_(std::move(coord)), io_(std::move(io)) {} + RequestRouter(CoordinatorClient coord, io::Io<TTransport> &&io) : coord_cli_(std::move(coord)), io_(std::move(io)) {} - ShardRequestManager(const ShardRequestManager &) = delete; - ShardRequestManager(ShardRequestManager &&) = delete; - ShardRequestManager &operator=(const ShardRequestManager &) = delete; - ShardRequestManager &operator=(ShardRequestManager &&) = delete; + RequestRouter(const RequestRouter &) = delete; + RequestRouter(RequestRouter &&) = delete; + RequestRouter &operator=(const RequestRouter &) = delete; + RequestRouter &operator=(RequestRouter &&) = delete; - ~ShardRequestManager() override {} + ~RequestRouter() override {} void StartTransaction() override { coordinator::HlcRequest req{.last_shard_map_version = shards_map_.GetHlc()}; diff --git a/tests/simulation/shard_request_manager.cpp b/tests/simulation/request_router.cpp similarity index 94% rename from tests/simulation/shard_request_manager.cpp rename to tests/simulation/request_router.cpp index 9db18659e..ddd9351ae 100644 --- a/tests/simulation/shard_request_manager.cpp +++ b/tests/simulation/request_router.cpp @@ -31,8 +31,8 @@ #include "io/simulator/simulator_transport.hpp" #include "query/v2/accessors.hpp" #include "query/v2/conversions.hpp" +#include "query/v2/request_router.hpp" #include "query/v2/requests.hpp" -#include "query/v2/shard_request_manager.hpp" #include "storage/v3/property_value.hpp" #include "utils/result.hpp" @@ -151,7 +151,7 @@ void RunStorageRaft(Raft<IoImpl, MockedShardRsm, WriteRequests, WriteResponses, server.Run(); } -void TestScanVertices(query::v2::ShardRequestManagerInterface &io) { +void TestScanVertices(query::v2::RequestRouterInterface &io) { msgs::ExecutionState<ScanVerticesRequest> state{.label = "test_label"}; auto result = io.Request(state); @@ -171,7 +171,7 @@ void TestScanVertices(query::v2::ShardRequestManagerInterface &io) { } } -void TestCreateVertices(query::v2::ShardRequestManagerInterface &io) { +void TestCreateVertices(query::v2::RequestRouterInterface &io) { using PropVal = msgs::Value; msgs::ExecutionState<CreateVerticesRequest> state; std::vector<msgs::NewVertex> new_vertices; @@ -187,7 +187,7 @@ void TestCreateVertices(query::v2::ShardRequestManagerInterface &io) { MG_ASSERT(result.size() == 2); } -void TestCreateExpand(query::v2::ShardRequestManagerInterface &io) { +void TestCreateExpand(query::v2::RequestRouterInterface &io) { using PropVal = msgs::Value; msgs::ExecutionState<msgs::CreateExpandRequest> state; std::vector<msgs::NewExpand> new_expands; @@ -209,20 +209,20 @@ void TestCreateExpand(query::v2::ShardRequestManagerInterface &io) { MG_ASSERT(responses[1].success); } -void TestExpandOne(query::v2::ShardRequestManagerInterface &shard_request_manager) { +void TestExpandOne(query::v2::RequestRouterInterface &request_router) { msgs::ExecutionState<msgs::ExpandOneRequest> state{}; msgs::ExpandOneRequest request; - const auto edge_type_id = shard_request_manager.NameToEdgeType("edge_type"); - const auto label = msgs::Label{shard_request_manager.NameToLabel("test_label")}; + const auto edge_type_id = request_router.NameToEdgeType("edge_type"); + const auto label = msgs::Label{request_router.NameToLabel("test_label")}; request.src_vertices.push_back(msgs::VertexId{label, {msgs::Value(int64_t(0)), msgs::Value(int64_t(0))}}); request.edge_types.push_back(msgs::EdgeType{edge_type_id}); request.direction = msgs::EdgeDirection::BOTH; - auto result_rows = shard_request_manager.Request(state, std::move(request)); + auto result_rows = request_router.Request(state, std::move(request)); MG_ASSERT(result_rows.size() == 2); } -template <typename ShardRequestManager> -void TestAggregate(ShardRequestManager &io) {} +template <typename RequestRouter> +void TestAggregate(RequestRouter &io) {} void DoTest() { SimulatorConfig config{ @@ -337,7 +337,7 @@ void DoTest() { // also get the current shard map CoordinatorClient<SimulatorTransport> coordinator_client(cli_io, c_addrs[0], c_addrs); - query::v2::ShardRequestManager<SimulatorTransport> io(std::move(coordinator_client), std::move(cli_io)); + query::v2::RequestRouter<SimulatorTransport> io(std::move(coordinator_client), std::move(cli_io)); io.StartTransaction(); TestScanVertices(io); diff --git a/tests/simulation/test_cluster.hpp b/tests/simulation/test_cluster.hpp index fd62b99f9..99f617cda 100644 --- a/tests/simulation/test_cluster.hpp +++ b/tests/simulation/test_cluster.hpp @@ -30,8 +30,8 @@ #include "io/simulator/simulator_transport.hpp" #include "machine_manager/machine_config.hpp" #include "machine_manager/machine_manager.hpp" +#include "query/v2/request_router.hpp" #include "query/v2/requests.hpp" -#include "query/v2/shard_request_manager.hpp" #include "testing_constants.hpp" #include "utils/print_helpers.hpp" #include "utils/variant_helpers.hpp" @@ -151,8 +151,8 @@ ShardMap TestShardMap(int n_splits, int replication_factor) { return sm; } -void ExecuteOp(query::v2::ShardRequestManager<SimulatorTransport> &shard_request_manager, - std::set<CompoundKey> &correctness_model, CreateVertex create_vertex) { +void ExecuteOp(query::v2::RequestRouter<SimulatorTransport> &request_router, std::set<CompoundKey> &correctness_model, + CreateVertex create_vertex) { const auto key1 = memgraph::storage::v3::PropertyValue(create_vertex.first); const auto key2 = memgraph::storage::v3::PropertyValue(create_vertex.second); @@ -166,7 +166,7 @@ void ExecuteOp(query::v2::ShardRequestManager<SimulatorTransport> &shard_request query::v2::ExecutionState<msgs::CreateVerticesRequest> state; - auto label_id = shard_request_manager.NameToLabel("test_label"); + auto label_id = request_router.NameToLabel("test_label"); msgs::NewVertex nv{.primary_key = primary_key}; nv.label_ids.push_back({label_id}); @@ -174,7 +174,7 @@ void ExecuteOp(query::v2::ShardRequestManager<SimulatorTransport> &shard_request std::vector<msgs::NewVertex> new_vertices; new_vertices.push_back(std::move(nv)); - auto result = shard_request_manager.Request(state, std::move(new_vertices)); + auto result = request_router.Request(state, std::move(new_vertices)); RC_ASSERT(result.size() == 1); RC_ASSERT(!result[0].error.has_value()); @@ -182,11 +182,11 @@ void ExecuteOp(query::v2::ShardRequestManager<SimulatorTransport> &shard_request correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(query::v2::ShardRequestManager<SimulatorTransport> &shard_request_manager, - std::set<CompoundKey> &correctness_model, ScanAll scan_all) { +void ExecuteOp(query::v2::RequestRouter<SimulatorTransport> &request_router, std::set<CompoundKey> &correctness_model, + ScanAll scan_all) { query::v2::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; - auto results = shard_request_manager.Request(request); + auto results = request_router.Request(request); RC_ASSERT(results.size() == correctness_model.size()); @@ -247,15 +247,14 @@ std::pair<SimulatorStats, LatencyHistogramSummaries> RunClusterSimulation(const CoordinatorClient<SimulatorTransport> coordinator_client(cli_io, coordinator_address, {coordinator_address}); WaitForShardsToInitialize(coordinator_client); - query::v2::ShardRequestManager<SimulatorTransport> shard_request_manager(std::move(coordinator_client), - std::move(cli_io)); + query::v2::RequestRouter<SimulatorTransport> request_router(std::move(coordinator_client), std::move(cli_io)); - shard_request_manager.StartTransaction(); + request_router.StartTransaction(); auto correctness_model = std::set<CompoundKey>{}; for (const Op &op : ops) { - std::visit([&](auto &o) { ExecuteOp(shard_request_manager, correctness_model, o); }, op.inner); + std::visit([&](auto &o) { ExecuteOp(request_router, correctness_model, o); }, op.inner); } // We have now completed our workload without failing any assertions, so we can diff --git a/tests/unit/high_density_shard_create_scan.cpp b/tests/unit/high_density_shard_create_scan.cpp index e586a3556..22af9c702 100644 --- a/tests/unit/high_density_shard_create_scan.cpp +++ b/tests/unit/high_density_shard_create_scan.cpp @@ -29,8 +29,8 @@ #include "io/simulator/simulator_transport.hpp" #include "machine_manager/machine_config.hpp" #include "machine_manager/machine_manager.hpp" +#include "query/v2/request_router.hpp" #include "query/v2/requests.hpp" -#include "query/v2/shard_request_manager.hpp" #include "utils/variant_helpers.hpp" namespace memgraph::tests::simulation { @@ -161,8 +161,8 @@ ShardMap TestShardMap(int shards, int replication_factor, int gap_between_shards return sm; } -void ExecuteOp(query::v2::ShardRequestManager<LocalTransport> &shard_request_manager, - std::set<CompoundKey> &correctness_model, CreateVertex create_vertex) { +void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::set<CompoundKey> &correctness_model, + CreateVertex create_vertex) { const auto key1 = memgraph::storage::v3::PropertyValue(create_vertex.first); const auto key2 = memgraph::storage::v3::PropertyValue(create_vertex.second); @@ -176,7 +176,7 @@ void ExecuteOp(query::v2::ShardRequestManager<LocalTransport> &shard_request_man query::v2::ExecutionState<msgs::CreateVerticesRequest> state; - auto label_id = shard_request_manager.NameToLabel("test_label"); + auto label_id = request_router.NameToLabel("test_label"); msgs::NewVertex nv{.primary_key = primary_key}; nv.label_ids.push_back({label_id}); @@ -184,7 +184,7 @@ void ExecuteOp(query::v2::ShardRequestManager<LocalTransport> &shard_request_man std::vector<msgs::NewVertex> new_vertices; new_vertices.push_back(std::move(nv)); - auto result = shard_request_manager.Request(state, std::move(new_vertices)); + auto result = request_router.Request(state, std::move(new_vertices)); MG_ASSERT(result.size() == 1); MG_ASSERT(!result[0].error.has_value()); @@ -192,11 +192,11 @@ void ExecuteOp(query::v2::ShardRequestManager<LocalTransport> &shard_request_man correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(query::v2::ShardRequestManager<LocalTransport> &shard_request_manager, - std::set<CompoundKey> &correctness_model, ScanAll scan_all) { +void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::set<CompoundKey> &correctness_model, + ScanAll scan_all) { query::v2::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; - auto results = shard_request_manager.Request(request); + auto results = request_router.Request(request); MG_ASSERT(results.size() == correctness_model.size()); @@ -245,23 +245,22 @@ void RunWorkload(int shards, int replication_factor, int create_ops, int scan_op WaitForShardsToInitialize(coordinator_client); auto time_after_shard_stabilization = cli_io_2.Now(); - query::v2::ShardRequestManager<LocalTransport> shard_request_manager(std::move(coordinator_client), - std::move(cli_io)); + query::v2::RequestRouter<LocalTransport> request_router(std::move(coordinator_client), std::move(cli_io)); - shard_request_manager.StartTransaction(); + request_router.StartTransaction(); auto correctness_model = std::set<CompoundKey>{}; auto time_before_creates = cli_io_2.Now(); for (int i = 0; i < create_ops; i++) { - ExecuteOp(shard_request_manager, correctness_model, CreateVertex{.first = i, .second = i}); + ExecuteOp(request_router, correctness_model, CreateVertex{.first = i, .second = i}); } auto time_after_creates = cli_io_2.Now(); for (int i = 0; i < scan_ops; i++) { - ExecuteOp(shard_request_manager, correctness_model, ScanAll{}); + ExecuteOp(request_router, correctness_model, ScanAll{}); } auto time_after_scan = cli_io_2.Now(); diff --git a/tests/unit/machine_manager.cpp b/tests/unit/machine_manager.cpp index 834523fee..0b081e5a1 100644 --- a/tests/unit/machine_manager.cpp +++ b/tests/unit/machine_manager.cpp @@ -27,7 +27,7 @@ #include <machine_manager/machine_manager.hpp> #include <query/v2/requests.hpp> #include "io/rsm/rsm_client.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "storage/v3/id_types.hpp" #include "storage/v3/schemas.hpp" @@ -109,19 +109,19 @@ ShardMap TestShardMap() { return sm; } -template <typename ShardRequestManager> -void TestScanAll(ShardRequestManager &shard_request_manager) { +template <typename RequestRouter> +void TestScanAll(RequestRouter &request_router) { query::v2::ExecutionState<msgs::ScanVerticesRequest> state{.label = kLabelName}; - auto result = shard_request_manager.Request(state); + auto result = request_router.Request(state); EXPECT_EQ(result.size(), 2); } -void TestCreateVertices(query::v2::ShardRequestManagerInterface &shard_request_manager) { +void TestCreateVertices(query::v2::RequestRouterInterface &request_router) { using PropVal = msgs::Value; query::v2::ExecutionState<msgs::CreateVerticesRequest> state; std::vector<msgs::NewVertex> new_vertices; - auto label_id = shard_request_manager.NameToLabel(kLabelName); + auto label_id = request_router.NameToLabel(kLabelName); msgs::NewVertex a1{.primary_key = {PropVal(int64_t(0)), PropVal(int64_t(0))}}; a1.label_ids.push_back({label_id}); msgs::NewVertex a2{.primary_key = {PropVal(int64_t(13)), PropVal(int64_t(13))}}; @@ -129,18 +129,18 @@ void TestCreateVertices(query::v2::ShardRequestManagerInterface &shard_request_m new_vertices.push_back(std::move(a1)); new_vertices.push_back(std::move(a2)); - auto result = shard_request_manager.Request(state, std::move(new_vertices)); + auto result = request_router.Request(state, std::move(new_vertices)); EXPECT_EQ(result.size(), 1); EXPECT_FALSE(result[0].error.has_value()) << result[0].error->message; } -void TestCreateExpand(query::v2::ShardRequestManagerInterface &shard_request_manager) { +void TestCreateExpand(query::v2::RequestRouterInterface &request_router) { using PropVal = msgs::Value; query::v2::ExecutionState<msgs::CreateExpandRequest> state; std::vector<msgs::NewExpand> new_expands; - const auto edge_type_id = shard_request_manager.NameToEdgeType("edge_type"); - const auto label = msgs::Label{shard_request_manager.NameToLabel("test_label")}; + const auto edge_type_id = request_router.NameToEdgeType("edge_type"); + const auto label = msgs::Label{request_router.NameToLabel("test_label")}; const msgs::VertexId vertex_id_1{label, {PropVal(int64_t(0)), PropVal(int64_t(0))}}; const msgs::VertexId vertex_id_2{label, {PropVal(int64_t(13)), PropVal(int64_t(13))}}; msgs::NewExpand expand_1{ @@ -150,27 +150,27 @@ void TestCreateExpand(query::v2::ShardRequestManagerInterface &shard_request_man new_expands.push_back(std::move(expand_1)); new_expands.push_back(std::move(expand_2)); - auto responses = shard_request_manager.Request(state, std::move(new_expands)); + auto responses = request_router.Request(state, std::move(new_expands)); MG_ASSERT(responses.size() == 1); MG_ASSERT(!responses[0].error.has_value()); } -void TestExpandOne(query::v2::ShardRequestManagerInterface &shard_request_manager) { +void TestExpandOne(query::v2::RequestRouterInterface &request_router) { query::v2::ExecutionState<msgs::ExpandOneRequest> state{}; msgs::ExpandOneRequest request; - const auto edge_type_id = shard_request_manager.NameToEdgeType("edge_type"); - const auto label = msgs::Label{shard_request_manager.NameToLabel("test_label")}; + const auto edge_type_id = request_router.NameToEdgeType("edge_type"); + const auto label = msgs::Label{request_router.NameToLabel("test_label")}; request.src_vertices.push_back(msgs::VertexId{label, {msgs::Value(int64_t(0)), msgs::Value(int64_t(0))}}); request.edge_types.push_back(msgs::EdgeType{edge_type_id}); request.direction = msgs::EdgeDirection::BOTH; - auto result_rows = shard_request_manager.Request(state, std::move(request)); + auto result_rows = request_router.Request(state, std::move(request)); MG_ASSERT(result_rows.size() == 1); MG_ASSERT(result_rows[0].in_edges_with_all_properties.size() == 1); MG_ASSERT(result_rows[0].out_edges_with_all_properties.size() == 1); } -template <typename ShardRequestManager> -void TestAggregate(ShardRequestManager &shard_request_manager) {} +template <typename RequestRouter> +void TestAggregate(RequestRouter &request_router) {} MachineManager<LocalTransport> MkMm(LocalSystem &local_system, std::vector<Address> coordinator_addresses, Address addr, ShardMap shard_map) { @@ -226,14 +226,13 @@ TEST(MachineManager, BasicFunctionality) { CoordinatorClient<LocalTransport> coordinator_client(cli_io, coordinator_address, {coordinator_address}); - query::v2::ShardRequestManager<LocalTransport> shard_request_manager(std::move(coordinator_client), - std::move(cli_io)); + query::v2::RequestRouter<LocalTransport> request_router(std::move(coordinator_client), std::move(cli_io)); - shard_request_manager.StartTransaction(); - TestCreateVertices(shard_request_manager); - TestScanAll(shard_request_manager); - TestCreateExpand(shard_request_manager); - TestExpandOne(shard_request_manager); + request_router.StartTransaction(); + TestCreateVertices(request_router); + TestScanAll(request_router); + TestCreateExpand(request_router); + TestExpandOne(request_router); local_system.ShutDown(); }; From 9fc7f9dcedb42eb233eefc3ff3ca2aabba42ed59 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Mon, 28 Nov 2022 13:03:07 +0000 Subject: [PATCH 14/26] Standardize RequestRouter variable names as request_router --- src/query/v2/accessors.cpp | 25 ++--- src/query/v2/accessors.hpp | 13 +-- src/query/v2/bindings/eval.hpp | 4 +- src/query/v2/conversions.hpp | 10 +- src/query/v2/cypher_query_interpreter.cpp | 8 +- src/query/v2/cypher_query_interpreter.hpp | 4 +- .../interpret/awesome_memgraph_functions.hpp | 2 +- src/query/v2/interpreter.cpp | 26 +++--- src/query/v2/plan/operator.cpp | 19 ++-- src/query/v2/plan/pretty_print.cpp | 92 +++++++++---------- src/query/v2/plan/pretty_print.hpp | 28 +++--- tests/simulation/request_router.cpp | 32 +++---- 12 files changed, 133 insertions(+), 130 deletions(-) diff --git a/src/query/v2/accessors.cpp b/src/query/v2/accessors.cpp index a28df0fe5..2eedfcf4d 100644 --- a/src/query/v2/accessors.cpp +++ b/src/query/v2/accessors.cpp @@ -15,15 +15,15 @@ #include "storage/v3/id_types.hpp" namespace memgraph::query::v2::accessors { -EdgeAccessor::EdgeAccessor(Edge edge, const RequestRouterInterface *manager) - : edge(std::move(edge)), manager_(manager) {} +EdgeAccessor::EdgeAccessor(Edge edge, const RequestRouterInterface *request_router) + : edge(std::move(edge)), request_router_(request_router) {} EdgeTypeId EdgeAccessor::EdgeType() const { return edge.type.id; } const std::vector<std::pair<PropertyId, Value>> &EdgeAccessor::Properties() const { return edge.properties; } Value EdgeAccessor::GetProperty(const std::string &prop_name) const { - auto prop_id = manager_->NameToProperty(prop_name); + auto prop_id = request_router_->NameToProperty(prop_name); auto it = std::find_if(edge.properties.begin(), edge.properties.end(), [&](auto &pr) { return prop_id == pr.first; }); if (it == edge.properties.end()) { return {}; @@ -36,19 +36,20 @@ const Edge &EdgeAccessor::GetEdge() const { return edge; } bool EdgeAccessor::IsCycle() const { return edge.src == edge.dst; }; VertexAccessor EdgeAccessor::To() const { - return VertexAccessor(Vertex{edge.dst}, std::vector<std::pair<PropertyId, msgs::Value>>{}, manager_); + return VertexAccessor(Vertex{edge.dst}, std::vector<std::pair<PropertyId, msgs::Value>>{}, request_router_); } VertexAccessor EdgeAccessor::From() const { - return VertexAccessor(Vertex{edge.src}, std::vector<std::pair<PropertyId, msgs::Value>>{}, manager_); + return VertexAccessor(Vertex{edge.src}, std::vector<std::pair<PropertyId, msgs::Value>>{}, request_router_); } VertexAccessor::VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, - const RequestRouterInterface *manager) - : vertex(std::move(v)), properties(std::move(props)), manager_(manager) {} + const RequestRouterInterface *request_router) + : vertex(std::move(v)), properties(std::move(props)), request_router_(request_router) {} -VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const RequestRouterInterface *manager) - : vertex(std::move(v)), manager_(manager) { +VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, + const RequestRouterInterface *request_router) + : vertex(std::move(v)), request_router_(request_router) { properties.reserve(props.size()); for (auto &[id, value] : props) { properties.emplace_back(std::make_pair(id, std::move(value))); @@ -56,8 +57,8 @@ VertexAccessor::VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, co } VertexAccessor::VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, - const RequestRouterInterface *manager) - : vertex(std::move(v)), manager_(manager) { + const RequestRouterInterface *request_router) + : vertex(std::move(v)), request_router_(request_router) { properties.reserve(props.size()); for (const auto &[id, value] : props) { properties.emplace_back(std::make_pair(id, value)); @@ -87,7 +88,7 @@ Value VertexAccessor::GetProperty(PropertyId prop_id) const { // NOLINTNEXTLINE(readability-convert-member-functions-to-static) Value VertexAccessor::GetProperty(const std::string &prop_name) const { - return GetProperty(manager_->NameToProperty(prop_name)); + return GetProperty(request_router_->NameToProperty(prop_name)); } msgs::Vertex VertexAccessor::GetVertex() const { return vertex; } diff --git a/src/query/v2/accessors.hpp b/src/query/v2/accessors.hpp index b5585953f..db22d29cc 100644 --- a/src/query/v2/accessors.hpp +++ b/src/query/v2/accessors.hpp @@ -41,7 +41,7 @@ class VertexAccessor; class EdgeAccessor final { public: - explicit EdgeAccessor(Edge edge, const RequestRouterInterface *manager); + explicit EdgeAccessor(Edge edge, const RequestRouterInterface *request_router); [[nodiscard]] EdgeTypeId EdgeType() const; @@ -69,7 +69,7 @@ class EdgeAccessor final { private: Edge edge; - const RequestRouterInterface *manager_; + const RequestRouterInterface *request_router_; }; class VertexAccessor final { @@ -77,10 +77,11 @@ class VertexAccessor final { using PropertyId = msgs::PropertyId; using Label = msgs::Label; using VertexId = msgs::VertexId; - VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, const RequestRouterInterface *manager); + VertexAccessor(Vertex v, std::vector<std::pair<PropertyId, Value>> props, + const RequestRouterInterface *request_router); - VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const RequestRouterInterface *manager); - VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, const RequestRouterInterface *manager); + VertexAccessor(Vertex v, std::map<PropertyId, Value> &&props, const RequestRouterInterface *request_router); + VertexAccessor(Vertex v, const std::map<PropertyId, Value> &props, const RequestRouterInterface *request_router); [[nodiscard]] Label PrimaryLabel() const; @@ -149,7 +150,7 @@ class VertexAccessor final { private: Vertex vertex; std::vector<std::pair<PropertyId, Value>> properties; - const RequestRouterInterface *manager_; + const RequestRouterInterface *request_router_; }; // inline VertexAccessor EdgeAccessor::To() const { return VertexAccessor(impl_.ToVertex()); } diff --git a/src/query/v2/bindings/eval.hpp b/src/query/v2/bindings/eval.hpp index 912850e87..c7f52f201 100644 --- a/src/query/v2/bindings/eval.hpp +++ b/src/query/v2/bindings/eval.hpp @@ -35,8 +35,8 @@ class Callable { auto operator()(const storage::v3::PropertyValue &val) const { return storage::v3::PropertyToTypedValue<TypedValue>(val); }; - auto operator()(const msgs::Value &val, RequestRouterInterface *manager) const { - return ValueToTypedValue(val, manager); + auto operator()(const msgs::Value &val, RequestRouterInterface *request_router) const { + return ValueToTypedValue(val, request_router); }; }; diff --git a/src/query/v2/conversions.hpp b/src/query/v2/conversions.hpp index 161f89979..ac052327d 100644 --- a/src/query/v2/conversions.hpp +++ b/src/query/v2/conversions.hpp @@ -17,7 +17,7 @@ namespace memgraph::query::v2 { -inline TypedValue ValueToTypedValue(const msgs::Value &value, RequestRouterInterface *manager) { +inline TypedValue ValueToTypedValue(const msgs::Value &value, RequestRouterInterface *request_router) { using Value = msgs::Value; switch (value.type) { case Value::Type::Null: @@ -35,7 +35,7 @@ inline TypedValue ValueToTypedValue(const msgs::Value &value, RequestRouterInter std::vector<TypedValue> dst; dst.reserve(lst.size()); for (const auto &elem : lst) { - dst.push_back(ValueToTypedValue(elem, manager)); + dst.push_back(ValueToTypedValue(elem, request_router)); } return TypedValue(std::move(dst)); } @@ -43,15 +43,15 @@ inline TypedValue ValueToTypedValue(const msgs::Value &value, RequestRouterInter const auto &value_map = value.map_v; std::map<std::string, TypedValue> dst; for (const auto &[key, val] : value_map) { - dst[key] = ValueToTypedValue(val, manager); + dst[key] = ValueToTypedValue(val, request_router); } return TypedValue(std::move(dst)); } case Value::Type::Vertex: return TypedValue(accessors::VertexAccessor( - value.vertex_v, std::vector<std::pair<storage::v3::PropertyId, msgs::Value>>{}, manager)); + value.vertex_v, std::vector<std::pair<storage::v3::PropertyId, msgs::Value>>{}, request_router)); case Value::Type::Edge: - return TypedValue(accessors::EdgeAccessor(value.edge_v, manager)); + return TypedValue(accessors::EdgeAccessor(value.edge_v, request_router)); } throw std::runtime_error("Incorrect type in conversion"); } diff --git a/src/query/v2/cypher_query_interpreter.cpp b/src/query/v2/cypher_query_interpreter.cpp index 880165ad8..f3f8e48d7 100644 --- a/src/query/v2/cypher_query_interpreter.cpp +++ b/src/query/v2/cypher_query_interpreter.cpp @@ -118,9 +118,9 @@ ParsedQuery ParseQuery(const std::string &query_string, const std::map<std::stri } std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector<Identifier *> &predefined_identifiers) { - auto vertex_counts = plan::MakeVertexCountCache(shard_manager); + auto vertex_counts = plan::MakeVertexCountCache(request_router); auto symbol_table = expr::MakeSymbolTable(query, predefined_identifiers); auto planning_context = plan::MakePlanningContext(&ast_storage, &symbol_table, query, &vertex_counts); auto [root, cost] = plan::MakeLogicalPlan(&planning_context, parameters, FLAGS_query_cost_planner); @@ -130,7 +130,7 @@ std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery std::shared_ptr<CachedPlan> CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList<PlanCacheEntry> *plan_cache, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector<Identifier *> &predefined_identifiers) { std::optional<utils::SkipList<PlanCacheEntry>::Accessor> plan_cache_access; if (plan_cache) { @@ -146,7 +146,7 @@ std::shared_ptr<CachedPlan> CypherQueryToPlan(uint64_t hash, AstStorage ast_stor } auto plan = std::make_shared<CachedPlan>( - MakeLogicalPlan(std::move(ast_storage), query, parameters, shard_manager, predefined_identifiers)); + MakeLogicalPlan(std::move(ast_storage), query, parameters, request_router, predefined_identifiers)); if (plan_cache_access) { plan_cache_access->insert({hash, plan}); } diff --git a/src/query/v2/cypher_query_interpreter.hpp b/src/query/v2/cypher_query_interpreter.hpp index c9d65047c..688e52fed 100644 --- a/src/query/v2/cypher_query_interpreter.hpp +++ b/src/query/v2/cypher_query_interpreter.hpp @@ -132,7 +132,7 @@ class SingleNodeLogicalPlan final : public LogicalPlan { }; std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector<Identifier *> &predefined_identifiers); /** @@ -145,7 +145,7 @@ std::unique_ptr<LogicalPlan> MakeLogicalPlan(AstStorage ast_storage, CypherQuery */ std::shared_ptr<CachedPlan> CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList<PlanCacheEntry> *plan_cache, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector<Identifier *> &predefined_identifiers = {}); } // namespace memgraph::query::v2 diff --git a/src/query/v2/interpret/awesome_memgraph_functions.hpp b/src/query/v2/interpret/awesome_memgraph_functions.hpp index 35ed1d797..8ca3eacb3 100644 --- a/src/query/v2/interpret/awesome_memgraph_functions.hpp +++ b/src/query/v2/interpret/awesome_memgraph_functions.hpp @@ -34,7 +34,7 @@ const char kId[] = "ID"; struct FunctionContext { // TODO(kostasrim) consider optional here. RequestRouter does not exist on the storage. // DbAccessor *db_accessor; - RequestRouterInterface *manager; + RequestRouterInterface *request_router; utils::MemoryResource *memory; int64_t timestamp; std::unordered_map<std::string, int64_t> *counters; diff --git a/src/query/v2/interpreter.cpp b/src/query/v2/interpreter.cpp index 94ff7a8ff..1c2d6dadf 100644 --- a/src/query/v2/interpreter.cpp +++ b/src/query/v2/interpreter.cpp @@ -143,7 +143,7 @@ class ReplQueryHandler final : public query::v2::ReplicationQueryHandler { /// @throw QueryRuntimeException if an error ocurred. Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Parameters ¶meters, - RequestRouterInterface *manager) { + RequestRouterInterface *request_router) { // Empty frame for evaluation of password expression. This is OK since // password should be either null or string literal and it's evaluation // should not depend on frame. @@ -154,7 +154,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa // the argument to Callback. evaluation_context.timestamp = QueryTimestamp(); evaluation_context.parameters = parameters; - ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, manager, storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, request_router, storage::v3::View::OLD); std::string username = auth_query->user_; std::string rolename = auth_query->role_; @@ -312,7 +312,7 @@ Callback HandleAuthQuery(AuthQuery *auth_query, AuthQueryHandler *auth, const Pa } Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters ¶meters, - InterpreterContext *interpreter_context, RequestRouterInterface *manager, + InterpreterContext *interpreter_context, RequestRouterInterface *request_router, std::vector<Notification> *notifications) { expr::Frame<TypedValue> frame(0); SymbolTable symbol_table; @@ -321,7 +321,7 @@ Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters & // the argument to Callback. evaluation_context.timestamp = QueryTimestamp(); evaluation_context.parameters = parameters; - ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, manager, storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, request_router, storage::v3::View::OLD); Callback callback; switch (repl_query->action_) { @@ -448,7 +448,7 @@ Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters & } Callback HandleSettingQuery(SettingQuery *setting_query, const Parameters ¶meters, - RequestRouterInterface *manager) { + RequestRouterInterface *request_router) { expr::Frame<TypedValue> frame(0); SymbolTable symbol_table; EvaluationContext evaluation_context; @@ -458,7 +458,7 @@ Callback HandleSettingQuery(SettingQuery *setting_query, const Parameters ¶m std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()) .count(); evaluation_context.parameters = parameters; - ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, manager, storage::v3::View::OLD); + ExpressionEvaluator evaluator(&frame, symbol_table, evaluation_context, request_router, storage::v3::View::OLD); Callback callback; switch (setting_query->action_) { @@ -1182,14 +1182,14 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans PreparedQuery PrepareAuthQuery(ParsedQuery parsed_query, bool in_explicit_transaction, std::map<std::string, TypedValue> *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, - RequestRouterInterface *manager) { + RequestRouterInterface *request_router) { if (in_explicit_transaction) { throw UserModificationInMulticommandTxException(); } auto *auth_query = utils::Downcast<AuthQuery>(parsed_query.query); - auto callback = HandleAuthQuery(auth_query, interpreter_context->auth, parsed_query.parameters, manager); + auto callback = HandleAuthQuery(auth_query, interpreter_context->auth, parsed_query.parameters, request_router); SymbolTable symbol_table; std::vector<Symbol> output_symbols; @@ -1218,14 +1218,14 @@ PreparedQuery PrepareAuthQuery(ParsedQuery parsed_query, bool in_explicit_transa PreparedQuery PrepareReplicationQuery(ParsedQuery parsed_query, const bool in_explicit_transaction, std::vector<Notification> *notifications, InterpreterContext *interpreter_context, - RequestRouterInterface *manager) { + RequestRouterInterface *request_router) { if (in_explicit_transaction) { throw ReplicationModificationInMulticommandTxException(); } auto *replication_query = utils::Downcast<ReplicationQuery>(parsed_query.query); - auto callback = - HandleReplicationQuery(replication_query, parsed_query.parameters, interpreter_context, manager, notifications); + auto callback = HandleReplicationQuery(replication_query, parsed_query.parameters, interpreter_context, + request_router, notifications); return PreparedQuery{callback.header, std::move(parsed_query.required_privileges), [callback_fn = std::move(callback.fn), pull_plan = std::shared_ptr<PullPlanVector>{nullptr}]( @@ -1314,14 +1314,14 @@ PreparedQuery PrepareCreateSnapshotQuery(ParsedQuery parsed_query, bool in_expli } PreparedQuery PrepareSettingQuery(ParsedQuery parsed_query, const bool in_explicit_transaction, - RequestRouterInterface *manager) { + RequestRouterInterface *request_router) { if (in_explicit_transaction) { throw SettingConfigInMulticommandTxException{}; } auto *setting_query = utils::Downcast<SettingQuery>(parsed_query.query); MG_ASSERT(setting_query); - auto callback = HandleSettingQuery(setting_query, parsed_query.parameters, manager); + auto callback = HandleSettingQuery(setting_query, parsed_query.parameters, request_router); return PreparedQuery{std::move(callback.header), std::move(parsed_query.required_privileges), [callback_fn = std::move(callback.fn), pull_plan = std::shared_ptr<PullPlanVector>{nullptr}]( diff --git a/src/query/v2/plan/operator.cpp b/src/query/v2/plan/operator.cpp index 2d2849f0d..014be0d62 100644 --- a/src/query/v2/plan/operator.cpp +++ b/src/query/v2/plan/operator.cpp @@ -177,10 +177,10 @@ class DistributedCreateNodeCursor : public Cursor { bool Pull(Frame &frame, ExecutionContext &context) override { SCOPED_PROFILE_OP("CreateNode"); if (input_cursor_->Pull(frame, context)) { - auto &shard_manager = context.request_router; + auto &request_router = context.request_router; { SCOPED_REQUEST_WAIT_PROFILE; - shard_manager->Request(state_, NodeCreationInfoToRequest(context, frame)); + request_router->Request(state_, NodeCreationInfoToRequest(context, frame)); } PlaceNodeOnTheFrame(frame, context); return true; @@ -386,10 +386,10 @@ class DistributedScanAllAndFilterCursor : public Cursor { using VertexAccessor = accessors::VertexAccessor; - bool MakeRequest(RequestRouterInterface &shard_manager, ExecutionContext &context) { + bool MakeRequest(RequestRouterInterface &request_router, ExecutionContext &context) { { SCOPED_REQUEST_WAIT_PROFILE; - current_batch = shard_manager.Request(request_state_); + current_batch = request_router.Request(request_state_); } current_vertex_it = current_batch.begin(); return !current_batch.empty(); @@ -398,7 +398,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { bool Pull(Frame &frame, ExecutionContext &context) override { SCOPED_PROFILE_OP(op_name_); - auto &shard_manager = *context.request_router; + auto &request_router = *context.request_router; while (true) { if (MustAbort(context)) { throw HintedAbortError(); @@ -411,10 +411,11 @@ class DistributedScanAllAndFilterCursor : public Cursor { } } - request_state_.label = label_.has_value() ? std::make_optional(shard_manager.LabelToName(*label_)) : std::nullopt; + request_state_.label = + label_.has_value() ? std::make_optional(request_router.LabelToName(*label_)) : std::nullopt; if (current_vertex_it == current_batch.end() && - (request_state_.state == State::COMPLETED || !MakeRequest(shard_manager, context))) { + (request_state_.state == State::COMPLETED || !MakeRequest(request_router, context))) { ResetExecutionState(); continue; } @@ -2338,11 +2339,11 @@ class DistributedCreateExpandCursor : public Cursor { if (!input_cursor_->Pull(frame, context)) { return false; } - auto &shard_manager = context.request_router; + auto &request_router = context.request_router; ResetExecutionState(); { SCOPED_REQUEST_WAIT_PROFILE; - shard_manager->Request(state_, ExpandCreationInfoToRequest(context, frame)); + request_router->Request(state_, ExpandCreationInfoToRequest(context, frame)); } return true; } diff --git a/src/query/v2/plan/pretty_print.cpp b/src/query/v2/plan/pretty_print.cpp index 0e8d09e2b..bc30a3890 100644 --- a/src/query/v2/plan/pretty_print.cpp +++ b/src/query/v2/plan/pretty_print.cpp @@ -19,8 +19,8 @@ namespace memgraph::query::v2::plan { -PlanPrinter::PlanPrinter(const RequestRouterInterface *request_manager, std::ostream *out) - : request_manager_(request_manager), out_(out) {} +PlanPrinter::PlanPrinter(const RequestRouterInterface *request_router, std::ostream *out) + : request_router_(request_router), out_(out) {} #define PRE_VISIT(TOp) \ bool PlanPrinter::PreVisit(TOp &) { \ @@ -34,7 +34,7 @@ bool PlanPrinter::PreVisit(CreateExpand &op) { WithPrintLn([&](auto &out) { out << "* CreateExpand (" << op.input_symbol_.name() << ")" << (op.edge_info_.direction == query::v2::EdgeAtom::Direction::IN ? "<-" : "-") << "[" - << op.edge_info_.symbol.name() << ":" << request_manager_->EdgeTypeToName(op.edge_info_.edge_type) << "]" + << op.edge_info_.symbol.name() << ":" << request_router_->EdgeTypeToName(op.edge_info_.edge_type) << "]" << (op.edge_info_.direction == query::v2::EdgeAtom::Direction::OUT ? "->" : "-") << "(" << op.node_info_.symbol.name() << ")"; }); @@ -54,7 +54,7 @@ bool PlanPrinter::PreVisit(query::v2::plan::ScanAll &op) { bool PlanPrinter::PreVisit(query::v2::plan::ScanAllByLabel &op) { WithPrintLn([&](auto &out) { out << "* ScanAllByLabel" - << " (" << op.output_symbol_.name() << " :" << request_manager_->LabelToName(op.label_) << ")"; + << " (" << op.output_symbol_.name() << " :" << request_router_->LabelToName(op.label_) << ")"; }); return true; } @@ -62,8 +62,8 @@ bool PlanPrinter::PreVisit(query::v2::plan::ScanAllByLabel &op) { bool PlanPrinter::PreVisit(query::v2::plan::ScanAllByLabelPropertyValue &op) { WithPrintLn([&](auto &out) { out << "* ScanAllByLabelPropertyValue" - << " (" << op.output_symbol_.name() << " :" << request_manager_->LabelToName(op.label_) << " {" - << request_manager_->PropertyToName(op.property_) << "})"; + << " (" << op.output_symbol_.name() << " :" << request_router_->LabelToName(op.label_) << " {" + << request_router_->PropertyToName(op.property_) << "})"; }); return true; } @@ -71,8 +71,8 @@ bool PlanPrinter::PreVisit(query::v2::plan::ScanAllByLabelPropertyValue &op) { bool PlanPrinter::PreVisit(query::v2::plan::ScanAllByLabelPropertyRange &op) { WithPrintLn([&](auto &out) { out << "* ScanAllByLabelPropertyRange" - << " (" << op.output_symbol_.name() << " :" << request_manager_->LabelToName(op.label_) << " {" - << request_manager_->PropertyToName(op.property_) << "})"; + << " (" << op.output_symbol_.name() << " :" << request_router_->LabelToName(op.label_) << " {" + << request_router_->PropertyToName(op.property_) << "})"; }); return true; } @@ -80,8 +80,8 @@ bool PlanPrinter::PreVisit(query::v2::plan::ScanAllByLabelPropertyRange &op) { bool PlanPrinter::PreVisit(query::v2::plan::ScanAllByLabelProperty &op) { WithPrintLn([&](auto &out) { out << "* ScanAllByLabelProperty" - << " (" << op.output_symbol_.name() << " :" << request_manager_->LabelToName(op.label_) << " {" - << request_manager_->PropertyToName(op.property_) << "})"; + << " (" << op.output_symbol_.name() << " :" << request_router_->LabelToName(op.label_) << " {" + << request_router_->PropertyToName(op.property_) << "})"; }); return true; } @@ -100,7 +100,7 @@ bool PlanPrinter::PreVisit(query::v2::plan::Expand &op) { << (op.common_.direction == query::v2::EdgeAtom::Direction::IN ? "<-" : "-") << "[" << op.common_.edge_symbol.name(); utils::PrintIterable(*out_, op.common_.edge_types, "|", [this](auto &stream, const auto &edge_type) { - stream << ":" << request_manager_->EdgeTypeToName(edge_type); + stream << ":" << request_router_->EdgeTypeToName(edge_type); }); *out_ << "]" << (op.common_.direction == query::v2::EdgeAtom::Direction::OUT ? "->" : "-") << "(" << op.common_.node_symbol.name() << ")"; @@ -129,7 +129,7 @@ bool PlanPrinter::PreVisit(query::v2::plan::ExpandVariable &op) { << (op.common_.direction == query::v2::EdgeAtom::Direction::IN ? "<-" : "-") << "[" << op.common_.edge_symbol.name(); utils::PrintIterable(*out_, op.common_.edge_types, "|", [this](auto &stream, const auto &edge_type) { - stream << ":" << request_manager_->EdgeTypeToName(edge_type); + stream << ":" << request_router_->EdgeTypeToName(edge_type); }); *out_ << "]" << (op.common_.direction == query::v2::EdgeAtom::Direction::OUT ? "->" : "-") << "(" << op.common_.node_symbol.name() << ")"; @@ -263,14 +263,14 @@ void PlanPrinter::Branch(query::v2::plan::LogicalOperator &op, const std::string --depth_; } -void PrettyPrint(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root, std::ostream *out) { - PlanPrinter printer(&request_manager, out); +void PrettyPrint(const RequestRouterInterface &request_router, const LogicalOperator *plan_root, std::ostream *out) { + PlanPrinter printer(&request_router, out); // FIXME(mtomic): We should make visitors that take const arguments. const_cast<LogicalOperator *>(plan_root)->Accept(printer); } -nlohmann::json PlanToJson(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root) { - impl::PlanToJsonVisitor visitor(&request_manager); +nlohmann::json PlanToJson(const RequestRouterInterface &request_router, const LogicalOperator *plan_root) { + impl::PlanToJsonVisitor visitor(&request_router); // FIXME(mtomic): We should make visitors that take const arguments. const_cast<LogicalOperator *>(plan_root)->Accept(visitor); return visitor.output(); @@ -348,16 +348,16 @@ json ToJson(const utils::Bound<Expression *> &bound) { json ToJson(const Symbol &symbol) { return symbol.name(); } -json ToJson(storage::v3::EdgeTypeId edge_type, const RequestRouterInterface &request_manager) { - return request_manager.EdgeTypeToName(edge_type); +json ToJson(storage::v3::EdgeTypeId edge_type, const RequestRouterInterface &request_router) { + return request_router.EdgeTypeToName(edge_type); } -json ToJson(storage::v3::LabelId label, const RequestRouterInterface &request_manager) { - return request_manager.LabelToName(label); +json ToJson(storage::v3::LabelId label, const RequestRouterInterface &request_router) { + return request_router.LabelToName(label); } -json ToJson(storage::v3::PropertyId property, const RequestRouterInterface &request_manager) { - return request_manager.PropertyToName(property); +json ToJson(storage::v3::PropertyId property, const RequestRouterInterface &request_router) { + return request_router.PropertyToName(property); } json ToJson(NamedExpression *nexpr) { @@ -368,29 +368,29 @@ json ToJson(NamedExpression *nexpr) { } json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> &properties, - const RequestRouterInterface &request_manager) { + const RequestRouterInterface &request_router) { json json; for (const auto &prop_pair : properties) { - json.emplace(ToJson(prop_pair.first, request_manager), ToJson(prop_pair.second)); + json.emplace(ToJson(prop_pair.first, request_router), ToJson(prop_pair.second)); } return json; } -json ToJson(const NodeCreationInfo &node_info, const RequestRouterInterface &request_manager) { +json ToJson(const NodeCreationInfo &node_info, const RequestRouterInterface &request_router) { json self; self["symbol"] = ToJson(node_info.symbol); - self["labels"] = ToJson(node_info.labels, request_manager); + self["labels"] = ToJson(node_info.labels, request_router); const auto *props = std::get_if<PropertiesMapList>(&node_info.properties); - self["properties"] = ToJson(props ? *props : PropertiesMapList{}, request_manager); + self["properties"] = ToJson(props ? *props : PropertiesMapList{}, request_router); return self; } -json ToJson(const EdgeCreationInfo &edge_info, const RequestRouterInterface &request_manager) { +json ToJson(const EdgeCreationInfo &edge_info, const RequestRouterInterface &request_router) { json self; self["symbol"] = ToJson(edge_info.symbol); const auto *props = std::get_if<PropertiesMapList>(&edge_info.properties); - self["properties"] = ToJson(props ? *props : PropertiesMapList{}, request_manager); - self["edge_type"] = ToJson(edge_info.edge_type, request_manager); + self["properties"] = ToJson(props ? *props : PropertiesMapList{}, request_router); + self["edge_type"] = ToJson(edge_info.edge_type, request_router); self["direction"] = ToString(edge_info.direction); return self; } @@ -432,7 +432,7 @@ bool PlanToJsonVisitor::PreVisit(ScanAll &op) { bool PlanToJsonVisitor::PreVisit(ScanAllByLabel &op) { json self; self["name"] = "ScanAllByLabel"; - self["label"] = ToJson(op.label_, *request_manager_); + self["label"] = ToJson(op.label_, *request_router_); self["output_symbol"] = ToJson(op.output_symbol_); op.input_->Accept(*this); @@ -445,8 +445,8 @@ bool PlanToJsonVisitor::PreVisit(ScanAllByLabel &op) { bool PlanToJsonVisitor::PreVisit(ScanAllByLabelPropertyRange &op) { json self; self["name"] = "ScanAllByLabelPropertyRange"; - self["label"] = ToJson(op.label_, *request_manager_); - self["property"] = ToJson(op.property_, *request_manager_); + self["label"] = ToJson(op.label_, *request_router_); + self["property"] = ToJson(op.property_, *request_router_); self["lower_bound"] = op.lower_bound_ ? ToJson(*op.lower_bound_) : json(); self["upper_bound"] = op.upper_bound_ ? ToJson(*op.upper_bound_) : json(); self["output_symbol"] = ToJson(op.output_symbol_); @@ -461,8 +461,8 @@ bool PlanToJsonVisitor::PreVisit(ScanAllByLabelPropertyRange &op) { bool PlanToJsonVisitor::PreVisit(ScanAllByLabelPropertyValue &op) { json self; self["name"] = "ScanAllByLabelPropertyValue"; - self["label"] = ToJson(op.label_, *request_manager_); - self["property"] = ToJson(op.property_, *request_manager_); + self["label"] = ToJson(op.label_, *request_router_); + self["property"] = ToJson(op.property_, *request_router_); self["expression"] = ToJson(op.expression_); self["output_symbol"] = ToJson(op.output_symbol_); @@ -476,8 +476,8 @@ bool PlanToJsonVisitor::PreVisit(ScanAllByLabelPropertyValue &op) { bool PlanToJsonVisitor::PreVisit(ScanAllByLabelProperty &op) { json self; self["name"] = "ScanAllByLabelProperty"; - self["label"] = ToJson(op.label_, *request_manager_); - self["property"] = ToJson(op.property_, *request_manager_); + self["label"] = ToJson(op.label_, *request_router_); + self["property"] = ToJson(op.property_, *request_router_); self["output_symbol"] = ToJson(op.output_symbol_); op.input_->Accept(*this); @@ -500,7 +500,7 @@ bool PlanToJsonVisitor::PreVisit(ScanAllById &op) { bool PlanToJsonVisitor::PreVisit(CreateNode &op) { json self; self["name"] = "CreateNode"; - self["node_info"] = ToJson(op.node_info_, *request_manager_); + self["node_info"] = ToJson(op.node_info_, *request_router_); op.input_->Accept(*this); self["input"] = PopOutput(); @@ -513,8 +513,8 @@ bool PlanToJsonVisitor::PreVisit(CreateExpand &op) { json self; self["name"] = "CreateExpand"; self["input_symbol"] = ToJson(op.input_symbol_); - self["node_info"] = ToJson(op.node_info_, *request_manager_); - self["edge_info"] = ToJson(op.edge_info_, *request_manager_); + self["node_info"] = ToJson(op.node_info_, *request_router_); + self["edge_info"] = ToJson(op.edge_info_, *request_router_); self["existing_node"] = op.existing_node_; op.input_->Accept(*this); @@ -530,7 +530,7 @@ bool PlanToJsonVisitor::PreVisit(Expand &op) { self["input_symbol"] = ToJson(op.input_symbol_); self["node_symbol"] = ToJson(op.common_.node_symbol); self["edge_symbol"] = ToJson(op.common_.edge_symbol); - self["edge_types"] = ToJson(op.common_.edge_types, *request_manager_); + self["edge_types"] = ToJson(op.common_.edge_types, *request_router_); self["direction"] = ToString(op.common_.direction); self["existing_node"] = op.common_.existing_node; @@ -547,7 +547,7 @@ bool PlanToJsonVisitor::PreVisit(ExpandVariable &op) { self["input_symbol"] = ToJson(op.input_symbol_); self["node_symbol"] = ToJson(op.common_.node_symbol); self["edge_symbol"] = ToJson(op.common_.edge_symbol); - self["edge_types"] = ToJson(op.common_.edge_types, *request_manager_); + self["edge_types"] = ToJson(op.common_.edge_types, *request_router_); self["direction"] = ToString(op.common_.direction); self["type"] = ToString(op.type_); self["is_reverse"] = op.is_reverse_; @@ -622,7 +622,7 @@ bool PlanToJsonVisitor::PreVisit(Delete &op) { bool PlanToJsonVisitor::PreVisit(SetProperty &op) { json self; self["name"] = "SetProperty"; - self["property"] = ToJson(op.property_, *request_manager_); + self["property"] = ToJson(op.property_, *request_router_); self["lhs"] = ToJson(op.lhs_); self["rhs"] = ToJson(op.rhs_); @@ -659,7 +659,7 @@ bool PlanToJsonVisitor::PreVisit(SetLabels &op) { json self; self["name"] = "SetLabels"; self["input_symbol"] = ToJson(op.input_symbol_); - self["labels"] = ToJson(op.labels_, *request_manager_); + self["labels"] = ToJson(op.labels_, *request_router_); op.input_->Accept(*this); self["input"] = PopOutput(); @@ -671,7 +671,7 @@ bool PlanToJsonVisitor::PreVisit(SetLabels &op) { bool PlanToJsonVisitor::PreVisit(RemoveProperty &op) { json self; self["name"] = "RemoveProperty"; - self["property"] = ToJson(op.property_, *request_manager_); + self["property"] = ToJson(op.property_, *request_router_); self["lhs"] = ToJson(op.lhs_); op.input_->Accept(*this); @@ -685,7 +685,7 @@ bool PlanToJsonVisitor::PreVisit(RemoveLabels &op) { json self; self["name"] = "RemoveLabels"; self["input_symbol"] = ToJson(op.input_symbol_); - self["labels"] = ToJson(op.labels_, *request_manager_); + self["labels"] = ToJson(op.labels_, *request_router_); op.input_->Accept(*this); self["input"] = PopOutput(); diff --git a/src/query/v2/plan/pretty_print.hpp b/src/query/v2/plan/pretty_print.hpp index 7e97de3ff..4094d7c81 100644 --- a/src/query/v2/plan/pretty_print.hpp +++ b/src/query/v2/plan/pretty_print.hpp @@ -30,16 +30,16 @@ class LogicalOperator; /// RequestRouter is needed for resolving label and property names. /// Note that `plan_root` isn't modified, but we can't take it as a const /// because we don't have support for visiting a const LogicalOperator. -void PrettyPrint(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root, std::ostream *out); +void PrettyPrint(const RequestRouterInterface &request_router, const LogicalOperator *plan_root, std::ostream *out); /// Overload of `PrettyPrint` which defaults the `std::ostream` to `std::cout`. -inline void PrettyPrint(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root) { - PrettyPrint(request_manager, plan_root, &std::cout); +inline void PrettyPrint(const RequestRouterInterface &request_router, const LogicalOperator *plan_root) { + PrettyPrint(request_router, plan_root, &std::cout); } /// Convert a `LogicalOperator` plan to a JSON representation. /// DbAccessor is needed for resolving label and property names. -nlohmann::json PlanToJson(const RequestRouterInterface &request_manager, const LogicalOperator *plan_root); +nlohmann::json PlanToJson(const RequestRouterInterface &request_router, const LogicalOperator *plan_root); class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { public: @@ -47,7 +47,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { using HierarchicalLogicalOperatorVisitor::PreVisit; using HierarchicalLogicalOperatorVisitor::Visit; - PlanPrinter(const RequestRouterInterface *request_manager, std::ostream *out); + PlanPrinter(const RequestRouterInterface *request_router, std::ostream *out); bool DefaultPreVisit() override; @@ -114,7 +114,7 @@ class PlanPrinter : public virtual HierarchicalLogicalOperatorVisitor { void Branch(LogicalOperator &op, const std::string &branch_name = ""); int64_t depth_{0}; - const RequestRouterInterface *request_manager_{nullptr}; + const RequestRouterInterface *request_router_{nullptr}; std::ostream *out_{nullptr}; }; @@ -132,20 +132,20 @@ nlohmann::json ToJson(const utils::Bound<Expression *> &bound); nlohmann::json ToJson(const Symbol &symbol); -nlohmann::json ToJson(storage::v3::EdgeTypeId edge_type, const RequestRouterInterface &request_manager); +nlohmann::json ToJson(storage::v3::EdgeTypeId edge_type, const RequestRouterInterface &request_router); -nlohmann::json ToJson(storage::v3::LabelId label, const RequestRouterInterface &request_manager); +nlohmann::json ToJson(storage::v3::LabelId label, const RequestRouterInterface &request_router); -nlohmann::json ToJson(storage::v3::PropertyId property, const RequestRouterInterface &request_manager); +nlohmann::json ToJson(storage::v3::PropertyId property, const RequestRouterInterface &request_router); nlohmann::json ToJson(NamedExpression *nexpr); nlohmann::json ToJson(const std::vector<std::pair<storage::v3::PropertyId, Expression *>> &properties, - const RequestRouterInterface &request_manager); + const RequestRouterInterface &request_router); -nlohmann::json ToJson(const NodeCreationInfo &node_info, const RequestRouterInterface &request_manager); +nlohmann::json ToJson(const NodeCreationInfo &node_info, const RequestRouterInterface &request_router); -nlohmann::json ToJson(const EdgeCreationInfo &edge_info, const RequestRouterInterface &request_manager); +nlohmann::json ToJson(const EdgeCreationInfo &edge_info, const RequestRouterInterface &request_router); nlohmann::json ToJson(const Aggregate::Element &elem); @@ -160,7 +160,7 @@ nlohmann::json ToJson(const std::vector<T> &items, Args &&...args) { class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { public: - explicit PlanToJsonVisitor(const RequestRouterInterface *request_manager) : request_manager_(request_manager) {} + explicit PlanToJsonVisitor(const RequestRouterInterface *request_router) : request_router_(request_router) {} using HierarchicalLogicalOperatorVisitor::PostVisit; using HierarchicalLogicalOperatorVisitor::PreVisit; @@ -216,7 +216,7 @@ class PlanToJsonVisitor : public virtual HierarchicalLogicalOperatorVisitor { protected: nlohmann::json output_; - const RequestRouterInterface *request_manager_; + const RequestRouterInterface *request_router_; nlohmann::json PopOutput() { nlohmann::json tmp; diff --git a/tests/simulation/request_router.cpp b/tests/simulation/request_router.cpp index ddd9351ae..8187f138b 100644 --- a/tests/simulation/request_router.cpp +++ b/tests/simulation/request_router.cpp @@ -151,10 +151,10 @@ void RunStorageRaft(Raft<IoImpl, MockedShardRsm, WriteRequests, WriteResponses, server.Run(); } -void TestScanVertices(query::v2::RequestRouterInterface &io) { +void TestScanVertices(query::v2::RequestRouterInterface &request_router) { msgs::ExecutionState<ScanVerticesRequest> state{.label = "test_label"}; - auto result = io.Request(state); + auto result = request_router.Request(state); MG_ASSERT(result.size() == 2); { auto prop = result[0].GetProperty(msgs::PropertyId::FromUint(0)); @@ -163,7 +163,7 @@ void TestScanVertices(query::v2::RequestRouterInterface &io) { MG_ASSERT(prop.int_v == 444); } - result = io.Request(state); + result = request_router.Request(state); { MG_ASSERT(result.size() == 1); auto prop = result[0].GetProperty(msgs::PropertyId::FromUint(0)); @@ -171,11 +171,11 @@ void TestScanVertices(query::v2::RequestRouterInterface &io) { } } -void TestCreateVertices(query::v2::RequestRouterInterface &io) { +void TestCreateVertices(query::v2::RequestRouterInterface &request_router) { using PropVal = msgs::Value; msgs::ExecutionState<CreateVerticesRequest> state; std::vector<msgs::NewVertex> new_vertices; - auto label_id = io.NameToLabel("test_label"); + auto label_id = request_router.NameToLabel("test_label"); msgs::NewVertex a1{.primary_key = {PropVal(int64_t(1)), PropVal(int64_t(0))}}; a1.label_ids.push_back({label_id}); msgs::NewVertex a2{.primary_key = {PropVal(int64_t(13)), PropVal(int64_t(13))}}; @@ -183,17 +183,17 @@ void TestCreateVertices(query::v2::RequestRouterInterface &io) { new_vertices.push_back(std::move(a1)); new_vertices.push_back(std::move(a2)); - auto result = io.Request(state, std::move(new_vertices)); + auto result = request_router.Request(state, std::move(new_vertices)); MG_ASSERT(result.size() == 2); } -void TestCreateExpand(query::v2::RequestRouterInterface &io) { +void TestCreateExpand(query::v2::RequestRouterInterface &request_router) { using PropVal = msgs::Value; msgs::ExecutionState<msgs::CreateExpandRequest> state; std::vector<msgs::NewExpand> new_expands; - const auto edge_type_id = io.NameToEdgeType("edge_type"); - const auto label = msgs::Label{io.NameToLabel("test_label")}; + const auto edge_type_id = request_router.NameToEdgeType("edge_type"); + const auto label = msgs::Label{request_router.NameToLabel("test_label")}; const msgs::VertexId vertex_id_1{label, {PropVal(int64_t(0)), PropVal(int64_t(0))}}; const msgs::VertexId vertex_id_2{label, {PropVal(int64_t(13)), PropVal(int64_t(13))}}; msgs::NewExpand expand_1{ @@ -203,7 +203,7 @@ void TestCreateExpand(query::v2::RequestRouterInterface &io) { new_expands.push_back(std::move(expand_1)); new_expands.push_back(std::move(expand_2)); - auto responses = io.Request(state, std::move(new_expands)); + auto responses = request_router.Request(state, std::move(new_expands)); MG_ASSERT(responses.size() == 2); MG_ASSERT(responses[0].success); MG_ASSERT(responses[1].success); @@ -222,7 +222,7 @@ void TestExpandOne(query::v2::RequestRouterInterface &request_router) { } template <typename RequestRouter> -void TestAggregate(RequestRouter &io) {} +void TestAggregate(RequestRouter &request_router) {} void DoTest() { SimulatorConfig config{ @@ -337,12 +337,12 @@ void DoTest() { // also get the current shard map CoordinatorClient<SimulatorTransport> coordinator_client(cli_io, c_addrs[0], c_addrs); - query::v2::RequestRouter<SimulatorTransport> io(std::move(coordinator_client), std::move(cli_io)); + query::v2::RequestRouter<SimulatorTransport> request_router(std::move(coordinator_client), std::move(cli_io)); - io.StartTransaction(); - TestScanVertices(io); - TestCreateVertices(io); - TestCreateExpand(io); + request_router.StartTransaction(); + TestScanVertices(request_router); + TestCreateVertices(request_router); + TestCreateExpand(request_router); simulator.ShutDown(); From 8fd7327fbd89375d0ec2a010f356df33909f404e Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Mon, 28 Nov 2022 15:38:12 +0200 Subject: [PATCH 15/26] Address GH comments --- tests/unit/query_v2_expression_evaluator.cpp | 55 +++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp index c2e0beee7..1fb4cf6dd 100644 --- a/tests/unit/query_v2_expression_evaluator.cpp +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -20,7 +20,6 @@ #include <gtest/gtest.h> #include "coordinator/shard_map.hpp" -#include "exceptions.hpp" #include "functions/awesome_memgraph_functions.hpp" #include "parser/opencypher/parser.hpp" #include "query/v2/accessors.hpp" @@ -539,29 +538,31 @@ TEST_F(ExpressionEvaluatorTest, MapIndexing) { using Vertex = memgraph::msgs::Vertex; using Edge = memgraph::msgs::Edge; using EdgeType = memgraph::msgs::EdgeType; +using EdgeId = memgraph::msgs::EdgeId; using Value = memgraph::msgs::Value; using VertexId = memgraph::msgs::VertexId; using Label = memgraph::msgs::Label; accessors::VertexAccessor CreateVertex(std::vector<std::pair<PropertyId, Value>> props, - const ShardRequestManagerInterface *manager, Label label = {}) { - static int64_t id = 0; - return {Vertex{VertexId{label, {memgraph::msgs::Value(id++)}}, {label}}, std::move(props), manager}; + const ShardRequestManagerInterface *manager, Vertex v = {}) { + return {std::move(v), std::move(props), manager}; } accessors::EdgeAccessor CreateEdge(std::vector<std::pair<PropertyId, Value>> props, - const ShardRequestManagerInterface *manager) { - auto edge = Edge{.src = VertexId{{}, {}}, - .dst = VertexId{{}, {}}, + const ShardRequestManagerInterface *manager, EdgeId edge_id = {}, VertexId src = {}, + VertexId dst = {}) { + auto edge = Edge{.src = std::move(src), + .dst = std::move(dst), .properties = std::move(props), + .id = edge_id, .type = EdgeType{manager->NameToEdgeType("edge_type")}}; return accessors::EdgeAccessor{std::move(edge), manager}; } TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) { auto prop = shard_manager->NameToProperty("prop"); - auto vertex = CreateVertex({{prop, Value(static_cast<int64_t>(42))}}, shard_manager.get()); - auto edge = CreateEdge({{prop, Value(static_cast<int64_t>(43))}}, shard_manager.get()); + auto vertex = CreateVertex({{prop, Value(static_cast<int64_t>(42))}}, shard_manager.get(), {}); + auto edge = CreateEdge({{prop, Value(static_cast<int64_t>(43))}}, shard_manager.get(), {}, {}, {}); auto *vertex_id = CreateIdentifierWithValue("v1", TypedValue(vertex)); auto *edge_id = CreateIdentifierWithValue("e11", TypedValue(edge)); @@ -741,7 +742,8 @@ TEST_F(ExpressionEvaluatorTest, IsNullOperator) { TEST_F(ExpressionEvaluatorTest, LabelsTest) { Label label{shard_manager->NameToLabel("label1")}; - auto v1 = CreateVertex({}, shard_manager.get(), label); + Vertex vertex = {{}, {label}}; + auto v1 = CreateVertex({}, shard_manager.get(), vertex); auto *identifier = storage.Create<Identifier>("n"); auto node_symbol = symbol_table.CreateSymbol("n", true); identifier->MapTo(node_symbol); @@ -1189,11 +1191,12 @@ static TypedValue MakeTypedValueList(TArgs &&...args) { TEST_F(FunctionTest, EndNode) { ASSERT_THROW(EvaluateFunction("ENDNODE"), FunctionRuntimeException); ASSERT_TRUE(EvaluateFunction("ENDNODE", TypedValue()).IsNull()); - auto v1 = CreateVertex({}, shard_manager.get()); - auto e = CreateEdge({}, shard_manager.get()); - const auto expected = VertexId{{}, 0}; + Label l{shard_manager->NameToLabel("label1")}; + EdgeId e_id{10}; + VertexId dst{l, {msgs::Value(static_cast<int64_t>(2))}}; + auto e = CreateEdge({}, shard_manager.get(), e_id, {}, dst); const auto res = EvaluateFunction("ENDNODE", e).ValueVertex().Id(); - ASSERT_EQ(res, expected); + ASSERT_EQ(res, dst); ASSERT_THROW(EvaluateFunction("ENDNODE", 2), FunctionRuntimeException); } @@ -1259,11 +1262,12 @@ TEST_F(FunctionTest, Size) { TEST_F(FunctionTest, StartNode) { ASSERT_THROW(EvaluateFunction("STARTNODE"), FunctionRuntimeException); ASSERT_TRUE(EvaluateFunction("STARTNODE", TypedValue()).IsNull()); - auto v1 = CreateVertex({}, shard_manager.get()); - auto e = CreateEdge({}, shard_manager.get()); - const auto expected = VertexId{{}, 0}; + Label l{shard_manager->NameToLabel("label1")}; + EdgeId e_id{5}; + VertexId src{l, {msgs::Value(static_cast<int64_t>(4))}}; + auto e = CreateEdge({}, shard_manager.get(), e_id, src); const auto res = EvaluateFunction("STARTNODE", e).ValueVertex().Id(); - ASSERT_EQ(res, expected); + ASSERT_EQ(res, src); ASSERT_THROW(EvaluateFunction("STARTNODE", 2), FunctionRuntimeException); } @@ -1329,16 +1333,13 @@ TEST_F(FunctionTest, ValueType) { ASSERT_EQ(EvaluateFunction("VALUETYPE", v1).ValueString(), "NODE"); auto e = CreateEdge({}, shard_manager.get()); ASSERT_EQ(EvaluateFunction("VALUETYPE", e).ValueString(), "RELATIONSHIP"); - // TODO(kostasrim) Fix this when we add Path to accessors - // Path p(v1, *e, v2); - // ASSERT_EQ(EvaluateFunction("VALUETYPE", p).ValueString(), "PATH"); } TEST_F(FunctionTest, Labels) { ASSERT_THROW(EvaluateFunction("LABELS"), FunctionRuntimeException); ASSERT_TRUE(EvaluateFunction("LABELS", TypedValue()).IsNull()); Label label{shard_manager->NameToLabel("label1")}; - auto v = CreateVertex({}, shard_manager.get(), std::move(label)); + auto v = CreateVertex({}, shard_manager.get(), {{}, {label}}); std::vector<std::string> labels; auto evaluated_labels = EvaluateFunction("LABELS", v).ValueList(); labels.reserve(evaluated_labels.size()); @@ -1349,9 +1350,6 @@ TEST_F(FunctionTest, Labels) { ASSERT_THROW(EvaluateFunction("LABELS", 2), FunctionRuntimeException); } -// TODO(kostasrim) Enable this once we fix accessors Path -// TEST_F(FunctionTest, NodesRelationships) {} - TEST_F(FunctionTest, Range) { EXPECT_THROW(EvaluateFunction("RANGE"), FunctionRuntimeException); EXPECT_TRUE(EvaluateFunction("RANGE", 1, 2, TypedValue()).IsNull()); @@ -1557,6 +1555,13 @@ TEST_F(FunctionTest, Counter) { EXPECT_THROW(EvaluateFunction("COUNTER", "c6", 0, 0), FunctionRuntimeException); } +TEST_F(FunctionTest, Id) { + auto v = CreateVertex({}, shard_manager.get()); + EXPECT_THROW(EvaluateFunction("ID", v), FunctionRuntimeException); + auto e = CreateEdge({}, shard_manager.get(), EdgeId{10}); + EXPECT_EQ(EvaluateFunction("ID", e).ValueInt(), 10); +} + TEST_F(FunctionTest, ToStringNull) { EXPECT_TRUE(EvaluateFunction("TOSTRING", TypedValue()).IsNull()); } TEST_F(FunctionTest, ToStringString) { From 50df0d4d53ccdc8c008931a9c9fa88a03dd0d3ad Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis <kostaskyrim@gmail.com> Date: Mon, 28 Nov 2022 17:13:58 +0200 Subject: [PATCH 16/26] Fix python imports and replace const char array with constexpr --- .github/workflows/diff.yaml | 2 +- .pre-commit-config.yaml | 1 + src/functions/awesome_memgraph_functions.hpp | 8 ++++---- .../distributed_queries/awesome_memgraph_functions.py | 9 ++++++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/diff.yaml b/.github/workflows/diff.yaml index 8b47b3bb3..a7faa7d22 100644 --- a/.github/workflows/diff.yaml +++ b/.github/workflows/diff.yaml @@ -99,7 +99,7 @@ jobs: echo ${file} if [[ ${file} == *.py ]]; then python3 -m black --check --diff ${file} - python3 -m isort --check-only --diff ${file} + python3 -m isort --check-only --profile "black" --diff ${file} fi done diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5abd746c9..26b7c8e05 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,6 +14,7 @@ repos: hooks: - id: isort name: isort (python) + args: ["--profile", "black"] - repo: https://github.com/pre-commit/mirrors-clang-format rev: v13.0.0 hooks: diff --git a/src/functions/awesome_memgraph_functions.hpp b/src/functions/awesome_memgraph_functions.hpp index 7acfa6943..7e716d970 100644 --- a/src/functions/awesome_memgraph_functions.hpp +++ b/src/functions/awesome_memgraph_functions.hpp @@ -56,10 +56,10 @@ template <typename TypedValueT, typename FunctionContextT, typename Tag, typenam std::function<TypedValueT(const TypedValueT *arguments, int64_t num_arguments, const FunctionContextT &context)> NameToFunction(const std::string &function_name); -inline const char kStartsWith[] = "STARTSWITH"; -inline const char kEndsWith[] = "ENDSWITH"; -inline const char kContains[] = "CONTAINS"; -inline const char kId[] = "ID"; +inline constexpr char kStartsWith[] = "STARTSWITH"; +inline constexpr char kEndsWith[] = "ENDSWITH"; +inline constexpr char kContains[] = "CONTAINS"; +inline constexpr char kId[] = "ID"; } // namespace memgraph::functions diff --git a/tests/e2e/distributed_queries/awesome_memgraph_functions.py b/tests/e2e/distributed_queries/awesome_memgraph_functions.py index 1c4bc87a4..0bdaa07a4 100644 --- a/tests/e2e/distributed_queries/awesome_memgraph_functions.py +++ b/tests/e2e/distributed_queries/awesome_memgraph_functions.py @@ -10,13 +10,16 @@ # licenses/APL.txt. import sys -import time -import typing import mgclient import pytest -from common import * +from common import ( + connection, + execute_and_fetch_all, + has_n_result_row, + wait_for_shard_manager_to_initialize, +) def test_awesome_memgraph_functions(connection): From 4f18fa7431d9ef6a63a29e9e6da2089649fa75ed Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 09:07:18 +0000 Subject: [PATCH 17/26] Fix LCP that broke with invisible merge conflict --- src/query/v2/frontend/ast/ast.lcp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/query/v2/frontend/ast/ast.lcp b/src/query/v2/frontend/ast/ast.lcp index dadcc9fa7..03c0c99f0 100644 --- a/src/query/v2/frontend/ast/ast.lcp +++ b/src/query/v2/frontend/ast/ast.lcp @@ -24,7 +24,7 @@ #include "query/v2/bindings/typed_value.hpp" #include "query/v2/db_accessor.hpp" #include "query/v2/path.hpp" -#include "query/v2/shard_request_manager.hpp" +#include "query/v2/request_router.hpp" #include "utils/typeinfo.hpp" #include "query/v2/conversions.hpp" @@ -838,14 +838,14 @@ cpp<# :slk-load (slk-load-ast-vector "Expression")) (function-name "std::string" :scope :public) (function "std::function<TypedValue(const TypedValue *, int64_t, - const functions::FunctionContext<ShardRequestManagerInterface> &)>" + const functions::FunctionContext<RequestRouterInterface> &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp self->${member} = functions::NameToFunction<TypedValue, - functions::FunctionContext<ShardRequestManagerInterface>, + functions::FunctionContext<RequestRouterInterface>, functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(self->function_name_); cpp<#))) (:public @@ -869,7 +869,7 @@ cpp<# const std::vector<Expression *> &arguments) : arguments_(arguments), function_name_(function_name), - function_(functions::NameToFunction<TypedValue, functions::FunctionContext<ShardRequestManagerInterface>, + function_(functions::NameToFunction<TypedValue, functions::FunctionContext<RequestRouterInterface>, functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(function_name_)) { if (!function_) { throw SemanticException("Function '{}' doesn't exist.", function_name); From a308ee501aaf9a6aa6f5081b7b6739c31629bba2 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 11:25:29 +0000 Subject: [PATCH 18/26] Unify the driving of read and write requests in the RequestRouter --- src/io/rsm/rsm_client.hpp | 6 +- src/query/v2/request_router.hpp | 115 ++++++-------------------------- 2 files changed, 23 insertions(+), 98 deletions(-) diff --git a/src/io/rsm/rsm_client.hpp b/src/io/rsm/rsm_client.hpp index ce6781956..92cfe12ac 100644 --- a/src/io/rsm/rsm_client.hpp +++ b/src/io/rsm/rsm_client.hpp @@ -73,10 +73,7 @@ class RsmClient { size_t addr_index = io_.Rand(addr_distrib); leader_ = server_addrs_[addr_index]; - spdlog::debug( - "client NOT redirected to leader server despite our success failing to be processed (it probably was sent to " - "a RSM Candidate) trying a random one at index {} with address {}", - addr_index, leader_.ToString()); + spdlog::debug("selecting a random leader at index {} with address {}", addr_index, leader_.ToString()); } template <typename ResponseT> @@ -227,6 +224,7 @@ class RsmClient { if (read_get_response.success) { async_reads_.erase(token.GetId()); + spdlog::debug("returning read_return for RSM request"); return std::move(read_get_response.read_return); } } else { diff --git a/src/query/v2/request_router.hpp b/src/query/v2/request_router.hpp index a4e7a1462..224ea8674 100644 --- a/src/query/v2/request_router.hpp +++ b/src/query/v2/request_router.hpp @@ -96,13 +96,6 @@ struct ExecutionState { // the RequestRouter impl will send requests to. When a request to a shard exhausts it, meaning that // it pulled all the requested data from the given Shard, it will be removed from the Vector. When the Vector becomes // empty, it means that all of the requests have completed succefully. - // TODO(gvolfing) - // Maybe make this into a more complex object to be able to keep track of paginated results. E.g. instead of a vector - // of Shards make it into a std::vector<std::pair<Shard, PaginatedResultType>> (probably a struct instead of a pair) - // where PaginatedResultType is an enum signaling the progress on the given request. This way we can easily check if - // a partial response on a shard(if there is one) is finished and we can send off the request for the next batch. - // 1-1 mapping with `shard_cache`. - // A vector that tracks request metadata for each shard (For example, next_id for a ScanAll on Shard A) std::vector<ShardRequestState<TRequest>> requests; State state = INITIALIZING; }; @@ -257,20 +250,10 @@ class RequestRouter : public RequestRouterInterface { std::vector<msgs::ScanVerticesResponse> responses; SendAllRequests(state); - auto all_requests_gathered = [](auto &paginated_rsp_tracker) { - return std::ranges::all_of(paginated_rsp_tracker, [](const auto &state) { - return state.second == PaginatedResponseState::PartiallyFinished; - }); - }; - - std::map<Shard, PaginatedResponseState> paginated_response_tracker; - for (const auto &request : state.requests) { - paginated_response_tracker.insert(std::make_pair(request.shard, PaginatedResponseState::Pending)); - } do { - AwaitOnPaginatedRequests(state, responses, paginated_response_tracker); - } while (!all_requests_gathered(paginated_response_tracker)); + DriveReadResponses(state, responses); + } while (!state.requests.empty()); MaybeCompleteState(state); // TODO(kostasrim) Before returning start prefetching the batch (this shall be done once we get MgFuture as return @@ -289,7 +272,7 @@ class RequestRouter : public RequestRouterInterface { // 2. Block untill all the futures are exhausted do { - AwaitOnResponses(state, responses); + DriveWriteResponses(state, responses); } while (!state.requests.empty()); MaybeCompleteState(state); @@ -339,7 +322,7 @@ class RequestRouter : public RequestRouterInterface { // 2. Block untill all the futures are exhausted do { - AwaitOnResponses(state, responses); + DriveReadResponses(state, responses); } while (!state.requests.empty()); std::vector<msgs::ExpandOneResultRow> result_rows; const auto total_row_count = std::accumulate(responses.begin(), responses.end(), 0, @@ -369,8 +352,6 @@ class RequestRouter : public RequestRouterInterface { } private: - enum class PaginatedResponseState { Pending, PartiallyFinished }; - std::vector<VertexAccessor> PostProcess(std::vector<msgs::ScanVerticesResponse> &&responses) const { std::vector<VertexAccessor> accessors; for (auto &response : responses) { @@ -602,33 +583,8 @@ class RequestRouter : public RequestRouterInterface { } } - void AwaitOnResponses(ExecutionState<msgs::CreateVerticesRequest> &state, - std::vector<msgs::CreateVerticesResponse> &responses) { - for (auto &request : state.requests) { - auto &storage_client = GetStorageClientForShard(request.shard); - - auto poll_result = storage_client.AwaitAsyncWriteRequest(request.async_request_token.value()); - while (!poll_result) { - poll_result = storage_client.AwaitAsyncWriteRequest(request.async_request_token.value()); - } - - if (poll_result->HasError()) { - throw std::runtime_error("CreateVertices request timed out"); - } - - msgs::WriteResponses response_variant = poll_result->GetValue(); - auto response = std::get<msgs::CreateVerticesResponse>(response_variant); - - if (response.error) { - throw std::runtime_error("CreateVertices request did not succeed"); - } - responses.push_back(response); - } - state.requests.clear(); - } - - void AwaitOnResponses(ExecutionState<msgs::ExpandOneRequest> &state, - std::vector<msgs::ExpandOneResponse> &responses) { + template <typename RequestT, typename ResponseT> + void DriveReadResponses(ExecutionState<RequestT> &state, std::vector<ResponseT> &responses) { for (auto &request : state.requests) { auto &storage_client = GetStorageClientForShard(request.shard); @@ -638,17 +594,13 @@ class RequestRouter : public RequestRouterInterface { } if (poll_result->HasError()) { - throw std::runtime_error("ExpandOne request timed out"); + throw std::runtime_error("RequestRouter Read request timed out"); } msgs::ReadResponses response_variant = poll_result->GetValue(); - auto response = std::get<msgs::ExpandOneResponse>(response_variant); - // -NOTE- - // Currently a boolean flag for signaling the overall success of the - // ExpandOne request does not exist. But it should, so here we assume - // that it is already in place. + auto response = std::get<ResponseT>(response_variant); if (response.error) { - throw std::runtime_error("ExpandOne request did not succeed"); + throw std::runtime_error("RequestRouter Read request did not succeed"); } responses.push_back(std::move(response)); @@ -656,54 +608,29 @@ class RequestRouter : public RequestRouterInterface { state.requests.clear(); } - void AwaitOnPaginatedRequests(ExecutionState<msgs::ScanVerticesRequest> &state, - std::vector<msgs::ScanVerticesResponse> &responses, - std::map<Shard, PaginatedResponseState> &paginated_response_tracker) { - std::vector<int> to_erase{}; - - for (int i = 0; i < state.requests.size(); i++) { - auto &request = state.requests[i]; - // only operate on paginated requests - if (paginated_response_tracker.at(request.shard) != PaginatedResponseState::Pending) { - continue; - } - + template <typename RequestT, typename ResponseT> + void DriveWriteResponses(ExecutionState<RequestT> &state, std::vector<ResponseT> &responses) { + for (auto &request : state.requests) { auto &storage_client = GetStorageClientForShard(request.shard); - // drive it to completion - auto await_result = storage_client.AwaitAsyncReadRequest(request.async_request_token.value()); - while (!await_result) { - await_result = storage_client.AwaitAsyncReadRequest(request.async_request_token.value()); + auto poll_result = storage_client.AwaitAsyncWriteRequest(request.async_request_token.value()); + while (!poll_result) { + poll_result = storage_client.AwaitAsyncWriteRequest(request.async_request_token.value()); } - if (await_result->HasError()) { - throw std::runtime_error("ScanAll request timed out"); + if (poll_result->HasError()) { + throw std::runtime_error("RequestRouter Write request timed out"); } - msgs::ReadResponses read_response_variant = await_result->GetValue(); - auto response = std::get<msgs::ScanVerticesResponse>(read_response_variant); + msgs::WriteResponses response_variant = poll_result->GetValue(); + auto response = std::get<ResponseT>(response_variant); if (response.error) { - throw std::runtime_error("ScanAll request did not succeed"); - } - - if (!response.next_start_id) { - paginated_response_tracker.erase(request.shard); - to_erase.push_back(i); - } else { - request.request.start_id.second = response.next_start_id->second; - paginated_response_tracker[request.shard] = PaginatedResponseState::PartiallyFinished; + throw std::runtime_error("RequestRouter Write request did not succeed"); } responses.push_back(std::move(response)); - - // reverse sort to_erase to remove requests in reverse order for correctness - std::sort(to_erase.begin(), to_erase.end(), std::greater<>()); - - auto requests_begin = state.requests.begin(); - for (int i : to_erase) { - state.requests.erase(requests_begin + i); - } } + state.requests.clear(); } void SetUpNameIdMappers() { From 1b77e029cab8b4c1c568ad7de008be7bd7973dac Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 11:33:49 +0000 Subject: [PATCH 19/26] Use the Async methods under the hood for the blocking RsmClient::Send*Request methods for code-reuse --- src/io/rsm/rsm_client.hpp | 71 +++++++-------------------------------- 1 file changed, 12 insertions(+), 59 deletions(-) diff --git a/src/io/rsm/rsm_client.hpp b/src/io/rsm/rsm_client.hpp index 92cfe12ac..1e5415a90 100644 --- a/src/io/rsm/rsm_client.hpp +++ b/src/io/rsm/rsm_client.hpp @@ -101,68 +101,21 @@ class RsmClient { ~RsmClient() = default; BasicResult<TimedOut, WriteResponseT> SendWriteRequest(WriteRequestT req) { - WriteRequest<WriteRequestT> client_req; - client_req.operation = req; - - const Duration overall_timeout = io_.GetDefaultTimeout(); - const Time before = io_.Now(); - - do { - spdlog::debug("client sending WriteRequest to Leader {}", leader_.ToString()); - ResponseFuture<WriteResponse<WriteResponseT>> response_future = - io_.template Request<WriteRequest<WriteRequestT>, WriteResponse<WriteResponseT>>(leader_, client_req); - ResponseResult<WriteResponse<WriteResponseT>> response_result = std::move(response_future).Wait(); - - if (response_result.HasError()) { - spdlog::debug("client timed out while trying to communicate with leader server {}", leader_.ToString()); - return response_result.GetError(); - } - - ResponseEnvelope<WriteResponse<WriteResponseT>> &&response_envelope = std::move(response_result.GetValue()); - WriteResponse<WriteResponseT> &&write_response = std::move(response_envelope.message); - - if (write_response.success) { - return std::move(write_response.write_return); - } - - PossiblyRedirectLeader(write_response); - } while (io_.Now() < before + overall_timeout); - - return TimedOut{}; + auto token = SendAsyncWriteRequest(req); + auto poll_result = AwaitAsyncWriteRequest(token); + while (!poll_result) { + poll_result = AwaitAsyncWriteRequest(token); + } + return poll_result.value(); } BasicResult<TimedOut, ReadResponseT> SendReadRequest(ReadRequestT req) { - ReadRequest<ReadRequestT> read_req; - read_req.operation = req; - - const Duration overall_timeout = io_.GetDefaultTimeout(); - const Time before = io_.Now(); - - do { - spdlog::debug("client sending ReadRequest to Leader {}", leader_.ToString()); - - ResponseFuture<ReadResponse<ReadResponseT>> get_response_future = - io_.template Request<ReadRequest<ReadRequestT>, ReadResponse<ReadResponseT>>(leader_, read_req); - - // receive response - ResponseResult<ReadResponse<ReadResponseT>> get_response_result = std::move(get_response_future).Wait(); - - if (get_response_result.HasError()) { - spdlog::debug("client timed out while trying to communicate with leader server {}", leader_.ToString()); - return get_response_result.GetError(); - } - - ResponseEnvelope<ReadResponse<ReadResponseT>> &&get_response_envelope = std::move(get_response_result.GetValue()); - ReadResponse<ReadResponseT> &&read_get_response = std::move(get_response_envelope.message); - - if (read_get_response.success) { - return std::move(read_get_response.read_return); - } - - PossiblyRedirectLeader(read_get_response); - } while (io_.Now() < before + overall_timeout); - - return TimedOut{}; + auto token = SendAsyncReadRequest(req); + auto poll_result = AwaitAsyncReadRequest(token); + while (!poll_result) { + poll_result = AwaitAsyncReadRequest(token); + } + return poll_result.value(); } /// AsyncRead methods From ec529da8d243cc28d9e03492e31b0218a661543f Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 12:28:19 +0000 Subject: [PATCH 20/26] Address clang-tidy feedback --- src/io/rsm/rsm_client.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/io/rsm/rsm_client.hpp b/src/io/rsm/rsm_client.hpp index 1e5415a90..5eb4aee5f 100644 --- a/src/io/rsm/rsm_client.hpp +++ b/src/io/rsm/rsm_client.hpp @@ -41,7 +41,7 @@ class AsyncRequestToken { size_t id_; public: - AsyncRequestToken(size_t id) : id_(id) {} + explicit AsyncRequestToken(size_t id) : id_(id) {} size_t GetId() const { return id_; } }; @@ -132,7 +132,7 @@ class RsmClient { async_reads_.emplace(token, std::move(async_request)); - return AsyncRequestToken(token); + return AsyncRequestToken{token}; } void ResendAsyncReadRequest(AsyncRequestToken &token) { @@ -203,7 +203,7 @@ class RsmClient { async_writes_.emplace(token, std::move(async_request)); - return AsyncRequestToken(token); + return AsyncRequestToken{token}; } void ResendAsyncWriteRequest(AsyncRequestToken &token) { From 9144d2dccde7cb0f0cb3c1728f7956f74b63c947 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 14:30:59 +0000 Subject: [PATCH 21/26] Remove bug-prone inverted ownership of ExecutionState as a consideration of operators --- src/query/v2/plan/operator.cpp | 40 +++++----- src/query/v2/request_router.hpp | 73 ++++--------------- tests/unit/high_density_shard_create_scan.cpp | 4 +- 3 files changed, 33 insertions(+), 84 deletions(-) diff --git a/src/query/v2/plan/operator.cpp b/src/query/v2/plan/operator.cpp index 014be0d62..b45ea457e 100644 --- a/src/query/v2/plan/operator.cpp +++ b/src/query/v2/plan/operator.cpp @@ -180,7 +180,7 @@ class DistributedCreateNodeCursor : public Cursor { auto &request_router = context.request_router; { SCOPED_REQUEST_WAIT_PROFILE; - request_router->Request(state_, NodeCreationInfoToRequest(context, frame)); + request_router->Request(NodeCreationInfoToRequest(context, frame)); } PlaceNodeOnTheFrame(frame, context); return true; @@ -191,7 +191,7 @@ class DistributedCreateNodeCursor : public Cursor { void Shutdown() override { input_cursor_->Shutdown(); } - void Reset() override { state_ = {}; } + void Reset() override {} void PlaceNodeOnTheFrame(Frame &frame, ExecutionContext &context) { // TODO(kostasrim) Make this work with batching @@ -252,7 +252,6 @@ class DistributedCreateNodeCursor : public Cursor { std::vector<const NodeCreationInfo *> nodes_info_; std::vector<std::vector<std::pair<storage::v3::PropertyId, msgs::Value>>> src_vertex_props_; std::vector<msgs::PrimaryKey> primary_keys_; - ExecutionState<msgs::CreateVerticesRequest> state_; }; bool Once::OnceCursor::Pull(Frame &, ExecutionContext &context) { @@ -365,7 +364,6 @@ class ScanAllCursor : public Cursor { std::optional<decltype(vertices_.value().begin())> vertices_it_; const char *op_name_; std::vector<msgs::ScanVerticesResponse> current_batch; - ExecutionState<msgs::ScanVerticesRequest> request_state; }; class DistributedScanAllAndFilterCursor : public Cursor { @@ -384,14 +382,21 @@ class DistributedScanAllAndFilterCursor : public Cursor { ResetExecutionState(); } + enum class State : int8_t { INITIALIZING, COMPLETED }; + using VertexAccessor = accessors::VertexAccessor; bool MakeRequest(RequestRouterInterface &request_router, ExecutionContext &context) { { SCOPED_REQUEST_WAIT_PROFILE; - current_batch = request_router.Request(request_state_); + std::optional<std::string> request_label = std::nullopt; + if (label_.has_value()) { + request_label = request_router.LabelToName(*label_); + } + current_batch = request_router.Request(request_label); } current_vertex_it = current_batch.begin(); + request_state_ = State::COMPLETED; return !current_batch.empty(); } @@ -403,19 +408,15 @@ class DistributedScanAllAndFilterCursor : public Cursor { if (MustAbort(context)) { throw HintedAbortError(); } - using State = ExecutionState<msgs::ScanVerticesRequest>; - if (request_state_.state == State::INITIALIZING) { + if (request_state_ == State::INITIALIZING) { if (!input_cursor_->Pull(frame, context)) { return false; } } - request_state_.label = - label_.has_value() ? std::make_optional(request_router.LabelToName(*label_)) : std::nullopt; - if (current_vertex_it == current_batch.end() && - (request_state_.state == State::COMPLETED || !MakeRequest(request_router, context))) { + (request_state_ == State::COMPLETED || !MakeRequest(request_router, context))) { ResetExecutionState(); continue; } @@ -431,7 +432,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { void ResetExecutionState() { current_batch.clear(); current_vertex_it = current_batch.end(); - request_state_ = ExecutionState<msgs::ScanVerticesRequest>{}; + request_state_ = State::INITIALIZING; } void Reset() override { @@ -445,7 +446,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { const char *op_name_; std::vector<VertexAccessor> current_batch; std::vector<VertexAccessor>::iterator current_vertex_it; - ExecutionState<msgs::ScanVerticesRequest> request_state_; + State request_state_ = State::INITIALIZING; std::optional<storage::v3::LabelId> label_; std::optional<std::pair<storage::v3::PropertyId, Expression *>> property_expression_pair_; std::optional<std::vector<Expression *>> filter_expressions_; @@ -2343,7 +2344,7 @@ class DistributedCreateExpandCursor : public Cursor { ResetExecutionState(); { SCOPED_REQUEST_WAIT_PROFILE; - request_router->Request(state_, ExpandCreationInfoToRequest(context, frame)); + request_router->Request(ExpandCreationInfoToRequest(context, frame)); } return true; } @@ -2423,11 +2424,10 @@ class DistributedCreateExpandCursor : public Cursor { } private: - void ResetExecutionState() { state_ = {}; } + void ResetExecutionState() {} const UniqueCursorPtr input_cursor_; const CreateExpand &self_; - ExecutionState<msgs::CreateExpandRequest> state_; }; class DistributedExpandCursor : public Cursor { @@ -2474,8 +2474,7 @@ class DistributedExpandCursor : public Cursor { request.edge_properties.emplace(); request.src_vertices.push_back(get_dst_vertex(edge, direction)); request.direction = (direction == EdgeAtom::Direction::IN) ? msgs::EdgeDirection::OUT : msgs::EdgeDirection::IN; - ExecutionState<msgs::ExpandOneRequest> request_state; - auto result_rows = context.request_router->Request(request_state, std::move(request)); + auto result_rows = context.request_router->Request(std::move(request)); MG_ASSERT(result_rows.size() == 1); auto &result_row = result_rows.front(); frame[self_.common_.node_symbol] = accessors::VertexAccessor( @@ -2500,10 +2499,9 @@ class DistributedExpandCursor : public Cursor { // to not fetch any properties of the edges request.edge_properties.emplace(); request.src_vertices.push_back(vertex.Id()); - ExecutionState<msgs::ExpandOneRequest> request_state; - auto result_rows = std::invoke([&context, &request_state, &request]() mutable { + auto result_rows = std::invoke([&context, &request]() mutable { SCOPED_REQUEST_WAIT_PROFILE; - return context.request_router->Request(request_state, std::move(request)); + return context.request_router->Request(std::move(request)); }); MG_ASSERT(result_rows.size() == 1); auto &result_row = result_rows.front(); diff --git a/src/query/v2/request_router.hpp b/src/query/v2/request_router.hpp index 224ea8674..42f2da702 100644 --- a/src/query/v2/request_router.hpp +++ b/src/query/v2/request_router.hpp @@ -83,7 +83,6 @@ struct ExecutionState { using CompoundKey = io::rsm::ShardRsmKey; using Shard = coordinator::Shard; - enum State : int8_t { INITIALIZING, EXECUTING, COMPLETED }; // label is optional because some operators can create/remove etc, vertices. These kind of requests contain the label // on the request itself. std::optional<std::string> label; @@ -97,7 +96,6 @@ struct ExecutionState { // it pulled all the requested data from the given Shard, it will be removed from the Vector. When the Vector becomes // empty, it means that all of the requests have completed succefully. std::vector<ShardRequestState<TRequest>> requests; - State state = INITIALIZING; }; class RequestRouterInterface { @@ -113,13 +111,10 @@ class RequestRouterInterface { virtual void StartTransaction() = 0; virtual void Commit() = 0; - virtual std::vector<VertexAccessor> Request(ExecutionState<msgs::ScanVerticesRequest> &state) = 0; - virtual std::vector<msgs::CreateVerticesResponse> Request(ExecutionState<msgs::CreateVerticesRequest> &state, - std::vector<msgs::NewVertex> new_vertices) = 0; - virtual std::vector<msgs::ExpandOneResultRow> Request(ExecutionState<msgs::ExpandOneRequest> &state, - msgs::ExpandOneRequest request) = 0; - virtual std::vector<msgs::CreateExpandResponse> Request(ExecutionState<msgs::CreateExpandRequest> &state, - std::vector<msgs::NewExpand> new_edges) = 0; + virtual std::vector<VertexAccessor> Request(std::optional<std::string> &label) = 0; + virtual std::vector<msgs::CreateVerticesResponse> Request(std::vector<msgs::NewVertex> new_vertices) = 0; + virtual std::vector<msgs::ExpandOneResultRow> Request(msgs::ExpandOneRequest request) = 0; + virtual std::vector<msgs::CreateExpandResponse> Request(std::vector<msgs::NewExpand> new_edges) = 0; virtual storage::v3::EdgeTypeId NameToEdgeType(const std::string &name) const = 0; virtual storage::v3::PropertyId NameToProperty(const std::string &name) const = 0; @@ -245,7 +240,9 @@ class RequestRouter : public RequestRouterInterface { bool IsPrimaryLabel(storage::v3::LabelId label) const override { return shards_map_.label_spaces.contains(label); } // TODO(kostasrim) Simplify return result - std::vector<VertexAccessor> Request(ExecutionState<msgs::ScanVerticesRequest> &state) override { + std::vector<VertexAccessor> Request(std::optional<std::string> &label) override { + ExecutionState<msgs::ScanVerticesRequest> state = {}; + state.label = label; MaybeInitializeExecutionState(state); std::vector<msgs::ScanVerticesResponse> responses; @@ -255,14 +252,13 @@ class RequestRouter : public RequestRouterInterface { DriveReadResponses(state, responses); } while (!state.requests.empty()); - MaybeCompleteState(state); // TODO(kostasrim) Before returning start prefetching the batch (this shall be done once we get MgFuture as return // result of storage_client.SendReadRequest()). return PostProcess(std::move(responses)); } - std::vector<msgs::CreateVerticesResponse> Request(ExecutionState<msgs::CreateVerticesRequest> &state, - std::vector<msgs::NewVertex> new_vertices) override { + std::vector<msgs::CreateVerticesResponse> Request(std::vector<msgs::NewVertex> new_vertices) override { + ExecutionState<msgs::CreateVerticesRequest> state = {}; MG_ASSERT(!new_vertices.empty()); MaybeInitializeExecutionState(state, new_vertices); std::vector<msgs::CreateVerticesResponse> responses; @@ -275,14 +271,13 @@ class RequestRouter : public RequestRouterInterface { DriveWriteResponses(state, responses); } while (!state.requests.empty()); - MaybeCompleteState(state); // TODO(kostasrim) Before returning start prefetching the batch (this shall be done once we get MgFuture as return // result of storage_client.SendReadRequest()). return responses; } - std::vector<msgs::CreateExpandResponse> Request(ExecutionState<msgs::CreateExpandRequest> &state, - std::vector<msgs::NewExpand> new_edges) override { + std::vector<msgs::CreateExpandResponse> Request(std::vector<msgs::NewExpand> new_edges) override { + ExecutionState<msgs::CreateExpandRequest> state = {}; MG_ASSERT(!new_edges.empty()); MaybeInitializeExecutionState(state, new_edges); std::vector<msgs::CreateExpandResponse> responses; @@ -303,12 +298,11 @@ class RequestRouter : public RequestRouterInterface { } // We are done with this state state.requests.clear(); - MaybeCompleteState(state); return responses; } - std::vector<msgs::ExpandOneResultRow> Request(ExecutionState<msgs::ExpandOneRequest> &state, - msgs::ExpandOneRequest request) override { + std::vector<msgs::ExpandOneResultRow> Request(msgs::ExpandOneRequest request) override { + ExecutionState<msgs::ExpandOneRequest> state = {}; // TODO(kostasrim)Update to limit the batch size here // Expansions of the destination must be handled by the caller. For example // match (u:L1 { prop : 1 })-[:Friend]-(v:L1) @@ -335,7 +329,6 @@ class RequestRouter : public RequestRouterInterface { result_rows.insert(result_rows.end(), std::make_move_iterator(response.result.begin()), std::make_move_iterator(response.result.end())); } - MaybeCompleteState(state); return result_rows; } @@ -362,31 +355,8 @@ class RequestRouter : public RequestRouterInterface { return accessors; } - template <typename ExecutionState> - void ThrowIfStateCompleted(ExecutionState &state) const { - if (state.state == ExecutionState::COMPLETED) [[unlikely]] { - throw std::runtime_error("State is completed and must be reset"); - } - } - - template <typename ExecutionState> - void MaybeCompleteState(ExecutionState &state) const { - if (state.requests.empty()) { - state.state = ExecutionState::COMPLETED; - } - } - - template <typename ExecutionState> - bool ShallNotInitializeState(ExecutionState &state) const { - return state.state != ExecutionState::INITIALIZING; - } - void MaybeInitializeExecutionState(ExecutionState<msgs::CreateVerticesRequest> &state, std::vector<msgs::NewVertex> new_vertices) { - ThrowIfStateCompleted(state); - if (ShallNotInitializeState(state)) { - return; - } state.transaction_id = transaction_id_; std::map<Shard, msgs::CreateVerticesRequest> per_shard_request_table; @@ -410,15 +380,10 @@ class RequestRouter : public RequestRouterInterface { }; state.requests.emplace_back(std::move(shard_request_state)); } - state.state = ExecutionState<msgs::CreateVerticesRequest>::EXECUTING; } void MaybeInitializeExecutionState(ExecutionState<msgs::CreateExpandRequest> &state, std::vector<msgs::NewExpand> new_expands) { - ThrowIfStateCompleted(state); - if (ShallNotInitializeState(state)) { - return; - } state.transaction_id = transaction_id_; std::map<Shard, msgs::CreateExpandRequest> per_shard_request_table; @@ -453,15 +418,9 @@ class RequestRouter : public RequestRouterInterface { }; state.requests.emplace_back(std::move(shard_request_state)); } - state.state = ExecutionState<msgs::CreateExpandRequest>::EXECUTING; } void MaybeInitializeExecutionState(ExecutionState<msgs::ScanVerticesRequest> &state) { - ThrowIfStateCompleted(state); - if (ShallNotInitializeState(state)) { - return; - } - std::vector<coordinator::Shards> multi_shards; state.transaction_id = transaction_id_; if (!state.label) { @@ -489,14 +448,9 @@ class RequestRouter : public RequestRouterInterface { state.requests.emplace_back(std::move(shard_request_state)); } } - state.state = ExecutionState<msgs::ScanVerticesRequest>::EXECUTING; } void MaybeInitializeExecutionState(ExecutionState<msgs::ExpandOneRequest> &state, msgs::ExpandOneRequest request) { - ThrowIfStateCompleted(state); - if (ShallNotInitializeState(state)) { - return; - } state.transaction_id = transaction_id_; std::map<Shard, msgs::ExpandOneRequest> per_shard_request_table; @@ -522,7 +476,6 @@ class RequestRouter : public RequestRouterInterface { state.requests.emplace_back(std::move(shard_request_state)); } - state.state = ExecutionState<msgs::ExpandOneRequest>::EXECUTING; } StorageClient &GetStorageClientForShard(Shard shard) { diff --git a/tests/unit/high_density_shard_create_scan.cpp b/tests/unit/high_density_shard_create_scan.cpp index 22af9c702..362e3525e 100644 --- a/tests/unit/high_density_shard_create_scan.cpp +++ b/tests/unit/high_density_shard_create_scan.cpp @@ -174,8 +174,6 @@ void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::se return; } - query::v2::ExecutionState<msgs::CreateVerticesRequest> state; - auto label_id = request_router.NameToLabel("test_label"); msgs::NewVertex nv{.primary_key = primary_key}; @@ -184,7 +182,7 @@ void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::se std::vector<msgs::NewVertex> new_vertices; new_vertices.push_back(std::move(nv)); - auto result = request_router.Request(state, std::move(new_vertices)); + auto result = request_router.Request(std::move(new_vertices)); MG_ASSERT(result.size() == 1); MG_ASSERT(!result[0].error.has_value()); From 8f08d986cb882ce4af7a79aac17d71bcab869021 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 14:47:32 +0000 Subject: [PATCH 22/26] Make method names clear for RequestRouter requests, avoid unnecessary overloading --- src/query/v2/plan/operator.cpp | 10 ++--- src/query/v2/request_router.hpp | 39 +++++++++---------- tests/simulation/test_cluster.hpp | 8 +--- tests/unit/high_density_shard_create_scan.cpp | 4 +- tests/unit/machine_manager.cpp | 13 ++----- tests/unit/query_v2_expression_evaluator.cpp | 18 +++------ 6 files changed, 36 insertions(+), 56 deletions(-) diff --git a/src/query/v2/plan/operator.cpp b/src/query/v2/plan/operator.cpp index b45ea457e..21440a42d 100644 --- a/src/query/v2/plan/operator.cpp +++ b/src/query/v2/plan/operator.cpp @@ -180,7 +180,7 @@ class DistributedCreateNodeCursor : public Cursor { auto &request_router = context.request_router; { SCOPED_REQUEST_WAIT_PROFILE; - request_router->Request(NodeCreationInfoToRequest(context, frame)); + request_router->CreateVertices(NodeCreationInfoToRequest(context, frame)); } PlaceNodeOnTheFrame(frame, context); return true; @@ -393,7 +393,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { if (label_.has_value()) { request_label = request_router.LabelToName(*label_); } - current_batch = request_router.Request(request_label); + current_batch = request_router.ScanVertices(request_label); } current_vertex_it = current_batch.begin(); request_state_ = State::COMPLETED; @@ -2344,7 +2344,7 @@ class DistributedCreateExpandCursor : public Cursor { ResetExecutionState(); { SCOPED_REQUEST_WAIT_PROFILE; - request_router->Request(ExpandCreationInfoToRequest(context, frame)); + request_router->CreateExpand(ExpandCreationInfoToRequest(context, frame)); } return true; } @@ -2474,7 +2474,7 @@ class DistributedExpandCursor : public Cursor { request.edge_properties.emplace(); request.src_vertices.push_back(get_dst_vertex(edge, direction)); request.direction = (direction == EdgeAtom::Direction::IN) ? msgs::EdgeDirection::OUT : msgs::EdgeDirection::IN; - auto result_rows = context.request_router->Request(std::move(request)); + auto result_rows = context.request_router->ExpandOne(std::move(request)); MG_ASSERT(result_rows.size() == 1); auto &result_row = result_rows.front(); frame[self_.common_.node_symbol] = accessors::VertexAccessor( @@ -2501,7 +2501,7 @@ class DistributedExpandCursor : public Cursor { request.src_vertices.push_back(vertex.Id()); auto result_rows = std::invoke([&context, &request]() mutable { SCOPED_REQUEST_WAIT_PROFILE; - return context.request_router->Request(std::move(request)); + return context.request_router->ExpandOne(std::move(request)); }); MG_ASSERT(result_rows.size() == 1); auto &result_row = result_rows.front(); diff --git a/src/query/v2/request_router.hpp b/src/query/v2/request_router.hpp index 42f2da702..05ce6eb2c 100644 --- a/src/query/v2/request_router.hpp +++ b/src/query/v2/request_router.hpp @@ -86,9 +86,6 @@ struct ExecutionState { // label is optional because some operators can create/remove etc, vertices. These kind of requests contain the label // on the request itself. std::optional<std::string> label; - // CompoundKey is optional because some operators require to iterate over all the available keys - // of a shard. One example is ScanAll, where we only require the field label. - std::optional<CompoundKey> key; // Transaction id to be filled by the RequestRouter implementation coordinator::Hlc transaction_id; // Initialized by RequestRouter implementation. This vector is filled with the shards that @@ -111,10 +108,10 @@ class RequestRouterInterface { virtual void StartTransaction() = 0; virtual void Commit() = 0; - virtual std::vector<VertexAccessor> Request(std::optional<std::string> &label) = 0; - virtual std::vector<msgs::CreateVerticesResponse> Request(std::vector<msgs::NewVertex> new_vertices) = 0; - virtual std::vector<msgs::ExpandOneResultRow> Request(msgs::ExpandOneRequest request) = 0; - virtual std::vector<msgs::CreateExpandResponse> Request(std::vector<msgs::NewExpand> new_edges) = 0; + virtual std::vector<VertexAccessor> ScanVertices(std::optional<std::string> label) = 0; + virtual std::vector<msgs::CreateVerticesResponse> CreateVertices(std::vector<msgs::NewVertex> new_vertices) = 0; + virtual std::vector<msgs::ExpandOneResultRow> ExpandOne(msgs::ExpandOneRequest request) = 0; + virtual std::vector<msgs::CreateExpandResponse> CreateExpand(std::vector<msgs::NewExpand> new_edges) = 0; virtual storage::v3::EdgeTypeId NameToEdgeType(const std::string &name) const = 0; virtual storage::v3::PropertyId NameToProperty(const std::string &name) const = 0; @@ -240,10 +237,10 @@ class RequestRouter : public RequestRouterInterface { bool IsPrimaryLabel(storage::v3::LabelId label) const override { return shards_map_.label_spaces.contains(label); } // TODO(kostasrim) Simplify return result - std::vector<VertexAccessor> Request(std::optional<std::string> &label) override { + std::vector<VertexAccessor> ScanVertices(std::optional<std::string> label) override { ExecutionState<msgs::ScanVerticesRequest> state = {}; state.label = label; - MaybeInitializeExecutionState(state); + InitializeExecutionState(state); std::vector<msgs::ScanVerticesResponse> responses; SendAllRequests(state); @@ -257,10 +254,10 @@ class RequestRouter : public RequestRouterInterface { return PostProcess(std::move(responses)); } - std::vector<msgs::CreateVerticesResponse> Request(std::vector<msgs::NewVertex> new_vertices) override { + std::vector<msgs::CreateVerticesResponse> CreateVertices(std::vector<msgs::NewVertex> new_vertices) override { ExecutionState<msgs::CreateVerticesRequest> state = {}; MG_ASSERT(!new_vertices.empty()); - MaybeInitializeExecutionState(state, new_vertices); + InitializeExecutionState(state, new_vertices); std::vector<msgs::CreateVerticesResponse> responses; // 1. Send the requests. @@ -276,10 +273,10 @@ class RequestRouter : public RequestRouterInterface { return responses; } - std::vector<msgs::CreateExpandResponse> Request(std::vector<msgs::NewExpand> new_edges) override { + std::vector<msgs::CreateExpandResponse> CreateExpand(std::vector<msgs::NewExpand> new_edges) override { ExecutionState<msgs::CreateExpandRequest> state = {}; MG_ASSERT(!new_edges.empty()); - MaybeInitializeExecutionState(state, new_edges); + InitializeExecutionState(state, new_edges); std::vector<msgs::CreateExpandResponse> responses; for (auto &request : state.requests) { auto &storage_client = GetStorageClientForShard(request.shard); @@ -301,14 +298,14 @@ class RequestRouter : public RequestRouterInterface { return responses; } - std::vector<msgs::ExpandOneResultRow> Request(msgs::ExpandOneRequest request) override { + std::vector<msgs::ExpandOneResultRow> ExpandOne(msgs::ExpandOneRequest request) override { ExecutionState<msgs::ExpandOneRequest> state = {}; // TODO(kostasrim)Update to limit the batch size here // Expansions of the destination must be handled by the caller. For example // match (u:L1 { prop : 1 })-[:Friend]-(v:L1) // For each vertex U, the ExpandOne will result in <U, Edges>. The destination vertex and its properties // must be fetched again with an ExpandOne(Edges.dst) - MaybeInitializeExecutionState(state, std::move(request)); + InitializeExecutionState(state, std::move(request)); std::vector<msgs::ExpandOneResponse> responses; // 1. Send the requests. @@ -355,8 +352,8 @@ class RequestRouter : public RequestRouterInterface { return accessors; } - void MaybeInitializeExecutionState(ExecutionState<msgs::CreateVerticesRequest> &state, - std::vector<msgs::NewVertex> new_vertices) { + void InitializeExecutionState(ExecutionState<msgs::CreateVerticesRequest> &state, + std::vector<msgs::NewVertex> new_vertices) { state.transaction_id = transaction_id_; std::map<Shard, msgs::CreateVerticesRequest> per_shard_request_table; @@ -382,8 +379,8 @@ class RequestRouter : public RequestRouterInterface { } } - void MaybeInitializeExecutionState(ExecutionState<msgs::CreateExpandRequest> &state, - std::vector<msgs::NewExpand> new_expands) { + void InitializeExecutionState(ExecutionState<msgs::CreateExpandRequest> &state, + std::vector<msgs::NewExpand> new_expands) { state.transaction_id = transaction_id_; std::map<Shard, msgs::CreateExpandRequest> per_shard_request_table; @@ -420,7 +417,7 @@ class RequestRouter : public RequestRouterInterface { } } - void MaybeInitializeExecutionState(ExecutionState<msgs::ScanVerticesRequest> &state) { + void InitializeExecutionState(ExecutionState<msgs::ScanVerticesRequest> &state) { std::vector<coordinator::Shards> multi_shards; state.transaction_id = transaction_id_; if (!state.label) { @@ -450,7 +447,7 @@ class RequestRouter : public RequestRouterInterface { } } - void MaybeInitializeExecutionState(ExecutionState<msgs::ExpandOneRequest> &state, msgs::ExpandOneRequest request) { + void InitializeExecutionState(ExecutionState<msgs::ExpandOneRequest> &state, msgs::ExpandOneRequest request) { state.transaction_id = transaction_id_; std::map<Shard, msgs::ExpandOneRequest> per_shard_request_table; diff --git a/tests/simulation/test_cluster.hpp b/tests/simulation/test_cluster.hpp index 99f617cda..1392a0632 100644 --- a/tests/simulation/test_cluster.hpp +++ b/tests/simulation/test_cluster.hpp @@ -164,8 +164,6 @@ void ExecuteOp(query::v2::RequestRouter<SimulatorTransport> &request_router, std return; } - query::v2::ExecutionState<msgs::CreateVerticesRequest> state; - auto label_id = request_router.NameToLabel("test_label"); msgs::NewVertex nv{.primary_key = primary_key}; @@ -174,7 +172,7 @@ void ExecuteOp(query::v2::RequestRouter<SimulatorTransport> &request_router, std std::vector<msgs::NewVertex> new_vertices; new_vertices.push_back(std::move(nv)); - auto result = request_router.Request(state, std::move(new_vertices)); + auto result = request_router.CreateVertices(std::move(new_vertices)); RC_ASSERT(result.size() == 1); RC_ASSERT(!result[0].error.has_value()); @@ -184,9 +182,7 @@ void ExecuteOp(query::v2::RequestRouter<SimulatorTransport> &request_router, std void ExecuteOp(query::v2::RequestRouter<SimulatorTransport> &request_router, std::set<CompoundKey> &correctness_model, ScanAll scan_all) { - query::v2::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; - - auto results = request_router.Request(request); + auto results = request_router.ScanVertices("test_label"); RC_ASSERT(results.size() == correctness_model.size()); diff --git a/tests/unit/high_density_shard_create_scan.cpp b/tests/unit/high_density_shard_create_scan.cpp index 362e3525e..982f3e69a 100644 --- a/tests/unit/high_density_shard_create_scan.cpp +++ b/tests/unit/high_density_shard_create_scan.cpp @@ -182,7 +182,7 @@ void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::se std::vector<msgs::NewVertex> new_vertices; new_vertices.push_back(std::move(nv)); - auto result = request_router.Request(std::move(new_vertices)); + auto result = request_router.CreateVertices(std::move(new_vertices)); MG_ASSERT(result.size() == 1); MG_ASSERT(!result[0].error.has_value()); @@ -194,7 +194,7 @@ void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::se ScanAll scan_all) { query::v2::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; - auto results = request_router.Request(request); + auto results = request_router.ScanVertices("test_label"); MG_ASSERT(results.size() == correctness_model.size()); diff --git a/tests/unit/machine_manager.cpp b/tests/unit/machine_manager.cpp index 0b081e5a1..748233737 100644 --- a/tests/unit/machine_manager.cpp +++ b/tests/unit/machine_manager.cpp @@ -111,15 +111,12 @@ ShardMap TestShardMap() { template <typename RequestRouter> void TestScanAll(RequestRouter &request_router) { - query::v2::ExecutionState<msgs::ScanVerticesRequest> state{.label = kLabelName}; - - auto result = request_router.Request(state); + auto result = request_router.ScanVertices(kLabelName); EXPECT_EQ(result.size(), 2); } void TestCreateVertices(query::v2::RequestRouterInterface &request_router) { using PropVal = msgs::Value; - query::v2::ExecutionState<msgs::CreateVerticesRequest> state; std::vector<msgs::NewVertex> new_vertices; auto label_id = request_router.NameToLabel(kLabelName); msgs::NewVertex a1{.primary_key = {PropVal(int64_t(0)), PropVal(int64_t(0))}}; @@ -129,14 +126,13 @@ void TestCreateVertices(query::v2::RequestRouterInterface &request_router) { new_vertices.push_back(std::move(a1)); new_vertices.push_back(std::move(a2)); - auto result = request_router.Request(state, std::move(new_vertices)); + auto result = request_router.CreateVertices(std::move(new_vertices)); EXPECT_EQ(result.size(), 1); EXPECT_FALSE(result[0].error.has_value()) << result[0].error->message; } void TestCreateExpand(query::v2::RequestRouterInterface &request_router) { using PropVal = msgs::Value; - query::v2::ExecutionState<msgs::CreateExpandRequest> state; std::vector<msgs::NewExpand> new_expands; const auto edge_type_id = request_router.NameToEdgeType("edge_type"); @@ -150,20 +146,19 @@ void TestCreateExpand(query::v2::RequestRouterInterface &request_router) { new_expands.push_back(std::move(expand_1)); new_expands.push_back(std::move(expand_2)); - auto responses = request_router.Request(state, std::move(new_expands)); + auto responses = request_router.CreateExpand(std::move(new_expands)); MG_ASSERT(responses.size() == 1); MG_ASSERT(!responses[0].error.has_value()); } void TestExpandOne(query::v2::RequestRouterInterface &request_router) { - query::v2::ExecutionState<msgs::ExpandOneRequest> state{}; msgs::ExpandOneRequest request; const auto edge_type_id = request_router.NameToEdgeType("edge_type"); const auto label = msgs::Label{request_router.NameToLabel("test_label")}; request.src_vertices.push_back(msgs::VertexId{label, {msgs::Value(int64_t(0)), msgs::Value(int64_t(0))}}); request.edge_types.push_back(msgs::EdgeType{edge_type_id}); request.direction = msgs::EdgeDirection::BOTH; - auto result_rows = request_router.Request(state, std::move(request)); + auto result_rows = request_router.ExpandOne(std::move(request)); MG_ASSERT(result_rows.size() == 1); MG_ASSERT(result_rows[0].in_edges_with_all_properties.size() == 1); MG_ASSERT(result_rows[0].out_edges_with_all_properties.size() == 1); diff --git a/tests/unit/query_v2_expression_evaluator.cpp b/tests/unit/query_v2_expression_evaluator.cpp index 112ecd29e..5f77ed4e7 100644 --- a/tests/unit/query_v2_expression_evaluator.cpp +++ b/tests/unit/query_v2_expression_evaluator.cpp @@ -82,23 +82,15 @@ class MockedRequestRouter : public RequestRouterInterface { } void StartTransaction() override {} void Commit() override {} - std::vector<VertexAccessor> Request(ExecutionState<memgraph::msgs::ScanVerticesRequest> &state) override { + std::vector<VertexAccessor> ScanVertices(std::optional<std::string> /* label */) override { return {}; } + + std::vector<CreateVerticesResponse> CreateVertices(std::vector<memgraph::msgs::NewVertex> new_vertices) override { return {}; } - std::vector<CreateVerticesResponse> Request(ExecutionState<CreateVerticesRequest> &state, - std::vector<memgraph::msgs::NewVertex> new_vertices) override { - return {}; - } + std::vector<ExpandOneResultRow> ExpandOne(ExpandOneRequest request) override { return {}; } - std::vector<ExpandOneResultRow> Request(ExecutionState<ExpandOneRequest> &state, ExpandOneRequest request) override { - return {}; - } - - std::vector<CreateExpandResponse> Request(ExecutionState<CreateExpandRequest> &state, - std::vector<NewExpand> new_edges) override { - return {}; - } + std::vector<CreateExpandResponse> CreateExpand(std::vector<NewExpand> new_edges) override { return {}; } const std::string &PropertyToName(memgraph::storage::v3::PropertyId id) const override { return properties_.IdToName(id.AsUint()); From f8215306e833110729ed113178e438673166ec60 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 15:06:01 +0000 Subject: [PATCH 23/26] A variety of small code clean-ups, remove overloaded methods --- src/query/v2/request_router.hpp | 119 +++++++++++++++----------------- 1 file changed, 56 insertions(+), 63 deletions(-) diff --git a/src/query/v2/request_router.hpp b/src/query/v2/request_router.hpp index 05ce6eb2c..58caa95c0 100644 --- a/src/query/v2/request_router.hpp +++ b/src/query/v2/request_router.hpp @@ -240,42 +240,70 @@ class RequestRouter : public RequestRouterInterface { std::vector<VertexAccessor> ScanVertices(std::optional<std::string> label) override { ExecutionState<msgs::ScanVerticesRequest> state = {}; state.label = label; + + // create requests InitializeExecutionState(state); + + // begin all requests in parallel + for (auto &request : state.requests) { + auto &storage_client = GetStorageClientForShard(request.shard); + msgs::ReadRequests req = request.request; + + request.async_request_token = storage_client.SendAsyncReadRequest(request.request); + } + + // drive requests to completion std::vector<msgs::ScanVerticesResponse> responses; - - SendAllRequests(state); - do { DriveReadResponses(state, responses); } while (!state.requests.empty()); - // TODO(kostasrim) Before returning start prefetching the batch (this shall be done once we get MgFuture as return - // result of storage_client.SendReadRequest()). - return PostProcess(std::move(responses)); + // convert responses into VertexAccessor objects to return + std::vector<VertexAccessor> accessors; + for (auto &response : responses) { + for (auto &result_row : response.results) { + accessors.emplace_back(VertexAccessor(std::move(result_row.vertex), std::move(result_row.props), this)); + } + } + + return accessors; } std::vector<msgs::CreateVerticesResponse> CreateVertices(std::vector<msgs::NewVertex> new_vertices) override { ExecutionState<msgs::CreateVerticesRequest> state = {}; MG_ASSERT(!new_vertices.empty()); + + // create requests InitializeExecutionState(state, new_vertices); + + // begin all requests in parallel + for (auto &request : state.requests) { + auto req_deep_copy = request.request; + + for (auto &new_vertex : req_deep_copy.new_vertices) { + new_vertex.label_ids.erase(new_vertex.label_ids.begin()); + } + + auto &storage_client = GetStorageClientForShard(request.shard); + + msgs::WriteRequests req = req_deep_copy; + request.async_request_token = storage_client.SendAsyncWriteRequest(req); + } + + // drive requests to completion std::vector<msgs::CreateVerticesResponse> responses; - - // 1. Send the requests. - SendAllRequests(state); - - // 2. Block untill all the futures are exhausted do { DriveWriteResponses(state, responses); } while (!state.requests.empty()); - // TODO(kostasrim) Before returning start prefetching the batch (this shall be done once we get MgFuture as return - // result of storage_client.SendReadRequest()). return responses; } std::vector<msgs::CreateExpandResponse> CreateExpand(std::vector<msgs::NewExpand> new_edges) override { ExecutionState<msgs::CreateExpandRequest> state = {}; MG_ASSERT(!new_edges.empty()); + + // create requests InitializeExecutionState(state, new_edges); std::vector<msgs::CreateExpandResponse> responses; for (auto &request : state.requests) { @@ -305,16 +333,24 @@ class RequestRouter : public RequestRouterInterface { // match (u:L1 { prop : 1 })-[:Friend]-(v:L1) // For each vertex U, the ExpandOne will result in <U, Edges>. The destination vertex and its properties // must be fetched again with an ExpandOne(Edges.dst) + + // create requests InitializeExecutionState(state, std::move(request)); + + // begin all requests in parallel + for (auto &request : state.requests) { + auto &storage_client = GetStorageClientForShard(request.shard); + msgs::ReadRequests req = request.request; + request.async_request_token = storage_client.SendAsyncReadRequest(req); + } + + // drive requests to completion std::vector<msgs::ExpandOneResponse> responses; - - // 1. Send the requests. - SendAllRequests(state); - - // 2. Block untill all the futures are exhausted do { DriveReadResponses(state, responses); } while (!state.requests.empty()); + + // post-process responses std::vector<msgs::ExpandOneResultRow> result_rows; const auto total_row_count = std::accumulate(responses.begin(), responses.end(), 0, [](const int64_t partial_count, const msgs::ExpandOneResponse &resp) { @@ -326,6 +362,7 @@ class RequestRouter : public RequestRouterInterface { result_rows.insert(result_rows.end(), std::make_move_iterator(response.result.begin()), std::make_move_iterator(response.result.end())); } + return result_rows; } @@ -342,16 +379,6 @@ class RequestRouter : public RequestRouterInterface { } private: - std::vector<VertexAccessor> PostProcess(std::vector<msgs::ScanVerticesResponse> &&responses) const { - std::vector<VertexAccessor> accessors; - for (auto &response : responses) { - for (auto &result_row : response.results) { - accessors.emplace_back(VertexAccessor(std::move(result_row.vertex), std::move(result_row.props), this)); - } - } - return accessors; - } - void InitializeExecutionState(ExecutionState<msgs::CreateVerticesRequest> &state, std::vector<msgs::NewVertex> new_vertices) { state.transaction_id = transaction_id_; @@ -359,7 +386,7 @@ class RequestRouter : public RequestRouterInterface { std::map<Shard, msgs::CreateVerticesRequest> per_shard_request_table; for (auto &new_vertex : new_vertices) { - MG_ASSERT(!new_vertex.label_ids.empty(), "This is error!"); + MG_ASSERT(!new_vertex.label_ids.empty(), "No label_ids provided for new vertex in RequestRouter::CreateVertices"); auto shard = shards_map_.GetShardForKey(new_vertex.label_ids[0].id, storage::conversions::ConvertPropertyVector(new_vertex.primary_key)); if (!per_shard_request_table.contains(shard)) { @@ -499,40 +526,6 @@ class RequestRouter : public RequestRouterInterface { storage_cli_manager_.AddClient(target_shard, std::move(cli)); } - void SendAllRequests(ExecutionState<msgs::ScanVerticesRequest> &state) { - for (auto &request : state.requests) { - const auto ¤t_shard = request.shard; - - auto &storage_client = GetStorageClientForShard(current_shard); - msgs::ReadRequests req = request.request; - - request.async_request_token = storage_client.SendAsyncReadRequest(request.request); - } - } - - void SendAllRequests(ExecutionState<msgs::CreateVerticesRequest> &state) { - for (auto &request : state.requests) { - auto req_deep_copy = request.request; - - for (auto &new_vertex : req_deep_copy.new_vertices) { - new_vertex.label_ids.erase(new_vertex.label_ids.begin()); - } - - auto &storage_client = GetStorageClientForShard(request.shard); - - msgs::WriteRequests req = req_deep_copy; - request.async_request_token = storage_client.SendAsyncWriteRequest(req); - } - } - - void SendAllRequests(ExecutionState<msgs::ExpandOneRequest> &state) { - for (auto &request : state.requests) { - auto &storage_client = GetStorageClientForShard(request.shard); - msgs::ReadRequests req = request.request; - request.async_request_token = storage_client.SendAsyncReadRequest(req); - } - } - template <typename RequestT, typename ResponseT> void DriveReadResponses(ExecutionState<RequestT> &state, std::vector<ResponseT> &responses) { for (auto &request : state.requests) { From 7df3a743b997f0e9d91a3af83e355a7cafb577a9 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 15:07:59 +0000 Subject: [PATCH 24/26] Simplify and parallelize CreateExpand --- src/query/v2/request_router.hpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/query/v2/request_router.hpp b/src/query/v2/request_router.hpp index 58caa95c0..7a0fb9d8d 100644 --- a/src/query/v2/request_router.hpp +++ b/src/query/v2/request_router.hpp @@ -305,24 +305,20 @@ class RequestRouter : public RequestRouterInterface { // create requests InitializeExecutionState(state, new_edges); - std::vector<msgs::CreateExpandResponse> responses; + + // begin all requests in parallel for (auto &request : state.requests) { auto &storage_client = GetStorageClientForShard(request.shard); - msgs::WriteRequests req = request.request; - auto write_response_result = storage_client.SendWriteRequest(std::move(req)); - if (write_response_result.HasError()) { - throw std::runtime_error("CreateVertices request timedout"); - } - msgs::WriteResponses response_variant = write_response_result.GetValue(); - msgs::CreateExpandResponse mapped_response = std::get<msgs::CreateExpandResponse>(response_variant); - - if (mapped_response.error) { - throw std::runtime_error("CreateExpand request did not succeed"); - } - responses.push_back(mapped_response); + msgs::ReadRequests req = request.request; + request.async_request_token = storage_client.SendAsyncReadRequest(req); } - // We are done with this state - state.requests.clear(); + + // drive requests to completion + std::vector<msgs::ExpandOneResponse> responses; + do { + DriveReadResponses(state, responses); + } while (!state.requests.empty()); + return responses; } From b3605c9ab19331d18bab146ee892966c30280d02 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 15:11:35 +0000 Subject: [PATCH 25/26] Fix typo in new simplified RequestRouter::CreateExpand method --- src/query/v2/request_router.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/query/v2/request_router.hpp b/src/query/v2/request_router.hpp index 7a0fb9d8d..ffb075da0 100644 --- a/src/query/v2/request_router.hpp +++ b/src/query/v2/request_router.hpp @@ -309,14 +309,14 @@ class RequestRouter : public RequestRouterInterface { // begin all requests in parallel for (auto &request : state.requests) { auto &storage_client = GetStorageClientForShard(request.shard); - msgs::ReadRequests req = request.request; - request.async_request_token = storage_client.SendAsyncReadRequest(req); + msgs::WriteRequests req = request.request; + request.async_request_token = storage_client.SendAsyncWriteRequest(req); } // drive requests to completion - std::vector<msgs::ExpandOneResponse> responses; + std::vector<msgs::CreateExpandResponse> responses; do { - DriveReadResponses(state, responses); + DriveWriteResponses(state, responses); } while (!state.requests.empty()); return responses; From 04124a1e9b60ac04d4292c693ccfbf3d4448a352 Mon Sep 17 00:00:00 2001 From: Tyler Neely <t@jujit.su> Date: Tue, 29 Nov 2022 15:50:35 +0000 Subject: [PATCH 26/26] Make AsyncRequestToken arguments const, reserve size in response vectors --- src/io/rsm/rsm_client.hpp | 12 ++++++------ src/query/v2/request_router.hpp | 5 +++++ tests/unit/high_density_shard_create_scan.cpp | 2 -- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/io/rsm/rsm_client.hpp b/src/io/rsm/rsm_client.hpp index 5eb4aee5f..920866c7a 100644 --- a/src/io/rsm/rsm_client.hpp +++ b/src/io/rsm/rsm_client.hpp @@ -135,7 +135,7 @@ class RsmClient { return AsyncRequestToken{token}; } - void ResendAsyncReadRequest(AsyncRequestToken &token) { + void ResendAsyncReadRequest(const AsyncRequestToken &token) { auto &async_request = async_reads_.at(token.GetId()); ReadRequest<ReadRequestT> read_req = {.operation = async_request.request}; @@ -144,7 +144,7 @@ class RsmClient { io_.template Request<ReadRequest<ReadRequestT>, ReadResponse<ReadResponseT>>(leader_, read_req); } - std::optional<BasicResult<TimedOut, ReadResponseT>> PollAsyncReadRequest(AsyncRequestToken &token) { + std::optional<BasicResult<TimedOut, ReadResponseT>> PollAsyncReadRequest(const AsyncRequestToken &token) { auto &async_request = async_reads_.at(token.GetId()); if (!async_request.future.IsReady()) { @@ -154,7 +154,7 @@ class RsmClient { return AwaitAsyncReadRequest(); } - std::optional<BasicResult<TimedOut, ReadResponseT>> AwaitAsyncReadRequest(AsyncRequestToken &token) { + std::optional<BasicResult<TimedOut, ReadResponseT>> AwaitAsyncReadRequest(const AsyncRequestToken &token) { auto &async_request = async_reads_.at(token.GetId()); ResponseResult<ReadResponse<ReadResponseT>> get_response_result = std::move(async_request.future).Wait(); @@ -206,7 +206,7 @@ class RsmClient { return AsyncRequestToken{token}; } - void ResendAsyncWriteRequest(AsyncRequestToken &token) { + void ResendAsyncWriteRequest(const AsyncRequestToken &token) { auto &async_request = async_writes_.at(token.GetId()); WriteRequest<WriteRequestT> write_req = {.operation = async_request.request}; @@ -215,7 +215,7 @@ class RsmClient { io_.template Request<WriteRequest<WriteRequestT>, WriteResponse<WriteResponseT>>(leader_, write_req); } - std::optional<BasicResult<TimedOut, WriteResponseT>> PollAsyncWriteRequest(AsyncRequestToken &token) { + std::optional<BasicResult<TimedOut, WriteResponseT>> PollAsyncWriteRequest(const AsyncRequestToken &token) { auto &async_request = async_writes_.at(token.GetId()); if (!async_request.future.IsReady()) { @@ -225,7 +225,7 @@ class RsmClient { return AwaitAsyncWriteRequest(); } - std::optional<BasicResult<TimedOut, WriteResponseT>> AwaitAsyncWriteRequest(AsyncRequestToken &token) { + std::optional<BasicResult<TimedOut, WriteResponseT>> AwaitAsyncWriteRequest(const AsyncRequestToken &token) { auto &async_request = async_writes_.at(token.GetId()); ResponseResult<WriteResponse<WriteResponseT>> get_response_result = std::move(async_request.future).Wait(); diff --git a/src/query/v2/request_router.hpp b/src/query/v2/request_router.hpp index ffb075da0..996272fdc 100644 --- a/src/query/v2/request_router.hpp +++ b/src/query/v2/request_router.hpp @@ -254,12 +254,14 @@ class RequestRouter : public RequestRouterInterface { // drive requests to completion std::vector<msgs::ScanVerticesResponse> responses; + responses.reserve(state.requests.size()); do { DriveReadResponses(state, responses); } while (!state.requests.empty()); // convert responses into VertexAccessor objects to return std::vector<VertexAccessor> accessors; + accessors.reserve(responses.size()); for (auto &response : responses) { for (auto &result_row : response.results) { accessors.emplace_back(VertexAccessor(std::move(result_row.vertex), std::move(result_row.props), this)); @@ -292,6 +294,7 @@ class RequestRouter : public RequestRouterInterface { // drive requests to completion std::vector<msgs::CreateVerticesResponse> responses; + responses.reserve(state.requests.size()); do { DriveWriteResponses(state, responses); } while (!state.requests.empty()); @@ -315,6 +318,7 @@ class RequestRouter : public RequestRouterInterface { // drive requests to completion std::vector<msgs::CreateExpandResponse> responses; + responses.reserve(state.requests.size()); do { DriveWriteResponses(state, responses); } while (!state.requests.empty()); @@ -342,6 +346,7 @@ class RequestRouter : public RequestRouterInterface { // drive requests to completion std::vector<msgs::ExpandOneResponse> responses; + responses.reserve(state.requests.size()); do { DriveReadResponses(state, responses); } while (!state.requests.empty()); diff --git a/tests/unit/high_density_shard_create_scan.cpp b/tests/unit/high_density_shard_create_scan.cpp index 982f3e69a..2be48fc77 100644 --- a/tests/unit/high_density_shard_create_scan.cpp +++ b/tests/unit/high_density_shard_create_scan.cpp @@ -192,8 +192,6 @@ void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::se void ExecuteOp(query::v2::RequestRouter<LocalTransport> &request_router, std::set<CompoundKey> &correctness_model, ScanAll scan_all) { - query::v2::ExecutionState<msgs::ScanVerticesRequest> request{.label = "test_label"}; - auto results = request_router.ScanVertices("test_label"); MG_ASSERT(results.size() == correctness_model.size());