From 02ef954e5134d79e0831d28796bec50c96721de8 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis Date: Mon, 7 Nov 2022 18:28:35 +0200 Subject: [PATCH 01/16] 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 Visit(Function &function) override { - FunctionContext function_ctx{dba_, ctx_->memory, ctx_->timestamp, &ctx_->counters, view_}; + functions::FunctionContext 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 +#include +#include +#include + +#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 +struct FunctionContext { + TAccessor *db_accessor; + utils::MemoryResource *memory; + int64_t timestamp; + std::unordered_map *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 +std::function +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` 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, 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` check. +// * Two arguments were supplied, the 1st one passes `Or` 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, NonNegativeInteger, +// Optional>("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 +bool ArgIsType(const TypedValueT &arg) { + if constexpr (std::is_same_v) { + return arg.IsNull(); + } else if constexpr (std::is_same_v) { + return arg.IsBool(); + } else if constexpr (std::is_same_v) { + return arg.IsInt(); + } else if constexpr (std::is_same_v) { + return arg.IsInt() && arg.ValueInt() > 0; + } else if constexpr (std::is_same_v) { + return arg.IsInt() && arg.ValueInt() != 0; + } else if constexpr (std::is_same_v) { + return arg.IsInt() && arg.ValueInt() >= 0; + } else if constexpr (std::is_same_v) { + return arg.IsDouble(); + } else if constexpr (std::is_same_v) { + return arg.IsNumeric(); + } else if constexpr (std::is_same_v) { + return arg.IsList(); + } else if constexpr (std::is_same_v) { + return arg.IsString(); + } else if constexpr (std::is_same_v) { + return arg.IsMap(); + } else if constexpr (std::is_same_v) { + return arg.IsVertex(); + } else if constexpr (std::is_same_v) { + return arg.IsEdge(); + } else if constexpr (std::is_same_v) { + return arg.IsPath(); + } else if constexpr (std::is_same_v) { + return arg.IsDate(); + } else if constexpr (std::is_same_v) { + return arg.IsLocalTime(); + } else if constexpr (std::is_same_v) { + return arg.IsLocalDateTime(); + } else if constexpr (std::is_same_v) { + return arg.IsDuration(); + } else if constexpr (std::is_same_v) { + return true; + } else { + static_assert(std::is_same_v, "Unknown ArgType"); + } + return false; +} + +template +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) { + return "null"; + } else if constexpr (std::is_same_v) { + return "boolean"; + } else if constexpr (std::is_same_v) { + return "integer"; + } else if constexpr (std::is_same_v) { + return "positive integer"; + } else if constexpr (std::is_same_v) { + return "non-zero integer"; + } else if constexpr (std::is_same_v) { + return "non-negative integer"; + } else if constexpr (std::is_same_v) { + return "float"; + } else if constexpr (std::is_same_v) { + return "number"; + } else if constexpr (std::is_same_v) { + return "list"; + } else if constexpr (std::is_same_v) { + return "string"; + } else if constexpr (std::is_same_v) { + return "map"; + } else if constexpr (std::is_same_v) { + return "node"; + } else if constexpr (std::is_same_v) { + return "relationship"; + } else if constexpr (std::is_same_v) { + return "path"; + } else if constexpr (std::is_same_v) { + return "void"; + } else if constexpr (std::is_same_v) { + return "Date"; + } else if constexpr (std::is_same_v) { + return "LocalTime"; + } else if constexpr (std::is_same_v) { + return "LocalDateTime"; + } else if constexpr (std::is_same_v) { + return "Duration"; + } else { + static_assert(std::is_same_v, "Unknown ArgType"); + } + return ""; +} + +template +struct Or; + +template +struct Or { + template + static bool Check(const TypedValueT &arg) { + return ArgIsType(arg); + } + + static std::string TypeNames() { return ArgTypeName(); } +}; + +template +struct Or { + template + static bool Check(const TypedValueT &arg) { + if (ArgIsType(arg)) return true; + return Or::Check(arg); + } + + static std::string TypeNames() { + if constexpr (sizeof...(ArgTypes) > 1) { + return fmt::format("'{}', {}", ArgTypeName(), Or::TypeNames()); + } else { + return fmt::format("'{}' or '{}'", ArgTypeName(), Or::TypeNames()); + } + } +}; + +template +struct IsOrType { + static constexpr bool value = false; +}; + +template +struct IsOrType> { + static constexpr bool value = true; +}; + +template +struct Optional; + +template +struct Optional { + static constexpr size_t size = 1; + + template + 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::value) { + if (!ArgType::Check(arg)) { + throw FunctionRuntimeException("Optional '{}' argument at position {} must be either {}.", name, pos, + ArgType::TypeNames()); + } + } else { + if (!ArgIsType(arg)) + throw FunctionRuntimeException("Optional '{}' argument at position {} must be '{}'.", name, pos, + ArgTypeName()); + } + } +}; + +template +struct Optional { + static constexpr size_t size = 1 + sizeof...(ArgTypes); + + template + static void Check(const char *name, const TypedValueT *args, int64_t nargs, int64_t pos) { + if (nargs == 0) return; + Optional::Check(name, args, nargs, pos); + Optional::Check(name, args + 1, nargs - 1, pos + 1); + } +}; + +template +struct IsOptional { + static constexpr bool value = false; +}; + +template +struct IsOptional> { + static constexpr bool value = true; +}; + +template +constexpr size_t FTypeRequiredArgs() { + if constexpr (IsOptional::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(); + } +} + +template +constexpr size_t FTypeOptionalArgs() { + if constexpr (IsOptional::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(); + } +} + +template +void FType(const char *name, const TypedValueT *args, int64_t nargs, int64_t pos = 1) { + if constexpr (std::is_same_v) { + if (nargs != 0) { + throw FunctionRuntimeException("'{}' requires no arguments.", name); + } + return; + } + static constexpr int64_t required_args = FTypeRequiredArgs(); + static constexpr int64_t optional_args = FTypeOptionalArgs(); + 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::value) { + if (!ArgType::Check(arg)) { + throw FunctionRuntimeException("'{}' argument at position {} must be either {}.", name, pos, + ArgType::TypeNames()); + } + } else if constexpr (IsOptional::value) { + static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); + ArgType::Check(name, args, nargs, pos); + } else { + if (!ArgIsType(arg)) { + throw FunctionRuntimeException("'{}' argument at position {} must be '{}'", name, pos, ArgTypeName()); + } + } + if constexpr (sizeof...(ArgTypes) > 0) { + FType(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 +TypedValueT EndNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("endNode", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + if constexpr (std::is_same_v) { + 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 +TypedValueT Head(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT Last(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT Properties(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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) { + 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 +TypedValueT Size(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("size", args, nargs); + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsList()) { + return TypedValueT(static_cast(value.ValueList().size()), ctx.memory); + } else if (value.IsString()) { + return TypedValueT(static_cast(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(value.ValueMap().size()), ctx.memory); + } else { + return TypedValueT(static_cast(value.ValuePath().edges().size()), ctx.memory); + } +} + +template +TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("startNode", args, nargs); + if (args[0].IsNull()) return TypedValueT(ctx.memory); + if constexpr (std::is_same_v) { + 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 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 +TypedValueT Degree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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) { + 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(out_degree + in_degree), ctx.memory); +} + +template +TypedValueT InDegree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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) { + in_degree = UnwrapDegreeResult(vertex.InDegree(ctx.view)); + } else { + in_degree = vertex.InDegree(); + } + return TypedValueT(static_cast(in_degree), ctx.memory); +} + +template +TypedValueT OutDegree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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) { + out_degree = UnwrapDegreeResult(vertex.OutDegree(ctx.view)); + } else { + out_degree = vertex.OutDegree(); + } + return TypedValueT(static_cast(out_degree), ctx.memory); +} + +template +TypedValueT ToBoolean(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT ToFloat(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("toFloat", args, nargs); + const auto &value = args[0]; + if (value.IsNull()) { + return TypedValueT(ctx.memory); + } else if (value.IsInt()) { + return TypedValueT(static_cast(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 +TypedValueT ToInteger(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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(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(utils::ParseDouble(utils::Trim(value.ValueString()))), ctx.memory); + } catch (const utils::BasicException &) { + return TypedValueT(ctx.memory); + } + } +} + +template +TypedValueT Type(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT ValueType(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT Keys(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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) { + 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 +TypedValueT Labels(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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) { + 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 +TypedValueT Nodes(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT Relationships(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT Range(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or, Optional>>("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 +TypedValueT Tail(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT UniformSample(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or>("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 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 +TypedValueT Abs(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 \ + TypedValueT name(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { \ + FType>(#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 +TypedValueT Atan2(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or>("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 +TypedValueT Sign(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT E(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType("e", args, nargs); + return TypedValueT(M_E, ctx.memory); +} + +template +TypedValueT Pi(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType("pi", args, nargs); + return TypedValueT(M_PI, ctx.memory); +} + +template +TypedValueT Rand(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType("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 +TypedValueT StringMatchOperator(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or>(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 +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 +inline auto StartsWith = StringMatchOperator, TypedValueT, FunctionContextT>; + +// Check if s1 ends with s2. +template +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 +inline auto EndsWith = StringMatchOperator, TypedValueT, FunctionContextT>; + +// Check if s1 contains s2. +template +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 +inline auto Contains = StringMatchOperator, TypedValueT, FunctionContextT>; + +template +TypedValueT Assert(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT Counter(const TypedValueT *args, int64_t nargs, const FunctionContextT &context) { + FType>("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 +TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("id", args, nargs); + const auto &arg = args[0]; + if (arg.IsNull()) { + return TypedValueT(ctx.memory); + } else if (arg.IsVertex()) { + return TypedValueT(static_cast(arg.ValueVertex().CypherId()), ctx.memory); + } else { + return TypedValueT(static_cast(arg.ValueEdge().CypherId()), ctx.memory); + } +} + +template +TypedValueT ToString(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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 +TypedValueT Timestamp(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>>("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 +TypedValueT Left(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or>("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 +TypedValueT Right(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or>("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 +TypedValueT CallStringFunction( + const TypedValueT *args, int64_t nargs, utils::MemoryResource *memory, const char *name, + std::function fun) { + FType>(name, args, nargs); + if (args[0].IsNull()) return TypedValueT(memory); + return TypedValueT(fun(args[0].ValueString()), memory); +} + +template +TypedValueT LTrim(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction(args, nargs, ctx.memory, "lTrim", [&](const auto &str) { + return typename TypedValueT::TString(utils::LTrim(str), ctx.memory); + }); +} + +template +TypedValueT RTrim(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction(args, nargs, ctx.memory, "rTrim", [&](const auto &str) { + return typename TypedValueT::TString(utils::RTrim(str), ctx.memory); + }); +} + +template +TypedValueT Trim(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction(args, nargs, ctx.memory, "trim", [&](const auto &str) { + return typename TypedValueT::TString(utils::Trim(str), ctx.memory); + }); +} + +template +TypedValueT Reverse(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction( + args, nargs, ctx.memory, "reverse", [&](const auto &str) { return utils::Reversed(str, ctx.memory); }); +} + +template +TypedValueT ToLower(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction(args, nargs, ctx.memory, "toLower", [&](const auto &str) { + typename TypedValueT::TString res(ctx.memory); + utils::ToLowerCase(&res, str); + return res; + }); +} + +template +TypedValueT ToUpper(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + return CallStringFunction(args, nargs, ctx.memory, "toUpper", [&](const auto &str) { + typename TypedValueT::TString res(ctx.memory); + utils::ToUpperCase(&res, str); + return res; + }); +} + +template +TypedValueT Replace(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or, Or>("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 +TypedValueT Split(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, Or>("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 +TypedValueT Substring(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType, NonNegativeInteger, Optional>("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 +TypedValueT ToByteString(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType("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(byte)); + } + return TypedValueT(std::move(bytes)); +} + +template +TypedValueT FromByteString(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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(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('0') + val : static_cast('a') + val - 10U; + return utils::MemcpyCast(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 +concept IsNumberOrInteger = utils::SameAsAnyOf; + +template +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 && value.IsDouble()) { + *it->second = value.ValueDouble(); + } else { + std::string_view error = std::is_same_v ? "an integer." : "a numeric value."; + throw FunctionRuntimeException("Invalid value for key '{}'. Expected {}", key, error); + } + } else { + throw FunctionRuntimeException("Unknown key '{}'.", key); + } + } +} + +template +TypedValueT Date(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>>("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(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::Date(date_parameters), ctx.memory); +} + +template +TypedValueT LocalTime(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>>("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(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::LocalTime(local_time_parameters), ctx.memory); +} + +template +TypedValueT LocalDateTime(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>>("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(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::LocalDateTime(date_parameters, local_time_parameters), ctx.memory); +} + +template +TypedValueT Duration(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { + FType>("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(parameter_mappings, args[0].ValueMap()); + return TypedValueT(utils::Duration(duration_parameters), ctx.memory); +} + +} // namespace memgraph::functions::impl + +namespace memgraph::functions { + +template +std::function +NameToFunction(const std::string &function_name) { + // Scalar functions + if (function_name == "DEGREE") return functions::impl::Degree; + if (function_name == "INDEGREE") return functions::impl::InDegree; + if (function_name == "OUTDEGREE") return functions::impl::OutDegree; + if (function_name == "ENDNODE") return functions::impl::EndNode; + if (function_name == "HEAD") return functions::impl::Head; + if (function_name == kId) return functions::impl::Id; + if (function_name == "LAST") return functions::impl::Last; + if (function_name == "PROPERTIES") return functions::impl::Properties; + if (function_name == "SIZE") return functions::impl::Size; + if (function_name == "STARTNODE") return functions::impl::StartNode; + if (function_name == "TIMESTAMP") return functions::impl::Timestamp; + if (function_name == "TOBOOLEAN") return functions::impl::ToBoolean; + if (function_name == "TOFLOAT") return functions::impl::ToFloat; + if (function_name == "TOINTEGER") return functions::impl::ToInteger; + if (function_name == "TYPE") return functions::impl::Type; + if (function_name == "VALUETYPE") return functions::impl::ValueType; + + // List functions + if (function_name == "KEYS") return functions::impl::Keys; + if (function_name == "LABELS") return functions::impl::Labels; + if (function_name == "NODES") return functions::impl::Nodes; + if (function_name == "RANGE") return functions::impl::Range; + if (function_name == "RELATIONSHIPS") return functions::impl::Relationships; + if (function_name == "TAIL") return functions::impl::Tail; + if (function_name == "UNIFORMSAMPLE") return functions::impl::UniformSample; + + // Mathematical functions - numeric + if (function_name == "ABS") return functions::impl::Abs; + if (function_name == "CEIL") return functions::impl::Ceil; + if (function_name == "FLOOR") return functions::impl::Floor; + if (function_name == "RAND") return functions::impl::Rand; + if (function_name == "ROUND") return functions::impl::Round; + if (function_name == "SIGN") return functions::impl::Sign; + + // Mathematical functions - logarithmic + if (function_name == "E") return functions::impl::E; + if (function_name == "EXP") return functions::impl::Exp; + if (function_name == "LOG") return functions::impl::Log; + if (function_name == "LOG10") return functions::impl::Log10; + if (function_name == "SQRT") return functions::impl::Sqrt; + + // Mathematical functions - trigonometric + if (function_name == "ACOS") return functions::impl::Acos; + if (function_name == "ASIN") return functions::impl::Asin; + if (function_name == "ATAN") return functions::impl::Atan; + if (function_name == "ATAN2") return functions::impl::Atan2; + if (function_name == "COS") return functions::impl::Cos; + if (function_name == "PI") return functions::impl::Pi; + if (function_name == "SIN") return functions::impl::Sin; + if (function_name == "TAN") return functions::impl::Tan; + + // String functions + if (function_name == kContains) return functions::impl::Contains; + if (function_name == kEndsWith) return functions::impl::EndsWith; + if (function_name == "LEFT") return functions::impl::Left; + if (function_name == "LTRIM") return functions::impl::LTrim; + if (function_name == "REPLACE") return functions::impl::Replace; + if (function_name == "REVERSE") return functions::impl::Reverse; + if (function_name == "RIGHT") return functions::impl::Right; + if (function_name == "RTRIM") return functions::impl::RTrim; + if (function_name == "SPLIT") return functions::impl::Split; + if (function_name == kStartsWith) return functions::impl::StartsWith; + if (function_name == "SUBSTRING") return functions::impl::Substring; + if (function_name == "TOLOWER") return functions::impl::ToLower; + if (function_name == "TOSTRING") return functions::impl::ToString; + if (function_name == "TOUPPER") return functions::impl::ToUpper; + if (function_name == "TRIM") return functions::impl::Trim; + + // Memgraph specific functions + if (function_name == "ASSERT") return functions::impl::Assert; + if (function_name == "COUNTER") return functions::impl::Counter; + if (function_name == "TOBYTESTRING") return functions::impl::ToByteString; + if (function_name == "FROMBYTESTRING") return functions::impl::FromByteString; + + // Functions for temporal types + if (function_name == "DATE") return functions::impl::Date; + if (function_name == "LOCALTIME") return functions::impl::LocalTime; + if (function_name == "LOCALDATETIME") return functions::impl::LocalDateTime; + if (function_name == "DURATION") return functions::impl::Duration; + + 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 InDegree(storage::View view) const { return impl_.InDegree(view); } - // - // storage::Result 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 vertices_; + std::vector 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" + const functions::FunctionContext &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp - self->${member} = query::v2::NameToFunction(self->function_name_); + self->${member} = functions::NameToFunction, + functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(self->function_name_); cpp<#))) (:public #>cpp @@ -865,7 +869,8 @@ cpp<# const std::vector &arguments) : arguments_(arguments), function_name_(function_name), - function_(NameToFunction(function_name_)) { + function_(functions::NameToFunction, + 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 -#include -#include -#include -#include -#include -#include -#include - -#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` 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, 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` check. -// * Two arguments were supplied, the 1st one passes `Or` 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, NonNegativeInteger, -// Optional>("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 -bool ArgIsType(const TypedValue &arg) { - if constexpr (std::is_same_v) { - return arg.IsNull(); - } else if constexpr (std::is_same_v) { - return arg.IsBool(); - } else if constexpr (std::is_same_v) { - return arg.IsInt(); - } else if constexpr (std::is_same_v) { - return arg.IsInt() && arg.ValueInt() > 0; - } else if constexpr (std::is_same_v) { - return arg.IsInt() && arg.ValueInt() != 0; - } else if constexpr (std::is_same_v) { - return arg.IsInt() && arg.ValueInt() >= 0; - } else if constexpr (std::is_same_v) { - return arg.IsDouble(); - } else if constexpr (std::is_same_v) { - return arg.IsNumeric(); - } else if constexpr (std::is_same_v) { - return arg.IsList(); - } else if constexpr (std::is_same_v) { - return arg.IsString(); - } else if constexpr (std::is_same_v) { - return arg.IsMap(); - } else if constexpr (std::is_same_v) { - return arg.IsVertex(); - } else if constexpr (std::is_same_v) { - return arg.IsEdge(); - } else if constexpr (std::is_same_v) { - return arg.IsPath(); - } else if constexpr (std::is_same_v) { - return arg.IsDate(); - } else if constexpr (std::is_same_v) { - return arg.IsLocalTime(); - } else if constexpr (std::is_same_v) { - return arg.IsLocalDateTime(); - } else if constexpr (std::is_same_v) { - return arg.IsDuration(); - } else if constexpr (std::is_same_v) { - return true; - } else { - static_assert(std::is_same_v, "Unknown ArgType"); - } - return false; -} - -template -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) { - return "null"; - } else if constexpr (std::is_same_v) { - return "boolean"; - } else if constexpr (std::is_same_v) { - return "integer"; - } else if constexpr (std::is_same_v) { - return "positive integer"; - } else if constexpr (std::is_same_v) { - return "non-zero integer"; - } else if constexpr (std::is_same_v) { - return "non-negative integer"; - } else if constexpr (std::is_same_v) { - return "float"; - } else if constexpr (std::is_same_v) { - return "number"; - } else if constexpr (std::is_same_v) { - return "list"; - } else if constexpr (std::is_same_v) { - return "string"; - } else if constexpr (std::is_same_v) { - return "map"; - } else if constexpr (std::is_same_v) { - return "node"; - } else if constexpr (std::is_same_v) { - return "relationship"; - } else if constexpr (std::is_same_v) { - return "path"; - } else if constexpr (std::is_same_v) { - return "void"; - } else if constexpr (std::is_same_v) { - return "Date"; - } else if constexpr (std::is_same_v) { - return "LocalTime"; - } else if constexpr (std::is_same_v) { - return "LocalDateTime"; - } else if constexpr (std::is_same_v) { - return "Duration"; - } else { - static_assert(std::is_same_v, "Unknown ArgType"); - } - return ""; -} - -template -struct Or; - -template -struct Or { - static bool Check(const TypedValue &arg) { return ArgIsType(arg); } - - static std::string TypeNames() { return ArgTypeName(); } -}; - -template -struct Or { - static bool Check(const TypedValue &arg) { - if (ArgIsType(arg)) return true; - return Or::Check(arg); - } - - static std::string TypeNames() { - if constexpr (sizeof...(ArgTypes) > 1) { - return fmt::format("'{}', {}", ArgTypeName(), Or::TypeNames()); - } else { - return fmt::format("'{}' or '{}'", ArgTypeName(), Or::TypeNames()); - } - } -}; - -template -struct IsOrType { - static constexpr bool value = false; -}; - -template -struct IsOrType> { - static constexpr bool value = true; -}; - -template -struct Optional; - -template -struct Optional { - 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::value) { - if (!ArgType::Check(arg)) { - throw QueryRuntimeException("Optional '{}' argument at position {} must be either {}.", name, pos, - ArgType::TypeNames()); - } - } else { - if (!ArgIsType(arg)) - throw QueryRuntimeException("Optional '{}' argument at position {} must be '{}'.", name, pos, - ArgTypeName()); - } - } -}; - -template -struct Optional { - 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::Check(name, args, nargs, pos); - Optional::Check(name, args + 1, nargs - 1, pos + 1); - } -}; - -template -struct IsOptional { - static constexpr bool value = false; -}; - -template -struct IsOptional> { - static constexpr bool value = true; -}; - -template -constexpr size_t FTypeRequiredArgs() { - if constexpr (IsOptional::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(); - } -} - -template -constexpr size_t FTypeOptionalArgs() { - if constexpr (IsOptional::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(); - } -} - -template -void FType(const char *name, const TypedValue *args, int64_t nargs, int64_t pos = 1) { - if constexpr (std::is_same_v) { - if (nargs != 0) { - throw QueryRuntimeException("'{}' requires no arguments.", name); - } - return; - } - static constexpr int64_t required_args = FTypeRequiredArgs(); - static constexpr int64_t optional_args = FTypeOptionalArgs(); - 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::value) { - if (!ArgType::Check(arg)) { - throw QueryRuntimeException("'{}' argument at position {} must be either {}.", name, pos, ArgType::TypeNames()); - } - } else if constexpr (IsOptional::value) { - static_assert(sizeof...(ArgTypes) == 0, "Optional arguments must be last!"); - ArgType::Check(name, args, nargs, pos); - } else { - if (!ArgIsType(arg)) { - throw QueryRuntimeException("'{}' argument at position {} must be '{}'", name, pos, ArgTypeName()); - } - } - if constexpr (sizeof...(ArgTypes) > 0) { - FType(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>("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>("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>("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>("size", args, nargs); - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsList()) { - return TypedValue(static_cast(value.ValueList().size()), ctx.memory); - } else if (value.IsString()) { - return TypedValue(static_cast(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(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>("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>("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>("toFloat", args, nargs); - const auto &value = args[0]; - if (value.IsNull()) { - return TypedValue(ctx.memory); - } else if (value.IsInt()) { - return TypedValue(static_cast(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>("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(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(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>("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>("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, Optional>>("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>("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>("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 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>("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>(#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>("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>("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("e", args, nargs); - return TypedValue(M_E, ctx.memory); -} - -TypedValue Pi(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType("pi", args, nargs); - return TypedValue(M_PI, ctx.memory); -} - -TypedValue Rand(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType("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 -TypedValue StringMatchOperator(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType, Or>(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; - -// 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; - -// 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; - -TypedValue Assert(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType>("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>("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>("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>("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>>("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>("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>("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 fun) { - FType>(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, Or>("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>("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, NonNegativeInteger, Optional>("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("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(byte)); - } - return TypedValue(std::move(bytes)); -} - -TypedValue FromByteString(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) { - FType>("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(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('0') + val : static_cast('a') + val - 10U; - return utils::MemcpyCast(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 -concept IsNumberOrInteger = utils::SameAsAnyOf; - -template -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 && value.IsDouble()) { - *it->second = value.ValueDouble(); - } else { - std::string_view error = std::is_same_v ? "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>>("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(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>>("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(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>>("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(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>("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(parameter_mappings, args[0].ValueMap()); - return TypedValue(utils::Duration(duration_parameters), ctx.memory); -} - -} // namespace - -std::function 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 -#include -#include - -#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 *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 -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(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(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 *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" + const functions::FunctionContext &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp + self->${member} = functions::NameToFunction, + functions::StorageEngineTag, Conv>(self->function_name_); cpp<#))) (:public #>cpp Function() = default; + using Conv = decltype(PropertyToTypedValueFunctor); + class SemanticException : public memgraph::utils::BasicException { + using utils::BasicException::BasicException; + }; + DEFVISITABLE(ExpressionVisitor); DEFVISITABLE(ExpressionVisitor); @@ -872,7 +874,13 @@ cpp<# Function(const std::string &function_name, const std::vector &arguments) : arguments_(arguments), - function_name_(function_name) { + function_name_(function_name), + function_(functions::NameToFunction, + 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> 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 +inline const auto PropertyToTypedValueFunctor = + [](const PropertyValue &value) { return PropertyToTypedValue(value); }; + template 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 EdgeAccessor::SetProperty(PropertyId property, const PropertyValue &value) { utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception; @@ -179,4 +179,7 @@ Result> 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>>> 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>>> 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 &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 &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 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 Date: Wed, 9 Nov 2022 18:15:30 +0200 Subject: [PATCH 02/16] 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 Date: Mon, 14 Nov 2022 20:44:32 +0200 Subject: [PATCH 03/16] 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 +#include +#include +#include +#include +#include + +#include +#include + +#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 Request( + memgraph::msgs::ExecutionState &state) override { + return {}; + } + + std::vector Request(memgraph::msgs::ExecutionState &state, + std::vector new_vertices) override { + return {}; + } + + std::vector Request(memgraph::msgs::ExecutionState &state, + ExpandOneRequest request) override { + return {}; + } + + std::vector Request(memgraph::msgs::ExecutionState &state, + std::vector 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 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 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 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{"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 shard_manager = + std::make_unique(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(name, true); + auto symbol = symbol_table.CreateSymbol(name, true); + id->MapTo(symbol); + frame[symbol] = value; + return id; + } + + template + 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(storage.Create(true), storage.Create(false)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create(storage.Create(true), storage.Create(true)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, XorOperator) { + auto *op = + storage.Create(storage.Create(true), storage.Create(false)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create(storage.Create(true), storage.Create(true)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, AndOperator) { + auto *op = + storage.Create(storage.Create(true), storage.Create(true)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create(storage.Create(false), storage.Create(true)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, AndOperatorShortCircuit) { + { + auto *op = + storage.Create(storage.Create(false), storage.Create(5)); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), false); + } + { + auto *op = + storage.Create(storage.Create(5), storage.Create(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(storage.Create(TypedValue()), + storage.Create(5)); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + auto *op = storage.Create(storage.Create(TypedValue()), + storage.Create(true)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + auto *op = storage.Create(storage.Create(TypedValue()), + storage.Create(false)); + auto value = Eval(op); + ASSERT_TRUE(value.IsBool()); + EXPECT_EQ(value.ValueBool(), false); + } +} + +TEST_F(ExpressionEvaluatorTest, AdditionOperator) { + auto *op = storage.Create(storage.Create(2), storage.Create(3)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, SubtractionOperator) { + auto *op = + storage.Create(storage.Create(2), storage.Create(3)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), -1); +} + +TEST_F(ExpressionEvaluatorTest, MultiplicationOperator) { + auto *op = + storage.Create(storage.Create(2), storage.Create(3)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 6); +} + +TEST_F(ExpressionEvaluatorTest, DivisionOperator) { + auto *op = + storage.Create(storage.Create(50), storage.Create(10)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, ModOperator) { + auto *op = storage.Create(storage.Create(65), storage.Create(10)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, EqualOperator) { + auto *op = storage.Create(storage.Create(10), storage.Create(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create(storage.Create(15), storage.Create(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); + op = storage.Create(storage.Create(20), storage.Create(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, NotEqualOperator) { + auto *op = + storage.Create(storage.Create(10), storage.Create(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create(storage.Create(15), storage.Create(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); + op = storage.Create(storage.Create(20), storage.Create(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, LessOperator) { + auto *op = storage.Create(storage.Create(10), storage.Create(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create(storage.Create(15), storage.Create(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); + op = storage.Create(storage.Create(20), storage.Create(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, GreaterOperator) { + auto *op = + storage.Create(storage.Create(10), storage.Create(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create(storage.Create(15), storage.Create(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), false); + op = storage.Create(storage.Create(20), storage.Create(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, LessEqualOperator) { + auto *op = + storage.Create(storage.Create(10), storage.Create(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), true); + op = storage.Create(storage.Create(15), storage.Create(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); + op = storage.Create(storage.Create(20), storage.Create(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), false); +} + +TEST_F(ExpressionEvaluatorTest, GreaterEqualOperator) { + auto *op = + storage.Create(storage.Create(10), storage.Create(15)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create(storage.Create(15), storage.Create(15)); + auto val2 = Eval(op); + ASSERT_EQ(val2.ValueBool(), true); + op = storage.Create(storage.Create(20), storage.Create(15)); + auto val3 = Eval(op); + ASSERT_EQ(val3.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, InListOperator) { + auto *list_literal = storage.Create(std::vector{ + storage.Create(1), storage.Create(2), storage.Create("a")}); + { + // Element exists in list. + auto *op = storage.Create(storage.Create(2), list_literal); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), true); + } + { + // Element doesn't exist in list. + auto *op = storage.Create(storage.Create("x"), list_literal); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), false); + } + { + auto *list_literal = storage.Create( + std::vector{storage.Create(TypedValue()), storage.Create(2), + storage.Create("a")}); + // Element doesn't exist in list with null element. + auto *op = storage.Create(storage.Create("x"), list_literal); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Null list. + auto *op = storage.Create(storage.Create("x"), + storage.Create(TypedValue())); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Null literal. + auto *op = storage.Create(storage.Create(TypedValue()), list_literal); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Null literal, empty list. + auto *op = storage.Create(storage.Create(TypedValue()), + storage.Create(std::vector())); + auto value = Eval(op); + EXPECT_FALSE(value.ValueBool()); + } +} + +TEST_F(ExpressionEvaluatorTest, ListIndexing) { + auto *list_literal = storage.Create( + std::vector{storage.Create(1), storage.Create(2), + storage.Create(3), storage.Create(4)}); + { + // Legal indexing. + auto *op = storage.Create(list_literal, storage.Create(2)); + auto value = Eval(op); + EXPECT_EQ(value.ValueInt(), 3); + } + { + // Out of bounds indexing. + auto *op = storage.Create(list_literal, storage.Create(4)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Out of bounds indexing with negative bound. + auto *op = storage.Create(list_literal, storage.Create(-100)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Legal indexing with negative index. + auto *op = storage.Create(list_literal, storage.Create(-2)); + auto value = Eval(op); + EXPECT_EQ(value.ValueInt(), 3); + } + { + // Indexing with one operator being null. + auto *op = storage.Create(storage.Create(TypedValue()), + storage.Create(-2)); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Indexing with incompatible type. + auto *op = storage.Create(list_literal, storage.Create("bla")); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } +} + +TEST_F(ExpressionEvaluatorTest, MapIndexing) { + auto *map_literal = storage.Create( + std::unordered_map{{storage.GetPropertyIx("a"), storage.Create(1)}, + {storage.GetPropertyIx("b"), storage.Create(2)}, + {storage.GetPropertyIx("c"), storage.Create(3)}}); + { + // Legal indexing. + auto *op = storage.Create(map_literal, storage.Create("b")); + auto value = Eval(op); + EXPECT_EQ(value.ValueInt(), 2); + } + { + // Legal indexing, non-existing key. + auto *op = storage.Create(map_literal, storage.Create("z")); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } + { + // Wrong key type. + auto *op = storage.Create(map_literal, storage.Create(42)); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + // Indexing with Null. + auto *op = storage.Create(map_literal, storage.Create(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> 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> 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(42))}}, shard_manager.get()); + auto edge = CreateEdge({{prop, Value(static_cast(43))}}, shard_manager.get()); + + auto *vertex_id = CreateIdentifierWithValue("v1", TypedValue(vertex)); + auto *edge_id = CreateIdentifierWithValue("e11", TypedValue(edge)); + { + // Legal indexing. + auto *op1 = storage.Create(vertex_id, storage.Create("prop")); + auto value1 = Eval(op1); + EXPECT_EQ(value1.ValueInt(), 42); + + auto *op2 = storage.Create(edge_id, storage.Create("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(vertex_id, storage.Create("blah")); + // auto value1 = Eval(op1); + // EXPECT_TRUE(value1.IsNull()); + // + // auto *op2 = storage.Create(edge_id, storage.Create("blah")); + // auto value2 = Eval(op2); + // EXPECT_TRUE(value2.IsNull()); + // } + // { + // // Wrong key type. + // auto *op1 = storage.Create(vertex_id, storage.Create(1)); + // EXPECT_THROW(Eval(op1), ExpressionRuntimeException); + // + // auto *op2 = storage.Create(edge_id, storage.Create(1)); + // EXPECT_THROW(Eval(op2), ExpressionRuntimeException); + // } + // { + // // Indexing with Null. + // auto *op1 = storage.Create(vertex_id, + // storage.Create(memgraph::storage::PropertyValue())); + // auto value1 = Eval(op1); + // EXPECT_TRUE(value1.IsNull()); + // + // auto *op2 = storage.Create(edge_id, + // storage.Create(memgraph::storage::PropertyValue())); + // auto value2 = Eval(op2); + // EXPECT_TRUE(value2.IsNull()); + // } +} + +TEST_F(ExpressionEvaluatorTest, ListSlicingOperator) { + auto *list_literal = storage.Create( + std::vector{storage.Create(1), storage.Create(2), + storage.Create(3), storage.Create(4)}); + + auto extract_ints = [](TypedValue list) { + std::vector 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(list_literal, storage.Create(2), + storage.Create(4)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(3, 4)); + } + { + // Legal slicing with negative bound. + auto *op = storage.Create(list_literal, storage.Create(2), + storage.Create(-1)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(3)); + } + { + // Lower bound larger than upper bound. + auto *op = storage.Create(list_literal, storage.Create(2), + storage.Create(-4)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre()); + } + { + // Bounds ouf or range. + auto *op = storage.Create(list_literal, storage.Create(-100), + storage.Create(10)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(1, 2, 3, 4)); + } + { + // Lower bound undefined. + auto *op = storage.Create(list_literal, nullptr, storage.Create(3)); + auto value = Eval(op); + EXPECT_THAT(extract_ints(value), ElementsAre(1, 2, 3)); + } + { + // Upper bound undefined. + auto *op = storage.Create(list_literal, storage.Create(-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(list_literal, storage.Create(TypedValue()), + storage.Create("mirko")); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + // List of illegal type. + auto *op = storage.Create(storage.Create("a"), + storage.Create(-2), nullptr); + EXPECT_THROW(Eval(op), ExpressionRuntimeException); + } + { + // Null value list with undefined upper bound. + auto *op = storage.Create(storage.Create(TypedValue()), + storage.Create(-2), nullptr); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + ; + } + { + // Null value index. + auto *op = storage.Create(list_literal, storage.Create(-2), + storage.Create(TypedValue())); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + ; + } +} + +TEST_F(ExpressionEvaluatorTest, IfOperator) { + auto *then_expression = storage.Create(10); + auto *else_expression = storage.Create(20); + { + auto *condition_true = + storage.Create(storage.Create(2), storage.Create(2)); + auto *op = storage.Create(condition_true, then_expression, else_expression); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 10); + } + { + auto *condition_false = + storage.Create(storage.Create(2), storage.Create(3)); + auto *op = storage.Create(condition_false, then_expression, else_expression); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 20); + } + { + auto *condition_exception = + storage.Create(storage.Create(2), storage.Create(3)); + auto *op = storage.Create(condition_exception, then_expression, else_expression); + ASSERT_THROW(Eval(op), ExpressionRuntimeException); + } +} + +TEST_F(ExpressionEvaluatorTest, NotOperator) { + auto *op = storage.Create(storage.Create(false)); + auto value = Eval(op); + ASSERT_EQ(value.ValueBool(), true); +} + +TEST_F(ExpressionEvaluatorTest, UnaryPlusOperator) { + auto *op = storage.Create(storage.Create(5)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), 5); +} + +TEST_F(ExpressionEvaluatorTest, UnaryMinusOperator) { + auto *op = storage.Create(storage.Create(5)); + auto value = Eval(op); + ASSERT_EQ(value.ValueInt(), -5); +} + +TEST_F(ExpressionEvaluatorTest, IsNullOperator) { + auto *op = storage.Create(storage.Create(1)); + auto val1 = Eval(op); + ASSERT_EQ(val1.ValueBool(), false); + op = storage.Create(storage.Create(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("n"); +// auto node_symbol = symbol_table.CreateSymbol("n", true); +// identifier->MapTo(node_symbol); +// frame[node_symbol] = TypedValue(v1); +// { +// auto *op = storage.Create( +// identifier, std::vector{storage.GetLabelIx("DOG"), storage.GetLabelIx("ANIMAL")}); +// auto value = Eval(op); +// EXPECT_EQ(value.ValueBool(), true); +// } +// { +// auto *op = storage.Create( +// identifier, +// std::vector{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( +// identifier, +// std::vector{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(storage.Create(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(std::vector{storage.Create(1), + storage.Create("bla"), + storage.Create(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(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(LITERAL(TypedValue()), LITERAL("regex"))).IsNull()); + EXPECT_TRUE(Eval(storage.Create(LITERAL(3), LITERAL("regex"))).IsNull()); + EXPECT_TRUE(Eval(storage.Create(LIST(LITERAL("string")), LITERAL("regex"))).IsNull()); + EXPECT_TRUE(Eval(storage.Create(LITERAL("string"), LITERAL(TypedValue()))).IsNull()); + EXPECT_THROW(Eval(storage.Create(LITERAL("string"), LITERAL(42))), ExpressionRuntimeException); + EXPECT_THROW(Eval(storage.Create(LITERAL("string"), LIST(LITERAL("regex")))), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, RegexMatchInvalidRegex) { + EXPECT_THROW(Eval(storage.Create(LITERAL("text"), LITERAL("*ext"))), ExpressionRuntimeException); + EXPECT_THROW(Eval(storage.Create(LITERAL("text"), LITERAL("[ext"))), ExpressionRuntimeException); +} + +TEST_F(ExpressionEvaluatorTest, RegexMatch) { + EXPECT_FALSE(Eval(storage.Create(LITERAL("text"), LITERAL(".*ex"))).ValueBool()); + EXPECT_TRUE(Eval(storage.Create(LITERAL("text"), LITERAL(".*ext"))).ValueBool()); + EXPECT_FALSE(Eval(storage.Create(LITERAL("text"), LITERAL("[ext]"))).ValueBool()); + EXPECT_TRUE(Eval(storage.Create(LITERAL("text"), LITERAL(".+[ext]"))).ValueBool()); +} + +class ExpressionEvaluatorPropertyLookup : public ExpressionEvaluatorTest { + protected: + std::pair prop_age = + std::make_pair("age", shard_manager->NameToProperty("age")); + std::pair prop_height = + std::make_pair("height", shard_manager->NameToProperty("height")); + Identifier *identifier = storage.Create("element"); + Symbol symbol = symbol_table.CreateSymbol("element", true); + + void SetUp() { identifier->MapTo(symbol); } + + auto Value(std::pair property) { + auto *op = storage.Create(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{{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 ExpressionsFromTypedValues(const std::vector &tvs) { + std::vector expressions; + expressions.reserve(tvs.size()); + + for (size_t i = 0; i < tvs.size(); ++i) { + auto *ident = storage.Create("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 &expressions) { + auto *op = storage.Create(function_name, expressions); + return Eval(op); + } + + template + TypedValue EvaluateFunction(const std::string &function_name, std::tuple args) { + std::vector 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 + TypedValue EvaluateFunction(const std::string &function_name, TArgs &&...args) { + return EvaluateFunctionWithExprs(function_name, + ExpressionsFromTypedValues(std::vector{TypedValue(args)...})); + } +}; + +template +static TypedValue MakeTypedValueList(TArgs &&...args) { + return TypedValue(std::vector{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(5))}, {age, Value(static_cast(10))}}, + shard_manager.get()); + auto e = CreateEdge({{height, Value(static_cast(3))}, {age, Value(static_cast(15))}}, + shard_manager.get()); + + auto prop_values_to_int = [](TypedValue t) { + std::unordered_map 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{ + {"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(1), TypedValue(2)})).ValueString(), + "LIST"); + ASSERT_EQ(EvaluateFunction("VALUETYPE", TypedValue(std::map{{"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 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 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 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(5))}, {age, Value(static_cast(10))}}, + shard_manager.get()); + auto edge = CreateEdge({{height, Value(static_cast(3))}, {age, Value(static_cast(15))}}, + shard_manager.get()); + auto prop_keys_to_string = [](TypedValue t) { + std::vector 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{{"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{{"years", TypedValue(1970)}}), +// ExpressionRuntimeException); +// EXPECT_THROW(EvaluateFunction("DATE", std::map{{"mnths", TypedValue(1970)}}), +// ExpressionRuntimeException); +// EXPECT_THROW(EvaluateFunction("DATE", std::map{{"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{{"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{{"hous", +// TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("LOCALTIME", TypedValue(std::map{{"minut", TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("LOCALTIME", TypedValue(std::map{{"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{{"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{{"hours", TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("LOCALDATETIME", TypedValue(std::map{{"seconds", +// TypedValue(1970)}})), ExpressionRuntimeException); +// } +// +// TEST_F(FunctionTest, Duration) { +// const auto map_param = TypedValue(std::map{{"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{{"hours", +// TypedValue(1970)}})), +// ExpressionRuntimeException); +// EXPECT_THROW( +// EvaluateFunction("DURATION", TypedValue(std::map{{"seconds", TypedValue(1970)}})), +// ExpressionRuntimeException); +// +// const auto map_param_negative = TypedValue(std::map{{"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 Date: Mon, 14 Nov 2022 21:22:28 +0200 Subject: [PATCH 04/16] 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 { 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 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 @@ -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(value.ValueList().size()), ctx.memory); - } else if (value.IsString()) { + } + if (value.IsString()) { return TypedValueT(static_cast(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(value.ValueMap().size()), ctx.memory); - } else { - return TypedValueT(static_cast(value.ValuePath().edges().size()), ctx.memory); } + return TypedValueT(static_cast(value.ValuePath().edges().size()), ctx.memory); } template @@ -527,9 +527,9 @@ TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionCont } } -namespace { - -size_t UnwrapDegreeResult(storage::v3::Result 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 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 maybe_degree) { return *maybe_degree; } -} // namespace - template TypedValueT Degree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType>("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 @@ -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(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(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(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(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 @@ -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 \ 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 @@ -962,7 +964,7 @@ struct StartsWithPredicate { }; template -inline auto StartsWith = StringMatchOperator, TypedValueT, FunctionContextT>; +inline const auto StartsWith = StringMatchOperator, TypedValueT, FunctionContextT>; // Check if s1 ends with s2. template @@ -975,7 +977,7 @@ struct EndsWithPredicate { }; template -inline auto EndsWith = StringMatchOperator, TypedValueT, FunctionContextT>; +inline const auto EndsWith = StringMatchOperator, TypedValueT, FunctionContextT>; // Check if s1 contains s2. template @@ -988,7 +990,7 @@ struct ContainsPredicate { }; template -inline auto Contains = StringMatchOperator, TypedValueT, FunctionContextT>; +inline const auto Contains = StringMatchOperator, TypedValueT, FunctionContextT>; template 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(arg.ValueVertex().CypherId()), ctx.memory); - } else { - return TypedValueT(static_cast(arg.ValueEdge().CypherId()), ctx.memory); } + if (arg.IsVertex()) { + return TypedValueT(static_cast(arg.ValueVertex().CypherId()), ctx.memory); + } + return TypedValueT(static_cast(arg.ValueEdge().CypherId()), ctx.memory); } template 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> &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(vertex_id, storage.Create("blah")); - // auto value1 = Eval(op1); - // EXPECT_TRUE(value1.IsNull()); - // - // auto *op2 = storage.Create(edge_id, storage.Create("blah")); - // auto value2 = Eval(op2); - // EXPECT_TRUE(value2.IsNull()); - // } - // { - // // Wrong key type. - // auto *op1 = storage.Create(vertex_id, storage.Create(1)); - // EXPECT_THROW(Eval(op1), ExpressionRuntimeException); - // - // auto *op2 = storage.Create(edge_id, storage.Create(1)); - // EXPECT_THROW(Eval(op2), ExpressionRuntimeException); - // } - // { - // // Indexing with Null. - // auto *op1 = storage.Create(vertex_id, - // storage.Create(memgraph::storage::PropertyValue())); - // auto value1 = Eval(op1); - // EXPECT_TRUE(value1.IsNull()); - // - // auto *op2 = storage.Create(edge_id, - // storage.Create(memgraph::storage::PropertyValue())); - // auto value2 = Eval(op2); - // EXPECT_TRUE(value2.IsNull()); - // } + { + // Legal indexing, non-existing key. + auto *op1 = storage.Create(vertex_id, storage.Create("blah")); + auto value1 = Eval(op1); + EXPECT_TRUE(value1.IsNull()); + auto *op2 = storage.Create(edge_id, storage.Create("blah")); + auto value2 = Eval(op2); + EXPECT_TRUE(value2.IsNull()); + } + { + // Wrong key type. + auto *op1 = storage.Create(vertex_id, storage.Create(1)); + EXPECT_THROW(Eval(op1), ExpressionRuntimeException); + + auto *op2 = storage.Create(edge_id, storage.Create(1)); + EXPECT_THROW(Eval(op2), ExpressionRuntimeException); + } + { + // Indexing with Null. + auto *op1 = storage.Create(vertex_id, storage.Create(TypedValue{})); + auto value1 = Eval(op1); + EXPECT_TRUE(value1.IsNull()); + + auto *op2 = storage.Create(edge_id, storage.Create(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("n"); -// auto node_symbol = symbol_table.CreateSymbol("n", true); -// identifier->MapTo(node_symbol); -// frame[node_symbol] = TypedValue(v1); -// { -// auto *op = storage.Create( -// identifier, std::vector{storage.GetLabelIx("DOG"), storage.GetLabelIx("ANIMAL")}); -// auto value = Eval(op); -// EXPECT_EQ(value.ValueBool(), true); -// } -// { -// auto *op = storage.Create( -// identifier, -// std::vector{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( -// identifier, -// std::vector{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("n"); + auto node_symbol = symbol_table.CreateSymbol("n", true); + identifier->MapTo(node_symbol); + frame[node_symbol] = TypedValue(v1); + { + auto *op = storage.Create(identifier, std::vector{LabelIx{"label1", label.id.AsInt()}}); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), true); + } + { + auto *op = storage.Create(identifier, std::vector{LabelIx{"label2", 10}}); + auto value = Eval(op); + EXPECT_EQ(value.ValueBool(), false); + } + { + auto *op = storage.Create(identifier, std::vector{LabelIx{"label2", 10}}); + frame[node_symbol] = TypedValue(); + auto value = Eval(op); + EXPECT_TRUE(value.IsNull()); + } +} + TEST_F(ExpressionEvaluatorTest, Aggregation) { auto aggr = storage.Create(storage.Create(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(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 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 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{{"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{{"years", TypedValue(1970)}}), -// ExpressionRuntimeException); -// EXPECT_THROW(EvaluateFunction("DATE", std::map{{"mnths", TypedValue(1970)}}), -// ExpressionRuntimeException); -// EXPECT_THROW(EvaluateFunction("DATE", std::map{{"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{{"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{{"hous", -// TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("LOCALTIME", TypedValue(std::map{{"minut", TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("LOCALTIME", TypedValue(std::map{{"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{{"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{{"hours", TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("LOCALDATETIME", TypedValue(std::map{{"seconds", -// TypedValue(1970)}})), ExpressionRuntimeException); -// } -// -// TEST_F(FunctionTest, Duration) { -// const auto map_param = TypedValue(std::map{{"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{{"hours", -// TypedValue(1970)}})), -// ExpressionRuntimeException); -// EXPECT_THROW( -// EvaluateFunction("DURATION", TypedValue(std::map{{"seconds", TypedValue(1970)}})), -// ExpressionRuntimeException); -// -// const auto map_param_negative = TypedValue(std::map{{"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 6d544e4fc0e92490b657c1523ae5a71022f04bb4 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis Date: Wed, 23 Nov 2022 14:51:38 +0200 Subject: [PATCH 05/16] 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 { typename TReturnType = std::enable_if_t, 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 +template TypedValueT EndNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType>("endNode", args, nargs); - if (args[0].IsNull()) return TypedValueT(ctx.memory); - if constexpr (std::is_same_v) { - 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 @@ -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) { 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(value.ValuePath().edges().size()), ctx.memory); } -template +template TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType>("startNode", args, nargs); - if (args[0].IsNull()) return TypedValueT(ctx.memory); - if constexpr (std::is_same_v) { - 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 -TypedValueT Keys(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { - FType>("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) { - 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 TypedValueT Labels(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType>("labels", args, nargs); @@ -1026,12 +966,9 @@ template TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { FType>("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(arg.ValueVertex().CypherId()), ctx.memory); - } return TypedValueT(static_cast(arg.ValueEdge().CypherId()), ctx.memory); } @@ -1382,22 +1319,24 @@ NameToFunction(const std::string &function_name) { if (function_name == "DEGREE") return functions::impl::Degree; if (function_name == "INDEGREE") return functions::impl::InDegree; if (function_name == "OUTDEGREE") return functions::impl::OutDegree; - if (function_name == "ENDNODE") return functions::impl::EndNode; if (function_name == "HEAD") return functions::impl::Head; if (function_name == kId) return functions::impl::Id; if (function_name == "LAST") return functions::impl::Last; if (function_name == "PROPERTIES") return functions::impl::Properties; if (function_name == "SIZE") return functions::impl::Size; - if (function_name == "STARTNODE") return functions::impl::StartNode; if (function_name == "TIMESTAMP") return functions::impl::Timestamp; if (function_name == "TOBOOLEAN") return functions::impl::ToBoolean; if (function_name == "TOFLOAT") return functions::impl::ToFloat; if (function_name == "TOINTEGER") return functions::impl::ToInteger; if (function_name == "TYPE") return functions::impl::Type; if (function_name == "VALUETYPE") return functions::impl::ValueType; + // Only on QE + if constexpr (std::is_same_v) { + if (function_name == "STARTNODE") return functions::impl::StartNode; + if (function_name == "ENDNODE") return functions::impl::EndNode; + } // List functions - if (function_name == "KEYS") return functions::impl::Keys; if (function_name == "LABELS") return functions::impl::Labels; if (function_name == "NODES") return functions::impl::Nodes; if (function_name == "RANGE") return functions::impl::Range; @@ -1449,9 +1388,12 @@ NameToFunction(const std::string &function_name) { // Memgraph specific functions if (function_name == "ASSERT") return functions::impl::Assert; - if (function_name == "COUNTER") return functions::impl::Counter; if (function_name == "TOBYTESTRING") return functions::impl::ToByteString; if (function_name == "FROMBYTESTRING") return functions::impl::FromByteString; + // Only on QE + if constexpr (std::is_same_v) { + if (function_name == "COUNTER") return functions::impl::Counter; + } // Functions for temporal types if (function_name == "DATE") return functions::impl::Date; @@ -1459,6 +1401,13 @@ NameToFunction(const std::string &function_name) { if (function_name == "LOCALDATETIME") return functions::impl::LocalDateTime; if (function_name == "DURATION") return functions::impl::Duration; + // Only on QE + if constexpr (std::is_same_v) { + if (function_name == "COUNTER") return functions::impl::Counter; + if (function_name == "STARTNODE") return functions::impl::StartNode; + if (function_name == "ENDNODE") return functions::impl::EndNode; + } + 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> &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>{}, 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 &edge_types) const - // -> storage::Result { - // 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 &edge_types, const VertexAccessor &dest) - // const - // -> storage::Result { - // 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 &edge_types) const - // -> storage::Result { - // 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 &edge_types, - // const VertexAccessor &dest) const - // -> storage::Result { - // 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 MaybeNameToProperty(const std::string &name) const = 0; + virtual std::optional MaybeNameToEdge(const std::string &name) const = 0; + virtual std::optional 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 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 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 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 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 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 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> 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> 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> props, - const memgraph::msgs::ShardRequestManagerInterface *manager) { - auto edge = Edge{.src = VertexId{{}, 0}, - .dst = VertexId{{}, 0}, +accessors::EdgeAccessor CreateEdge(std::vector> 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(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 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(5))}, {age, Value(static_cast(10))}}, - shard_manager.get()); - auto edge = CreateEdge({{height, Value(static_cast(3))}, {age, Value(static_cast(15))}}, - shard_manager.get()); - auto prop_keys_to_string = [](TypedValue t) { - std::vector 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::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits::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::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::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits::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::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::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits::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::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::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits::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::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::max()); -// memgraph::storage::Gid gid_vertex2 = memgraph::storage::Gid::FromUint(std::numeric_limits::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::max()); -// memgraph::storage::Gid gid_to = memgraph::storage::Gid::FromUint(std::numeric_limits::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::max()); -// memgraph::storage::Gid gid_vertex2 = memgraph::storage::Gid::FromUint(std::numeric_limits::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::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::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::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::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 Date: Wed, 23 Nov 2022 15:16:14 +0200 Subject: [PATCH 06/16] 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 +template std::function 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> 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 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?= Date: Thu, 24 Nov 2022 11:13:55 +0100 Subject: [PATCH 07/16] 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(session); + return HandleRoute(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, 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, 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 Date: Fri, 25 Nov 2022 16:20:38 +0200 Subject: [PATCH 08/16] 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 #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) { 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 maybe_degree) { +inline size_t UnwrapDegreeResult(storage::v3::ShardResult 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) { 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 TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { - FType>("id", args, nargs); + FType>("id", args, nargs); const auto &arg = args[0]; - if (arg.IsNull() || arg.IsVertex()) { + if (arg.IsNull()) { return TypedValueT(ctx.memory); } return TypedValueT(static_cast(arg.ValueEdge().CypherId()), ctx.memory); @@ -1395,13 +1417,6 @@ NameToFunction(const std::string &function_name) { if (function_name == "LOCALDATETIME") return functions::impl::LocalDateTime; if (function_name == "DURATION") return functions::impl::Duration; - // Only on QE - if constexpr (std::is_same_v) { - if (function_name == "COUNTER") return functions::impl::Counter; - if (function_name == "STARTNODE") return functions::impl::StartNode; - if (function_name == "ENDNODE") return functions::impl::EndNode; - } - 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 MaybeNameToProperty(const std::string &name) const = 0; - virtual std::optional MaybeNameToEdge(const std::string &name) const = 0; + virtual std::optional MaybeNameToEdgeType(const std::string &name) const = 0; virtual std::optional 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 MaybeNameToEdge(const std::string &name) const override { + std::optional 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> 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 &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 &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 MaybeNameToEdge(const std::string &name) const override { + std::optional MaybeNameToEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name); } From a8dc6fd41e6480e546f0efca30df8bc7926b72f5 Mon Sep 17 00:00:00 2001 From: Tyler Neely Date: Mon, 28 Nov 2022 09:43:56 +0000 Subject: [PATCH 09/16] 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 &values) { @@ -512,7 +513,7 @@ class BoltSession final : public memgraph::communication::bolt::Session> props, - const msgs::ShardRequestManagerInterface *manager) + const ShardRequestManagerInterface *manager) : vertex(std::move(v)), properties(std::move(props)), manager_(manager) {} VertexAccessor::VertexAccessor(Vertex v, std::map &&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 &&props, } VertexAccessor::VertexAccessor(Vertex v, const std::map &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> props, - const msgs::ShardRequestManagerInterface *manager); + const ShardRequestManagerInterface *manager); - VertexAccessor(Vertex v, std::map &&props, const msgs::ShardRequestManagerInterface *manager); - VertexAccessor(Vertex v, const std::map &props, const msgs::ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, std::map &&props, const ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, const std::map &props, const ShardRequestManagerInterface *manager); [[nodiscard]] Label PrimaryLabel() const; @@ -150,7 +150,7 @@ class VertexAccessor final { private: Vertex vertex; std::vector> 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(val); + auto operator()(const storage::v3::PropertyValue &val) const { + return storage::v3::PropertyToTypedValue(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; } // 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 counters; }; -inline std::vector NamesToProperties( - const std::vector &property_names, msgs::ShardRequestManagerInterface *shard_request_manager) { +inline std::vector NamesToProperties(const std::vector &property_names, + ShardRequestManagerInterface *shard_request_manager) { std::vector properties; // TODO Fix by using reference properties.reserve(property_names.size()); @@ -74,7 +74,7 @@ inline std::vector NamesToProperties( } inline std::vector NamesToLabels(const std::vector &label_names, - msgs::ShardRequestManagerInterface *shard_request_manager) { + ShardRequestManagerInterface *shard_request_manager) { std::vector 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 MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector &predefined_identifiers) { auto vertex_counts = plan::MakeVertexCountCache(shard_manager); auto symbol_table = expr::MakeSymbolTable(query, predefined_identifiers); @@ -130,7 +130,7 @@ std::unique_ptr MakeLogicalPlan(AstStorage ast_storage, CypherQuery std::shared_ptr CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList *plan_cache, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector &predefined_identifiers) { std::optional::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 MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector &predefined_identifiers); /** @@ -145,7 +145,7 @@ std::unique_ptr MakeLogicalPlan(AstStorage ast_storage, CypherQuery */ std::shared_ptr CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList *plan_cache, - msgs::ShardRequestManagerInterface *shard_manager, + ShardRequestManagerInterface *shard_manager, const std::vector &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 *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 *notifications) { expr::Frame 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 frame(0); SymbolTable symbol_table; EvaluationContext evaluation_context; @@ -649,7 +649,7 @@ struct PullPlanVector { struct PullPlan { explicit PullPlan(std::shared_ptr 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 memory_limit = {}); std::optional Pull(AnyStream *stream, std::optional n, @@ -679,7 +679,7 @@ struct PullPlan { PullPlan::PullPlan(const std::shared_ptr 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 memory_limit) + ShardRequestManagerInterface *shard_request_manager, const std::optional 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>( + shard_request_manager_ = std::make_unique>( coordinator::CoordinatorClient( 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 *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, std::vector *notifications, - msgs::ShardRequestManagerInterface *shard_request_manager) { + ShardRequestManagerInterface *shard_request_manager) { // TriggerContextCollector *trigger_context_collector = nullptr) { auto *cypher_query = utils::Downcast(parsed_query.query); @@ -942,7 +942,7 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::map *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 *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 *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 *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 db_accessor_; std::optional execution_db_accessor_; - std::unique_ptr shard_request_manager_; + std::unique_ptr 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 nodes_info_; std::vector>> src_vertex_props_; std::vector primary_keys_; - msgs::ExecutionState state_; + ExecutionState state_; }; bool Once::OnceCursor::Pull(Frame &, ExecutionContext &context) { @@ -365,7 +365,7 @@ class ScanAllCursor : public Cursor { std::optional vertices_it_; const char *op_name_; std::vector current_batch; - msgs::ExecutionState request_state; + ExecutionState 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; + using State = ExecutionState; 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{}; + request_state_ = ExecutionState{}; } void Reset() override { @@ -444,7 +444,7 @@ class DistributedScanAllAndFilterCursor : public Cursor { const char *op_name_; std::vector current_batch; std::vector::iterator current_vertex_it; - msgs::ExecutionState request_state_; + ExecutionState request_state_; std::optional label_; std::optional> property_expression_pair_; std::optional> filter_expressions_; @@ -2426,7 +2426,7 @@ class DistributedCreateExpandCursor : public Cursor { const UniqueCursorPtr input_cursor_; const CreateExpand &self_; - msgs::ExecutionState state_; + ExecutionState 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 request_state; + ExecutionState 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 request_state; + ExecutionState 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(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(plan_root)->Accept(visitor); @@ -349,15 +349,15 @@ json ToJson(const utils::Bound &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> &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> 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(&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 &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> &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 &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 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 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 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 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 Request(ExecutionState &state) = 0; - virtual std::vector Request(ExecutionState &state, - std::vector new_vertices) = 0; - virtual std::vector Request(ExecutionState &state, - ExpandOneRequest request) = 0; - virtual std::vector Request(ExecutionState &state, - std::vector new_edges) = 0; + virtual std::vector Request(ExecutionState &state) = 0; + virtual std::vector Request(ExecutionState &state, + std::vector new_vertices) = 0; + virtual std::vector Request(ExecutionState &state, + msgs::ExpandOneRequest request) = 0; + virtual std::vector Request(ExecutionState &state, + std::vector 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 class ShardRequestManager : public ShardRequestManagerInterface { public: - using StorageClient = - memgraph::coordinator::RsmClient; - using CoordinatorWriteRequests = memgraph::coordinator::CoordinatorWriteRequests; - using CoordinatorClient = memgraph::coordinator::CoordinatorClient; - 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 &&io) + using StorageClient = coordinator::RsmClient; + using CoordinatorWriteRequests = coordinator::CoordinatorWriteRequests; + using CoordinatorClient = coordinator::CoordinatorClient; + 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 &&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(coordinator_write_response); + auto hlc_response = std::get(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(coordinator_write_response); + auto hlc_response = std::get(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(write_response_variant); + msgs::WriteResponses write_response_variant = commit_response.GetValue(); + auto &response = std::get(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 Request(ExecutionState &state) override { + std::vector Request(ExecutionState &state) override { MaybeInitializeExecutionState(state); - std::vector responses; + std::vector 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 Request(ExecutionState &state, - std::vector new_vertices) override { + std::vector Request(ExecutionState &state, + std::vector new_vertices) override { MG_ASSERT(!new_vertices.empty()); MaybeInitializeExecutionState(state, new_vertices); - std::vector responses; + std::vector responses; auto &shard_cache_ref = state.shard_cache; // 1. Send the requests. @@ -294,22 +291,22 @@ class ShardRequestManager : public ShardRequestManagerInterface { return responses; } - std::vector Request(ExecutionState &state, - std::vector new_edges) override { + std::vector Request(ExecutionState &state, + std::vector new_edges) override { MG_ASSERT(!new_edges.empty()); MaybeInitializeExecutionState(state, new_edges); - std::vector responses; + std::vector 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(response_variant); + msgs::WriteResponses response_variant = write_response_result.GetValue(); + msgs::CreateExpandResponse mapped_response = std::get(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 Request(ExecutionState &state, ExpandOneRequest request) override { + std::vector Request(ExecutionState &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 . The destination vertex and its properties // must be fetched again with an ExpandOne(Edges.dst) MaybeInitializeExecutionState(state, std::move(request)); - std::vector responses; + std::vector 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 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 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 PostProcess(std::vector &&responses) const { + std::vector PostProcess(std::vector &&responses) const { std::vector 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 &state, - std::vector new_vertices) { + void MaybeInitializeExecutionState(ExecutionState &state, + std::vector new_vertices) { ThrowIfStateCompleted(state); if (ShallNotInitializeState(state)) { return; } state.transaction_id = transaction_id_; - std::map per_shard_request_table; + std::map 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::EXECUTING; + state.state = ExecutionState::EXECUTING; } - void MaybeInitializeExecutionState(ExecutionState &state, std::vector new_expands) { + void MaybeInitializeExecutionState(ExecutionState &state, + std::vector new_expands) { ThrowIfStateCompleted(state); if (ShallNotInitializeState(state)) { return; } state.transaction_id = transaction_id_; - std::map per_shard_request_table; + std::map 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::EXECUTING; + state.state = ExecutionState::EXECUTING; } - void MaybeInitializeExecutionState(ExecutionState &state) { + void MaybeInitializeExecutionState(ExecutionState &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::EXECUTING; + state.state = ExecutionState::EXECUTING; } - void MaybeInitializeExecutionState(ExecutionState &state, ExpandOneRequest request) { + void MaybeInitializeExecutionState(ExecutionState &state, msgs::ExpandOneRequest request) { ThrowIfStateCompleted(state); if (ShallNotInitializeState(state)) { return; } state.transaction_id = transaction_id_; - std::map per_shard_request_table; + std::map 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::EXECUTING; + state.state = ExecutionState::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 &state) { + void SendAllRequests(ExecutionState &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 &state, + void SendAllRequests(ExecutionState &state, std::vector &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 &state, + void SendAllRequests(ExecutionState &state, std::vector &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 &state, std::vector &responses) { + void AwaitOnResponses(ExecutionState &state, + std::vector &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(response_variant); + msgs::WriteResponses response_variant = poll_result->GetValue(); + auto response = std::get(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 &state, std::vector &responses) { + void AwaitOnResponses(ExecutionState &state, + std::vector &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(response_variant); + msgs::ReadResponses response_variant = poll_result->GetValue(); + auto response = std::get(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 &state, - std::vector &responses, + void AwaitOnPaginatedRequests(ExecutionState &state, + std::vector &responses, std::map &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(read_response_variant); + msgs::ReadResponses read_response_variant = await_result->GetValue(); + auto response = std::get(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 storage_cli_manager_; - memgraph::io::Io io_; - memgraph::coordinator::Hlc transaction_id_; + io::Io 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 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 state; std::vector 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 state; std::vector 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 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 coordinator_client(cli_io, c_addrs[0], c_addrs); - msgs::ShardRequestManager io(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager 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 &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager &shard_request_manager, std::set &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 &shard_request_mana return; } - msgs::ExecutionState state; + query::v2::ExecutionState state; auto label_id = shard_request_manager.NameToLabel("test_label"); @@ -182,9 +182,9 @@ void ExecuteOp(msgs::ShardRequestManager &shard_request_mana correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(msgs::ShardRequestManager &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager &shard_request_manager, std::set &correctness_model, ScanAll scan_all) { - msgs::ExecutionState request{.label = "test_label"}; + query::v2::ExecutionState request{.label = "test_label"}; auto results = shard_request_manager.Request(request); @@ -247,7 +247,8 @@ std::pair RunClusterSimulation(const CoordinatorClient coordinator_client(cli_io, coordinator_address, {coordinator_address}); WaitForShardsToInitialize(coordinator_client); - msgs::ShardRequestManager shard_request_manager(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager 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 &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager &shard_request_manager, std::set &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 &shard_request_manager, return; } - msgs::ExecutionState state; + query::v2::ExecutionState state; auto label_id = shard_request_manager.NameToLabel("test_label"); @@ -192,9 +192,9 @@ void ExecuteOp(msgs::ShardRequestManager &shard_request_manager, correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(msgs::ShardRequestManager &shard_request_manager, +void ExecuteOp(query::v2::ShardRequestManager &shard_request_manager, std::set &correctness_model, ScanAll scan_all) { - msgs::ExecutionState request{.label = "test_label"}; + query::v2::ExecutionState 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 shard_request_manager(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager 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 void TestScanAll(ShardRequestManager &shard_request_manager) { - msgs::ExecutionState state{.label = kLabelName}; + query::v2::ExecutionState 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 state; + query::v2::ExecutionState state; std::vector 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 state; + query::v2::ExecutionState state; std::vector 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 state{}; +void TestExpandOne(query::v2::ShardRequestManagerInterface &shard_request_manager) { + query::v2::ExecutionState 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 coordinator_client(cli_io, coordinator_address, {coordinator_address}); - msgs::ShardRequestManager shard_request_manager(std::move(coordinator_client), std::move(cli_io)); + query::v2::ShardRequestManager 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 Date: Mon, 28 Nov 2022 10:09:59 +0000 Subject: [PATCH 10/16] 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 Date: Mon, 28 Nov 2022 13:38:12 +0200 Subject: [PATCH 11/16] 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 &)>" + const functions::FunctionContext &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp self->${member} = functions::NameToFunction, + functions::FunctionContext, functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(self->function_name_); cpp<#))) (:public @@ -869,7 +869,7 @@ cpp<# const std::vector &arguments) : arguments_(arguments), function_name_(function_name), - function_(functions::NameToFunction, + function_(functions::NameToFunction, 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 MaybeNameToProperty(const std::string &name) const = 0; virtual std::optional MaybeNameToEdgeType(const std::string &name) const = 0; virtual std::optional 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 Request( - memgraph::msgs::ExecutionState &state) override { + std::vector Request(ExecutionState &state) override { return {}; } - std::vector Request(memgraph::msgs::ExecutionState &state, + std::vector Request(ExecutionState &state, std::vector new_vertices) override { return {}; } - std::vector Request(memgraph::msgs::ExecutionState &state, - ExpandOneRequest request) override { + std::vector Request(ExecutionState &state, ExpandOneRequest request) override { return {}; } - std::vector Request(memgraph::msgs::ExecutionState &state, + std::vector Request(ExecutionState &state, std::vector new_edges) override { return {}; } @@ -218,7 +216,7 @@ class ExpressionEvaluatorTest : public ::testing::Test { SymbolTable symbol_table; Frame frame{128}; - std::unique_ptr shard_manager = + std::unique_ptr shard_manager = std::make_unique(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> 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> 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 Date: Mon, 28 Nov 2022 12:38:38 +0000 Subject: [PATCH 12/16] 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 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 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 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 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 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 Pull(TEncoder *encoder, std::optional n, std::optional 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 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 &values) { std::vector 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> props, - const ShardRequestManagerInterface *manager) + const RequestRouterInterface *manager) : vertex(std::move(v)), properties(std::move(props)), manager_(manager) {} -VertexAccessor::VertexAccessor(Vertex v, std::map &&props, - const ShardRequestManagerInterface *manager) +VertexAccessor::VertexAccessor(Vertex v, std::map &&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 &&props, } VertexAccessor::VertexAccessor(Vertex v, const std::map &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> props, - const ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, std::vector> props, const RequestRouterInterface *manager); - VertexAccessor(Vertex v, std::map &&props, const ShardRequestManagerInterface *manager); - VertexAccessor(Vertex v, const std::map &props, const ShardRequestManagerInterface *manager); + VertexAccessor(Vertex v, std::map &&props, const RequestRouterInterface *manager); + VertexAccessor(Vertex v, const std::map &props, const RequestRouterInterface *manager); [[nodiscard]] Label PrimaryLabel() const; @@ -150,7 +149,7 @@ class VertexAccessor final { private: Vertex vertex; std::vector> 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(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; +using ExpressionEvaluator = expr::ExpressionEvaluator; } // 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 NamesToProperties(const std::vector &property_names, - ShardRequestManagerInterface *shard_request_manager) { + RequestRouterInterface *request_router) { std::vector 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 NamesToLabels(const std::vector &label_names, - ShardRequestManagerInterface *shard_request_manager) { + RequestRouterInterface *request_router) { std::vector 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 MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector &predefined_identifiers) { auto vertex_counts = plan::MakeVertexCountCache(shard_manager); auto symbol_table = expr::MakeSymbolTable(query, predefined_identifiers); @@ -130,7 +130,7 @@ std::unique_ptr MakeLogicalPlan(AstStorage ast_storage, CypherQuery std::shared_ptr CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList *plan_cache, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector &predefined_identifiers) { std::optional::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 MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector &predefined_identifiers); /** @@ -145,7 +145,7 @@ std::unique_ptr MakeLogicalPlan(AstStorage ast_storage, CypherQuery */ std::shared_ptr CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList *plan_cache, - ShardRequestManagerInterface *shard_manager, + RequestRouterInterface *shard_manager, const std::vector &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 *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 *notifications) { expr::Frame 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 frame(0); SymbolTable symbol_table; EvaluationContext evaluation_context; @@ -649,7 +649,7 @@ struct PullPlanVector { struct PullPlan { explicit PullPlan(std::shared_ptr 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 memory_limit = {}); std::optional Pull(AnyStream *stream, std::optional n, @@ -679,7 +679,7 @@ struct PullPlan { PullPlan::PullPlan(const std::shared_ptr 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 memory_limit) + RequestRouterInterface *request_router, const std::optional 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 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>( + request_router_ = std::make_unique>( coordinator::CoordinatorClient( 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 *summary, InterpreterContext *interpreter_context, DbAccessor *dba, utils::MemoryResource *execution_memory, std::vector *notifications, - ShardRequestManagerInterface *shard_request_manager) { + RequestRouterInterface *request_router) { // TriggerContextCollector *trigger_context_collector = nullptr) { auto *cypher_query = utils::Downcast(parsed_query.query); @@ -890,8 +890,7 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::mapmemory_limit_, cypher_query->memory_scale_); if (memory_limit) { @@ -906,9 +905,9 @@ PreparedQuery PrepareCypherQuery(ParsedQuery parsed_query, std::mapplan_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(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 *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(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> printed_plan_rows; for (const auto &row : utils::Split(utils::RTrim(printed_plan.str()), "\n")) { printed_plan_rows.push_back(std::vector{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 *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(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{}, @@ -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(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 *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 *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(parsed_query.query) || utils::Downcast(parsed_query.query) || utils::Downcast(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(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(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(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(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(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(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(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(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(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(parsed_query.query)) { prepared_query = PrepareVersionQuery(std::move(parsed_query), in_explicit_transaction_); } else if (utils::Downcast(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 db_accessor_; std::optional execution_db_accessor_; - std::unique_ptr shard_request_manager_; + std::unique_ptr 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 NodeCreationInfoToRequest(ExecutionContext &context, Frame &frame) { @@ -218,7 +218,7 @@ class DistributedCreateNodeCursor : public Cursor { if (const auto *node_info_properties = std::get_if(&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(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(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 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 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(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(plan_root)->Accept(visitor); @@ -349,15 +348,15 @@ json ToJson(const utils::Bound &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> &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> 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(&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 &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> &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 &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 #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 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 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 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 -class ShardRequestManager : public ShardRequestManagerInterface { +class RequestRouter : public RequestRouterInterface { public: using StorageClient = coordinator::RsmClient; @@ -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 &&io) - : coord_cli_(std::move(coord)), io_(std::move(io)) {} + RequestRouter(CoordinatorClient coord, io::Io &&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 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 state; std::vector 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 state; std::vector 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 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 -void TestAggregate(ShardRequestManager &io) {} +template +void TestAggregate(RequestRouter &io) {} void DoTest() { SimulatorConfig config{ @@ -337,7 +337,7 @@ void DoTest() { // also get the current shard map CoordinatorClient coordinator_client(cli_io, c_addrs[0], c_addrs); - query::v2::ShardRequestManager io(std::move(coordinator_client), std::move(cli_io)); + query::v2::RequestRouter 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 &shard_request_manager, - std::set &correctness_model, CreateVertex create_vertex) { +void ExecuteOp(query::v2::RequestRouter &request_router, std::set &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 &shard_request query::v2::ExecutionState 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 &shard_request std::vector 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 &shard_request correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(query::v2::ShardRequestManager &shard_request_manager, - std::set &correctness_model, ScanAll scan_all) { +void ExecuteOp(query::v2::RequestRouter &request_router, std::set &correctness_model, + ScanAll scan_all) { query::v2::ExecutionState 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 RunClusterSimulation(const CoordinatorClient coordinator_client(cli_io, coordinator_address, {coordinator_address}); WaitForShardsToInitialize(coordinator_client); - query::v2::ShardRequestManager shard_request_manager(std::move(coordinator_client), - std::move(cli_io)); + query::v2::RequestRouter request_router(std::move(coordinator_client), std::move(cli_io)); - shard_request_manager.StartTransaction(); + request_router.StartTransaction(); auto correctness_model = std::set{}; 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 &shard_request_manager, - std::set &correctness_model, CreateVertex create_vertex) { +void ExecuteOp(query::v2::RequestRouter &request_router, std::set &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 &shard_request_man query::v2::ExecutionState 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 &shard_request_man std::vector 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 &shard_request_man correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second)); } -void ExecuteOp(query::v2::ShardRequestManager &shard_request_manager, - std::set &correctness_model, ScanAll scan_all) { +void ExecuteOp(query::v2::RequestRouter &request_router, std::set &correctness_model, + ScanAll scan_all) { query::v2::ExecutionState 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 shard_request_manager(std::move(coordinator_client), - std::move(cli_io)); + query::v2::RequestRouter request_router(std::move(coordinator_client), std::move(cli_io)); - shard_request_manager.StartTransaction(); + request_router.StartTransaction(); auto correctness_model = std::set{}; 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 #include #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 -void TestScanAll(ShardRequestManager &shard_request_manager) { +template +void TestScanAll(RequestRouter &request_router) { query::v2::ExecutionState 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 state; std::vector 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 state; std::vector 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 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 -void TestAggregate(ShardRequestManager &shard_request_manager) {} +template +void TestAggregate(RequestRouter &request_router) {} MachineManager MkMm(LocalSystem &local_system, std::vector
coordinator_addresses, Address addr, ShardMap shard_map) { @@ -226,14 +226,13 @@ TEST(MachineManager, BasicFunctionality) { CoordinatorClient coordinator_client(cli_io, coordinator_address, {coordinator_address}); - query::v2::ShardRequestManager shard_request_manager(std::move(coordinator_client), - std::move(cli_io)); + query::v2::RequestRouter 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 Date: Mon, 28 Nov 2022 13:03:07 +0000 Subject: [PATCH 13/16] 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> &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>{}, manager_); + return VertexAccessor(Vertex{edge.dst}, std::vector>{}, request_router_); } VertexAccessor EdgeAccessor::From() const { - return VertexAccessor(Vertex{edge.src}, std::vector>{}, manager_); + return VertexAccessor(Vertex{edge.src}, std::vector>{}, request_router_); } VertexAccessor::VertexAccessor(Vertex v, std::vector> 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 &&props, const RequestRouterInterface *manager) - : vertex(std::move(v)), manager_(manager) { +VertexAccessor::VertexAccessor(Vertex v, std::map &&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 &&props, co } VertexAccessor::VertexAccessor(Vertex v, const std::map &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> props, const RequestRouterInterface *manager); + VertexAccessor(Vertex v, std::vector> props, + const RequestRouterInterface *request_router); - VertexAccessor(Vertex v, std::map &&props, const RequestRouterInterface *manager); - VertexAccessor(Vertex v, const std::map &props, const RequestRouterInterface *manager); + VertexAccessor(Vertex v, std::map &&props, const RequestRouterInterface *request_router); + VertexAccessor(Vertex v, const std::map &props, const RequestRouterInterface *request_router); [[nodiscard]] Label PrimaryLabel() const; @@ -149,7 +150,7 @@ class VertexAccessor final { private: Vertex vertex; std::vector> 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(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 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 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>{}, manager)); + value.vertex_v, std::vector>{}, 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 MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector &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 MakeLogicalPlan(AstStorage ast_storage, CypherQuery std::shared_ptr CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList *plan_cache, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector &predefined_identifiers) { std::optional::Accessor> plan_cache_access; if (plan_cache) { @@ -146,7 +146,7 @@ std::shared_ptr CypherQueryToPlan(uint64_t hash, AstStorage ast_stor } auto plan = std::make_shared( - 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 MakeLogicalPlan(AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector &predefined_identifiers); /** @@ -145,7 +145,7 @@ std::unique_ptr MakeLogicalPlan(AstStorage ast_storage, CypherQuery */ std::shared_ptr CypherQueryToPlan(uint64_t hash, AstStorage ast_storage, CypherQuery *query, const Parameters ¶meters, utils::SkipList *plan_cache, - RequestRouterInterface *shard_manager, + RequestRouterInterface *request_router, const std::vector &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 *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 *notifications) { expr::Frame 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 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::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 *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(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 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 *notifications, InterpreterContext *interpreter_context, - RequestRouterInterface *manager) { + RequestRouterInterface *request_router) { if (in_explicit_transaction) { throw ReplicationModificationInMulticommandTxException(); } auto *replication_query = utils::Downcast(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{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(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{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(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(plan_root)->Accept(visitor); return visitor.output(); @@ -348,16 +348,16 @@ json ToJson(const utils::Bound &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> &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(&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(&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 &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> &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 &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 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 state; std::vector 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 state; std::vector 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 -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 coordinator_client(cli_io, c_addrs[0], c_addrs); - query::v2::RequestRouter io(std::move(coordinator_client), std::move(cli_io)); + query::v2::RequestRouter 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 Date: Mon, 28 Nov 2022 15:38:12 +0200 Subject: [PATCH 14/16] 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 #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> 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> 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(42))}}, shard_manager.get()); - auto edge = CreateEdge({{prop, Value(static_cast(43))}}, shard_manager.get()); + auto vertex = CreateVertex({{prop, Value(static_cast(42))}}, shard_manager.get(), {}); + auto edge = CreateEdge({{prop, Value(static_cast(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("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(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(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 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 Date: Mon, 28 Nov 2022 17:13:58 +0200 Subject: [PATCH 15/16] 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 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 Date: Tue, 29 Nov 2022 09:07:18 +0000 Subject: [PATCH 16/16] 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 &)>" + const functions::FunctionContext &)>" :scope :public :dont-save t :clone :copy :slk-load (lambda (member) #>cpp self->${member} = functions::NameToFunction, + functions::FunctionContext, functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(self->function_name_); cpp<#))) (:public @@ -869,7 +869,7 @@ cpp<# const std::vector &arguments) : arguments_(arguments), function_name_(function_name), - function_(functions::NameToFunction, + function_(functions::NameToFunction, functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(function_name_)) { if (!function_) { throw SemanticException("Function '{}' doesn't exist.", function_name);