Merge branch 'project-pineapples' of github.com:memgraph/memgraph into tyler_rename_ShardRequestManager_to_RequestRouter

This commit is contained in:
Tyler Neely 2022-11-29 08:57:28 +00:00
commit 9f10c3ea06
31 changed files with 3435 additions and 5325 deletions

View File

@ -99,7 +99,7 @@ jobs:
echo ${file} echo ${file}
if [[ ${file} == *.py ]]; then if [[ ${file} == *.py ]]; then
python3 -m black --check --diff ${file} python3 -m black --check --diff ${file}
python3 -m isort --check-only --diff ${file} python3 -m isort --check-only --profile "black" --diff ${file}
fi fi
done done

View File

@ -14,6 +14,7 @@ repos:
hooks: hooks:
- id: isort - id: isort
name: isort (python) name: isort (python)
args: ["--profile", "black"]
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: v13.0.0 rev: v13.0.0
hooks: hooks:

View File

@ -21,6 +21,7 @@ add_subdirectory(auth)
add_subdirectory(parser) add_subdirectory(parser)
add_subdirectory(expr) add_subdirectory(expr)
add_subdirectory(coordinator) add_subdirectory(coordinator)
add_subdirectory(functions)
if (MG_ENTERPRISE) if (MG_ENTERPRISE)
add_subdirectory(audit) add_subdirectory(audit)

View File

@ -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}/ast)
target_include_directories(mg-expr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/interpret) target_include_directories(mg-expr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/interpret)
target_include_directories(mg-expr PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/semantic) 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)

View File

@ -24,6 +24,7 @@
#include "expr/exceptions.hpp" #include "expr/exceptions.hpp"
#include "expr/interpret/frame.hpp" #include "expr/interpret/frame.hpp"
#include "expr/semantic/symbol_table.hpp" #include "expr/semantic/symbol_table.hpp"
#include "functions/awesome_memgraph_functions.hpp"
#include "utils/exceptions.hpp" #include "utils/exceptions.hpp"
namespace memgraph::expr { namespace memgraph::expr {
@ -427,8 +428,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
typename TReturnType = std::enable_if_t<std::is_same_v<TTag, QueryEngineTag>, bool>> typename TReturnType = std::enable_if_t<std::is_same_v<TTag, QueryEngineTag>, bool>>
TReturnType HasLabelImpl(const VertexAccessor &vertex, const LabelIx &label_ix, QueryEngineTag /*tag*/) { TReturnType HasLabelImpl(const VertexAccessor &vertex, const LabelIx &label_ix, QueryEngineTag /*tag*/) {
auto label = typename VertexAccessor::Label{LabelId::FromUint(label_ix.ix)}; auto label = typename VertexAccessor::Label{LabelId::FromUint(label_ix.ix)};
auto has_label = vertex.HasLabel(label); return vertex.HasLabel(label);
return !has_label;
} }
TypedValue Visit(LabelsTest &labels_test) override { TypedValue Visit(LabelsTest &labels_test) override {
@ -491,7 +491,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
} }
TypedValue Visit(Function &function) override { TypedValue Visit(Function &function) override {
FunctionContext function_ctx{dba_, ctx_->memory, ctx_->timestamp, &ctx_->counters, view_}; functions::FunctionContext<DbAccessor> function_ctx{dba_, ctx_->memory, ctx_->timestamp, &ctx_->counters, view_};
// Stack allocate evaluated arguments when there's a small number of them. // Stack allocate evaluated arguments when there's a small number of them.
if (function.arguments_.size() <= 8) { if (function.arguments_.size() <= 8) {
TypedValue arguments[8] = {TypedValue(ctx_->memory), TypedValue(ctx_->memory), TypedValue(ctx_->memory), TypedValue arguments[8] = {TypedValue(ctx_->memory), TypedValue(ctx_->memory), TypedValue(ctx_->memory),

View File

@ -0,0 +1 @@
add_library(mg-functions INTERFACE)

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@ set(mg_query_v2_sources
cypher_query_interpreter.cpp cypher_query_interpreter.cpp
frontend/semantic/required_privileges.cpp frontend/semantic/required_privileges.cpp
frontend/stripped.cpp frontend/stripped.cpp
interpret/awesome_memgraph_functions.cpp
interpreter.cpp interpreter.cpp
metadata.cpp metadata.cpp
plan/operator.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_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 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-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 "") if(NOT "${MG_PYTHON_PATH}" STREQUAL "")
set(Python3_ROOT_DIR "${MG_PYTHON_PATH}") set(Python3_ROOT_DIR "${MG_PYTHON_PATH}")

View File

@ -23,11 +23,12 @@ EdgeTypeId EdgeAccessor::EdgeType() const { return edge.type.id; }
const std::vector<std::pair<PropertyId, Value>> &EdgeAccessor::Properties() const { return edge.properties; } const std::vector<std::pair<PropertyId, Value>> &EdgeAccessor::Properties() const { return edge.properties; }
Value EdgeAccessor::GetProperty(const std::string &prop_name) const { Value EdgeAccessor::GetProperty(const std::string &prop_name) const {
auto prop_id = request_router_->NameToProperty(prop_name); auto maybe_prop = request_router_->MaybeNameToProperty(prop_name);
auto it = std::find_if(edge.properties.begin(), edge.properties.end(), [&](auto &pr) { return prop_id == pr.first; }); if (!maybe_prop) {
if (it == edge.properties.end()) {
return {}; return {};
} }
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; return it->second;
} }
@ -35,6 +36,8 @@ const Edge &EdgeAccessor::GetEdge() const { return edge; }
bool EdgeAccessor::IsCycle() const { return edge.src == edge.dst; }; bool EdgeAccessor::IsCycle() const { return edge.src == edge.dst; };
size_t EdgeAccessor::CypherId() const { return edge.id.gid; }
VertexAccessor EdgeAccessor::To() const { VertexAccessor EdgeAccessor::To() const {
return VertexAccessor(Vertex{edge.dst}, std::vector<std::pair<PropertyId, msgs::Value>>{}, request_router_); return VertexAccessor(Vertex{edge.dst}, std::vector<std::pair<PropertyId, msgs::Value>>{}, request_router_);
} }
@ -88,7 +91,11 @@ Value VertexAccessor::GetProperty(PropertyId prop_id) const {
// NOLINTNEXTLINE(readability-convert-member-functions-to-static) // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
Value VertexAccessor::GetProperty(const std::string &prop_name) const { Value VertexAccessor::GetProperty(const std::string &prop_name) const {
return GetProperty(request_router_->NameToProperty(prop_name)); auto maybe_prop = request_router_->MaybeNameToProperty(prop_name);
if (!maybe_prop) {
return {};
}
return GetProperty(*maybe_prop);
} }
msgs::Vertex VertexAccessor::GetVertex() const { return vertex; } msgs::Vertex VertexAccessor::GetVertex() const { return vertex; }

View File

@ -53,12 +53,7 @@ class EdgeAccessor final {
[[nodiscard]] bool IsCycle() const; [[nodiscard]] bool IsCycle() const;
// Dummy function [[nodiscard]] size_t CypherId() const;
// 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]] VertexAccessor To() const; [[nodiscard]] VertexAccessor To() const;
[[nodiscard]] VertexAccessor From() const; [[nodiscard]] VertexAccessor From() const;
@ -98,48 +93,11 @@ class VertexAccessor final {
[[nodiscard]] msgs::Vertex GetVertex() const; [[nodiscard]] msgs::Vertex GetVertex() const;
// Dummy function
// NOLINTNEXTLINE(readability-convert-member-functions-to-static) // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
[[nodiscard]] size_t CypherId() const { return 10; } [[nodiscard]] size_t InDegree() const { throw utils::NotYetImplemented("InDegree() not yet implemented"); }
// auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types) const // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
// -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> { [[nodiscard]] size_t OutDegree() const { throw utils::NotYetImplemented("OutDegree() not yet implemented"); }
// auto maybe_edges = impl_.InEdges(view, edge_types);
// if (maybe_edges.HasError()) return maybe_edges.GetError();
// return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
// }
//
// auto InEdges(storage::View view) const { return InEdges(view, {}); }
//
// auto InEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types, const VertexAccessor &dest)
// const
// -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
// auto maybe_edges = impl_.InEdges(view, edge_types, &dest.impl_);
// if (maybe_edges.HasError()) return maybe_edges.GetError();
// return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
// }
//
// auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types) const
// -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
// auto maybe_edges = impl_.OutEdges(view, edge_types);
// if (maybe_edges.HasError()) return maybe_edges.GetError();
// return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
// }
//
// auto OutEdges(storage::View view) const { return OutEdges(view, {}); }
//
// auto OutEdges(storage::View view, const std::vector<storage::EdgeTypeId> &edge_types,
// const VertexAccessor &dest) const
// -> storage::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
// auto maybe_edges = impl_.OutEdges(view, edge_types, &dest.impl_);
// if (maybe_edges.HasError()) return maybe_edges.GetError();
// return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
// }
// storage::Result<size_t> InDegree(storage::View view) const { return impl_.InDegree(view); }
//
// storage::Result<size_t> OutDegree(storage::View view) const { return impl_.OutDegree(view); }
//
friend bool operator==(const VertexAccessor &lhs, const VertexAccessor &rhs) { friend bool operator==(const VertexAccessor &lhs, const VertexAccessor &rhs) {
return lhs.vertex == rhs.vertex && lhs.properties == rhs.properties; return lhs.vertex == rhs.vertex && lhs.properties == rhs.properties;
@ -153,10 +111,6 @@ class VertexAccessor final {
const RequestRouterInterface *request_router_; const RequestRouterInterface *request_router_;
}; };
// 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. // Highly mocked interface. Won't work if used.
class Path { class Path {
public: public:
@ -197,7 +151,14 @@ class Path {
friend bool operator==(const Path & /*lhs*/, const Path & /*rhs*/) { return true; }; friend bool operator==(const Path & /*lhs*/, const Path & /*rhs*/) { return true; };
utils::MemoryResource *GetMemoryResource() { return mem; } 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: private:
std::vector<VertexAccessor> vertices_;
std::vector<EdgeAccessor> edges_;
utils::MemoryResource *mem = utils::NewDeleteResource(); utils::MemoryResource *mem = utils::NewDeleteResource();
}; };
} // namespace memgraph::query::v2::accessors } // namespace memgraph::query::v2::accessors

View File

@ -28,7 +28,6 @@ namespace memgraph::query::v2 {
class RequestRouterInterface; class RequestRouterInterface;
inline const auto lam = [](const auto &val) { return ValueToTypedValue(val); };
namespace detail { namespace detail {
class Callable { class Callable {
public: public:

View File

@ -56,6 +56,10 @@ inline TypedValue ValueToTypedValue(const msgs::Value &value, RequestRouterInter
throw std::runtime_error("Incorrect type in conversion"); throw std::runtime_error("Incorrect type in conversion");
} }
inline const auto ValueToTypedValueFunctor = [](const msgs::Value &value, RequestRouterInterface *request_router) {
return ValueToTypedValue(value, request_router);
};
inline msgs::Value TypedValueToValue(const TypedValue &value) { inline msgs::Value TypedValueToValue(const TypedValue &value) {
using Value = msgs::Value; using Value = msgs::Value;
switch (value.type()) { switch (value.type()) {

View File

@ -20,11 +20,13 @@
#include "query/v2/bindings/ast_visitor.hpp" #include "query/v2/bindings/ast_visitor.hpp"
#include "common/types.hpp" #include "common/types.hpp"
#include "query/v2/bindings/symbol.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/bindings/typed_value.hpp"
#include "query/v2/db_accessor.hpp" #include "query/v2/db_accessor.hpp"
#include "query/v2/path.hpp" #include "query/v2/path.hpp"
#include "query/v2/shard_request_manager.hpp"
#include "utils/typeinfo.hpp" #include "utils/typeinfo.hpp"
#include "query/v2/conversions.hpp"
cpp<# cpp<#
@ -836,13 +838,15 @@ cpp<#
:slk-load (slk-load-ast-vector "Expression")) :slk-load (slk-load-ast-vector "Expression"))
(function-name "std::string" :scope :public) (function-name "std::string" :scope :public)
(function "std::function<TypedValue(const TypedValue *, int64_t, (function "std::function<TypedValue(const TypedValue *, int64_t,
const FunctionContext &)>" const functions::FunctionContext<ShardRequestManagerInterface> &)>"
:scope :public :scope :public
:dont-save t :dont-save t
:clone :copy :clone :copy
:slk-load (lambda (member) :slk-load (lambda (member)
#>cpp #>cpp
self->${member} = query::v2::NameToFunction(self->function_name_); self->${member} = functions::NameToFunction<TypedValue,
functions::FunctionContext<ShardRequestManagerInterface>,
functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(self->function_name_);
cpp<#))) cpp<#)))
(:public (:public
#>cpp #>cpp
@ -865,7 +869,8 @@ cpp<#
const std::vector<Expression *> &arguments) const std::vector<Expression *> &arguments)
: arguments_(arguments), : arguments_(arguments),
function_name_(function_name), function_name_(function_name),
function_(NameToFunction(function_name_)) { function_(functions::NameToFunction<TypedValue, functions::FunctionContext<ShardRequestManagerInterface>,
functions::QueryEngineTag, decltype(ValueToTypedValueFunctor)>(function_name_)) {
if (!function_) { if (!function_) {
throw SemanticException("Function '{}' doesn't exist.", function_name); throw SemanticException("Function '{}' doesn't exist.", function_name);
} }

File diff suppressed because it is too large Load Diff

View File

@ -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 add_id_equal = [&](auto *maybe_id_fun, auto *val_expr) -> bool {
auto *id_fun = utils::Downcast<Function>(maybe_id_fun); auto *id_fun = utils::Downcast<Function>(maybe_id_fun);
if (!id_fun) return false; 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; if (id_fun->arguments_.size() != 1U) return false;
auto *ident = utils::Downcast<Identifier>(id_fun->arguments_.front()); auto *ident = utils::Downcast<Identifier>(id_fun->arguments_.front());
if (!ident) return false; if (!ident) return false;

View File

@ -125,9 +125,12 @@ class RequestRouterInterface {
virtual storage::v3::EdgeTypeId NameToEdgeType(const std::string &name) const = 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::PropertyId NameToProperty(const std::string &name) const = 0;
virtual storage::v3::LabelId NameToLabel(const std::string &name) const = 0; virtual storage::v3::LabelId NameToLabel(const std::string &name) const = 0;
virtual const std::string &PropertyToName(storage::v3::PropertyId prop) const = 0; virtual const std::string &PropertyToName(memgraph::storage::v3::PropertyId prop) const = 0;
virtual const std::string &LabelToName(storage::v3::LabelId label) const = 0; virtual const std::string &LabelToName(memgraph::storage::v3::LabelId label) const = 0;
virtual const std::string &EdgeTypeToName(storage::v3::EdgeTypeId type) const = 0; virtual const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId type) const = 0;
virtual std::optional<storage::v3::PropertyId> MaybeNameToProperty(const std::string &name) const = 0;
virtual std::optional<storage::v3::EdgeTypeId> MaybeNameToEdgeType(const std::string &name) const = 0;
virtual std::optional<storage::v3::LabelId> MaybeNameToLabel(const std::string &name) const = 0;
virtual bool IsPrimaryLabel(storage::v3::LabelId label) 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; virtual bool IsPrimaryKey(storage::v3::LabelId primary_label, storage::v3::PropertyId property) const = 0;
}; };
@ -351,6 +354,18 @@ class RequestRouter : public RequestRouterInterface {
return result_rows; return result_rows;
} }
std::optional<storage::v3::PropertyId> MaybeNameToProperty(const std::string &name) const override {
return shards_map_.GetPropertyId(name);
}
std::optional<storage::v3::EdgeTypeId> MaybeNameToEdgeType(const std::string &name) const override {
return shards_map_.GetEdgeTypeId(name);
}
std::optional<storage::v3::LabelId> MaybeNameToLabel(const std::string &name) const override {
return shards_map_.GetLabelId(name);
}
private: private:
enum class PaginatedResponseState { Pending, PartiallyFinished }; enum class PaginatedResponseState { Pending, PartiallyFinished };

View File

@ -31,4 +31,4 @@ target_link_libraries(mg-storage-v3 Threads::Threads mg-utils gflags)
target_include_directories(mg-storage-v3 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bindings) target_include_directories(mg-storage-v3 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bindings)
add_dependencies(mg-storage-v3 generate_lcp_storage) 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)

View File

@ -24,6 +24,8 @@
#include "storage/v3/conversions.hpp" #include "storage/v3/conversions.hpp"
#include "storage/v3/path.hpp" #include "storage/v3/path.hpp"
#include "utils/typeinfo.hpp" #include "utils/typeinfo.hpp"
#include "utils/exceptions.hpp"
#include "functions/awesome_memgraph_functions.hpp"
cpp<# cpp<#
@ -178,14 +180,6 @@ cpp<#
(:serialize (:slk :load-args '((storage "storage::v3::AstStorage *"))))) (:serialize (:slk :load-args '((storage "storage::v3::AstStorage *")))))
#>cpp #>cpp
struct FunctionContext {
DbAccessor *db_accessor;
utils::MemoryResource *memory;
int64_t timestamp;
std::unordered_map<std::string, int64_t> *counters;
View view;
};
inline bool operator==(const LabelIx &a, const LabelIx &b) { inline bool operator==(const LabelIx &a, const LabelIx &b) {
return a.ix == b.ix && a.name == b.name; return a.ix == b.ix && a.name == b.name;
} }
@ -845,16 +839,24 @@ cpp<#
:slk-load (slk-load-ast-vector "Expression")) :slk-load (slk-load-ast-vector "Expression"))
(function-name "std::string" :scope :public) (function-name "std::string" :scope :public)
(function "std::function<TypedValue(const TypedValue *, int64_t, (function "std::function<TypedValue(const TypedValue *, int64_t,
const FunctionContext &)>" const functions::FunctionContext<memgraph::storage::v3::DbAccessor> &)>"
:scope :public :scope :public
:dont-save t :dont-save t
:clone :copy :clone :copy
:slk-load (lambda (member) :slk-load (lambda (member)
#>cpp #>cpp
self->${member} = functions::NameToFunction<memgraph::storage::v3::TypedValue,
functions::FunctionContext<memgraph::storage::v3::DbAccessor>,
functions::StorageEngineTag, Conv>(self->function_name_);
cpp<#))) cpp<#)))
(:public (:public
#>cpp #>cpp
Function() = default; Function() = default;
using Conv = decltype(PropertyToTypedValueFunctor<TypedValue>);
class SemanticException : public memgraph::utils::BasicException {
using utils::BasicException::BasicException;
};
DEFVISITABLE(ExpressionVisitor<TypedValue>); DEFVISITABLE(ExpressionVisitor<TypedValue>);
DEFVISITABLE(ExpressionVisitor<void>); DEFVISITABLE(ExpressionVisitor<void>);
@ -872,7 +874,13 @@ cpp<#
Function(const std::string &function_name, Function(const std::string &function_name,
const std::vector<Expression *> &arguments) const std::vector<Expression *> &arguments)
: arguments_(arguments), : arguments_(arguments),
function_name_(function_name) { function_name_(function_name),
function_(functions::NameToFunction<memgraph::storage::v3::TypedValue,
functions::FunctionContext<memgraph::storage::v3::DbAccessor>,
functions::StorageEngineTag, Conv>(function_name_)) {
if (!function_) {
throw SemanticException("Function '{}' doesn't exist.", function_name);
}
} }
cpp<#) cpp<#)
(:private (:private

View File

@ -88,7 +88,7 @@ class DbAccessor final {
} }
storage::v3::ShardResult<std::optional<EdgeAccessor>> RemoveEdge(EdgeAccessor *edge) { storage::v3::ShardResult<std::optional<EdgeAccessor>> RemoveEdge(EdgeAccessor *edge) {
auto res = accessor_->DeleteEdge(edge->FromVertex(), edge->ToVertex(), edge->Gid()); auto res = accessor_->DeleteEdge(edge->From(), edge->To(), edge->Gid());
if (res.HasError()) { if (res.HasError()) {
return res.GetError(); return res.GetError();
} }

View File

@ -69,6 +69,10 @@ TTypedValue PropertyToTypedValue(const PropertyValue &value) {
LOG_FATAL("Unsupported type"); LOG_FATAL("Unsupported type");
} }
template <typename TypedValueT>
inline const auto PropertyToTypedValueFunctor =
[](const PropertyValue &value) { return PropertyToTypedValue<TypedValueT>(value); };
template <typename TTypedValue> template <typename TTypedValue>
TTypedValue PropertyToTypedValue(const PropertyValue &value, utils::MemoryResource *mem) { TTypedValue PropertyToTypedValue(const PropertyValue &value, utils::MemoryResource *mem) {
switch (value.type()) { switch (value.type()) {

View File

@ -51,9 +51,9 @@ bool EdgeAccessor::IsVisible(const View view) const {
return exists && (for_deleted_ || !deleted); 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_; }
ShardResult<PropertyValue> EdgeAccessor::SetProperty(PropertyId property, const PropertyValue &value) { ShardResult<PropertyValue> EdgeAccessor::SetProperty(PropertyId property, const PropertyValue &value) {
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception; utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
@ -180,4 +180,7 @@ ShardResult<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View v
return std::move(properties); return std::move(properties);
} }
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
size_t EdgeAccessor::CypherId() const { return Gid().AsUint(); }
} // namespace memgraph::storage::v3 } // namespace memgraph::storage::v3

View File

@ -48,9 +48,9 @@ class EdgeAccessor final {
/// @return true if the object is visible from the current transaction /// @return true if the object is visible from the current transaction
bool IsVisible(View view) const; 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_; } EdgeTypeId EdgeType() const { return edge_type_; }
@ -84,6 +84,9 @@ class EdgeAccessor final {
} }
bool operator!=(const EdgeAccessor &other) const noexcept { return !(*this == other); } bool operator!=(const EdgeAccessor &other) const noexcept { return !(*this == other); }
// Dummy function
size_t CypherId() const;
private: private:
EdgeRef edge_; EdgeRef edge_;
EdgeTypeId edge_type_; EdgeTypeId edge_type_;

View File

@ -52,13 +52,12 @@ msgs::Value ConstructValueEdge(const EdgeAccessor &acc, View view) {
msgs::EdgeType type = {.id = acc.EdgeType()}; msgs::EdgeType type = {.id = acc.EdgeType()};
msgs::EdgeId gid = {.gid = acc.Gid().AsUint()}; 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 = 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::Label dst_prim_label = {.id = acc.To().primary_label};
msgs::VertexId dst_vertex = msgs::VertexId dst_vertex = std::make_pair(dst_prim_label, conversions::ConvertValueVector(acc.To().primary_key));
std::make_pair(dst_prim_label, conversions::ConvertValueVector(acc.ToVertex().primary_key));
auto properties = acc.Properties(view); auto properties = acc.Properties(view);

View File

@ -257,7 +257,7 @@ EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbo
case msgs::EdgeDirection::OUT: { case msgs::EdgeDirection::OUT: {
is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set, is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set,
const storage::v3::EdgeAccessor &edge_acc) { 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; return insertion_happened;
}; };
break; break;
@ -265,7 +265,7 @@ EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbo
case msgs::EdgeDirection::IN: { case msgs::EdgeDirection::IN: {
is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set, is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set,
const storage::v3::EdgeAccessor &edge_acc) { 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; return insertion_happened;
}; };
break; break;
@ -311,8 +311,8 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) {
value_properties.insert(std::make_pair(prop_key, FromPropertyValueToValue(std::move(prop_val)))); value_properties.insert(std::make_pair(prop_key, FromPropertyValueToValue(std::move(prop_val))));
} }
using EdgeWithAllProperties = msgs::ExpandOneResultRow::EdgeWithAllProperties; using EdgeWithAllProperties = msgs::ExpandOneResultRow::EdgeWithAllProperties;
EdgeWithAllProperties edges{ToMsgsVertexId(edge.FromVertex()), msgs::EdgeType{edge.EdgeType()}, EdgeWithAllProperties edges{ToMsgsVertexId(edge.From()), msgs::EdgeType{edge.EdgeType()}, edge.Gid().AsUint(),
edge.Gid().AsUint(), std::move(value_properties)}; std::move(value_properties)};
if (is_in_edge) { if (is_in_edge) {
result_row.in_edges_with_all_properties.push_back(std::move(edges)); result_row.in_edges_with_all_properties.push_back(std::move(edges));
} else { } else {
@ -336,7 +336,7 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) {
value_properties.emplace_back(FromPropertyValueToValue(std::move(property_result.GetValue()))); value_properties.emplace_back(FromPropertyValueToValue(std::move(property_result.GetValue())));
} }
using EdgeWithSpecificProperties = msgs::ExpandOneResultRow::EdgeWithSpecificProperties; 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)}; edge.Gid().AsUint(), std::move(value_properties)};
if (is_in_edge) { if (is_in_edge) {
result_row.in_edges_with_specific_properties.push_back(std::move(edges)); result_row.in_edges_with_specific_properties.push_back(std::move(edges));

View File

@ -442,7 +442,7 @@ ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>>
for (const auto &item : in_edges) { for (const auto &item : in_edges) {
auto [edge_type, from_vertex, edge] = item; auto [edge_type, from_vertex, edge] = item;
EdgeAccessor e(edge, edge_type, from_vertex, vertex_id, transaction_, &shard_->indices_, config_); 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()) { if (ret.HasError()) {
MG_ASSERT(ret.GetError() == common::ErrorCode::SERIALIZATION_ERROR, "Invalid database state!"); MG_ASSERT(ret.GetError() == common::ErrorCode::SERIALIZATION_ERROR, "Invalid database state!");
return ret.GetError(); return ret.GetError();
@ -455,7 +455,7 @@ ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>>
for (const auto &item : out_edges) { for (const auto &item : out_edges) {
auto [edge_type, to_vertex, edge] = item; auto [edge_type, to_vertex, edge] = item;
EdgeAccessor e(edge, edge_type, vertex_id, to_vertex, transaction_, &shard_->indices_, config_); 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()) { if (ret.HasError()) {
MG_ASSERT(ret.GetError() == common::ErrorCode::SERIALIZATION_ERROR, "Invalid database state!"); MG_ASSERT(ret.GetError() == common::ErrorCode::SERIALIZATION_ERROR, "Invalid database state!");
return ret.GetError(); return ret.GetError();

View File

@ -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(distinct.py)
distributed_queries_e2e_python_files(optional_match.py) distributed_queries_e2e_python_files(optional_match.py)
distributed_queries_e2e_python_files(common.py) distributed_queries_e2e_python_files(common.py)
distributed_queries_e2e_python_files(awesome_memgraph_functions.py)

View File

@ -0,0 +1,93 @@
# 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 mgclient
import pytest
from common import (
connection,
execute_and_fetch_all,
has_n_result_row,
wait_for_shard_manager_to_initialize,
)
def test_awesome_memgraph_functions(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"]))

View File

@ -36,3 +36,8 @@ workloads:
binary: "tests/e2e/pytest_runner.sh" binary: "tests/e2e/pytest_runner.sh"
args: ["distributed_queries/optional_match.py"] args: ["distributed_queries/optional_match.py"]
<<: *template_cluster <<: *template_cluster
- name: "Awesome memgraph functions"
binary: "tests/e2e/pytest_runner.sh"
args: ["distributed_queries/awesome_memgraph_functions.py"]
<<: *template_cluster

View File

@ -406,3 +406,7 @@ target_link_libraries(${test_prefix}coordinator_shard_map mg-coordinator)
# Tests for many shards, many creates, scan # Tests for many shards, many creates, scan
add_unit_test(high_density_shard_create_scan.cpp) 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) 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)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff